@decaf-ts/for-fabric 0.1.62 → 0.1.63
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 +2744 -2
- package/dist/for-fabric.js +2833 -2
- package/lib/bin/cli.cjs +2 -1
- package/lib/cli-module.cjs +50 -29
- package/lib/cli-utils.cjs +64 -2
- package/lib/cli-utils.d.ts +2 -0
- 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 +1 -1
- package/lib/client/indexes/generation.cjs +1 -1
- package/lib/client/indexes/index.cjs +1 -1
- package/lib/client/logging.cjs +1 -1
- package/lib/client/services/FabricEnrollmentService.cjs +1 -1
- package/lib/client/services/FabricIdentityService.cjs +1 -1
- package/lib/client/services/RegistrationRequestBuilder.cjs +1 -1
- package/lib/client/services/constants.cjs +1 -1
- package/lib/client/services/index.cjs +1 -1
- package/lib/client/types.cjs +1 -1
- package/lib/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/OtherProductContract.cjs +1 -1
- package/lib/contract/OtherProductSharedContract.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/OtherProduct.cjs +1 -1
- package/lib/contract/models/OtherProductShared.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/overrides.cjs +1 -1
- package/lib/contracts/private-data.cjs +1 -1
- package/lib/contracts/types.cjs +1 -1
- package/lib/contracts/uuid.cjs +1 -1
- package/lib/esm/bin/cli.js +1 -1
- package/lib/esm/cli-module.js +51 -30
- package/lib/esm/cli-utils.d.ts +2 -0
- package/lib/esm/cli-utils.js +60 -2
- 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.js +1 -1
- package/lib/esm/client/indexes/generation.js +1 -1
- package/lib/esm/client/indexes/index.js +1 -1
- package/lib/esm/client/logging.js +1 -1
- package/lib/esm/client/services/FabricEnrollmentService.js +1 -1
- package/lib/esm/client/services/FabricIdentityService.js +1 -1
- package/lib/esm/client/services/RegistrationRequestBuilder.js +1 -1
- package/lib/esm/client/services/constants.js +1 -1
- package/lib/esm/client/services/index.js +1 -1
- package/lib/esm/client/types.js +1 -1
- package/lib/esm/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/OtherProductContract.js +1 -1
- package/lib/esm/contract/OtherProductSharedContract.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/OtherProduct.js +1 -1
- package/lib/esm/contract/models/OtherProductShared.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/overrides.js +1 -1
- package/lib/esm/contracts/private-data.js +1 -1
- package/lib/esm/contracts/types.js +1 -1
- package/lib/esm/contracts/uuid.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 +3 -3
- 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/OtherProductContract.js.map +0 -1
- package/lib/contract/OtherProductSharedContract.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/OtherProduct.js.map +0 -1
- package/lib/contract/models/OtherProductShared.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/overrides.js.map +0 -1
- package/lib/contracts/private-data.js.map +0 -1
- package/lib/contracts/types.js.map +0 -1
- package/lib/contracts/uuid.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/OtherProductContract.js.map +0 -1
- package/lib/esm/contract/OtherProductSharedContract.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/OtherProduct.js.map +0 -1
- package/lib/esm/contract/models/OtherProductShared.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/overrides.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/contracts/uuid.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,2744 @@
|
|
|
1
|
-
var e,t;e=this,t=function(e,t,r,i,a,n,s,o,c,l,d,u,h,p,g,f,y,m,w){"use strict";function b(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function C(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach(r=>{if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:()=>e[r]})}}),t.default=e,Object.freeze(t)}var E=b(o),A=b(u),v=C(h),S=C(g),_=b(f),I=b(y),M=b(m);class x extends t.Repository{constructor(e,t){super(e,t),this._overrides=Object.assign({},super._overrides,{ignoreValidation:!0,ignoreHandlers:!0,allowRawStatements:!1,forcePrepareSimpleQueries:!0,forcePrepareComplexQueries:!0,allowGenerationOverride:!1})}async paginateBy(e,i,a={offset:1,limit:10},...n){const{log:s,ctxArgs:o}=(await this.logCtx(n,t.PreparedStatementKeys.PAGE_BY,!0)).for(this.paginateBy);return s.verbose(`paginating ${r.Model.tableName(this.class)} with page size ${a.limit}`),this.statement(this.paginateBy.name,e,i,{limit:a.limit,offset:a.offset,bookmark:a.bookmark},...o)}async listBy(e,i,...a){const{log:n,ctxArgs:s}=(await this.logCtx(a,t.PreparedStatementKeys.LIST_BY,!0)).for(this.listBy);return n.verbose(`listing ${r.Model.tableName(this.class)} by ${e} ${i}`),await this.statement(this.listBy.name,e,i,...s)}async findBy(e,i,...a){const{log:n,ctxArgs:s}=(await this.logCtx(a,t.PreparedStatementKeys.FIND_BY,!0)).for(this.findBy);return n.verbose(`finding all ${r.Model.tableName(this.class)} with ${e} ${i}`),await this.statement(this.findBy.name,e,i,...s)}async findOneBy(e,i,...a){const{log:n,ctxArgs:s}=(await this.logCtx(a,t.PreparedStatementKeys.FIND_ONE_BY,!0)).for(this.findOneBy);return n.verbose(`finding One ${r.Model.tableName(this.class)} with ${e} ${i}`),await this.statement(this.findOneBy.name,e,i,...s)}async statement(e,...i){const{log:n,ctx:s,ctxArgs:o}=(await this.logCtx(i,t.PersistenceKeys.STATEMENT,!0)).for(this.statement);n.verbose("Executing prepared statement "+e);const c=o.slice(0,-1),l=JSON.parse(this.adapter.decode(await this.adapter.evaluateTransaction(s,t.PersistenceKeys.STATEMENT,[e,JSON.stringify(c)],void 0,void 0,this.class.name)));return Array.isArray(l)?l.map(e=>e[a.CouchDBKeys.TABLE]&&e[a.CouchDBKeys.TABLE]===r.Model.tableName(this.class)?new this.class(e):e):l[a.CouchDBKeys.TABLE]&&l[a.CouchDBKeys.TABLE]===r.Model.tableName(this.class)?new this.class(l):t.Paginator.isSerializedPage(l)?Object.assign(l,{data:l.data.map(e=>new this.class(e))}):l}async create(e,...t){const{ctx:i,log:a,ctxArgs:n}=this.logCtx(t,this.create);a.debug(`Creating new ${this.class.name} in table ${r.Model.tableName(this.class)}`);let{record:s,id:o,transient:c}=this.adapter.prepare(e,i);return s=await this.adapter.create(this.class,o,s,c,...n),this.adapter.revert(s,this.class,o,c,i)}async update(e,...t){const{ctxArgs:i,log:a,ctx:n}=this.logCtx(t,this.update);let{record:s,id:o,transient:c}=this.adapter.prepare(e,n);return a.debug(`updating ${this.class.name} in table ${r.Model.tableName(this.class)} with id ${o}`),s=await this.adapter.update(this.class,o,s,c,...i),this.adapter.revert(s,this.class,o,c,n)}async createAllPrefix(e,...t){const{ctx:r,ctxArgs:a}=(await this.logCtx(t,i.OperationKeys.CREATE,!0)).for(this.createAllPrefix),n=r.get("ignoreHandlers"),s=r.get("ignoreValidation");if(!e.length)return[e,...a];if(e=await Promise.all(e.map(async e=>(e=new this.class(e),n||await i.enforceDBDecorators(this,r,e,i.OperationKeys.CREATE,i.OperationKeys.ON),e))),!s){const t=r.get("ignoredValidationProperties")||[],a=await Promise.all(e.map(e=>Promise.resolve(e.hasErrors(...t)))),n=i.reduceErrorsToPrint(a);if(n)throw new i.ValidationError(n)}return[e,...a]}async createAll(e,...t){if(!e.length)return e;const{ctx:i,log:a,ctxArgs:n}=this.logCtx(t,this.createAll);a.debug(`Creating ${e.length} new ${this.class.name} in table ${r.Model.tableName(this.class)}`);const s=e.map(e=>this.adapter.prepare(e,i)),o=s.map(e=>e.id);let c=s.map(e=>e.record);const l=s.map(e=>e.transient);return c=await this.adapter.createAll(this.class,o,c,l,...n),c.map((e,t)=>this.adapter.revert(e,this.class,o[t],i.get("rebuildWithTransient")?s[t].transient:void 0,i))}async updateAll(e,...t){const{ctx:i,log:a,ctxArgs:n}=this.logCtx(t,this.updateAll);a.debug(`Updating ${e.length} new ${this.class.name} in table ${r.Model.tableName(this.class)}`);const s=e.map(e=>this.adapter.prepare(e,i));return(await this.adapter.updateAll(this.class,s.map(e=>e.id),s.map(e=>e.record),s.map(e=>e.transient),...n)).map((e,t)=>this.adapter.revert(e,this.class,s[t].id,i.get("rebuildWithTransient")?s[t].transient:void 0,i))}}let O=class extends t.BaseModel{constructor(e){super(e)}};n.__decorate([t.pk({type:String}),n.__metadata("design:type",String)],O.prototype,"name",void 0),n.__decorate([t.column(),r.required(),n.__metadata("design:type",String)],O.prototype,"owner",void 0),n.__decorate([t.column(),r.required(),n.__metadata("design:type",String)],O.prototype,"symbol",void 0),n.__decorate([t.column(),r.required(),n.__metadata("design:type",Number)],O.prototype,"decimals",void 0),O=n.__decorate([t.table("erc20_tokens"),r.model(),n.__metadata("design:paramtypes",[Object])],O);let N=class extends t.BaseModel{constructor(e){super(e)}};n.__decorate([t.pk({type:String}),n.__metadata("design:type",String)],N.prototype,"id",void 0),n.__decorate([t.column(),r.required(),n.__metadata("design:type",String)],N.prototype,"token",void 0),n.__decorate([t.column(),r.required(),n.__metadata("design:type",Number)],N.prototype,"balance",void 0),n.__decorate([t.column(),n.__metadata("design:type",String)],N.prototype,"captive",void 0),N=n.__decorate([t.table("erc20_wallets"),r.model(),n.__metadata("design:paramtypes",[Object])],N);let T=class extends t.BaseModel{constructor(e){super(e)}};n.__decorate([t.pk({type:String}),t.column(),r.required(),n.__metadata("design:type",String)],T.prototype,"owner",void 0),n.__decorate([t.column(),r.required(),n.__metadata("design:type",String)],T.prototype,"spender",void 0),n.__decorate([t.column(),r.required(),n.__metadata("design:type",Number)],T.prototype,"value",void 0),T=n.__decorate([t.table("erc20_allowances"),r.model(),n.__metadata("design:paramtypes",[Object])],T);class F extends r.JSONSerializer{constructor(){super()}preSerialize(e,t){const a=Object.assign({},e);let n=s.Metadata.modelName(e.constructor);if(!n||"Object"===n){if(!t)throw new i.SerializationError("Could not find metadata for "+e.constructor.name);n=t}return a[r.ModelKeys.ANCHOR]=n,a}deserialize(e){const t=JSON.parse(e),i=t[r.ModelKeys.ANCHOR];if(!i)throw Error("Could not find class reference in serialized model");return r.Model.build(t,i)}serialize(e,t){return JSON.stringify(this.preSerialize(e,t))}}class R extends x{static{this.serializer=new F}static{this.decoder=new TextDecoder("utf8")}async updateObservers(e,a,n,...s){if(!this.observerHandler)throw new i.InternalError("ObserverHandler not initialized. Did you register any observables?");const{log:o,ctxArgs:c}=this.logCtx(s,this.updateObservers);let l;o.verbose(`Updating ${this.observerHandler.count()} observers for ${this}`),e="string"==typeof e?r.Model.get(e):e,l=void 0===n?void 0:Array.isArray(n)?n.map(i=>t.Sequence.parseValue(r.Model.sequenceFor(e).type,i)):t.Sequence.parseValue(r.Model.sequenceFor(e).type,n),await this.observerHandler.updateObservers(e,a,l,...c)}decode(e){return R.decoder.decode(e)}constructor(e){super(e,N),this.serializer=R.serializer}async tokenName(...e){const{ctx:t}=(await this.logCtx(e,"tokenName",!0)).for(this.tokenName),r=await this.adapter.evaluateTransaction(t,"TokenName");return this.decode(r)}async symbol(...e){const{ctx:t}=(await this.logCtx(e,"symbol",!0)).for(this.symbol),r=await this.adapter.evaluateTransaction(t,"Symbol");return this.decode(r)}async decimals(...e){const{ctx:t}=(await this.logCtx(e,"decimals",!0)).for(this.decimals),r=await this.adapter.evaluateTransaction(t,"Decimals");return Number(this.decode(r))}async totalSupply(...e){const{ctx:t}=(await this.logCtx(e,"totalSupply",!0)).for(this.totalSupply),r=await this.adapter.evaluateTransaction(t,"TotalSupply");return Number(this.decode(r))}async balanceOf(e,...t){const{ctx:r}=(await this.logCtx(t,"balance",!0)).for(this.balanceOf),i=await this.adapter.evaluateTransaction(r,"BalanceOf",[e]);return Number(this.decode(i))}async transfer(e,t,...r){const{ctx:i}=(await this.logCtx(r,"transfer",!0)).for(this.transfer),a=await this.adapter.submitTransaction(i,"Transfer",[e,t.toString()]);return"true"===this.decode(a)}async transferFrom(e,r,i){const a=await t.Context.args("transferFrom",this.class,[],this.adapter,this._overrides||{}),{ctx:n}=this.logCtx(a.args,this.transferFrom),s=await this.adapter.submitTransaction(n,"TransferFrom",[e,r,i.toString()]);return"true"===this.decode(s)}async approve(e,r){const i=await t.Context.args("approve",this.class,[],this.adapter,this._overrides||{}),{ctx:a}=this.logCtx(i.args,this.approve),n=await this.adapter.submitTransaction(a,"Approve",[e,r.toString()]);return"true"===this.decode(n)}async allowance(e,r){const i=await t.Context.args("allowance",this.class,[],this.adapter,this._overrides||{}),{ctx:a}=this.logCtx(i.args,this.allowance),n=await this.adapter.submitTransaction(a,"Allowance",[e,r]);return Number(this.decode(n))}async initialize(e){const r=await t.Context.args("initialize",this.class,[],this.adapter,this._overrides||{}),{ctx:i}=this.logCtx(r.args,this.initialize),a=await this.adapter.submitTransaction(i,"Initialize",[R.serializer.serialize(e)]);return"true"===this.decode(a)}async checkInitialized(){const e=await t.Context.args("checkInitialized",this.class,[],this.adapter,this._overrides||{}),{ctx:r}=this.logCtx(e.args,this.checkInitialized);await this.adapter.evaluateTransaction(r,"CheckInitialized")}async mint(e){const r=await t.Context.args("mint",this.class,[],this.adapter,this._overrides||{}),{ctx:i}=this.logCtx(r.args,this.mint);await this.adapter.submitTransaction(i,"Mint",[e.toString()])}async burn(e){const r=await t.Context.args("burn",this.class,[],this.adapter,this._overrides||{}),{ctx:i}=this.logCtx(r.args,this.burn);await this.adapter.submitTransaction(i,"Burn",[e.toString()])}async burnFrom(e,r){const i=await t.Context.args("burnFrom",this.class,[],this.adapter,this._overrides||{}),{ctx:a}=this.logCtx(i.args,this.burnFrom);await this.adapter.submitTransaction(a,"BurnFrom",[e,r.toString()])}async clientAccountBalance(){const e=await t.Context.args("accountBalance",this.class,[],this.adapter,this._overrides||{}),{ctx:r}=this.logCtx(e.args,this.clientAccountBalance),i=await this.adapter.evaluateTransaction(r,"ClientAccountBalance");return Number(this.decode(i))}async clientAccountID(){const e=await t.Context.args("accountId",this.class,[],this.adapter,this._overrides||{}),{ctx:r}=this.logCtx(e.args,this.clientAccountID),i=await this.adapter.evaluateTransaction(r,"ClientAccountID");return this.decode(i)}}function B(e,t,r){return[...e.map(e=>e===a.CouchDBKeys.TABLE?"table":e),...r||[],...t?[t]:[],"index"].join(s.Metadata.splitter)}function $(e,t,r,i){const n=t.pop();n&&n!==a.CouchDBKeys.TABLE?t.push(n):n===a.CouchDBKeys.TABLE&&t.unshift(n);const s=B(t,r,i);let o=[...t,...i||[]];r&&(o=o.reduce((e,t)=>{const i={};return i[t]=r,e.push(i),e},[]));const c={index:{fields:o},name:s,ddoc:s,type:"json"};e[s]=c}function K(e){const t=require("path"),i=require(t.join(process.cwd(),e.parentPath,e.name));return Object.values(i).filter(e=>{try{return new e instanceof r.Model}catch(e){return!1}})}var P;e.IdentityCredentials=class extends t.BaseModel{constructor(e){super(e)}},n.__decorate([s.description("Unique identifier of the credentials record"),t.column(),t.pk(),n.__metadata("design:type",String)],e.IdentityCredentials.prototype,"id",void 0),n.__decorate([s.description("PEM-encoded X.509 certificate for the identity"),t.column(),r.required(),n.__metadata("design:type",String)],e.IdentityCredentials.prototype,"certificate",void 0),n.__decorate([s.description("PEM-encoded root or intermediate certificate"),t.column(),r.required(),n.__metadata("design:type",String)],e.IdentityCredentials.prototype,"rootCertificate",void 0),n.__decorate([s.description("PEM-encoded private key"),t.column(),r.required(),n.__metadata("design:type",String)],e.IdentityCredentials.prototype,"privateKey",void 0),e.IdentityCredentials=n.__decorate([r.model(),n.__metadata("design:paramtypes",[Object])],e.IdentityCredentials),e.FabricModelKeys=void 0,(P=e.FabricModelKeys||(e.FabricModelKeys={})).PRIVATE="private",P.SHARED="shared",P.FABRIC="fabric",P.OWNED_BY="owned-by",P.TRANSACTION_ID="transaction-id",P.MIRROR="mirror",e.IdentityType=void 0,(e.IdentityType||(e.IdentityType={})).X509="X.509";const k="hlf-fabric";e.Identity=class extends t.BaseModel{constructor(t){super(t),this.type=e.IdentityType.X509}},n.__decorate([s.description("Unique identifier of the identity"),t.pk(),n.__metadata("design:type",String)],e.Identity.prototype,"id",void 0),n.__decorate([t.oneToOne(e.IdentityCredentials,{update:t.Cascade.CASCADE,delete:t.Cascade.CASCADE}),n.__metadata("design:type",e.IdentityCredentials)],e.Identity.prototype,"credentials",void 0),n.__decorate([t.column(),r.required(),t.index(),n.__metadata("design:type",String)],e.Identity.prototype,"mspId",void 0),n.__decorate([t.column(),r.required(),n.__metadata("design:type",String)],e.Identity.prototype,"type",void 0),e.Identity=n.__decorate([r.model(),n.__metadata("design:paramtypes",[Object])],e.Identity);class z{static{this.logger=new c.MiniLogger(z.name)}constructor(){}static async contentOfLoadFile(e,t){return e instanceof Uint8Array||e.match(/-----BEGIN (CERTIFICATE|KEY|PRIVATE KEY)-----.+?-----END \1-----$/gms)?e:await t(e)}static async readFile(e){return"string"!=typeof e?e:await(async e=>{const{promises:r}=await t.normalizeImport(import("fs"));return await r.readFile(e)})(e)}static async getCAUser(e,t,i,a,n){this.logger.debug(r.stringFormat("Creating CA {0} user {1} with certificate {2}",a,e,i));const s=new d.User(e),o=n?.hsm?{software:!1,lib:n.hsm.library,slot:n.hsm.slot,label:n.hsm.tokenLabel,pin:n.hsm.pin+""}:void 0,c=this.getCryptoSuite(o);s.setCryptoSuite(c);const l=n?.hsm?await this.getHSMEnrollmentKey(c,i,n.hsm):this.getSoftwareEnrollmentKey(c,t);return await s.setEnrollment(l,i,a),s}static getCryptoSuite(e){return e?(z.cryptoSuite||(z.cryptoSuite=d.User.newCryptoSuite(e)),z.cryptoSuite):d.User.newCryptoSuite()}static getSoftwareEnrollmentKey(e,t){if(!t)throw Error("Private key must be provided when HSM configuration is not supplied");return e.createKeyFromRaw(t)}static async getHSMEnrollmentKey(e,t,r){const i=r.keyIdHex&&r.keyIdHex.trim().length>0?Buffer.from(r.keyIdHex,"hex"):await this.getCertificateSKI(t),a=await e.getKey(i);if(!a||"function"==typeof a.isPrivate&&!a.isPrivate())throw Error("Unable to resolve private key from HSM");return a}static async getCertificateSKI(e){const t=new u.X509Certificate(e).publicKey.export({format:"jwk"}),r=Buffer.from([4]),i=Buffer.from(t.x||"","base64url"),a=Buffer.from(t.y||"","base64url");return A.default.createHash("sha256").update(Buffer.concat([r,i,a])).digest()}static async getIdentity(e,r){const i=await this.contentOfLoadFile(r,async e=>{const{promises:r}=await t.normalizeImport(import("fs")),i=await this.getFirstDirFileName(e);return await r.readFile(i)});return{mspId:e,credentials:i}}static async getFirstDirFileName(e){const{promises:r}=await t.normalizeImport(import("fs")),{join:i}=await t.normalizeImport(import("path"));return i(e,(await r.readdir(e))[0])}static async getFirstDirFileNameContent(e){const{promises:r}=await t.normalizeImport(import("fs")),{join:i}=await t.normalizeImport(import("path")),a=await r.readdir(e);return(await r.readFile(i(e,a[0]))).toString()}static async getFileContent(e){const{promises:r}=await t.normalizeImport(import("fs"));return(await r.readFile(e)).toString()}static async getSigner(e){const r=await this.contentOfLoadFile(e,async e=>{const{promises:r}=await t.normalizeImport(import("fs")),i=await this.getFirstDirFileName(e);return await r.readFile(i)}),i=await this.extractPrivateKey(r),a=i[Object.getOwnPropertySymbols(i)[0]];return l.signers.newPrivateKeySigner(a)}static async extractPrivateKey(e){let r;if(globalThis.window&&globalThis.window.Crypto)r=globalThis.Crypto.subtle;else{const e=await t.normalizeImport(import("crypto"));r=e.subtle||e.webcrypto.subtle}if(!r)throw Error("Could not load SubtleCrypto module");const i=e.toString("utf8").replace("-----BEGIN PRIVATE KEY-----","").replaceAll("\n","").replace("-----END PRIVATE KEY-----",""),a=(e=>{const t=new ArrayBuffer(e.length),r=new Uint8Array(t);for(let t=0,i=e.length;i>t;t++)r[t]=e.charCodeAt(t);return t})(Buffer.from(i,"base64").toString("binary"));return await r.importKey("pkcs8",a,{name:"ECDSA",namedCurve:"P-256"},!0,["sign"])}}const j=new p.Crypto;var L,H,U,q,Y;v.cryptoProvider.set(j),e.BASE_ALPHABET=void 0,(L=e.BASE_ALPHABET||(e.BASE_ALPHABET={})).BASE2="01",L.BASE8="01234567",L.BASE11="0123456789a",L.BASE16="0123456789abcdef",L.BASE32="0123456789ABCDEFGHJKMNPQRSTVWXYZ",L.BASE32_Z="ybndrfg8ejkmcpqxot1uwisza345h769",L.BASE36="0123456789abcdefghijklmnopqrstuvwxyz",L.BASE58="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",L.BASE62="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",L.BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",L.BASE67="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.!~",e.CRYPTO=void 0,(H=e.CRYPTO||(e.CRYPTO={})).HASH="SHA-256",H[H.ITERATIONS=1e3]="ITERATIONS",H[H.KEYLENGTH=48]="KEYLENGTH",H[H.DERIVED_IV_LENGTH=16]="DERIVED_IV_LENGTH",H[H.DERIVED_KEY_LENGTH=32]="DERIVED_KEY_LENGTH",H.ALGORYTHM="AES-GCM",H.KEY_ALGORYTHM="PBKDF2";class G{constructor(e){if(this.alphabet=e,this.baseMap=new Uint8Array(256),this.alphabet.length>=255)throw Error("Alphabet too long");for(let e=0;e<this.baseMap.length;e++)this.baseMap[e]=255;for(let t=0;t<e.length;t++){const r=e.charAt(t),i=r.charCodeAt(0);if(255!==this.baseMap[i])throw Error(r+" is ambiguous");this.baseMap[i]=t}this.base=this.alphabet.length,this.leader=this.alphabet.charAt(0),this.factor=Math.log(this.base)/Math.log(256),this.iFactor=Math.log(256)/Math.log(this.base)}encode(e){if("string"==typeof e?e=Buffer.from(e):ArrayBuffer.isView(e)?e=new Uint8Array(e.buffer,e.byteOffset,e.byteLength):Array.isArray(e)&&(e=Uint8Array.from(e)),0===e.length)return"";let t=0,r=0,i=0;const a=e.length;for(;i!==a&&0===e[i];)i++,t++;const n=(a-i)*this.iFactor+1>>>0,s=new Uint8Array(n);for(;i!==a;){let t=e[i],a=0;for(let e=n-1;(0!==t||r>a)&&-1!==e;e--,a++)t+=256*s[e]>>>0,s[e]=t%this.base>>>0,t=t/this.base>>>0;if(0!==t)throw Error("Non-zero carry");r=a,i++}let o=n-r;for(;o!==n&&0===s[o];)o++;let c=this.leader.repeat(t);for(;n>o;++o)c+=this.alphabet.charAt(s[o]);return c}decodeUnsafe(e){if(0===e.length)return new Uint8Array(0);let t=0,r=0,i=0;for(;e[t]===this.leader;)r++,t++;const a=(e.length-t)*this.factor+1>>>0,n=new Uint8Array(a);for(;e[t];){let r=this.baseMap[e.charCodeAt(t)];if(255===r)return;let s=0;for(let e=a-1;(0!==r||i>s)&&-1!==e;e--,s++)r+=this.base*n[e]>>>0,n[e]=r%256>>>0,r=r/256>>>0;if(0!==r)throw Error("Non-zero carry");i=s,t++}let s=a-i;for(;s!==a&&0===n[s];)s++;const o=new Uint8Array(r+(a-s));let c=r;for(;s!==a;)o[c++]=n[s++];return o}decode(e){const t=this.decodeUnsafe(e);if(t)return t;throw Error("Non-base"+this.base+" character")}}class V{static{this.b58encoder=new G(e.BASE_ALPHABET.BASE58)}static{this.logger=new c.MiniLogger(V.name)}constructor(){}static fabricIdFromCertificate(e){this.logger.debug(r.stringFormat("Parsing certificate: {0}",e));const t=new v.X509Certificate(e),{subject:i,issuer:a}=t;return this.logger.debug(r.stringFormat("Certificate parsed with subject {0} and issuer {1}",i,a)),`x509::/${i.replaceAll(", ","/")}::/${a.replaceAll(", ","/")}`}static encode(e){return this.b58encoder.encode(e)}static decode(e){const t=this.b58encoder.decode(e);return(new TextDecoder).decode(t)}static stringToArrayBuffer(e){const t=new ArrayBuffer(e.length),r=new Uint8Array(t);for(let t=0,i=e.length;i>t;t++)r[t]=e.charCodeAt(t);return t}static async extractKey(e,t,r){const i=j.subtle,a=t.toString("utf8").replace(RegExp(`-----BEGIN (${e.toUpperCase()} KEY|CERTIFICATE)-----`),"").replaceAll("\n","").replace(RegExp(`-----END (${e.toUpperCase()} KEY|CERTIFICATE)-----`),""),n=Buffer.from(a,"base64").toString("binary"),s=this.stringToArrayBuffer(n);return await i.importKey("pkcs8",s,{name:"ECDSA",namedCurve:"P-256"},!0,r||["sign"])}static async extractPrivateKey(e,t){return this.extractKey("private",e,t)}static async extractPublicKey(e,t){return this.extractKey("public",e,t)}static async sign(e,t){const r=await this.extractPrivateKey(e),i=await j.subtle.sign({name:"ECDSA",hash:"SHA-256"},r,t);return Array.from(new Uint8Array(i)).map(e=>e.toString(16).padStart(2,"0")).join("")}static async verify(e,t,r){const i=new v.X509Certificate(e),a=await i.publicKey.export();return t="string"==typeof t?Buffer.from(t,"hex"):t,r="string"==typeof r?Buffer.from(r):r,j.subtle.verify({name:"ECDSA",hash:"SHA-256"},a,t,r)}static async encrypt(e,t){const r=new v.X509Certificate(e),i=await r.publicKey.export();t="string"==typeof t?Buffer.from(t):t;const a=await this.getSubtleCrypto().encrypt({name:"ECDSA"},i,t);return Array.from(new Uint8Array(a)).map(e=>e.toString(16).padStart(2,"0")).join("")}static getSubtleCrypto(){return c.isBrowser()?globalThis.window.crypto.subtle:j.subtle}static async decrypt(e,t){const r=await this.extractPrivateKey(e);return t="string"==typeof t?Buffer.from(t,"hex"):t,this.getSubtleCrypto().decrypt({name:"ECDSA"},r,t)}static async getMaster(t){const r=new TextEncoder;if(void 0===t){const e=j.randomUUID();t=r.encode(e).buffer}return{key:await this.getSubtleCrypto().importKey("raw",t,e.CRYPTO.KEY_ALGORYTHM,!1,["deriveBits"]),iv:t}}static async getDerivationKey(t,r){const i=(new TextEncoder).encode(t),a=await this.getSubtleCrypto().digest("SHA-256",i),n={name:e.CRYPTO.KEY_ALGORYTHM,hash:e.CRYPTO.HASH,salt:a,iterations:e.CRYPTO.ITERATIONS},s=await this.getSubtleCrypto().deriveBits(n,r,8*e.CRYPTO.KEYLENGTH);return this.getKey(s)}static async getKey(t){const r=t.slice(0,32),i=t.slice(32);return{key:await this.getSubtleCrypto().importKey("raw",r,{name:e.CRYPTO.ALGORYTHM},!1,["encrypt","decrypt"]),iv:i}}static async encryptPin(t,r){const i=(new TextEncoder).encode(t);return await this.getSubtleCrypto().encrypt({name:e.CRYPTO.ALGORYTHM,iv:r.iv},r.key,i)}static async decryptPin(t,r){const i=new TextDecoder,a=await this.getSubtleCrypto().decrypt({name:e.CRYPTO.ALGORYTHM,iv:r.iv},r.key,t);return i.decode(a)}}class J extends i.InternalError{constructor(e){super(e,J.name)}}class Q extends i.InternalError{constructor(e){super(e,Q.name)}}class X extends i.InternalError{constructor(e){super(e,X.name)}}class W extends t.AuthorizationError{constructor(e){super(e,W.name)}}class Z extends i.InternalError{constructor(e){super(e,Z.name,500)}}class ee extends i.BaseError{constructor(e="MISSING_PRIVATE_DATA_ERROR_MESSAGE"){super(ee.name,e,403)}}class te extends i.BaseError{constructor(e){super(te.name,e,409)}}class re extends i.InternalError{constructor(e){super(e,re.name,500)}}class ie extends i.InternalError{constructor(e){super(e,ie.name,500)}}class ae extends i.InternalError{constructor(e){super(e,ae.name,500)}}class ne extends i.InternalError{constructor(e){super(e,ne.name,500)}}class se extends i.InternalError{constructor(e){super(e,se.name,500)}}e.HFCAIdentityType=void 0,(U=e.HFCAIdentityType||(e.HFCAIdentityType={})).PEER="peer",U.ORDERER="orderer",U.CLIENT="client",U.USER="user",U.ADMIN="admin",e.HFCAIdentityAttributes=void 0,(q=e.HFCAIdentityAttributes||(e.HFCAIdentityAttributes={})).HFREGISTRARROLES="hf.Registrar.Roles",q.HFREGISTRARDELEGATEROLES="hf.Registrar.DelegateRoles",q.HFREGISTRARATTRIBUTES="hf.Registrar.Attributes",q.HFINTERMEDIATECA="hf.IntermediateCA",q.HFREVOKER="hf.Revoker",q.HFAFFILIATIONMGR="hf.AffiliationMgr",q.HFGENCRL="hf.GenCRL";class oe extends c.LoggedClass{constructor(e){z.getCryptoSuite(e.hsm?{software:!1,lib:e.hsm.library,slot:e.hsm.slot,label:e.hsm.tokenLabel,pin:e.hsm.pin+""}:void 0),super(),this.caConfig=e}async User(){if(this.user)return this.user;const{caName:e,caCert:t,caKey:r,url:a,hsm:n}=this.caConfig,s=this.log.for(this.User);s.debug(`Creating CA user for ${e} at ${a}`),s.debug("Retrieving CA certificate from "+t);const o=await z.getFirstDirFileNameContent(t);let c;if(n)s.debug(`Using HSM configuration for CA ${e} with library ${n.library}`);else{if(!r)throw new i.InternalError(`Missing caKey configuration for CA ${e}. Provide a key directory or configure HSM support.`);s.debug("Retrieving CA key from "+r),c=await z.getFirstDirFileNameContent(r)}return s.debug("Loading Admin user for ca "+e),this.user=await z.getCAUser("admin",c,o,e,{hsm:n}),this.user}async CA(){if(this.ca)return this.ca;const e=this.log.for(this.CA),{url:t,tls:r,caName:i}=this.caConfig;let{trustedRoots:a,verify:n}=r;const s=a[0];e.debug(`Retrieving CA certificate from ${s}. cwd: ${process.cwd()}`);const o=await z.getFileContent(s);return e.debug(`Creating CA Client for CA ${i} under ${t}`),this.ca=new E.default(t,{trustedRoots:Buffer.from(o),verify:n},i),this.ca}async Client(){if(this.client)return this.client;const e=await this.CA();return this.client=e._FabricCAServices,this.client}async Certificate(){return this.certificateService||(this.certificateService=(await this.Client()).newCertificateService()),this.certificateService}async Affiliations(){return this.affiliationService||(this.affiliationService=(await this.CA()).newAffiliationService()),this.affiliationService}async Identities(){return this.identityService||(this.identityService=(await this.CA()).newIdentityService()),this.identityService}async getCertificates(e,t=!0){const r=await this.Certificate(),i=await this.User(),a=this.log.for(this.getCertificates);a.debug(`Retrieving certificates${e?" for "+e.id:""} for CA ${this.caConfig.caName}`);const n=(await r.getCertificates(e||{},i)).result;return a.debug(`Found ${n.certs.length} certificates: ${JSON.stringify(n)}`),t?n.certs.map(e=>e.PEM):n}async getIdentities(){const e=await this.Identities(),t=this.log.for(this.getIdentities);t.debug("Retrieving Identities under CA "+this.caConfig.caName);const r=(await e.getAll(await this.User())).result;return t.debug(`Found ${r.identities.length} Identities: ${JSON.stringify(r)}`),r.identities}parseError(e){const r=/.*code:\s(\d+).*?message:\s["'](.+)["']/gs.exec(e.message);if(!r)return new W(e);const[,a,n]=r;switch(a){case"74":case"71":return new i.ConflictError(n);case"20":return new t.AuthorizationError(n);default:return new W(n)}}async getAffiliations(){const e=await this.Affiliations(),t=this.log.for(this.getAffiliations);t.debug("Retrieving Affiliations under CA "+this.caConfig.caName);const r=(await e.getAll(await this.User())).result;return t.debug(`Found ${r.a.length} Affiliations: ${JSON.stringify(r)}`),r}async read(e){const t=await this.CA(),r=await this.User();let a;try{a=await t.newIdentityService().getOne(e,r)}catch(t){throw new i.NotFoundError(`Couldn't find enrollment with id ${e}: ${t}`)}if(!a.success)throw new i.NotFoundError(`Couldn't find enrollment with id ${e}: ${a.errors.join("\n")}`);return a.result}async register(e,t=!1,r="",i,a,n){let s;const o=this.log.for(this.register);try{const{userName:c,password:l}=e,d=await this.CA(),u=await this.User(),h={enrollmentID:c,enrollmentSecret:l,affiliation:r,userRole:i,attrs:a,maxEnrollments:n};s=await d.register(h,u),o.info(`Registration for ${c} created with user type ${i??"Undefined Role"} ${t?"as super user":""}`)}catch(e){throw this.parseError(e)}return s}static identityFromEnrollment(t,r){const{certificate:i,key:a,rootCertificate:n}=t,s=c.Logging.for(oe,{}).for(this.identityFromEnrollment);s.debug(`Generating Identity from certificate ${i} in msp ${r}`);const o=V.fabricIdFromCertificate(i),l=V.encode(o);s.debug(`Identity ${o} and encodedId ${l}`);const d=new Date;return new e.Identity({id:l,credentials:{id:l,certificate:i,privateKey:a.toBytes(),rootCertificate:n,createdOn:d,updatedOn:d},mspId:r,createdOn:d,updatedOn:d})}async enroll(e,t){let r;const i=this.log.for(this.enroll);try{const a=await this.CA();i.debug("Enrolling "+e);const n=await a.enroll({enrollmentID:e,enrollmentSecret:t});r=oe.identityFromEnrollment(n,this.caConfig.caName),i.info(`Successfully enrolled ${e} under ${this.caConfig.caName} as ${r.id}`)}catch(e){throw this.parseError(e)}return r}async registerAndEnroll(e,t=!1,r="",i,a,n){const s=await this.register(e,t,r,i,a,n),{userName:o}=e;return this.enroll(o,s)}async revoke(e){const t=await this.CA(),r=await this.User(),a=await this.read(e);if(!a)throw new i.NotFoundError("Could not find enrollment with id "+e);let n;try{n=await t.revoke({enrollmentID:a.id,reason:"User Deletation"},r)}catch(t){throw new i.InternalError(`Could not revoke enrollment with id ${e}: ${t}`)}if(!n.success)throw new i.InternalError(`Could not revoke enrollment with id ${e}: ${n.errors.join("\n")}`);return n}}class ce extends r.Model{constructor(){super(...arguments),this.affiliation=""}build(){const e=this.hasErrors();if(e)throw new i.ValidationError(e.toString());const t={enrollmentID:this.enrollmentID,enrollmentSecret:this.enrollmentSecret,role:this.role,affiliation:this.affiliation};return void 0!==this.maxEnrollments&&(t.maxEnrollments=this.maxEnrollments),this.attrs&&(t.attrs=this.attrs),t}setAffiliation(e){return this.affiliation=e,this}addAttr(e){return this.attrs=this.attrs||[],this.attrs.push(e),this}setAttrs(e){return this.attrs=e,this}setEnrollmentID(e){return this.enrollmentID=e,this}setEnrollmentSecret(e){return this.enrollmentSecret=e,this}setMaxEnrollments(e){return this.maxEnrollments=e,this}setRole(e){return this.role=e,this}}async function le(e,t,r,i){const{stub:a}=e,n=(await a.getCreator()).mspid;Object.defineProperty(i,r,{enumerable:!0,writable:!1,configurable:!0,value:n})}async function de(e,t,r,i){const{stub:a}=e;i[r]=a.getTxID()}async function ue(e,t,a){let n=t;if("string"!=typeof n)try{const i=r.Model.ownerOf(e)||a.get("stub").getCreator().toString();t&&"function"==typeof t&&(n=await t(e,i,a))}catch(e){throw new i.InternalError("Failed to resolve collection mirror name: "+e)}if(!n||"string"!=typeof n)throw new i.InternalError("No collection found model "+e.constructor.name);return n}async function he(e,t,i,a){const n=await ue(a,t.resolver,e),s=this.override(Object.assign({},this._overrides,{segregate:n,ignoreValidation:!0,ignoreHandlers:!0})),o=await s.create(a,e);e.logger.info(`Mirror for ${r.Model.tableName(this.class)} created with ${r.Model.pk(a)}: ${o[r.Model.pk(a)]}`)}async function pe(e,t,i,a){const n=await ue(a,t.resolver,e),s=this.override(Object.assign({},this._overrides,{segregate:n,ignoreValidation:!0,ignoreHandlers:!0})),o=await s.update(a,e);e.logger.info(`Mirror for ${r.Model.tableName(this.class)} updated with ${r.Model.pk(a)}: ${o[r.Model.pk(a)]}`)}async function ge(e,t,i,a){const n=await ue(a,t.resolver,e),s=this.override(Object.assign({},this._overrides,{segregate:n,ignoreValidation:!0,ignoreHandlers:!0})),o=await s.delete(r.Model.pk(a),e);e.logger.info(`Mirror for ${r.Model.tableName(this.class)} deleted with ${r.Model.pk(a)}: ${o[r.Model.pk(a)]}`)}n.__decorate([r.required(),n.__metadata("design:type",String)],ce.prototype,"affiliation",void 0),n.__decorate([r.minlength(1),n.__metadata("design:type",Array)],ce.prototype,"attrs",void 0),n.__decorate([r.required(),n.__metadata("design:type",String)],ce.prototype,"enrollmentID",void 0),n.__decorate([r.required(),n.__metadata("design:type",String)],ce.prototype,"enrollmentSecret",void 0),n.__decorate([r.min(0),n.__metadata("design:type",Number)],ce.prototype,"maxEnrollments",void 0),n.__decorate([r.required(),n.__metadata("design:type",String)],ce.prototype,"role",void 0),e.ERC20Events=void 0,(Y=e.ERC20Events||(e.ERC20Events={})).TRANSFER="Transfer",Y.APPROVAL="Approval",e.FabricBaseModel=class extends r.Model{constructor(e){super(e)}},n.__decorate([s.description("Stores the original timestamp of creation"),t.column(),t.createdAt(),n.__metadata("design:type",Date)],e.FabricBaseModel.prototype,"createdAt",void 0),n.__decorate([s.description("Stores the timestamp of the last update"),t.column(),t.updatedAt(),n.__metadata("design:type",Date)],e.FabricBaseModel.prototype,"updatedAt",void 0),n.__decorate([s.description("Stores the version of the model"),t.column(),i.version(),n.__metadata("design:type",Number)],e.FabricBaseModel.prototype,"version",void 0),e.FabricBaseModel=n.__decorate([s.uses(k),n.__metadata("design:paramtypes",[Object])],e.FabricBaseModel),e.FabricIdentifiedBaseModel=class extends e.FabricBaseModel{constructor(e){super(e)}},n.__decorate([s.description("Stores the creator"),t.column(),t.createdBy(),n.__metadata("design:type",String)],e.FabricIdentifiedBaseModel.prototype,"createdBy",void 0),n.__decorate([s.description("Stores the user that last updated the model"),t.column(),t.updatedBy(),n.__metadata("design:type",String)],e.FabricIdentifiedBaseModel.prototype,"updatedBy",void 0),e.FabricIdentifiedBaseModel=n.__decorate([s.uses(k),n.__metadata("design:paramtypes",[Object])],e.FabricIdentifiedBaseModel),r.Model.prototype.isShared=function(){return r.Model.isShared(this.constructor)},r.Model.prototype.isPrivate=function(){return r.Model.isPrivate(this.constructor)},r.Model.prototype.segregate=function(){return r.Model.segregate(this)},r.Model.segregate=(t=>{if(!r.Model.isTransient(t))return{model:t};const a=s.Metadata.validatableProperties(t.constructor),n=s.Metadata.get(t.constructor,i.DBKeys.TRANSIENT),o=s.Metadata.get(t.constructor,e.FabricModelKeys.PRIVATE),c=s.Metadata.get(t.constructor,e.FabricModelKeys.PRIVATE),l={model:{},transient:{},private:{},shared:{}},d=Object.keys(n),u=Object.keys(o),h=Object.keys(c);for(const e of a){const r=d.includes(e),i=u.includes(e),a=h.includes(e);r?(l.transient=l.transient||{},l.transient[e]=t[e],i&&(l.private=l.private||{},l.private[e]=t[e]),a&&(l.shared=l.shared||{},l.shared[e]=t[e])):(l.model=l.model||{},l.model[e]=t[e])}return l.model=r.Model.build(l.model,t.constructor.name),l}).bind(r.Model),r.Model.isPrivate=(t=>!!s.Metadata.get("function"!=typeof t?t.constructor:t,e.FabricModelKeys.PRIVATE)).bind(r.Model),r.Model.isShared=(t=>!!s.Metadata.get("function"!=typeof t?t.constructor:t,e.FabricModelKeys.SHARED)).bind(r.Model),r.Model.mirrored=(t=>s.Metadata.get("function"!=typeof t?t.constructor:t,s.Metadata.key(e.FabricModelKeys.FABRIC,e.FabricModelKeys.MIRROR))).bind(r.Model),r.Model.ownerOf=(t=>{const r=s.Metadata.get(t.constructor,s.Metadata.key(e.FabricModelKeys.FABRIC,e.FabricModelKeys.OWNED_BY));if(r)return t[r]}).bind(r.Model),r.Model.mirroredAt=(t=>(t="function"!=typeof t?t.constructor:t,s.Metadata.get(t,s.Metadata.key(e.FabricModelKeys.FABRIC,e.FabricModelKeys.MIRROR)))).bind(r.Model),r.Model.collectionsFor=(t=>{const r=[e.FabricModelKeys.PRIVATE],i=[e.FabricModelKeys.SHARED],a=s.Metadata.key(...r),n=s.Metadata.key(...i),o="function"==typeof t?t:t.constructor,c=s.Metadata.get(o,a),l=s.Metadata.get(o,n);return{privateCols:c?.collections||[],sharedCols:l?.collections||[]}}).bind(r.Model);const fe=(e,t)=>{const a=t||("function"!=typeof e?r.Model.ownerOf(e):void 0);if(!a)throw new i.InternalError(`Model ${e.constructor.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);return`__${c.toPascalCase(a)}PrivateCollection`};async function ye(e,a,n,s){if(n.length!==a.length)throw new i.InternalError("Segregated data keys and metadata length mismatch");const o=r.Model.ownerOf(s);if(!o)throw new i.ValidationError("There's no assigned organization for model "+s.constructor.name);const c=a[0].collections,l="string"==typeof c?c:c(s,o,e),d=n.reduce((r,i,n)=>{const c="string"==typeof a[n].collections?a[n].collections:a[n].collections(s,o,e);if(c!==l)throw new t.UnsupportedError(`Segregated data collection mismatch: ${c} vs ${l}`);return r[i]=s[i],r},{}),u=new this.class(d),h=await this.override({segregated:l,mergeModel:!1,ignoreHandlers:!0,ignoreValidation:!0}).create(u,e);Object.assign(s,h)}async function me(e,t,a,n){if(a.length!==t.length)throw new i.InternalError("Segregated data keys and metadata length mismatch");const s=r.Model.ownerOf(n);if(!s)throw new i.ValidationError("There's no assigned organization for model "+n.constructor.name);const o=t[0].collections,c="string"==typeof o?o:await o(n,s,e);a.reduce((r,i,a)=>(("string"==typeof t[a].collections?t[a].collections:t[a].collections(n,s,e))!==c||(r[i]=n[i]),r),{})}async function we(e,t,r,i,a){}async function be(e,t,r,i){}function Ce(e,t,r){return(a,n)=>{const o=[];return n?o.push(s.prop(),i.transient(),(r,i)=>{const a=s.Metadata.key(t,i),n=r.constructor,o=s.Metadata.get(n,a)||{},c=new Set(o.collections||[]);c.add(e),o.collections=[...c],s.Metadata.set(n,a,o);const l=s.Metadata.get(n,t)||{};new Set(l.collections||[]).add(e),o.collections=[...c],s.Metadata.set(n,t,o)},i.onCreate(ye,{collections:e},{priority:95,group:"string"==typeof e?e:e.toString()}),i.onRead(me,{collections:e},{priority:95,group:"string"==typeof e?e:e.toString()}),i.onUpdate(we,{collections:e},{priority:95,group:"string"==typeof e?e:e.toString()}),i.onDelete(be,{collections:e},{priority:95,group:"string"==typeof e?e:e.toString()})):s.Metadata.properties(a)?.forEach(i=>{r&&!r(i)||Ce(e,t)(a.prototype,i)}),s.apply(...o)(a,n)}}function Ee(t=fe){return s.Decoration.for(e.FabricModelKeys.PRIVATE).define({decorator:t=>Ce(t,e.FabricModelKeys.PRIVATE),args:[t]}).apply()}class Ae extends r.JSONSerializer{constructor(){super()}preSerialize(e){const t=Object.assign({},e);let i;try{i=s.Metadata.modelName(e.constructor)}catch(e){i=void 0}t[r.ModelKeys.ANCHOR]=i||e.constructor.name;const a=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 r.Model.relations(e).forEach(e=>{t[e]=a(t[e])}),t}deserialize(e){const t=JSON.parse(e),i=t[r.ModelKeys.ANCHOR];if(!i)throw Error("Could not find class reference in serialized model");return r.Model.build(t,i)}serialize(e){return require("json-stringify-deterministic")(require("sort-keys-recursive")(this.preSerialize(e)))}}function ve(e){const t=e.split("_");return 2>t.length||t.length>3?{table:void 0,event:e,owner:void 0}:{table:t[0],event:t[1],owner:t[2]}}class Se extends r.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,t=!0){const i=Object.assign({},e);let a;try{a=s.Metadata.modelName(e.constructor)}catch(e){a=void 0}function n(e){return"object"!=typeof e?e:Array.isArray(e)?e.map(n):this.preSerialize(e)}return t&&(i[r.ModelKeys.ANCHOR]=a||e.constructor.name),r.Model.relations(e).forEach(e=>{i[e]=n.call(this,i[e])}),i}}class _e extends t.ClientBasedService{constructor(){super()}get rootClient(){return this.client._FabricCaServices}get user(){if(!this._user)throw new i.InternalError("Fabric identity service not properly setup: missing user");return this._user}get certificates(){return this.rootClient.newCertificateService()}get affiliations(){return this.client.newAffiliationService()}get identities(){return this.client.newIdentityService()}async getUser(e,t){const r=t.logger.for(this.getUser),{caName:a,caCert:n,caKey:s,url:o,hsm:c}=e;r.info(`Creating CA user for ${a} at ${o}`),r.verbose("Retrieving CA certificate from "+n);const l=await z.getFirstDirFileNameContent(n);let d;if(c)r.debug(`Using HSM configuration for CA ${a} with library ${c.library}`);else{if(!s)throw new i.InternalError(`Missing caKey configuration for CA ${a}. Provide a key directory or configure HSM support.`);r.debug("Retrieving CA key from "+s),d=await z.getFirstDirFileNameContent(s)}return r.debug("Loading Admin user for ca "+a),this._user=await z.getCAUser("admin",d,l,a,{hsm:c}),this._user}async initialize(...e){const{log:t,ctx:r}=await this.logCtx(e,this.initialize,!0),[a]=e;if(!a)throw new i.InternalError("Missing Fabric CA configuration");const{url:n,tls:s,caName:o}=a;t.info(`Initializing CA Client for CA ${a.caName} at ${a.url}`);const{trustedRoots:c,verify:l}=s,d=c[0];t.debug(`Retrieving CA certificate from ${d}. cwd: ${process.cwd()}`);const u=await z.getFileContent(d);t.debug("CA Certificate: "+u.toString());const h=new E.default(n,{trustedRoots:Buffer.from(u),verify:l},o),p=await this.getUser(a,r);return t.debug("CA user loaded: "+p.getName()),{config:a,client:h}}async getCertificates(e,r=!0,...i){e instanceof t.Context?(i=[e],r=!0,e=void 0):"boolean"==typeof e?(r=e,e=void 0):"boolean"!=typeof r&&(i=[r,...i],r=!0);const{log:a}=await this.logCtx(i,this.getCertificates,!0);a.debug(`Retrieving certificates${e?" for "+e.id:""} for CA ${this.config.caName}`);const n=(await this.certificates.getCertificates(e||{},this.user)).result;return a.verbose(`Found ${n.certs.length} certificates`),a.debug(n.certs),r?n.certs.map(e=>e.PEM):n}async getIdentities(e){const t=e.logger.for(this.getIdentities);t.verbose("Retrieving Identities under CA "+this.config.caName);const r=(await this.identities.getAll(this.user)).result;return t.verbose(`Found ${r.identities.length} Identities`),t.debug(r.identities),r.identities}async getAffiliations(e){const t=e.logger.for(this.getAffiliations);t.verbose("Retrieving Affiliations under CA "+this.config.caName);const r=(await this.affiliations.getAll(this.user)).result;return t.verbose(`Found ${r.a.length} Affiliations`),t.debug(JSON.stringify(r)),r}parseError(e){const r=/.*code:\s(\d+).*?message:\s["'](.+)["']/gs.exec(e.message);if(!r)return new W(e);const[,a,n]=r;switch(a){case"74":case"71":return new i.ConflictError(n);case"20":return new t.AuthorizationError(n);default:return new W(n)}}async read(e,...t){const{log:r}=await this.logCtx(t,this.read,!0);let a;r.verbose("Retrieving identity with enrollment ID "+e);try{a=await this.identities.getOne(e,this.user)}catch(t){throw new i.NotFoundError(`Couldn't find enrollment with id ${e}: ${t}`)}if(!a.success)throw new i.NotFoundError(`Couldn't find enrollment with id ${e}: ${a.errors.join("\n")}`);return a.result}async register(e,t=!1,r="",i,a,n,...s){const{log:o}=await this.logCtx(s,this.register,!0);let c;try{const{userName:s,password:l}=e,d={enrollmentID:s,enrollmentSecret:l,affiliation:r,userRole:i,attrs:a,maxEnrollments:n};c=await this.client.register(d,this.user),o.info(`Registration for ${s} created with user type ${i??"Undefined Role"} ${t?"as super user":""}`)}catch(e){throw this.parseError(e)}return c}static identityFromEnrollment(t,r,i){const a=i.logger.for(this.identityFromEnrollment),{certificate:n,key:s,rootCertificate:o}=t;a.verbose(`Generating Identity from certificate ${n} in msp ${r}`);const c=V.fabricIdFromCertificate(n),l=V.encode(c);return a.debug(`Identity ${c} and encodedId ${l}`),new e.Identity({id:l,credentials:{id:l,certificate:n,privateKey:s.toBytes(),rootCertificate:o},mspId:r})}async enroll(e,t,...r){const{log:i,ctx:a}=await this.logCtx(r,this.enroll,!0);let n;try{i.debug("Enrolling "+e);const r=await this.client.enroll({enrollmentID:e,enrollmentSecret:t});n=_e.identityFromEnrollment(r,this.config.caName,a),i.info(`Successfully enrolled ${e} under ${this.config.caName} as ${n.id}`)}catch(e){throw this.parseError(e)}return n}async registerAndEnroll(e,t=!1,r="",i,a,n,...s){const{ctx:o}=await this.logCtx(s,this.registerAndEnroll,!0),c=await this.register(e,t,r,i,a,n,o),{userName:l}=e;return this.enroll(l,c,o)}async revoke(e,...t){const{log:r}=await this.logCtx(t,this.revoke,!0);r.verbose("Revoking identity with enrollment ID "+e);const a=await this.read(e);if(!a)throw new i.NotFoundError("Could not find enrollment with id "+e);let n;try{n=await this.client.revoke({enrollmentID:a.id,reason:"User Deletion"},this.user)}catch(t){throw new i.InternalError(`Could not revoke enrollment with id ${e}: ${t}`)}if(!n.success)throw new i.InternalError(`Could not revoke enrollment with id ${e}: ${n.errors.join("\n")}`);return n}}const Ie=Object.assign({evaluateTimeout:5,endorseTimeout:15,submitTimeout:5,commitTimeout:60},t.DefaultAdapterFlags),Me=new c.MiniLogger("fabric-fs");async function xe(e,t){return e instanceof Uint8Array||e.match(/-----BEGIN (CERTIFICATE|KEY|PRIVATE KEY)-----.+?-----END \1-----$/gms)?e:await t(e)}async function Oe(e,r){const i=await xe(r,async e=>{const{promises:r}=await t.normalizeImport(import("fs")),i=await Ne(e);return await r.readFile(i)});return{mspId:e,credentials:i}}async function Ne(e){const{promises:r}=await t.normalizeImport(import("fs")),{join:i}=await t.normalizeImport(import("path"));return i(e,(await r.readdir(e))[0])}async function Te(e){const r=await xe(e,async e=>{const{promises:r}=await t.normalizeImport(import("fs")),i=await Ne(e);return await r.readFile(i)}),i=await Fe(r),a=i[Object.getOwnPropertySymbols(i)[0]];return l.signers.newPrivateKeySigner(a)}async function Fe(e){let r;if(c.isBrowser())r=globalThis.crypto.subtle;else{const e=await t.normalizeImport(import("crypto"));r=e.subtle||e.webcrypto.subtle}if(!r)throw Error("Could not load SubtleCrypto module");const a=e.toString("utf8").replace("-----BEGIN PRIVATE KEY-----","").replaceAll("\n","").replace("-----END PRIVATE KEY-----",""),n=(e=>{const t=new ArrayBuffer(e.length),r=new Uint8Array(t);for(let t=0,i=e.length;i>t;t++)r[t]=e.charCodeAt(t);return t})(Buffer.from(a,"base64").toString("binary"));try{return await r.importKey("pkcs8",n,{name:"ECDSA",namedCurve:"P-256"},!0,["sign"])}catch(e){throw new i.InternalError(e)}}class Re{static#e=null;static#t=!1;constructor(e){if(Re.#e||(Re.#e=new _.default.PKCS11,Re.#e.load(this.findHSMPKCS11Lib(e))),!Re.#t){try{Re.#e.C_Initialize()}catch(e){if(e.code!==_.default.CKR_CRYPTOKI_ALREADY_INITIALIZED)throw e}Re.#t=!0}}findHSMPKCS11Lib(e){const t=["/usr/lib/softhsm/libsofthsm2.so","/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so","/usr/local/lib/softhsm/libsofthsm2.so","/usr/lib/libacsp-pkcs11.so","/opt/homebrew/lib/softhsm/libsofthsm2.so"];e&&t.push(e);for(const e of t)if(I.default.existsSync(e))return e;throw new re("Unable to find PKCS11 library")}dispose(){Re.#e.C_Finalize()}sanitizeOptions(e){const t=Object.assign({userType:_.default.CKU_USER},e);return this.assertNotEmpty(t.label,"label"),this.assertNotEmpty(t.pin,"pin"),this.assertNotEmpty(t.identifier,"identifier"),t}assertNotEmpty(e,t){if(!e||0===e.toString().trim().length)throw Error(t+" property must be provided")}findSlotForLabel(e){const t=Re.#e.C_GetSlotList(!0);if(0===t.length)throw Error("No pkcs11 slots can be found");const r=t.find(t=>Re.#e.C_GetTokenInfo(t).label.trim()===e);if(!r)throw Error(`label ${e} cannot be found in the pkcs11 slot list`);return r}login(e,t,r){try{Re.#e.C_Login(e,t,r)}catch(e){if(e.code!==_.default.CKR_USER_ALREADY_LOGGED_IN)throw e}}findObjectInHSM(e,t,r){const i=[{type:_.default.CKA_ID,value:r},{type:_.default.CKA_CLASS,value:t},{type:_.default.CKA_KEY_TYPE,value:_.default.CKK_EC}];Re.#e.C_FindObjectsInit(e,i);const a=Re.#e.C_FindObjects(e,1)[0];if(!a)throw Re.#e.C_FindObjectsFinal(e),Error("Unable to find object in HSM with ID "+r.toString());return Re.#e.C_FindObjectsFinal(e),a}newSigner(e){const t=this.sanitizeOptions(e),r=Re.#e,i=this.findSlotForLabel(t.label),a=r.C_OpenSession(i,_.default.CKF_SERIAL_SESSION);let n;try{this.login(a,t.userType,t.pin),n=this.findObjectInHSM(a,_.default.CKO_PRIVATE_KEY,t.identifier)}catch(e){throw Re.#e.C_CloseSession(a),e}return{signer:async e=>{Re.#e.C_SignInit(a,{mechanism:_.default.CKM_ECDSA},n);const t=await Re.#e.C_SignAsync(a,Buffer.from(e),Buffer.alloc(2*w.p256.Point.Fn.BYTES));return w.p256.Signature.fromBytes(t,"compact").normalizeS().toBytes("der")},close:()=>{Re.#e.C_CloseSession(a)}}}assertDefined(e){if(void 0===e)throw Error("required value was undefined");return e}getUncompressedPointOnCurve(e){const t=e.export({format:"jwk"}),r=Buffer.from(this.assertDefined(t.x),"base64url"),i=Buffer.from(this.assertDefined(t.y),"base64url"),a=Buffer.from("04","hex");return Buffer.concat([a,r,i])}getSKIFromCertificatePath(e){const t=e.endsWith(".pem")?e:M.default.join(e,"cert.pem"),r=I.default.readFileSync(t);return this.getSKIFromCertificate(r)}getSKIFromCertificate(e){const t=new A.default.X509Certificate(e),r=this.getUncompressedPointOnCurve(t.publicKey);return A.default.createHash("sha256").update(r).digest()}}class Be extends t.Statement{constructor(e,t){super(e,t)}squash(e){const r=super.squash(e);if(!r)return r;const{method:a,params:n,args:s}=r,{direction:o,limit:c}=n;switch(a){case t.PreparedStatementKeys.FIND_BY:break;case t.PreparedStatementKeys.LIST_BY:s.push(o);break;case t.PreparedStatementKeys.PAGE_BY:s.push(o,c);break;case t.PreparedStatementKeys.FIND_ONE_BY:break;default:throw new i.InternalError("Unsupported method "+a)}return r}async executePrepared(...e){const r=t.Repository.forModel(this.fromSelector,this.adapter.alias),{method:i,args:a}=this.prepared;return r.statement(i,...a,...e)}async prepare(e){if(e=e||await this.adapter.context(t.PersistenceKeys.QUERY,this.overrides||{},this.fromSelector),this.isSimpleQuery()&&e.get("forcePrepareSimpleQueries")){const t=this.squash(e);if(t)return this.prepared=t,this}const r=[],i={},a={class:this.fromSelector,args:r,params:i},n=[t.QueryClause.FIND_BY];if(this.whereCondition){const t=this.prepareCondition(this.whereCondition,e);n.push(t.method),t.args&&t.args.length&&r.push(...t.args)}return this.selectSelector&&n.push(t.QueryClause.SELECT,this.selectSelector.join(` ${t.QueryClause.AND.toLowerCase()} `)),this.orderBySelector&&(n.push(t.QueryClause.ORDER_BY,this.orderBySelector[0]),r.push(this.orderBySelector[1])),a.method=c.toCamelCase(n.join(" ")),a.params=i,this.prepared=a,this}build(){throw new t.UnsupportedError("This method is only called is prepared statements are not used. If so, a dedicated implementation for the native queries used is required")}parseCondition(e,...r){throw new t.UnsupportedError("This method is only called is prepared statements are not used. Is so, a dedicated implementation for the native queries used is required")}}class De extends t.Paginator{constructor(e,t,r,i){super(e,t,r,i)}prepare(e){throw new t.UnsupportedError("Raw query access must be implemented by a subclass. only prepared statements are natively available")}page(e=1,...t){return super.page(e,...t)}}var $e;class Ke extends t.Adapter{static{this.decoder=new TextDecoder("utf8")}static{this.serializer=new F}static{this.log=c.Logging.for(Ke)}constructor(e,t){super(e,k,t),this.serializer=Ke.serializer}Statement(e){return new Be(this,e)}Paginator(e,t,r){return new De(this,e,t,r)}flags(e,t,r,...i){return super.flags(e,t,r,...i)}async context(e,i,a,...n){this.log.for(this.context).silly(`creating new context for ${e} operation on ${a?Array.isArray(a)?a.map(e=>r.Model.tableName(e)):r.Model.tableName(a):"no"} table ${i&&Object.keys(i)?Object.keys(i).length:"no"} with flag overrides`);let s=n.pop();void 0===s||s instanceof t.Context||(n.push(s),s=void 0),i=s?Object.assign({},i,s.toOverrides()):i;const o=await this.flags("string"==typeof e?e:e.name,a,i,...n,s);if(s){if(!(s instanceof this.Context))return(new this.Context).accumulate({...s.cache,...o,parentContext:s});const t=s.get("operation"),r=s.get("affectedTables");return t!==e||a!==r?(new this.Context).accumulate({...s.cache,...o,parentContext:s}):s.accumulate(o)}return(new this.Context).accumulate({...Ie,...o})}decode(e){return Ke.decoder.decode(e)}repository(){return x}createPrefix(e,t,i,...n){const{ctxArgs:s}=this.logCtx(n,this.createPrefix),o=r.Model.tableName(e),c={};return c[a.CouchDBKeys.TABLE]=o,Object.assign(c,i),[e,t,c,...s]}createAllPrefix(e,t,n,...s){const o=r.Model.tableName(e);if(t.length!==n.length)throw new i.InternalError("Ids and models must have the same length");const{ctxArgs:c}=this.logCtx(s,this.createAllPrefix),l=t.map((e,t)=>{const r={};return r[a.CouchDBKeys.TABLE]=o,Object.assign(r,n[t]),r});return[e,t,l,...c]}updateAllPrefix(e,t,n,...s){const o=r.Model.tableName(e);if(t.length!==n.length)throw new i.InternalError("Ids and models must have the same length");const{ctxArgs:c}=this.logCtx(s,this.updateAllPrefix),l=t.map(()=>{const e={};return e[a.CouchDBKeys.TABLE]=o,e});return[e,t,l,...c]}async createAll(e,t,a,...n){if(t.length!==a.length)throw new i.InternalError("Ids and models must have the same length");const s=[...n],o=s.shift(),{log:c,ctx:l}=this.logCtx(s,this.createAll),d=r.Model.tableName(e);c.info(`adding ${t.length} entries to ${d} table`),c.verbose("pks: "+t);const u=await this.submitTransaction(l,i.BulkCrudOperationKeys.CREATE_ALL,[JSON.stringify(a.map(t=>this.serializer.serialize(t,e.name)))],o,void 0,e.name);try{return JSON.parse(this.decode(u)).map(e=>JSON.parse(e))}catch(e){throw new i.SerializationError(e)}}async readAll(e,t,...a){const{log:n,ctx:s}=this.logCtx(a,this.readAll),o=r.Model.tableName(e);n.info(`reading ${t.length} entries to ${o} table`),n.verbose("pks: "+t);const c=await this.evaluateTransaction(s,i.BulkCrudOperationKeys.READ_ALL,[JSON.stringify(t)],void 0,void 0,e.name);try{return JSON.parse(this.decode(c)).map(e=>JSON.parse(e))}catch(e){throw new i.SerializationError(e)}}async updateAll(e,t,a,...n){if(t.length!==a.length)throw new i.InternalError("Ids and models must have the same length");const s=[...n],o=s.shift(),{log:c,ctx:l}=this.logCtx(s,this.updateAll),d=r.Model.tableName(e);c.info(`updating ${t.length} entries to ${d} table`),c.verbose("pks: "+t);const u=await this.submitTransaction(l,i.BulkCrudOperationKeys.UPDATE_ALL,[JSON.stringify(a.map(t=>this.serializer.serialize(t,e.name)))],o,void 0,e.name);try{return JSON.parse(this.decode(u)).map(e=>JSON.parse(e))}catch(e){throw new i.SerializationError(e)}}async deleteAll(e,t,...a){const{log:n,ctx:s}=this.logCtx(a,this.deleteAll),o=r.Model.tableName(e);n.info(`deleting ${t.length} entries to ${o} table`),n.verbose("pks: "+t);const c=await this.submitTransaction(s,i.BulkCrudOperationKeys.DELETE_ALL,[JSON.stringify(t)],void 0,void 0,e.name);try{return JSON.parse(this.decode(c)).map(e=>JSON.parse(e))}catch(e){throw new i.SerializationError(e)}}prepare(e,...i){const{log:a}=this.logCtx(i,this.prepare),n=r.Model.segregate(e);return e[t.PersistenceKeys.METADATA]&&(a.silly("Passing along persistence metadata for "+e[t.PersistenceKeys.METADATA]),Object.defineProperty(n.model,t.PersistenceKeys.METADATA,{enumerable:!1,writable:!1,configurable:!0,value:e[t.PersistenceKeys.METADATA]})),{record:n.model,model:n.model,id:e[r.Model.pk(e.constructor)],transient:n.transient,private:n.private,shared:n.shared}}revert(e,t,r,a,...n){const{log:s}=this.logCtx(n,this.revert);return a&&(s.verbose("re-adding transient properties: "+Object.keys(a).join(", ")),Object.entries(a).forEach(([r,a])=>{if(r in e)throw new i.InternalError(`Transient property ${r} already exists on model ${"string"==typeof t?t:t.name}. should be impossible`);e[r]=a})),new t(e)}async create(e,t,a,n={},...s){const o=[...s],{log:c,ctx:l}=this.logCtx(o,this.create),d=r.Model.tableName(e);c.verbose(`adding entry to ${d} table`),c.debug("pk: "+t);const u=await this.submitTransaction(l,i.OperationKeys.CREATE,[this.serializer.serialize(a,e.name)],n,void 0,e.name);return this.serializer.deserialize(this.decode(u))}async read(e,t,...a){const{log:n,ctx:s}=this.logCtx(a,this.readAll),o=r.Model.tableName(e);n.verbose(`reading entry from ${o} table`),n.debug("pk: "+t);const c=await this.evaluateTransaction(s,i.OperationKeys.READ,[t.toString()],void 0,void 0,e.name);return this.serializer.deserialize(this.decode(c))}updatePrefix(e,t,i,...n){const s=r.Model.tableName(e),{ctxArgs:o}=this.logCtx(n,this.updatePrefix),c={};return c[a.CouchDBKeys.TABLE]=s,Object.assign(c,i),[e,t,c,...o]}async update(e,t,a,n={},...s){const o=[...s],{log:c,ctx:l}=this.logCtx(o,this.updateAll);c.info("CLIENT UPDATE class : "+typeof e);const d=r.Model.tableName(e);c.verbose(`updating entry to ${d} table`),c.debug("pk: "+t);const u=await this.submitTransaction(l,i.OperationKeys.UPDATE,[this.serializer.serialize(a,e.name||e)],n,void 0,e.name);return this.serializer.deserialize(this.decode(u))}async delete(e,t,...a){const{log:n,ctx:s}=this.logCtx(a,this.delete),o=r.Model.tableName(e);n.verbose(`deleting entry from ${o} table`),n.debug("pk: "+t);const c=await this.submitTransaction(s,i.OperationKeys.DELETE,[t.toString()],void 0,void 0,e.name);return this.serializer.deserialize(this.decode(c))}async raw(e,t=!0,a,...n){const{log:s,ctx:o}=this.logCtx(n,this.raw),c=a.name;let l,d;s.info("Performing raw statement on table "+r.Model.tableName(a));try{l=await this.evaluateTransaction(o,"raw",[JSON.stringify(e),t],void 0,void 0,c)}catch(e){throw this.parseError(e)}try{d=JSON.parse(this.decode(l))}catch(e){throw new i.SerializationError("Failed to process result: "+e)}if(Array.isArray(d)){if(!d.length)return d;const e=d[0];return r.Model.isModel(e)?d.map(e=>r.Model.build(e)):d}return u=d,r.Model.isModel(u)?r.Model.build(u):u;var u}getClient(){return this._client||(this._client=Ke.getClient(this.config)),this._client}async Gateway(e){return Ke.getGateway(e,this.config,this.client)}getContractName(e){if(e)return e+"Contract"}async Contract(e,t){return Ke.getContract(await this.Gateway(e),this.config,t)}async transaction(e,t,r=!0,i,a,n,s){const o=this.log.for(this.transaction),c=await this.Gateway(e);try{const c=await this.Contract(e,this.getContractName(s));o.verbose(`${r?"Submit":"Evaluate"}ting transaction ${this.getContractName(s)||this.config.contractName}.${t}`),o.debug("args: "+(i?.map(e=>e.toString()).join("\n")||"none"));const l=r?c.submit:c.evaluate;n=n?.length?n:void 0;const d={arguments:i||[],transientData:a};return await l.call(c,t,d)}catch(e){if(10===e.code)throw Error(""+e.details[0].message);throw this.parseError(e)}finally{this.log.debug(`Closing ${this.config.mspId} gateway connection`),c.close()}}parseError(e){return Ke.parseError(e)}async submitTransaction(e,t,r,i,a,n){return this.transaction(e,t,!0,r,i,a,n)}async evaluateTransaction(e,t,r,i,a,n){return this.transaction(e,t,!1,r,i,a,n)}async close(){this.client&&(this.log.verbose(`Closing ${this.config.mspId} gateway client`),this.client.close())}static getContract(e,t,r){const i=this.log.for(this.getContract),a=this.getNetwork(e,t.channel);let n;try{i.debug(`Retrieving chaincode ${t.chaincodeName} contract ${r||t.contractName} from network ${t.channel}`),r=r||t.contractName,n=a.getContract(t.chaincodeName,r)}catch(e){throw this.parseError(e)}return n}static getNetwork(e,t){const r=c.Logging.for(this.getNetwork);let i;try{r.debug("Connecting to channel "+t),i=e.getNetwork(t)}catch(e){throw this.parseError(e)}return i}static async getGateway(e,t,r){return await this.getConnection(r||await this.getClient(t),t,e)}static getClient(e){const t=this.log.for(this.getClient);t.debug("generating TLS credentials for msp "+e.mspId);let r=e.tlsCert;if("string"==typeof r)if(r.match(/-----BEGIN (CERTIFICATE|KEY|PRIVATE KEY)-----.+?-----END \1-----$/gms))r=Buffer.from(r,"utf8");else try{r=Buffer.from(I.default.readFileSync(r,"utf8"))}catch(e){throw new i.InternalError(`Failed to read the tls certificate from ${r}: ${e}`)}const a=S.credentials.createSsl(r);return t.debug("generating Gateway Client for url "+e.peerEndpoint),new g.Client(e.peerEndpoint,a,{"grpc.max_receive_message_length":1024*(e.sizeLimit||15)*1024,"grpc.max_send_message_length":1024*(e.sizeLimit||15)*1024})}static async getConnection(e,t,r){const i=c.Logging.for(this.getConnection);i.debug(`Retrieving Peer Identity for ${t.mspId} under ${t.certCertOrDirectoryPath}`);const a=await Oe(t.mspId,t.certCertOrDirectoryPath);i.debug("Retrieving signer key from "+t.keyCertOrDirectoryPath);let n,s=()=>{};if(t.hsm){const e=new Re(t.hsm.library),r=e.getSKIFromCertificatePath(t.certCertOrDirectoryPath),i=e.newSigner({label:t.hsm.tokenLabel,pin:t.hsm.pin+"",identifier:r});n=i.signer,s=i.close}else n=await Te(t.keyCertOrDirectoryPath);const o={client:e,identity:a,signer:n,evaluateOptions:()=>({deadline:Date.now()+1e3*r.get("evaluateTimeout")}),endorseOptions:()=>({deadline:Date.now()+1e3*r.get("endorseTimeout")}),submitOptions:()=>({deadline:Date.now()+1e3*r.get("submitTimeout")}),commitStatusOptions:()=>({deadline:Date.now()+1e3*r.get("commitTimeout")})};i.debug("Connecting to "+t.mspId);const d=l.connect(o);return t.hsm&&(d.close=new Proxy(d.close,{apply(e,t,r){Reflect.apply(e,t,r),s()}})),d}Dispatch(){return new Ke._baseDispatch}static parseError(e){const r="string"==typeof e?e:e.message;return r.includes("MVCC_READ_CONFLICT")?new ae(e):r.includes("ENDORSEMENT_POLICY_FAILURE")?new se(e):r.includes("PHANTOM_READ_CONFLICT")?new ne(e):e instanceof Error&&e.code&&9===e.code?new ie(e):r.includes(i.NotFoundError.name)?new i.NotFoundError(e):r.includes(i.ConflictError.name)?new i.ConflictError(e):r.includes(i.BadRequestError.name)?new i.BadRequestError(e):r.includes(t.QueryError.name)?new t.QueryError(e):r.includes(t.PagingError.name)?new t.PagingError(e):r.includes(t.UnsupportedError.name)?new t.UnsupportedError(e):r.includes(t.MigrationError.name)?new t.MigrationError(e):r.includes(t.ObserverError.name)?new t.ObserverError(e):r.includes(t.AuthorizationError.name)?new t.AuthorizationError(e):r.includes(t.ForbiddenError.name)?new t.ForbiddenError(e):r.includes(t.ConnectionError.name)?new t.ConnectionError(e):r.includes(i.SerializationError.name)?new i.SerializationError(e):new i.InternalError(e)}}n.__decorate([c.debug(),c.final(),n.__metadata("design:type",Function),n.__metadata("design:paramtypes",[Object,Object,Object,Object,t.Context]),n.__metadata("design:returntype",Promise)],Ke.prototype,"create",null),n.__decorate([c.debug(),c.final(),n.__metadata("design:type",Function),n.__metadata("design:paramtypes",[Object,Object,t.Context]),n.__metadata("design:returntype",Promise)],Ke.prototype,"read",null),n.__decorate([c.debug(),c.final(),n.__metadata("design:type",Function),n.__metadata("design:paramtypes",[Object,Object,Object,Object,t.Context]),n.__metadata("design:returntype",Promise)],Ke.prototype,"update",null),n.__decorate([c.debug(),c.final(),n.__metadata("design:type",Function),n.__metadata("design:paramtypes",[Object,Object,t.Context]),n.__metadata("design:returntype",Promise)],Ke.prototype,"delete",null),n.__decorate([c.debug(),n.__metadata("design:type",Function),n.__metadata("design:paramtypes",[Object,"function"==typeof($e="undefined"!=typeof D&&D)?$e:Object,Object,t.Context]),n.__metadata("design:returntype",Promise)],Ke.prototype,"raw",null),Ke.decoration(),t.Adapter.setCurrent(k);class Pe extends t.Dispatch{constructor(e){super(),this.client=e,this.decoder=new TextDecoder("utf8")}async close(){this.listeningStack&&this.listeningStack.close()}parsePayload(e){const t=this.decoder.decode(e);return JSON.parse(t)}observe(e){if(!(e instanceof Ke))throw new t.UnsupportedError("Only FabricClientAdapter can be observed by dispatch");return super.observe(e),()=>this.unObserve(e)}async updateObservers(e,a,n,...s){const{log:o,ctxArgs:c}=t.Adapter.logCtx(this.updateObservers,a,!1,...s);if(this.adapter)try{await this.adapter.refresh(e,a,n,...c)}catch(e){throw new i.InternalError("Failed to refresh dispatch: "+e)}else o.verbose(`No adapter observed for dispatch; skipping observer update for ${"string"==typeof e?e:r.Model.tableName(e)}:${a}`)}async handleEvents(e){if(!this.listeningStack)throw new i.InternalError('Event stack not initialized. Ensure that "startListening" is called before attempting this operation.');if(!this.adapter||!this.adapter.config)throw new i.InternalError("No adapter found. should be impossible");const t=e||await this.adapter.context(i.OperationKeys.READ,{correlationId:this.adapter.config.chaincodeName},this.models&&this.models[0]||r.Model),a=this.log.for(this.handleEvents);a.info(`Listening for incoming events on chaincode "${this.adapter.config.chaincodeName}" on channel "${this.adapter.config.channel}"...`);try{for await(const e of this.listeningStack){const{table:i,event:n,owner:s}=ve(e.eventName);if(s&&s!==this.adapter.config?.mspId)continue;const o=this.parsePayload(e.payload);try{const e=(i?r.Model.get(i):r.Model.get(this.models[0].name))??(i||this.models[0]?.name);await this.updateObservers(e,n,o.id,t)}catch(e){a.error(`Failed update observables for table ${i} event ${n} id: ${o.id}: ${e}`)}}}catch(e){a.error(`Failed to read event for chaincode "${this.adapter.config.chaincodeName}" on channel "${this.adapter.config.channel}": ${e}`),await this.close()}}async initialize(){if(!this.adapter)throw new i.InternalError("No adapter or config observed for dispatch");const e=await this.adapter.context("dispatch",{correlationId:this.adapter.config.chaincodeName},r.Model),{ctx:t}=this.logCtx([e],this.initialize),a=(await Ke.getGateway(t,this.adapter.config,this.client)).getNetwork(this.adapter.config.channel);if(!this.adapter)throw new i.InternalError("No adapter observed for dispatch");this.listeningStack=await a.getChaincodeEvents(this.adapter.config.chaincodeName),this.handleEvents(t)}}Ke&&(Ke._baseDispatch=Pe);const ke="##VERSION##",ze="##PACKAGE##";s.Metadata.registerLibrary(ze,ke),e.AllowanceError=X,e.BalanceError=Q,e.BaseEncoder=G,e.ClientSerializer=F,e.CoreUtils=z,e.CryptoUtils=V,e.DefaultFabricClientFlags=Ie,e.DeterministicSerializer=Ae,e.EndorsementError=ie,e.EndorsementPolicyError=se,e.FabricClientAdapter=Ke,e.FabricClientDispatch=Pe,e.FabricClientRepository=x,e.FabricERC20ClientRepository=R,e.FabricEnrollmentService=oe,e.FabricFlavour=k,e.FabricIdentityService=_e,e.ImplicitPrivateCollection=fe,e.MissingContextError=Z,e.MissingPKCSS11Lib=re,e.ModelCollection=(e,t)=>{const a=t||("function"!=typeof e?r.Model.ownerOf(e):void 0),n="function"==typeof e?e:e.constructor;if(!a)throw new i.InternalError(`Model ${n.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);return`${c.toPascalCase(n.name)}${t?c.toPascalCase(t):""}`},e.MvccReadConflictError=ae,e.NotInitializedError=te,e.OverflowError=J,e.Owner=function(){return function(e,r,a){const n=a.value;return a.value=async function(...e){const a=e[0],s=a.clientIdentity.getID(),o=await this.tokenRepository.select(),c=await o.execute(a);if(0==c.length)throw new i.NotFoundError("No tokens avaialble");if(c.length>1)throw new i.NotFoundError("To many token available : "+c.length);if(c[0].owner!=s)throw new t.AuthorizationError(`User not authorized to run ${r} on the token`);return await n.apply(this,e)},a}},e.PACKAGE_NAME=ze,e.PhantomReadConflictError=ne,e.RegistrationError=W,e.RegistrationRequestBuilder=ce,e.SimpleDeterministicSerializer=Se,e.UnauthorizedPrivateDataAccess=ee,e.VERSION=ke,e.add=(e,t)=>{const r=e+t;if(e!==r-t||t!==r-e)throw new J(`Addition overflow: ${e} + ${t}`);return r},e.contentOfLoadFile=xe,e.createMirrorHandler=he,e.deleteMirrorHandler=ge,e.evalMirrorMetadata=ue,e.extractPrivateKey=Fe,e.generateFabricEventName=(e,t,r)=>{const i=[e,t];return r&&i.push(r),i.join("_")},e.generateModelIndexes=(e,t)=>{const i=B([a.CouchDBKeys.TABLE]),n=t||{};n[i]={index:{fields:[a.CouchDBKeys.TABLE]},name:i,ddoc:i,type:"json"};const s={},o=r.Model.indexes(e);for(const e of Object.keys(o))for(const[,t]of Object.entries(o[e])){const r=t.directions,i=t.compositions,n=[e,a.CouchDBKeys.TABLE];$(s,n),i&&i.length&&$(s,n,void 0,i),r&&r.length&&r.forEach(e=>{$(s,n,e),i&&i.length&&$(s,n,e,i)})}return Object.entries(s).forEach(([e,t])=>{n[e]=t}),Object.values(s)},e.getCAUser=async(e,t,r,i)=>{Me.debug(`Creating a CA ${i} user ${e} with certificate ${r}`);const a=new d.User(e),n=d.User.newCryptoSuite();a.setCryptoSuite(n);const s=n.createKeyFromRaw(t);return await a.setEnrollment(s,r,i),a},e.getFirstDirFileName=Ne,e.getFirstDirFileNameContent=async e=>{const{promises:r}=await t.normalizeImport(import("fs")),{join:i}=await t.normalizeImport(import("path")),a=await r.readdir(e);return(await r.readFile(i(e,a[0]))).toString()},e.getIdentity=Oe,e.getSigner=Te,e.mirror=(t,r)=>s.Decoration.for(e.FabricModelKeys.MIRROR).define({decorator:(r,a)=>{const n={condition:a,resolver:r};return s.apply(s.metadata(s.Metadata.key(e.FabricModelKeys.FABRIC,e.FabricModelKeys.MIRROR),n),Ee(t),i.afterCreate(he,n,{priority:95}),i.afterUpdate(pe,n,{priority:95}),i.afterDelete(ge,n,{priority:95}))},args:[t,r]}).apply(),e.ownedBy=()=>s.Decoration.for(e.FabricModelKeys.OWNED_BY).define({decorator:()=>(t,a)=>s.apply(r.required(),i.readonly(),i.onCreate(le),s.propMetadata(s.Metadata.key(e.FabricModelKeys.FABRIC,e.FabricModelKeys.OWNED_BY),a))(t,a),args:[]}).apply(),e.ownedByOnCreate=le,e.parseEventName=ve,e.privateData=Ee,e.readFile=async e=>"string"!=typeof e?e:await(async e=>{const{promises:r}=await t.normalizeImport(import("fs"));return await r.readFile(e)})(e),e.readModelFile=K,e.readModelFolders=async(...e)=>{const t=require("fs"),r=[];for(const i of e){const e=t.readdirSync(i,{withFileTypes:!0,recursive:!0}).filter(e=>e.isFile()&&e.name.endsWith("js"));for(const t of e)r.push(...K(t))}return r},e.safeParseInt=e=>{if(!/^\d+$/.test(e))throw new i.ValidationError(r.stringFormat("Failed to parse: {0}","string contains digits"));const t=parseInt(e);if(isNaN(t))throw new i.ValidationError(r.stringFormat("Failed to parse: {0}","string is not a parsable integer"));return t},e.segregatedDataOnCreate=ye,e.segregatedDataOnDelete=be,e.segregatedDataOnRead=me,e.segregatedDataOnUpdate=we,e.sharedData=t=>s.Decoration.for(e.FabricModelKeys.SHARED).define({decorator:t=>Ce(t,e.FabricModelKeys.SHARED),args:[t]}).apply(),e.sub=(e,t)=>{const r=e-t;if(e!==r+t||t!==e-r)throw new J(`Subtraction overflow: ${e} - ${t}`);return r},e.transactionId=()=>s.Decoration.for(e.FabricModelKeys.TRANSACTION_ID).define({decorator:()=>(t,a)=>s.apply(r.required(),i.readonly(),i.onCreate(de),i.onUpdate(de),s.propMetadata(s.Metadata.key(e.FabricModelKeys.FABRIC,a,e.FabricModelKeys.TRANSACTION_ID),a))(t,a),args:[]}).apply(),e.transactionIdOnCreate=de,e.updateMirrorHandler=pe,e.writeIndexes=(e,t=process.cwd(),r)=>{const i=require("fs"),a=require("path");function n(e){const t=a.dirname(e);if(i.existsSync(t))return!0;n(t),i.mkdirSync(t)}e.forEach(e=>{const s=a.resolve(a.join(t,`./META-INF/statedb/couchdb/${r?`collections/${r}/`:""}indexes/${e.name}.json`));n(s),i.writeFileSync(s,JSON.stringify(e,void 0,2))})}},"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@decaf-ts/core"),require("@decaf-ts/decorator-validation"),require("@decaf-ts/db-decorators"),require("@decaf-ts/for-couchdb"),require("tslib"),require("@decaf-ts/decoration"),require("fabric-ca-client"),require("@decaf-ts/logging"),require("@hyperledger/fabric-gateway"),require("fabric-common"),require("crypto"),require("@peculiar/x509"),require("@peculiar/webcrypto"),require("@grpc/grpc-js"),require("pkcs11js"),require("fs"),require("path"),require("@noble/curves/nist")):"function"==typeof define&&define.amd?define(["exports","@decaf-ts/core","@decaf-ts/decorator-validation","@decaf-ts/db-decorators","@decaf-ts/for-couchdb","tslib","@decaf-ts/decoration","fabric-ca-client","@decaf-ts/logging","@hyperledger/fabric-gateway","fabric-common","crypto","@peculiar/x509","@peculiar/webcrypto","@grpc/grpc-js","pkcs11js","fs","path","@noble/curves/nist"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["for-fabric"]={},e.decafTsCore,e.decafTsDecoratorValidation,e.decafTsDbDecorators,e.decafTsForCouchdb,e.tslib,e.decafTsDecoration,e.fabricCaClient,e.decafTsLogging,e.hyperledgerFabricGateway,e.fabricCommon,e.crypto,e.peculiarX509,e.peculiarWebcrypto,e.grpcGrpcJs,e.pkcs11js,e.fs,e.path,e.nist);
|
|
2
|
-
|
|
1
|
+
(function(global, factory) {
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@decaf-ts/core"), require("@decaf-ts/decorator-validation"), require("@decaf-ts/db-decorators"), require("@decaf-ts/for-couchdb"), require("tslib"), require("@decaf-ts/decoration"), require("fabric-ca-client"), require("@decaf-ts/logging"), require("@hyperledger/fabric-gateway"), require("fabric-common"), require("crypto"), require("@peculiar/x509"), require("@peculiar/webcrypto"), require("@grpc/grpc-js"), require("pkcs11js"), require("fs"), require("path"), require("@noble/curves/nist")) : typeof define === "function" && define.amd ? define([ "exports", "@decaf-ts/core", "@decaf-ts/decorator-validation", "@decaf-ts/db-decorators", "@decaf-ts/for-couchdb", "tslib", "@decaf-ts/decoration", "fabric-ca-client", "@decaf-ts/logging", "@hyperledger/fabric-gateway", "fabric-common", "crypto", "@peculiar/x509", "@peculiar/webcrypto", "@grpc/grpc-js", "pkcs11js", "fs", "path", "@noble/curves/nist" ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self,
|
|
3
|
+
factory(global["for-fabric"] = {}, global.decafTsCore, global.decafTsDecoratorValidation, global.decafTsDbDecorators, global.decafTsForCouchdb, global.tslib, global.decafTsDecoration, global.fabricCaClient, global.decafTsLogging, global.hyperledgerFabricGateway, global.fabricCommon, global.crypto, global.peculiarX509, global.peculiarWebcrypto, global.grpcGrpcJs, global.pkcs11js, global.fs, global.path, global.nist));
|
|
4
|
+
})(this, function(exports, core, decoratorValidation, dbDecorators, forCouchdb, tslib, decoration, FabricCAServices, logging, fabricGateway, fabricCommon, crypto$1, x509, webcrypto, grpc, pkcs11, fs, path, nist) {
|
|
5
|
+
"use strict";
|
|
6
|
+
function _interopDefaultLegacy(e) {
|
|
7
|
+
return e && typeof e === "object" && "default" in e ? e : {
|
|
8
|
+
default: e
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function _interopNamespace(e) {
|
|
12
|
+
if (e && e.__esModule) return e;
|
|
13
|
+
var n = Object.create(null);
|
|
14
|
+
if (e) {
|
|
15
|
+
Object.keys(e).forEach(function(k) {
|
|
16
|
+
if (k !== "default") {
|
|
17
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
18
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function() {
|
|
21
|
+
return e[k];
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
n["default"] = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
var FabricCAServices__default = _interopDefaultLegacy(FabricCAServices);
|
|
31
|
+
var crypto__default = _interopDefaultLegacy(crypto$1);
|
|
32
|
+
var x509__namespace = _interopNamespace(x509);
|
|
33
|
+
var grpc__namespace = _interopNamespace(grpc);
|
|
34
|
+
var pkcs11__default = _interopDefaultLegacy(pkcs11);
|
|
35
|
+
var fs__default = _interopDefaultLegacy(fs);
|
|
36
|
+
var path__default = _interopDefaultLegacy(path);
|
|
37
|
+
class FabricClientRepository extends core.Repository {
|
|
38
|
+
constructor(adapter, clazz) {
|
|
39
|
+
super(adapter, clazz);
|
|
40
|
+
this._overrides = Object.assign({}, super["_overrides"], {
|
|
41
|
+
ignoreValidation: true,
|
|
42
|
+
ignoreHandlers: true,
|
|
43
|
+
allowRawStatements: false,
|
|
44
|
+
forcePrepareSimpleQueries: true,
|
|
45
|
+
forcePrepareComplexQueries: true,
|
|
46
|
+
allowGenerationOverride: false
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async paginateBy(key, order, ref = {
|
|
50
|
+
offset: 1,
|
|
51
|
+
limit: 10
|
|
52
|
+
}, ...args) {
|
|
53
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, core.PreparedStatementKeys.PAGE_BY, true)).for(this.paginateBy);
|
|
54
|
+
log.verbose(`paginating ${decoratorValidation.Model.tableName(this.class)} with page size ${ref.limit}`);
|
|
55
|
+
return this.statement(this.paginateBy.name, key, order, {
|
|
56
|
+
limit: ref.limit,
|
|
57
|
+
offset: ref.offset,
|
|
58
|
+
bookmark: ref.bookmark
|
|
59
|
+
}, ...ctxArgs);
|
|
60
|
+
}
|
|
61
|
+
async listBy(key, order, ...args) {
|
|
62
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, core.PreparedStatementKeys.LIST_BY, true)).for(this.listBy);
|
|
63
|
+
log.verbose(`listing ${decoratorValidation.Model.tableName(this.class)} by ${key} ${order}`);
|
|
64
|
+
return await this.statement(this.listBy.name, key, order, ...ctxArgs);
|
|
65
|
+
}
|
|
66
|
+
async findBy(key, value, ...args) {
|
|
67
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, core.PreparedStatementKeys.FIND_BY, true)).for(this.findBy);
|
|
68
|
+
log.verbose(`finding all ${decoratorValidation.Model.tableName(this.class)} with ${key} ${value}`);
|
|
69
|
+
return await this.statement(this.findBy.name, key, value, ...ctxArgs);
|
|
70
|
+
}
|
|
71
|
+
async findOneBy(key, value, ...args) {
|
|
72
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, core.PreparedStatementKeys.FIND_ONE_BY, true)).for(this.findOneBy);
|
|
73
|
+
log.verbose(`finding One ${decoratorValidation.Model.tableName(this.class)} with ${key} ${value}`);
|
|
74
|
+
return await this.statement(this.findOneBy.name, key, value, ...ctxArgs);
|
|
75
|
+
}
|
|
76
|
+
async statement(name, ...args) {
|
|
77
|
+
const {log: log, ctx: ctx, ctxArgs: ctxArgs} = (await this.logCtx(args, core.PersistenceKeys.STATEMENT, true)).for(this.statement);
|
|
78
|
+
log.verbose(`Executing prepared statement ${name}`);
|
|
79
|
+
const callArgs = ctxArgs.slice(0, -1);
|
|
80
|
+
const result = JSON.parse(this.adapter.decode(await this.adapter.evaluateTransaction(ctx, core.PersistenceKeys.STATEMENT, [ name, JSON.stringify(callArgs) ], undefined, undefined, this.class.name)));
|
|
81
|
+
if (Array.isArray(result)) {
|
|
82
|
+
return result.map(r => r[forCouchdb.CouchDBKeys.TABLE] && r[forCouchdb.CouchDBKeys.TABLE] === decoratorValidation.Model.tableName(this.class) ? new this.class(r) : r);
|
|
83
|
+
}
|
|
84
|
+
return result[forCouchdb.CouchDBKeys.TABLE] && result[forCouchdb.CouchDBKeys.TABLE] === decoratorValidation.Model.tableName(this.class) ? new this.class(result) : core.Paginator.isSerializedPage(result) ? Object.assign(result, {
|
|
85
|
+
data: result.data.map(d => new this.class(d))
|
|
86
|
+
}) : result;
|
|
87
|
+
}
|
|
88
|
+
async create(model, ...args) {
|
|
89
|
+
const {ctx: ctx, log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.create);
|
|
90
|
+
log.debug(`Creating new ${this.class.name} in table ${decoratorValidation.Model.tableName(this.class)}`);
|
|
91
|
+
let {record: record, id: id, transient: transient} = this.adapter.prepare(model, ctx);
|
|
92
|
+
record = await this.adapter.create(this.class, id, record, transient, ...ctxArgs);
|
|
93
|
+
return this.adapter.revert(record, this.class, id, transient, ctx);
|
|
94
|
+
}
|
|
95
|
+
async update(model, ...args) {
|
|
96
|
+
const {ctxArgs: ctxArgs, log: log, ctx: ctx} = this.logCtx(args, this.update);
|
|
97
|
+
let {record: record, id: id, transient: transient} = this.adapter.prepare(model, ctx);
|
|
98
|
+
log.debug(`updating ${this.class.name} in table ${decoratorValidation.Model.tableName(this.class)} with id ${id}`);
|
|
99
|
+
record = await this.adapter.update(this.class, id, record, transient, ...ctxArgs);
|
|
100
|
+
return this.adapter.revert(record, this.class, id, transient, ctx);
|
|
101
|
+
}
|
|
102
|
+
async createAllPrefix(models, ...args) {
|
|
103
|
+
const {ctx: ctx, ctxArgs: ctxArgs} = (await this.logCtx(args, dbDecorators.OperationKeys.CREATE, true)).for(this.createAllPrefix);
|
|
104
|
+
const ignoreHandlers = ctx.get("ignoreHandlers");
|
|
105
|
+
const ignoreValidate = ctx.get("ignoreValidation");
|
|
106
|
+
if (!models.length) return [ models, ...ctxArgs ];
|
|
107
|
+
models = await Promise.all(models.map(async m => {
|
|
108
|
+
m = new this.class(m);
|
|
109
|
+
if (!ignoreHandlers) await dbDecorators.enforceDBDecorators(this, ctx, m, dbDecorators.OperationKeys.CREATE, dbDecorators.OperationKeys.ON);
|
|
110
|
+
return m;
|
|
111
|
+
}));
|
|
112
|
+
if (!ignoreValidate) {
|
|
113
|
+
const ignoredProps = ctx.get("ignoredValidationProperties") || [];
|
|
114
|
+
const errors = await Promise.all(models.map(m => Promise.resolve(m.hasErrors(...ignoredProps))));
|
|
115
|
+
const errorMessages = dbDecorators.reduceErrorsToPrint(errors);
|
|
116
|
+
if (errorMessages) throw new dbDecorators.ValidationError(errorMessages);
|
|
117
|
+
}
|
|
118
|
+
return [ models, ...ctxArgs ];
|
|
119
|
+
}
|
|
120
|
+
async createAll(models, ...args) {
|
|
121
|
+
if (!models.length) return models;
|
|
122
|
+
const {ctx: ctx, log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.createAll);
|
|
123
|
+
log.debug(`Creating ${models.length} new ${this.class.name} in table ${decoratorValidation.Model.tableName(this.class)}`);
|
|
124
|
+
const prepared = models.map(m => this.adapter.prepare(m, ctx));
|
|
125
|
+
const ids = prepared.map(p => p.id);
|
|
126
|
+
let records = prepared.map(p => p.record);
|
|
127
|
+
const transient = prepared.map(p => p.transient);
|
|
128
|
+
records = await this.adapter.createAll(this.class, ids, records, transient, ...ctxArgs);
|
|
129
|
+
return records.map((r, i) => this.adapter.revert(r, this.class, ids[i], ctx.get("rebuildWithTransient") ? prepared[i].transient : undefined, ctx));
|
|
130
|
+
}
|
|
131
|
+
async updateAll(models, ...args) {
|
|
132
|
+
const {ctx: ctx, log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.updateAll);
|
|
133
|
+
log.debug(`Updating ${models.length} new ${this.class.name} in table ${decoratorValidation.Model.tableName(this.class)}`);
|
|
134
|
+
const records = models.map(m => this.adapter.prepare(m, ctx));
|
|
135
|
+
const updated = await this.adapter.updateAll(this.class, records.map(r => r.id), records.map(r => r.record), records.map(r => r.transient), ...ctxArgs);
|
|
136
|
+
return updated.map((u, i) => this.adapter.revert(u, this.class, records[i].id, ctx.get("rebuildWithTransient") ? records[i].transient : undefined, ctx));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
let ERC20Token = class ERC20Token extends core.BaseModel {
|
|
140
|
+
constructor(m) {
|
|
141
|
+
super(m);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
tslib.__decorate([ core.pk({
|
|
145
|
+
type: String
|
|
146
|
+
}), tslib.__metadata("design:type", String) ], ERC20Token.prototype, "name", void 0);
|
|
147
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], ERC20Token.prototype, "owner", void 0);
|
|
148
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], ERC20Token.prototype, "symbol", void 0);
|
|
149
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", Number) ], ERC20Token.prototype, "decimals", void 0);
|
|
150
|
+
ERC20Token = tslib.__decorate([ core.table("erc20_tokens"), decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], ERC20Token);
|
|
151
|
+
let ERC20Wallet = class ERC20Wallet extends core.BaseModel {
|
|
152
|
+
constructor(m) {
|
|
153
|
+
super(m);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
tslib.__decorate([ core.pk({
|
|
157
|
+
type: String
|
|
158
|
+
}), tslib.__metadata("design:type", String) ], ERC20Wallet.prototype, "id", void 0);
|
|
159
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], ERC20Wallet.prototype, "token", void 0);
|
|
160
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", Number) ], ERC20Wallet.prototype, "balance", void 0);
|
|
161
|
+
tslib.__decorate([ core.column(), tslib.__metadata("design:type", String) ], ERC20Wallet.prototype, "captive", void 0);
|
|
162
|
+
ERC20Wallet = tslib.__decorate([ core.table("erc20_wallets"), decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], ERC20Wallet);
|
|
163
|
+
let Allowance = class Allowance extends core.BaseModel {
|
|
164
|
+
constructor(m) {
|
|
165
|
+
super(m);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
tslib.__decorate([ core.pk({
|
|
169
|
+
type: String
|
|
170
|
+
}), core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], Allowance.prototype, "owner", void 0);
|
|
171
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], Allowance.prototype, "spender", void 0);
|
|
172
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", Number) ], Allowance.prototype, "value", void 0);
|
|
173
|
+
Allowance = tslib.__decorate([ core.table("erc20_allowances"), decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], Allowance);
|
|
174
|
+
class ClientSerializer extends decoratorValidation.JSONSerializer {
|
|
175
|
+
constructor() {
|
|
176
|
+
super();
|
|
177
|
+
}
|
|
178
|
+
preSerialize(model, modelName) {
|
|
179
|
+
const toSerialize = Object.assign({}, model);
|
|
180
|
+
let metadata = decoration.Metadata.modelName(model.constructor);
|
|
181
|
+
if (!metadata || metadata === "Object") if (modelName) metadata = modelName; else throw new dbDecorators.SerializationError(`Could not find metadata for ${model.constructor.name}`);
|
|
182
|
+
toSerialize[decoratorValidation.ModelKeys.ANCHOR] = metadata;
|
|
183
|
+
return toSerialize;
|
|
184
|
+
}
|
|
185
|
+
deserialize(str) {
|
|
186
|
+
const deserialization = JSON.parse(str);
|
|
187
|
+
const className = deserialization[decoratorValidation.ModelKeys.ANCHOR];
|
|
188
|
+
if (!className) throw new Error("Could not find class reference in serialized model");
|
|
189
|
+
const model = decoratorValidation.Model.build(deserialization, className);
|
|
190
|
+
return model;
|
|
191
|
+
}
|
|
192
|
+
serialize(model, modelName) {
|
|
193
|
+
return JSON.stringify(this.preSerialize(model, modelName));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
class FabricERC20ClientRepository extends FabricClientRepository {
|
|
197
|
+
static {
|
|
198
|
+
this.serializer = new ClientSerializer;
|
|
199
|
+
}
|
|
200
|
+
static {
|
|
201
|
+
this.decoder = new TextDecoder("utf8");
|
|
202
|
+
}
|
|
203
|
+
async updateObservers(table, event, id, ...args) {
|
|
204
|
+
if (!this.observerHandler) throw new dbDecorators.InternalError("ObserverHandler not initialized. Did you register any observables?");
|
|
205
|
+
const {log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.updateObservers);
|
|
206
|
+
log.verbose(`Updating ${this.observerHandler.count()} observers for ${this}`);
|
|
207
|
+
table = typeof table === "string" ? decoratorValidation.Model.get(table) : table;
|
|
208
|
+
let parsedId;
|
|
209
|
+
if (id === undefined) {
|
|
210
|
+
parsedId = undefined;
|
|
211
|
+
} else if (Array.isArray(id)) {
|
|
212
|
+
parsedId = id.map(i => core.Sequence.parseValue(decoratorValidation.Model.sequenceFor(table).type, i));
|
|
213
|
+
} else {
|
|
214
|
+
parsedId = core.Sequence.parseValue(decoratorValidation.Model.sequenceFor(table).type, id);
|
|
215
|
+
}
|
|
216
|
+
await this.observerHandler.updateObservers(table, event, parsedId, ...ctxArgs);
|
|
217
|
+
}
|
|
218
|
+
decode(data) {
|
|
219
|
+
return FabricERC20ClientRepository.decoder.decode(data);
|
|
220
|
+
}
|
|
221
|
+
constructor(adapter) {
|
|
222
|
+
super(adapter, ERC20Wallet);
|
|
223
|
+
this.serializer = FabricERC20ClientRepository.serializer;
|
|
224
|
+
}
|
|
225
|
+
async tokenName(...args) {
|
|
226
|
+
const {ctx: ctx} = (await this.logCtx(args, "tokenName", true)).for(this.tokenName);
|
|
227
|
+
const name = await this.adapter.evaluateTransaction(ctx, "TokenName");
|
|
228
|
+
return this.decode(name);
|
|
229
|
+
}
|
|
230
|
+
async symbol(...args) {
|
|
231
|
+
const {ctx: ctx} = (await this.logCtx(args, "symbol", true)).for(this.symbol);
|
|
232
|
+
const symbol = await this.adapter.evaluateTransaction(ctx, "Symbol");
|
|
233
|
+
return this.decode(symbol);
|
|
234
|
+
}
|
|
235
|
+
async decimals(...args) {
|
|
236
|
+
const {ctx: ctx} = (await this.logCtx(args, "decimals", true)).for(this.decimals);
|
|
237
|
+
const decimals = await this.adapter.evaluateTransaction(ctx, "Decimals");
|
|
238
|
+
return Number(this.decode(decimals));
|
|
239
|
+
}
|
|
240
|
+
async totalSupply(...args) {
|
|
241
|
+
const {ctx: ctx} = (await this.logCtx(args, "totalSupply", true)).for(this.totalSupply);
|
|
242
|
+
const total = await this.adapter.evaluateTransaction(ctx, "TotalSupply");
|
|
243
|
+
return Number(this.decode(total));
|
|
244
|
+
}
|
|
245
|
+
async balanceOf(owner, ...args) {
|
|
246
|
+
const {ctx: ctx} = (await this.logCtx(args, "balance", true)).for(this.balanceOf);
|
|
247
|
+
const balance = await this.adapter.evaluateTransaction(ctx, "BalanceOf", [ owner ]);
|
|
248
|
+
return Number(this.decode(balance));
|
|
249
|
+
}
|
|
250
|
+
async transfer(to, value, ...args) {
|
|
251
|
+
const {ctx: ctx} = (await this.logCtx(args, "transfer", true)).for(this.transfer);
|
|
252
|
+
const transferred = await this.adapter.submitTransaction(ctx, "Transfer", [ to, value.toString() ]);
|
|
253
|
+
return this.decode(transferred) === "true" ? true : false;
|
|
254
|
+
}
|
|
255
|
+
async transferFrom(from, to, value) {
|
|
256
|
+
const contextArgs = await core.Context.args("transferFrom", this.class, [], this.adapter, this._overrides || {});
|
|
257
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.transferFrom);
|
|
258
|
+
const transferred = await this.adapter.submitTransaction(ctx, "TransferFrom", [ from, to, value.toString() ]);
|
|
259
|
+
return this.decode(transferred) === "true" ? true : false;
|
|
260
|
+
}
|
|
261
|
+
async approve(spender, value) {
|
|
262
|
+
const contextArgs = await core.Context.args("approve", this.class, [], this.adapter, this._overrides || {});
|
|
263
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.approve);
|
|
264
|
+
const approved = await this.adapter.submitTransaction(ctx, "Approve", [ spender, value.toString() ]);
|
|
265
|
+
return this.decode(approved) === "true" ? true : false;
|
|
266
|
+
}
|
|
267
|
+
async allowance(owner, spender) {
|
|
268
|
+
const contextArgs = await core.Context.args("allowance", this.class, [], this.adapter, this._overrides || {});
|
|
269
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.allowance);
|
|
270
|
+
const allowance = await this.adapter.submitTransaction(ctx, "Allowance", [ owner, spender ]);
|
|
271
|
+
return Number(this.decode(allowance));
|
|
272
|
+
}
|
|
273
|
+
async initialize(token) {
|
|
274
|
+
const contextArgs = await core.Context.args("initialize", this.class, [], this.adapter, this._overrides || {});
|
|
275
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.initialize);
|
|
276
|
+
const initiliazed = await this.adapter.submitTransaction(ctx, "Initialize", [ FabricERC20ClientRepository.serializer.serialize(token) ]);
|
|
277
|
+
return this.decode(initiliazed) === "true" ? true : false;
|
|
278
|
+
}
|
|
279
|
+
async checkInitialized() {
|
|
280
|
+
const contextArgs = await core.Context.args("checkInitialized", this.class, [], this.adapter, this._overrides || {});
|
|
281
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.checkInitialized);
|
|
282
|
+
await this.adapter.evaluateTransaction(ctx, "CheckInitialized");
|
|
283
|
+
}
|
|
284
|
+
async mint(amount) {
|
|
285
|
+
const contextArgs = await core.Context.args("mint", this.class, [], this.adapter, this._overrides || {});
|
|
286
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.mint);
|
|
287
|
+
await this.adapter.submitTransaction(ctx, "Mint", [ amount.toString() ]);
|
|
288
|
+
}
|
|
289
|
+
async burn(amount) {
|
|
290
|
+
const contextArgs = await core.Context.args("burn", this.class, [], this.adapter, this._overrides || {});
|
|
291
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.burn);
|
|
292
|
+
await this.adapter.submitTransaction(ctx, "Burn", [ amount.toString() ]);
|
|
293
|
+
}
|
|
294
|
+
async burnFrom(account, amount) {
|
|
295
|
+
const contextArgs = await core.Context.args("burnFrom", this.class, [], this.adapter, this._overrides || {});
|
|
296
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.burnFrom);
|
|
297
|
+
await this.adapter.submitTransaction(ctx, "BurnFrom", [ account, amount.toString() ]);
|
|
298
|
+
}
|
|
299
|
+
async clientAccountBalance() {
|
|
300
|
+
const contextArgs = await core.Context.args("accountBalance", this.class, [], this.adapter, this._overrides || {});
|
|
301
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.clientAccountBalance);
|
|
302
|
+
const serializedAccountBalance = await this.adapter.evaluateTransaction(ctx, "ClientAccountBalance");
|
|
303
|
+
return Number(this.decode(serializedAccountBalance));
|
|
304
|
+
}
|
|
305
|
+
async clientAccountID() {
|
|
306
|
+
const contextArgs = await core.Context.args("accountId", this.class, [], this.adapter, this._overrides || {});
|
|
307
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.clientAccountID);
|
|
308
|
+
const clientAccountID = await this.adapter.evaluateTransaction(ctx, "ClientAccountID");
|
|
309
|
+
return this.decode(clientAccountID);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function getIndexReference(name, direction, compositions) {
|
|
313
|
+
return [ ...name.map(n => n === forCouchdb.CouchDBKeys.TABLE ? "table" : n), ...compositions || [], ...direction ? [ direction ] : [], "index" ].join(decoration.Metadata.splitter);
|
|
314
|
+
}
|
|
315
|
+
function addIndex(accum, fields, direction, compositions) {
|
|
316
|
+
const tableField = fields.pop();
|
|
317
|
+
if (tableField && tableField !== forCouchdb.CouchDBKeys.TABLE) {
|
|
318
|
+
fields.push(tableField);
|
|
319
|
+
} else if (tableField === forCouchdb.CouchDBKeys.TABLE) {
|
|
320
|
+
fields.unshift(tableField);
|
|
321
|
+
}
|
|
322
|
+
const name = getIndexReference(fields, direction, compositions);
|
|
323
|
+
let f = [ ...fields, ...compositions || [] ];
|
|
324
|
+
if (direction) f = f.reduce((accum, el) => {
|
|
325
|
+
const entry = {};
|
|
326
|
+
entry[el] = direction;
|
|
327
|
+
accum.push(entry);
|
|
328
|
+
return accum;
|
|
329
|
+
}, []);
|
|
330
|
+
const index = {
|
|
331
|
+
index: {
|
|
332
|
+
fields: f
|
|
333
|
+
},
|
|
334
|
+
name: name,
|
|
335
|
+
ddoc: name,
|
|
336
|
+
type: "json"
|
|
337
|
+
};
|
|
338
|
+
accum[name] = index;
|
|
339
|
+
}
|
|
340
|
+
function generateModelIndexes(m, accum) {
|
|
341
|
+
const tableName = getIndexReference([ forCouchdb.CouchDBKeys.TABLE ]);
|
|
342
|
+
const indexes = accum || {};
|
|
343
|
+
indexes[tableName] = {
|
|
344
|
+
index: {
|
|
345
|
+
fields: [ forCouchdb.CouchDBKeys.TABLE ]
|
|
346
|
+
},
|
|
347
|
+
name: tableName,
|
|
348
|
+
ddoc: tableName,
|
|
349
|
+
type: "json"
|
|
350
|
+
};
|
|
351
|
+
const result = {};
|
|
352
|
+
const modelIndexes = decoratorValidation.Model.indexes(m);
|
|
353
|
+
for (const prop of Object.keys(modelIndexes)) {
|
|
354
|
+
for (const [, dec] of Object.entries(modelIndexes[prop])) {
|
|
355
|
+
const directions = dec.directions;
|
|
356
|
+
const compositions = dec.compositions;
|
|
357
|
+
const fields = [ prop, forCouchdb.CouchDBKeys.TABLE ];
|
|
358
|
+
addIndex(result, fields);
|
|
359
|
+
if (compositions && compositions.length) addIndex(result, fields, undefined, compositions);
|
|
360
|
+
if (directions && directions.length) {
|
|
361
|
+
directions.forEach(d => {
|
|
362
|
+
addIndex(result, fields, d);
|
|
363
|
+
if (compositions && compositions.length) addIndex(result, fields, d, compositions);
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
Object.entries(result).forEach(([key, value]) => {
|
|
369
|
+
indexes[key] = value;
|
|
370
|
+
});
|
|
371
|
+
return Object.values(result);
|
|
372
|
+
}
|
|
373
|
+
function readModelFile(file) {
|
|
374
|
+
const path = require("path");
|
|
375
|
+
const exports = require(path.join(process.cwd(), file.parentPath, file.name));
|
|
376
|
+
const values = Object.values(exports).filter(e => {
|
|
377
|
+
try {
|
|
378
|
+
const m = new e;
|
|
379
|
+
return m instanceof decoratorValidation.Model;
|
|
380
|
+
} catch (e) {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
return values;
|
|
385
|
+
}
|
|
386
|
+
async function readModelFolders(...folders) {
|
|
387
|
+
const fs = require("fs");
|
|
388
|
+
const result = [];
|
|
389
|
+
for (const folder of folders) {
|
|
390
|
+
const files = fs.readdirSync(folder, {
|
|
391
|
+
withFileTypes: true,
|
|
392
|
+
recursive: true
|
|
393
|
+
}).filter(f => f.isFile() && f.name.endsWith("js"));
|
|
394
|
+
for (const file of files) {
|
|
395
|
+
result.push(...readModelFile(file));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return result;
|
|
399
|
+
}
|
|
400
|
+
function writeIndexes(indexes, p = process.cwd(), collection) {
|
|
401
|
+
const fs = require("fs");
|
|
402
|
+
const path = require("path");
|
|
403
|
+
function ensureDirectoryExistence(filePath) {
|
|
404
|
+
const dirname = path.dirname(filePath);
|
|
405
|
+
if (fs.existsSync(dirname)) {
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
ensureDirectoryExistence(dirname);
|
|
409
|
+
fs.mkdirSync(dirname);
|
|
410
|
+
}
|
|
411
|
+
indexes.forEach(index => {
|
|
412
|
+
const file = path.resolve(path.join(p, `./META-INF/statedb/couchdb/${collection ? `collections/${collection}/` : ""}indexes/${index.name}.json`));
|
|
413
|
+
ensureDirectoryExistence(file);
|
|
414
|
+
fs.writeFileSync(file, JSON.stringify(index, undefined, 2));
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
exports.IdentityCredentials = class IdentityCredentials extends core.BaseModel {
|
|
418
|
+
constructor(arg) {
|
|
419
|
+
super(arg);
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
tslib.__decorate([ decoration.description("Unique identifier of the credentials record"), core.column(), core.pk(), tslib.__metadata("design:type", String) ], exports.IdentityCredentials.prototype, "id", void 0);
|
|
423
|
+
tslib.__decorate([ decoration.description("PEM-encoded X.509 certificate for the identity"), core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], exports.IdentityCredentials.prototype, "certificate", void 0);
|
|
424
|
+
tslib.__decorate([ decoration.description("PEM-encoded root or intermediate certificate"), core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], exports.IdentityCredentials.prototype, "rootCertificate", void 0);
|
|
425
|
+
tslib.__decorate([ decoration.description("PEM-encoded private key"), core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], exports.IdentityCredentials.prototype, "privateKey", void 0);
|
|
426
|
+
exports.IdentityCredentials = tslib.__decorate([ decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], exports.IdentityCredentials);
|
|
427
|
+
exports.FabricModelKeys = void 0;
|
|
428
|
+
(function(FabricModelKeys) {
|
|
429
|
+
FabricModelKeys["PRIVATE"] = "private";
|
|
430
|
+
FabricModelKeys["SHARED"] = "shared";
|
|
431
|
+
FabricModelKeys["FABRIC"] = "fabric";
|
|
432
|
+
FabricModelKeys["OWNED_BY"] = "owned-by";
|
|
433
|
+
FabricModelKeys["TRANSACTION_ID"] = "transaction-id";
|
|
434
|
+
FabricModelKeys["MIRROR"] = "mirror";
|
|
435
|
+
})(exports.FabricModelKeys || (exports.FabricModelKeys = {}));
|
|
436
|
+
exports.IdentityType = void 0;
|
|
437
|
+
(function(IdentityType) {
|
|
438
|
+
IdentityType["X509"] = "X.509";
|
|
439
|
+
})(exports.IdentityType || (exports.IdentityType = {}));
|
|
440
|
+
const FabricFlavour = "hlf-fabric";
|
|
441
|
+
exports.Identity = class Identity extends core.BaseModel {
|
|
442
|
+
constructor(arg) {
|
|
443
|
+
super(arg);
|
|
444
|
+
this.type = exports.IdentityType.X509;
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
tslib.__decorate([ decoration.description("Unique identifier of the identity"), core.pk(), tslib.__metadata("design:type", String) ], exports.Identity.prototype, "id", void 0);
|
|
448
|
+
tslib.__decorate([ core.oneToOne(exports.IdentityCredentials, {
|
|
449
|
+
update: core.Cascade.CASCADE,
|
|
450
|
+
delete: core.Cascade.CASCADE
|
|
451
|
+
}), tslib.__metadata("design:type", exports.IdentityCredentials) ], exports.Identity.prototype, "credentials", void 0);
|
|
452
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), core.index(), tslib.__metadata("design:type", String) ], exports.Identity.prototype, "mspId", void 0);
|
|
453
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], exports.Identity.prototype, "type", void 0);
|
|
454
|
+
exports.Identity = tslib.__decorate([ decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], exports.Identity);
|
|
455
|
+
class CoreUtils {
|
|
456
|
+
static {
|
|
457
|
+
this.logger = new logging.MiniLogger(CoreUtils.name);
|
|
458
|
+
}
|
|
459
|
+
constructor() {}
|
|
460
|
+
static async contentOfLoadFile(contentOrPath, fileReader) {
|
|
461
|
+
if (contentOrPath instanceof Uint8Array) return contentOrPath;
|
|
462
|
+
if (contentOrPath.match(/-----BEGIN (CERTIFICATE|KEY|PRIVATE KEY)-----.+?-----END \1-----$/gms)) return contentOrPath;
|
|
463
|
+
return await fileReader(contentOrPath);
|
|
464
|
+
}
|
|
465
|
+
static async readFile(contentOrPath) {
|
|
466
|
+
if (typeof contentOrPath !== "string") return contentOrPath;
|
|
467
|
+
const fileReader = async path => {
|
|
468
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
469
|
+
return await promises.readFile(path);
|
|
470
|
+
};
|
|
471
|
+
return await fileReader(contentOrPath);
|
|
472
|
+
}
|
|
473
|
+
static async getCAUser(userName, privateKey, certificate, mspId, options) {
|
|
474
|
+
this.logger.debug(decoratorValidation.stringFormat("Creating CA {0} user {1} with certificate {2}", mspId, userName, certificate));
|
|
475
|
+
const user = new fabricCommon.User(userName);
|
|
476
|
+
const config = options?.hsm ? {
|
|
477
|
+
software: false,
|
|
478
|
+
lib: options.hsm.library,
|
|
479
|
+
slot: options.hsm.slot,
|
|
480
|
+
label: options.hsm.tokenLabel,
|
|
481
|
+
pin: String(options.hsm.pin)
|
|
482
|
+
} : undefined;
|
|
483
|
+
const cryptoSuite = this.getCryptoSuite(config);
|
|
484
|
+
user.setCryptoSuite(cryptoSuite);
|
|
485
|
+
const enrollmentKey = options?.hsm ? await this.getHSMEnrollmentKey(cryptoSuite, certificate, options.hsm) : this.getSoftwareEnrollmentKey(cryptoSuite, privateKey);
|
|
486
|
+
await user.setEnrollment(enrollmentKey, certificate, mspId);
|
|
487
|
+
return user;
|
|
488
|
+
}
|
|
489
|
+
static getCryptoSuite(options) {
|
|
490
|
+
if (!options) return fabricCommon.User.newCryptoSuite();
|
|
491
|
+
if (CoreUtils.cryptoSuite) return CoreUtils.cryptoSuite;
|
|
492
|
+
CoreUtils.cryptoSuite = fabricCommon.User.newCryptoSuite(options);
|
|
493
|
+
return CoreUtils.cryptoSuite;
|
|
494
|
+
}
|
|
495
|
+
static getSoftwareEnrollmentKey(cryptoSuite, privateKey) {
|
|
496
|
+
if (!privateKey) {
|
|
497
|
+
throw new Error("Private key must be provided when HSM configuration is not supplied");
|
|
498
|
+
}
|
|
499
|
+
return cryptoSuite.createKeyFromRaw(privateKey);
|
|
500
|
+
}
|
|
501
|
+
static async getHSMEnrollmentKey(cryptoSuite, certificate, hsm) {
|
|
502
|
+
const ski = hsm.keyIdHex && hsm.keyIdHex.trim().length > 0 ? Buffer.from(hsm.keyIdHex, "hex") : await this.getCertificateSKI(certificate);
|
|
503
|
+
const key = await cryptoSuite.getKey(ski);
|
|
504
|
+
if (!key || typeof key.isPrivate === "function" && !key.isPrivate()) {
|
|
505
|
+
throw new Error("Unable to resolve private key from HSM");
|
|
506
|
+
}
|
|
507
|
+
return key;
|
|
508
|
+
}
|
|
509
|
+
static async getCertificateSKI(certificate) {
|
|
510
|
+
const x509 = new crypto$1.X509Certificate(certificate);
|
|
511
|
+
const jwk = x509.publicKey.export({
|
|
512
|
+
format: "jwk"
|
|
513
|
+
});
|
|
514
|
+
const prefix = Buffer.from([ 4 ]);
|
|
515
|
+
const x = Buffer.from(jwk.x || "", "base64url");
|
|
516
|
+
const y = Buffer.from(jwk.y || "", "base64url");
|
|
517
|
+
return crypto__default["default"].createHash("sha256").update(Buffer.concat([ prefix, x, y ])).digest();
|
|
518
|
+
}
|
|
519
|
+
static async getIdentity(mspId, certDirectoryPath) {
|
|
520
|
+
const identityFileReader = async path => {
|
|
521
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
522
|
+
const certPath = await this.getFirstDirFileName(path);
|
|
523
|
+
const credentials = await promises.readFile(certPath);
|
|
524
|
+
return credentials;
|
|
525
|
+
};
|
|
526
|
+
const credentials = await this.contentOfLoadFile(certDirectoryPath, identityFileReader);
|
|
527
|
+
return {
|
|
528
|
+
mspId: mspId,
|
|
529
|
+
credentials: credentials
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
static async getFirstDirFileName(dirPath) {
|
|
533
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
534
|
+
const {join: join} = await core.normalizeImport(import("path"));
|
|
535
|
+
const files = await promises.readdir(dirPath);
|
|
536
|
+
return join(dirPath, files[0]);
|
|
537
|
+
}
|
|
538
|
+
static async getFirstDirFileNameContent(dirPath) {
|
|
539
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
540
|
+
const {join: join} = await core.normalizeImport(import("path"));
|
|
541
|
+
const files = await promises.readdir(dirPath);
|
|
542
|
+
return (await promises.readFile(join(dirPath, files[0]))).toString();
|
|
543
|
+
}
|
|
544
|
+
static async getFileContent(filePath) {
|
|
545
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
546
|
+
return (await promises.readFile(filePath)).toString();
|
|
547
|
+
}
|
|
548
|
+
static async getSigner(keyDirectoryPath) {
|
|
549
|
+
const signerFileReader = async path => {
|
|
550
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
551
|
+
const keyPath = await this.getFirstDirFileName(path);
|
|
552
|
+
return await promises.readFile(keyPath);
|
|
553
|
+
};
|
|
554
|
+
const privateKeyPem = await this.contentOfLoadFile(keyDirectoryPath, signerFileReader);
|
|
555
|
+
const privateKey = await this.extractPrivateKey(privateKeyPem);
|
|
556
|
+
const keys = Object.getOwnPropertySymbols(privateKey);
|
|
557
|
+
const k = privateKey[keys[0]];
|
|
558
|
+
return fabricGateway.signers.newPrivateKeySigner(k);
|
|
559
|
+
}
|
|
560
|
+
static async extractPrivateKey(pem) {
|
|
561
|
+
const libName = "crypto";
|
|
562
|
+
let subtle;
|
|
563
|
+
if (globalThis.window && globalThis.window.Crypto) {
|
|
564
|
+
subtle = globalThis.Crypto.subtle;
|
|
565
|
+
} else {
|
|
566
|
+
const lib = await core.normalizeImport(import(libName));
|
|
567
|
+
subtle = lib.subtle || lib.webcrypto.subtle;
|
|
568
|
+
}
|
|
569
|
+
if (!subtle) throw new Error("Could not load SubtleCrypto module");
|
|
570
|
+
function str2ab(str) {
|
|
571
|
+
const buf = new ArrayBuffer(str.length);
|
|
572
|
+
const bufView = new Uint8Array(buf);
|
|
573
|
+
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
574
|
+
bufView[i] = str.charCodeAt(i);
|
|
575
|
+
}
|
|
576
|
+
return buf;
|
|
577
|
+
}
|
|
578
|
+
const str = pem.toString("utf8").replace("-----BEGIN PRIVATE KEY-----", "").replaceAll("\n", "").replace("-----END PRIVATE KEY-----", "");
|
|
579
|
+
const decoded = Buffer.from(str, "base64").toString("binary");
|
|
580
|
+
const binaryDer = str2ab(decoded);
|
|
581
|
+
const key = await subtle.importKey("pkcs8", binaryDer, {
|
|
582
|
+
name: "ECDSA",
|
|
583
|
+
namedCurve: "P-256"
|
|
584
|
+
}, true, [ "sign" ]);
|
|
585
|
+
return key;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
const crypto = new webcrypto.Crypto;
|
|
589
|
+
x509__namespace.cryptoProvider.set(crypto);
|
|
590
|
+
exports.BASE_ALPHABET = void 0;
|
|
591
|
+
(function(BASE_ALPHABET) {
|
|
592
|
+
BASE_ALPHABET["BASE2"] = "01";
|
|
593
|
+
BASE_ALPHABET["BASE8"] = "01234567";
|
|
594
|
+
BASE_ALPHABET["BASE11"] = "0123456789a";
|
|
595
|
+
BASE_ALPHABET["BASE16"] = "0123456789abcdef";
|
|
596
|
+
BASE_ALPHABET["BASE32"] = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
597
|
+
BASE_ALPHABET["BASE32_Z"] = "ybndrfg8ejkmcpqxot1uwisza345h769";
|
|
598
|
+
BASE_ALPHABET["BASE36"] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
599
|
+
BASE_ALPHABET["BASE58"] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
600
|
+
BASE_ALPHABET["BASE62"] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
601
|
+
BASE_ALPHABET["BASE64"] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
602
|
+
BASE_ALPHABET["BASE67"] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.!~";
|
|
603
|
+
})(exports.BASE_ALPHABET || (exports.BASE_ALPHABET = {}));
|
|
604
|
+
exports.CRYPTO = void 0;
|
|
605
|
+
(function(CRYPTO) {
|
|
606
|
+
CRYPTO["HASH"] = "SHA-256";
|
|
607
|
+
CRYPTO[CRYPTO["ITERATIONS"] = 1e3] = "ITERATIONS";
|
|
608
|
+
CRYPTO[CRYPTO["KEYLENGTH"] = 48] = "KEYLENGTH";
|
|
609
|
+
CRYPTO[CRYPTO["DERIVED_IV_LENGTH"] = 16] = "DERIVED_IV_LENGTH";
|
|
610
|
+
CRYPTO[CRYPTO["DERIVED_KEY_LENGTH"] = 32] = "DERIVED_KEY_LENGTH";
|
|
611
|
+
CRYPTO["ALGORYTHM"] = "AES-GCM";
|
|
612
|
+
CRYPTO["KEY_ALGORYTHM"] = "PBKDF2";
|
|
613
|
+
})(exports.CRYPTO || (exports.CRYPTO = {}));
|
|
614
|
+
class BaseEncoder {
|
|
615
|
+
constructor(alphabet) {
|
|
616
|
+
this.alphabet = alphabet;
|
|
617
|
+
this.baseMap = new Uint8Array(256);
|
|
618
|
+
if (this.alphabet.length >= 255) throw new Error("Alphabet too long");
|
|
619
|
+
for (let j = 0; j < this.baseMap.length; j++) this.baseMap[j] = 255;
|
|
620
|
+
for (let i = 0; i < alphabet.length; i++) {
|
|
621
|
+
const x = alphabet.charAt(i);
|
|
622
|
+
const xc = x.charCodeAt(0);
|
|
623
|
+
if (this.baseMap[xc] !== 255) throw new Error(x + " is ambiguous");
|
|
624
|
+
this.baseMap[xc] = i;
|
|
625
|
+
}
|
|
626
|
+
this.base = this.alphabet.length;
|
|
627
|
+
this.leader = this.alphabet.charAt(0);
|
|
628
|
+
this.factor = Math.log(this.base) / Math.log(256);
|
|
629
|
+
this.iFactor = Math.log(256) / Math.log(this.base);
|
|
630
|
+
}
|
|
631
|
+
encode(source) {
|
|
632
|
+
if (typeof source === "string") {
|
|
633
|
+
source = Buffer.from(source);
|
|
634
|
+
} else if (ArrayBuffer.isView(source)) {
|
|
635
|
+
source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
636
|
+
} else if (Array.isArray(source)) {
|
|
637
|
+
source = Uint8Array.from(source);
|
|
638
|
+
}
|
|
639
|
+
if (source.length === 0) return "";
|
|
640
|
+
let zeroes = 0;
|
|
641
|
+
let length = 0;
|
|
642
|
+
let pbegin = 0;
|
|
643
|
+
const pend = source.length;
|
|
644
|
+
while (pbegin !== pend && source[pbegin] === 0) {
|
|
645
|
+
pbegin++;
|
|
646
|
+
zeroes++;
|
|
647
|
+
}
|
|
648
|
+
const size = (pend - pbegin) * this.iFactor + 1 >>> 0;
|
|
649
|
+
const b58 = new Uint8Array(size);
|
|
650
|
+
while (pbegin !== pend) {
|
|
651
|
+
let carry = source[pbegin];
|
|
652
|
+
let i = 0;
|
|
653
|
+
for (let it1 = size - 1; (carry !== 0 || i < length) && it1 !== -1; it1--, i++) {
|
|
654
|
+
carry += 256 * b58[it1] >>> 0;
|
|
655
|
+
b58[it1] = carry % this.base >>> 0;
|
|
656
|
+
carry = carry / this.base >>> 0;
|
|
657
|
+
}
|
|
658
|
+
if (carry !== 0) throw new Error("Non-zero carry");
|
|
659
|
+
length = i;
|
|
660
|
+
pbegin++;
|
|
661
|
+
}
|
|
662
|
+
let it2 = size - length;
|
|
663
|
+
while (it2 !== size && b58[it2] === 0) it2++;
|
|
664
|
+
let str = this.leader.repeat(zeroes);
|
|
665
|
+
for (;it2 < size; ++it2) {
|
|
666
|
+
str += this.alphabet.charAt(b58[it2]);
|
|
667
|
+
}
|
|
668
|
+
return str;
|
|
669
|
+
}
|
|
670
|
+
decodeUnsafe(source) {
|
|
671
|
+
if (source.length === 0) return new Uint8Array(0);
|
|
672
|
+
let psz = 0;
|
|
673
|
+
let zeroes = 0;
|
|
674
|
+
let length = 0;
|
|
675
|
+
while (source[psz] === this.leader) {
|
|
676
|
+
zeroes++;
|
|
677
|
+
psz++;
|
|
678
|
+
}
|
|
679
|
+
const size = (source.length - psz) * this.factor + 1 >>> 0;
|
|
680
|
+
const b256 = new Uint8Array(size);
|
|
681
|
+
while (source[psz]) {
|
|
682
|
+
let carry = this.baseMap[source.charCodeAt(psz)];
|
|
683
|
+
if (carry === 255) return;
|
|
684
|
+
let i = 0;
|
|
685
|
+
for (let it3 = size - 1; (carry !== 0 || i < length) && it3 !== -1; it3--, i++) {
|
|
686
|
+
carry += this.base * b256[it3] >>> 0;
|
|
687
|
+
b256[it3] = carry % 256 >>> 0;
|
|
688
|
+
carry = carry / 256 >>> 0;
|
|
689
|
+
}
|
|
690
|
+
if (carry !== 0) throw new Error("Non-zero carry");
|
|
691
|
+
length = i;
|
|
692
|
+
psz++;
|
|
693
|
+
}
|
|
694
|
+
let it4 = size - length;
|
|
695
|
+
while (it4 !== size && b256[it4] === 0) it4++;
|
|
696
|
+
const vch = new Uint8Array(zeroes + (size - it4));
|
|
697
|
+
let j = zeroes;
|
|
698
|
+
while (it4 !== size) vch[j++] = b256[it4++];
|
|
699
|
+
return vch;
|
|
700
|
+
}
|
|
701
|
+
decode(source) {
|
|
702
|
+
const buffer = this.decodeUnsafe(source);
|
|
703
|
+
if (buffer) return buffer;
|
|
704
|
+
throw new Error("Non-base" + this.base + " character");
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
class CryptoUtils {
|
|
708
|
+
static {
|
|
709
|
+
this.b58encoder = new BaseEncoder(exports.BASE_ALPHABET.BASE58);
|
|
710
|
+
}
|
|
711
|
+
static {
|
|
712
|
+
this.logger = new logging.MiniLogger(CryptoUtils.name);
|
|
713
|
+
}
|
|
714
|
+
constructor() {}
|
|
715
|
+
static fabricIdFromCertificate(certificate) {
|
|
716
|
+
this.logger.debug(decoratorValidation.stringFormat("Parsing certificate: {0}", certificate));
|
|
717
|
+
const cert = new x509__namespace.X509Certificate(certificate);
|
|
718
|
+
const {subject: subject, issuer: issuer} = cert;
|
|
719
|
+
this.logger.debug(decoratorValidation.stringFormat("Certificate parsed with subject {0} and issuer {1}", subject, issuer));
|
|
720
|
+
return `x509::/${subject.replaceAll(", ", "/")}::/${issuer.replaceAll(", ", "/")}`;
|
|
721
|
+
}
|
|
722
|
+
static encode(str) {
|
|
723
|
+
return this.b58encoder.encode(str);
|
|
724
|
+
}
|
|
725
|
+
static decode(str) {
|
|
726
|
+
const decoded = this.b58encoder.decode(str);
|
|
727
|
+
const result = (new TextDecoder).decode(decoded);
|
|
728
|
+
return result;
|
|
729
|
+
}
|
|
730
|
+
static stringToArrayBuffer(str) {
|
|
731
|
+
const buf = new ArrayBuffer(str.length);
|
|
732
|
+
const bufView = new Uint8Array(buf);
|
|
733
|
+
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
734
|
+
bufView[i] = str.charCodeAt(i);
|
|
735
|
+
}
|
|
736
|
+
return buf;
|
|
737
|
+
}
|
|
738
|
+
static async extractKey(type, pem, usages) {
|
|
739
|
+
const subtle = crypto.subtle;
|
|
740
|
+
const str = pem.toString("utf8").replace(new RegExp(`-----BEGIN (${type.toUpperCase()} KEY|CERTIFICATE)-----`), "").replaceAll("\n", "").replace(new RegExp(`-----END (${type.toUpperCase()} KEY|CERTIFICATE)-----`), "");
|
|
741
|
+
const decoded = Buffer.from(str, "base64").toString("binary");
|
|
742
|
+
const binaryDer = this.stringToArrayBuffer(decoded);
|
|
743
|
+
const key = await subtle.importKey("pkcs8", binaryDer, {
|
|
744
|
+
name: "ECDSA",
|
|
745
|
+
namedCurve: "P-256"
|
|
746
|
+
}, true, usages ? usages : [ "sign" ]);
|
|
747
|
+
return key;
|
|
748
|
+
}
|
|
749
|
+
static async extractPrivateKey(pem, usages) {
|
|
750
|
+
return this.extractKey("private", pem, usages);
|
|
751
|
+
}
|
|
752
|
+
static async extractPublicKey(pem, usages) {
|
|
753
|
+
return this.extractKey("public", pem, usages);
|
|
754
|
+
}
|
|
755
|
+
static async sign(privateKey, data) {
|
|
756
|
+
const key = await this.extractPrivateKey(privateKey);
|
|
757
|
+
const buff = await crypto.subtle.sign({
|
|
758
|
+
name: "ECDSA",
|
|
759
|
+
hash: "SHA-256"
|
|
760
|
+
}, key, data);
|
|
761
|
+
return Array.from(new Uint8Array(buff)).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
762
|
+
}
|
|
763
|
+
static async verify(certificate, signature, data) {
|
|
764
|
+
const cert = new x509__namespace.X509Certificate(certificate);
|
|
765
|
+
const key = await cert.publicKey.export();
|
|
766
|
+
signature = typeof signature === "string" ? Buffer.from(signature, "hex") : signature;
|
|
767
|
+
data = typeof data === "string" ? Buffer.from(data) : data;
|
|
768
|
+
return crypto.subtle.verify({
|
|
769
|
+
name: "ECDSA",
|
|
770
|
+
hash: "SHA-256"
|
|
771
|
+
}, key, signature, data);
|
|
772
|
+
}
|
|
773
|
+
static async encrypt(certificate, data) {
|
|
774
|
+
const cert = new x509__namespace.X509Certificate(certificate);
|
|
775
|
+
const key = await cert.publicKey.export();
|
|
776
|
+
data = typeof data === "string" ? Buffer.from(data) : data;
|
|
777
|
+
const buff = await this.getSubtleCrypto().encrypt({
|
|
778
|
+
name: "ECDSA"
|
|
779
|
+
}, key, data);
|
|
780
|
+
return Array.from(new Uint8Array(buff)).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
781
|
+
}
|
|
782
|
+
static getSubtleCrypto() {
|
|
783
|
+
return logging.isBrowser() ? globalThis.window.crypto.subtle : crypto.subtle;
|
|
784
|
+
}
|
|
785
|
+
static async decrypt(privateKey, data) {
|
|
786
|
+
const key = await this.extractPrivateKey(privateKey);
|
|
787
|
+
data = typeof data === "string" ? Buffer.from(data, "hex") : data;
|
|
788
|
+
return this.getSubtleCrypto().decrypt({
|
|
789
|
+
name: "ECDSA"
|
|
790
|
+
}, key, data);
|
|
791
|
+
}
|
|
792
|
+
static async getMaster(data) {
|
|
793
|
+
const textEncoder = new TextEncoder;
|
|
794
|
+
if (data === undefined) {
|
|
795
|
+
const genGenesis = crypto.randomUUID();
|
|
796
|
+
data = textEncoder.encode(genGenesis).buffer;
|
|
797
|
+
}
|
|
798
|
+
const importedKey = await this.getSubtleCrypto().importKey("raw", data, exports.CRYPTO.KEY_ALGORYTHM, false, [ "deriveBits" ]);
|
|
799
|
+
return {
|
|
800
|
+
key: importedKey,
|
|
801
|
+
iv: data
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
static async getDerivationKey(salt, key) {
|
|
805
|
+
const textEncoder = new TextEncoder;
|
|
806
|
+
const saltBuffer = textEncoder.encode(salt);
|
|
807
|
+
const saltHashed = await this.getSubtleCrypto().digest("SHA-256", saltBuffer);
|
|
808
|
+
const params = {
|
|
809
|
+
name: exports.CRYPTO.KEY_ALGORYTHM,
|
|
810
|
+
hash: exports.CRYPTO.HASH,
|
|
811
|
+
salt: saltHashed,
|
|
812
|
+
iterations: exports.CRYPTO.ITERATIONS
|
|
813
|
+
};
|
|
814
|
+
const derivation = await this.getSubtleCrypto().deriveBits(params, key, exports.CRYPTO.KEYLENGTH * 8);
|
|
815
|
+
return this.getKey(derivation);
|
|
816
|
+
}
|
|
817
|
+
static async getKey(derivation) {
|
|
818
|
+
const ivlen = 16;
|
|
819
|
+
const keylen = 32;
|
|
820
|
+
const derivedKey = derivation.slice(0, keylen);
|
|
821
|
+
const iv = derivation.slice(keylen);
|
|
822
|
+
const importedEncryptionKey = await this.getSubtleCrypto().importKey("raw", derivedKey, {
|
|
823
|
+
name: exports.CRYPTO.ALGORYTHM
|
|
824
|
+
}, false, [ "encrypt", "decrypt" ]);
|
|
825
|
+
return {
|
|
826
|
+
key: importedEncryptionKey,
|
|
827
|
+
iv: iv
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
static async encryptPin(text, keyObject) {
|
|
831
|
+
const textEncoder = new TextEncoder;
|
|
832
|
+
const textBuffer = textEncoder.encode(text);
|
|
833
|
+
const encryptedText = await this.getSubtleCrypto().encrypt({
|
|
834
|
+
name: exports.CRYPTO.ALGORYTHM,
|
|
835
|
+
iv: keyObject.iv
|
|
836
|
+
}, keyObject.key, textBuffer);
|
|
837
|
+
return encryptedText;
|
|
838
|
+
}
|
|
839
|
+
static async decryptPin(encryptedText, keyObject) {
|
|
840
|
+
const textDecoder = new TextDecoder;
|
|
841
|
+
const decryptedText = await this.getSubtleCrypto().decrypt({
|
|
842
|
+
name: exports.CRYPTO.ALGORYTHM,
|
|
843
|
+
iv: keyObject.iv
|
|
844
|
+
}, keyObject.key, encryptedText);
|
|
845
|
+
return textDecoder.decode(decryptedText);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
class OverflowError extends dbDecorators.InternalError {
|
|
849
|
+
constructor(msg) {
|
|
850
|
+
super(msg, OverflowError.name);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
class BalanceError extends dbDecorators.InternalError {
|
|
854
|
+
constructor(msg) {
|
|
855
|
+
super(msg, BalanceError.name);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
class AllowanceError extends dbDecorators.InternalError {
|
|
859
|
+
constructor(msg) {
|
|
860
|
+
super(msg, AllowanceError.name);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
class RegistrationError extends core.AuthorizationError {
|
|
864
|
+
constructor(msg) {
|
|
865
|
+
super(msg, RegistrationError.name);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
class MissingContextError extends dbDecorators.InternalError {
|
|
869
|
+
constructor(msg) {
|
|
870
|
+
super(msg, MissingContextError.name, 500);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
class UnauthorizedPrivateDataAccess extends dbDecorators.BaseError {
|
|
874
|
+
constructor(msg = "MISSING_PRIVATE_DATA_ERROR_MESSAGE") {
|
|
875
|
+
super(UnauthorizedPrivateDataAccess.name, msg, 403);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
class NotInitializedError extends dbDecorators.BaseError {
|
|
879
|
+
constructor(msg) {
|
|
880
|
+
super(NotInitializedError.name, msg, 409);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
class MissingPKCSS11Lib extends dbDecorators.InternalError {
|
|
884
|
+
constructor(msg) {
|
|
885
|
+
super(msg, MissingPKCSS11Lib.name, 500);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
class EndorsementError extends dbDecorators.InternalError {
|
|
889
|
+
constructor(message) {
|
|
890
|
+
super(message, EndorsementError.name, 500);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
class MvccReadConflictError extends dbDecorators.InternalError {
|
|
894
|
+
constructor(message) {
|
|
895
|
+
super(message, MvccReadConflictError.name, 500);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
class PhantomReadConflictError extends dbDecorators.InternalError {
|
|
899
|
+
constructor(message) {
|
|
900
|
+
super(message, PhantomReadConflictError.name, 500);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
class EndorsementPolicyError extends dbDecorators.InternalError {
|
|
904
|
+
constructor(message) {
|
|
905
|
+
super(message, EndorsementPolicyError.name, 500);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
exports.HFCAIdentityType = void 0;
|
|
909
|
+
(function(HFCAIdentityType) {
|
|
910
|
+
HFCAIdentityType["PEER"] = "peer";
|
|
911
|
+
HFCAIdentityType["ORDERER"] = "orderer";
|
|
912
|
+
HFCAIdentityType["CLIENT"] = "client";
|
|
913
|
+
HFCAIdentityType["USER"] = "user";
|
|
914
|
+
HFCAIdentityType["ADMIN"] = "admin";
|
|
915
|
+
})(exports.HFCAIdentityType || (exports.HFCAIdentityType = {}));
|
|
916
|
+
exports.HFCAIdentityAttributes = void 0;
|
|
917
|
+
(function(HFCAIdentityAttributes) {
|
|
918
|
+
HFCAIdentityAttributes["HFREGISTRARROLES"] = "hf.Registrar.Roles";
|
|
919
|
+
HFCAIdentityAttributes["HFREGISTRARDELEGATEROLES"] = "hf.Registrar.DelegateRoles";
|
|
920
|
+
HFCAIdentityAttributes["HFREGISTRARATTRIBUTES"] = "hf.Registrar.Attributes";
|
|
921
|
+
HFCAIdentityAttributes["HFINTERMEDIATECA"] = "hf.IntermediateCA";
|
|
922
|
+
HFCAIdentityAttributes["HFREVOKER"] = "hf.Revoker";
|
|
923
|
+
HFCAIdentityAttributes["HFAFFILIATIONMGR"] = "hf.AffiliationMgr";
|
|
924
|
+
HFCAIdentityAttributes["HFGENCRL"] = "hf.GenCRL";
|
|
925
|
+
})(exports.HFCAIdentityAttributes || (exports.HFCAIdentityAttributes = {}));
|
|
926
|
+
class FabricEnrollmentService extends logging.LoggedClass {
|
|
927
|
+
constructor(caConfig) {
|
|
928
|
+
CoreUtils.getCryptoSuite(caConfig.hsm ? {
|
|
929
|
+
software: false,
|
|
930
|
+
lib: caConfig.hsm.library,
|
|
931
|
+
slot: caConfig.hsm.slot,
|
|
932
|
+
label: caConfig.hsm.tokenLabel,
|
|
933
|
+
pin: String(caConfig.hsm.pin)
|
|
934
|
+
} : undefined);
|
|
935
|
+
super();
|
|
936
|
+
this.caConfig = caConfig;
|
|
937
|
+
}
|
|
938
|
+
async User() {
|
|
939
|
+
if (this.user) return this.user;
|
|
940
|
+
const {caName: caName, caCert: caCert, caKey: caKey, url: url, hsm: hsm} = this.caConfig;
|
|
941
|
+
const log = this.log.for(this.User);
|
|
942
|
+
log.debug(`Creating CA user for ${caName} at ${url}`);
|
|
943
|
+
log.debug(`Retrieving CA certificate from ${caCert}`);
|
|
944
|
+
const certificate = await CoreUtils.getFirstDirFileNameContent(caCert);
|
|
945
|
+
let key;
|
|
946
|
+
if (!hsm) {
|
|
947
|
+
if (!caKey) {
|
|
948
|
+
throw new dbDecorators.InternalError(`Missing caKey configuration for CA ${caName}. Provide a key directory or configure HSM support.`);
|
|
949
|
+
}
|
|
950
|
+
log.debug(`Retrieving CA key from ${caKey}`);
|
|
951
|
+
key = await CoreUtils.getFirstDirFileNameContent(caKey);
|
|
952
|
+
} else {
|
|
953
|
+
log.debug(`Using HSM configuration for CA ${caName} with library ${hsm.library}`);
|
|
954
|
+
}
|
|
955
|
+
log.debug(`Loading Admin user for ca ${caName}`);
|
|
956
|
+
this.user = await CoreUtils.getCAUser("admin", key, certificate, caName, {
|
|
957
|
+
hsm: hsm
|
|
958
|
+
});
|
|
959
|
+
return this.user;
|
|
960
|
+
}
|
|
961
|
+
async CA() {
|
|
962
|
+
if (this.ca) return this.ca;
|
|
963
|
+
const log = this.log.for(this.CA);
|
|
964
|
+
const {url: url, tls: tls, caName: caName} = this.caConfig;
|
|
965
|
+
let {trustedRoots: trustedRoots, verify: verify} = tls;
|
|
966
|
+
const root = trustedRoots[0];
|
|
967
|
+
log.debug(`Retrieving CA certificate from ${root}. cwd: ${process.cwd()}`);
|
|
968
|
+
const certificate = await CoreUtils.getFileContent(root);
|
|
969
|
+
log.debug(`Creating CA Client for CA ${caName} under ${url}`);
|
|
970
|
+
this.ca = new FabricCAServices__default["default"](url, {
|
|
971
|
+
trustedRoots: Buffer.from(certificate),
|
|
972
|
+
verify: verify
|
|
973
|
+
}, caName);
|
|
974
|
+
return this.ca;
|
|
975
|
+
}
|
|
976
|
+
async Client() {
|
|
977
|
+
if (this.client) return this.client;
|
|
978
|
+
const ca = await this.CA();
|
|
979
|
+
this.client = ca["_FabricCAServices"];
|
|
980
|
+
return this.client;
|
|
981
|
+
}
|
|
982
|
+
async Certificate() {
|
|
983
|
+
if (!this.certificateService) this.certificateService = (await this.Client()).newCertificateService();
|
|
984
|
+
return this.certificateService;
|
|
985
|
+
}
|
|
986
|
+
async Affiliations() {
|
|
987
|
+
if (!this.affiliationService) this.affiliationService = (await this.CA()).newAffiliationService();
|
|
988
|
+
return this.affiliationService;
|
|
989
|
+
}
|
|
990
|
+
async Identities() {
|
|
991
|
+
if (!this.identityService) this.identityService = (await this.CA()).newIdentityService();
|
|
992
|
+
return this.identityService;
|
|
993
|
+
}
|
|
994
|
+
async getCertificates(request, doMap = true) {
|
|
995
|
+
const certificateService = await this.Certificate();
|
|
996
|
+
const user = await this.User();
|
|
997
|
+
const log = this.log.for(this.getCertificates);
|
|
998
|
+
log.debug(`Retrieving certificates${request ? ` for ${request.id}` : ""} for CA ${this.caConfig.caName}`);
|
|
999
|
+
const response = (await certificateService.getCertificates(request || {}, user)).result;
|
|
1000
|
+
log.debug(`Found ${response.certs.length} certificates: ${JSON.stringify(response)}`);
|
|
1001
|
+
return doMap ? response.certs.map(c => c.PEM) : response;
|
|
1002
|
+
}
|
|
1003
|
+
async getIdentities() {
|
|
1004
|
+
const identitiesService = await this.Identities();
|
|
1005
|
+
const log = this.log.for(this.getIdentities);
|
|
1006
|
+
log.debug(`Retrieving Identities under CA ${this.caConfig.caName}`);
|
|
1007
|
+
const response = (await identitiesService.getAll(await this.User())).result;
|
|
1008
|
+
log.debug(`Found ${response.identities.length} Identities: ${JSON.stringify(response)}`);
|
|
1009
|
+
return response.identities;
|
|
1010
|
+
}
|
|
1011
|
+
parseError(e) {
|
|
1012
|
+
const regexp = /.*code:\s(\d+).*?message:\s["'](.+)["']/gs;
|
|
1013
|
+
const match = regexp.exec(e.message);
|
|
1014
|
+
if (!match) return new RegistrationError(e);
|
|
1015
|
+
const [, code, message] = match;
|
|
1016
|
+
switch (code) {
|
|
1017
|
+
case "74":
|
|
1018
|
+
case "71":
|
|
1019
|
+
return new dbDecorators.ConflictError(message);
|
|
1020
|
+
|
|
1021
|
+
case "20":
|
|
1022
|
+
return new core.AuthorizationError(message);
|
|
1023
|
+
|
|
1024
|
+
default:
|
|
1025
|
+
return new RegistrationError(message);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
async getAffiliations() {
|
|
1029
|
+
const affiliationService = await this.Affiliations();
|
|
1030
|
+
const log = this.log.for(this.getAffiliations);
|
|
1031
|
+
log.debug(`Retrieving Affiliations under CA ${this.caConfig.caName}`);
|
|
1032
|
+
const response = (await affiliationService.getAll(await this.User())).result;
|
|
1033
|
+
log.debug(`Found ${response.a.length} Affiliations: ${JSON.stringify(response)}`);
|
|
1034
|
+
return response;
|
|
1035
|
+
}
|
|
1036
|
+
async read(enrollmentId) {
|
|
1037
|
+
const ca = await this.CA();
|
|
1038
|
+
const user = await this.User();
|
|
1039
|
+
let result;
|
|
1040
|
+
try {
|
|
1041
|
+
result = await ca.newIdentityService().getOne(enrollmentId, user);
|
|
1042
|
+
} catch (e) {
|
|
1043
|
+
throw new dbDecorators.NotFoundError(`Couldn't find enrollment with id ${enrollmentId}: ${e}`);
|
|
1044
|
+
}
|
|
1045
|
+
if (!result.success) throw new dbDecorators.NotFoundError(`Couldn't find enrollment with id ${enrollmentId}: ${result.errors.join("\n")}`);
|
|
1046
|
+
return result.result;
|
|
1047
|
+
}
|
|
1048
|
+
async register(model, isSuperUser = false, affiliation = "", userRole, attrs, maxEnrollments) {
|
|
1049
|
+
let registration;
|
|
1050
|
+
const log = this.log.for(this.register);
|
|
1051
|
+
try {
|
|
1052
|
+
const {userName: userName, password: password} = model;
|
|
1053
|
+
const ca = await this.CA();
|
|
1054
|
+
const user = await this.User();
|
|
1055
|
+
const props = {
|
|
1056
|
+
enrollmentID: userName,
|
|
1057
|
+
enrollmentSecret: password,
|
|
1058
|
+
affiliation: affiliation,
|
|
1059
|
+
userRole: userRole,
|
|
1060
|
+
attrs: attrs,
|
|
1061
|
+
maxEnrollments: maxEnrollments
|
|
1062
|
+
};
|
|
1063
|
+
registration = await ca.register(props, user);
|
|
1064
|
+
log.info(`Registration for ${userName} created with user type ${userRole ?? "Undefined Role"} ${isSuperUser ? "as super user" : ""}`);
|
|
1065
|
+
} catch (e) {
|
|
1066
|
+
throw this.parseError(e);
|
|
1067
|
+
}
|
|
1068
|
+
return registration;
|
|
1069
|
+
}
|
|
1070
|
+
static identityFromEnrollment(enrollment, mspId) {
|
|
1071
|
+
const {certificate: certificate, key: key, rootCertificate: rootCertificate} = enrollment;
|
|
1072
|
+
const log = logging.Logging.for(FabricEnrollmentService, {}).for(this.identityFromEnrollment);
|
|
1073
|
+
log.debug(`Generating Identity from certificate ${certificate} in msp ${mspId}`);
|
|
1074
|
+
const clientId = CryptoUtils.fabricIdFromCertificate(certificate);
|
|
1075
|
+
const id = CryptoUtils.encode(clientId);
|
|
1076
|
+
log.debug(`Identity ${clientId} and encodedId ${id}`);
|
|
1077
|
+
const now = new Date;
|
|
1078
|
+
return new exports.Identity({
|
|
1079
|
+
id: id,
|
|
1080
|
+
credentials: {
|
|
1081
|
+
id: id,
|
|
1082
|
+
certificate: certificate,
|
|
1083
|
+
privateKey: key.toBytes(),
|
|
1084
|
+
rootCertificate: rootCertificate,
|
|
1085
|
+
createdOn: now,
|
|
1086
|
+
updatedOn: now
|
|
1087
|
+
},
|
|
1088
|
+
mspId: mspId,
|
|
1089
|
+
createdOn: now,
|
|
1090
|
+
updatedOn: now
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
async enroll(enrollmentId, registration) {
|
|
1094
|
+
let identity;
|
|
1095
|
+
const log = this.log.for(this.enroll);
|
|
1096
|
+
try {
|
|
1097
|
+
const ca = await this.CA();
|
|
1098
|
+
log.debug(`Enrolling ${enrollmentId}`);
|
|
1099
|
+
const enrollment = await ca.enroll({
|
|
1100
|
+
enrollmentID: enrollmentId,
|
|
1101
|
+
enrollmentSecret: registration
|
|
1102
|
+
});
|
|
1103
|
+
identity = FabricEnrollmentService.identityFromEnrollment(enrollment, this.caConfig.caName);
|
|
1104
|
+
log.info(`Successfully enrolled ${enrollmentId} under ${this.caConfig.caName} as ${identity.id}`);
|
|
1105
|
+
} catch (e) {
|
|
1106
|
+
throw this.parseError(e);
|
|
1107
|
+
}
|
|
1108
|
+
return identity;
|
|
1109
|
+
}
|
|
1110
|
+
async registerAndEnroll(model, isSuperUser = false, affiliation = "", userRole, attrs, maxEnrollments) {
|
|
1111
|
+
const registration = await this.register(model, isSuperUser, affiliation, userRole, attrs, maxEnrollments);
|
|
1112
|
+
const {userName: userName} = model;
|
|
1113
|
+
return this.enroll(userName, registration);
|
|
1114
|
+
}
|
|
1115
|
+
async revoke(enrollmentId) {
|
|
1116
|
+
const ca = await this.CA();
|
|
1117
|
+
const user = await this.User();
|
|
1118
|
+
const identity = await this.read(enrollmentId);
|
|
1119
|
+
if (!identity) throw new dbDecorators.NotFoundError(`Could not find enrollment with id ${enrollmentId}`);
|
|
1120
|
+
let result;
|
|
1121
|
+
try {
|
|
1122
|
+
result = await ca.revoke({
|
|
1123
|
+
enrollmentID: identity.id,
|
|
1124
|
+
reason: "User Deletation"
|
|
1125
|
+
}, user);
|
|
1126
|
+
} catch (e) {
|
|
1127
|
+
throw new dbDecorators.InternalError(`Could not revoke enrollment with id ${enrollmentId}: ${e}`);
|
|
1128
|
+
}
|
|
1129
|
+
if (!result.success) throw new dbDecorators.InternalError(`Could not revoke enrollment with id ${enrollmentId}: ${result.errors.join("\n")}`);
|
|
1130
|
+
return result;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
class RegistrationRequestBuilder extends decoratorValidation.Model {
|
|
1134
|
+
constructor() {
|
|
1135
|
+
super(...arguments);
|
|
1136
|
+
this.affiliation = "";
|
|
1137
|
+
}
|
|
1138
|
+
build() {
|
|
1139
|
+
const errs = this.hasErrors();
|
|
1140
|
+
if (errs) throw new dbDecorators.ValidationError(errs.toString());
|
|
1141
|
+
const response = {
|
|
1142
|
+
enrollmentID: this.enrollmentID,
|
|
1143
|
+
enrollmentSecret: this.enrollmentSecret,
|
|
1144
|
+
role: this.role,
|
|
1145
|
+
affiliation: this.affiliation
|
|
1146
|
+
};
|
|
1147
|
+
if (typeof this.maxEnrollments !== "undefined") response.maxEnrollments = this.maxEnrollments;
|
|
1148
|
+
if (this.attrs) response.attrs = this.attrs;
|
|
1149
|
+
return response;
|
|
1150
|
+
}
|
|
1151
|
+
setAffiliation(value) {
|
|
1152
|
+
this.affiliation = value;
|
|
1153
|
+
return this;
|
|
1154
|
+
}
|
|
1155
|
+
addAttr(attr) {
|
|
1156
|
+
this.attrs = this.attrs || [];
|
|
1157
|
+
this.attrs.push(attr);
|
|
1158
|
+
return this;
|
|
1159
|
+
}
|
|
1160
|
+
setAttrs(value) {
|
|
1161
|
+
this.attrs = value;
|
|
1162
|
+
return this;
|
|
1163
|
+
}
|
|
1164
|
+
setEnrollmentID(value) {
|
|
1165
|
+
this.enrollmentID = value;
|
|
1166
|
+
return this;
|
|
1167
|
+
}
|
|
1168
|
+
setEnrollmentSecret(value) {
|
|
1169
|
+
this.enrollmentSecret = value;
|
|
1170
|
+
return this;
|
|
1171
|
+
}
|
|
1172
|
+
setMaxEnrollments(value) {
|
|
1173
|
+
this.maxEnrollments = value;
|
|
1174
|
+
return this;
|
|
1175
|
+
}
|
|
1176
|
+
setRole(value) {
|
|
1177
|
+
this.role = value;
|
|
1178
|
+
return this;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
tslib.__decorate([ decoratorValidation.required(), tslib.__metadata("design:type", String) ], RegistrationRequestBuilder.prototype, "affiliation", void 0);
|
|
1182
|
+
tslib.__decorate([ decoratorValidation.minlength(1), tslib.__metadata("design:type", Array) ], RegistrationRequestBuilder.prototype, "attrs", void 0);
|
|
1183
|
+
tslib.__decorate([ decoratorValidation.required(), tslib.__metadata("design:type", String) ], RegistrationRequestBuilder.prototype, "enrollmentID", void 0);
|
|
1184
|
+
tslib.__decorate([ decoratorValidation.required(), tslib.__metadata("design:type", String) ], RegistrationRequestBuilder.prototype, "enrollmentSecret", void 0);
|
|
1185
|
+
tslib.__decorate([ decoratorValidation.min(0), tslib.__metadata("design:type", Number) ], RegistrationRequestBuilder.prototype, "maxEnrollments", void 0);
|
|
1186
|
+
tslib.__decorate([ decoratorValidation.required(), tslib.__metadata("design:type", String) ], RegistrationRequestBuilder.prototype, "role", void 0);
|
|
1187
|
+
exports.ERC20Events = void 0;
|
|
1188
|
+
(function(ERC20Events) {
|
|
1189
|
+
ERC20Events["TRANSFER"] = "Transfer";
|
|
1190
|
+
ERC20Events["APPROVAL"] = "Approval";
|
|
1191
|
+
})(exports.ERC20Events || (exports.ERC20Events = {}));
|
|
1192
|
+
exports.FabricBaseModel = class FabricBaseModel extends decoratorValidation.Model {
|
|
1193
|
+
constructor(arg) {
|
|
1194
|
+
super(arg);
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
tslib.__decorate([ decoration.description("Stores the original timestamp of creation"), core.column(), core.createdAt(), tslib.__metadata("design:type", Date) ], exports.FabricBaseModel.prototype, "createdAt", void 0);
|
|
1198
|
+
tslib.__decorate([ decoration.description("Stores the timestamp of the last update"), core.column(), core.updatedAt(), tslib.__metadata("design:type", Date) ], exports.FabricBaseModel.prototype, "updatedAt", void 0);
|
|
1199
|
+
tslib.__decorate([ decoration.description("Stores the version of the model"), core.column(), dbDecorators.version(), tslib.__metadata("design:type", Number) ], exports.FabricBaseModel.prototype, "version", void 0);
|
|
1200
|
+
exports.FabricBaseModel = tslib.__decorate([ decoration.uses(FabricFlavour), tslib.__metadata("design:paramtypes", [ Object ]) ], exports.FabricBaseModel);
|
|
1201
|
+
exports.FabricIdentifiedBaseModel = class FabricIdentifiedBaseModel extends exports.FabricBaseModel {
|
|
1202
|
+
constructor(arg) {
|
|
1203
|
+
super(arg);
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
tslib.__decorate([ decoration.description("Stores the creator"), core.column(), core.createdBy(), tslib.__metadata("design:type", String) ], exports.FabricIdentifiedBaseModel.prototype, "createdBy", void 0);
|
|
1207
|
+
tslib.__decorate([ decoration.description("Stores the user that last updated the model"), core.column(), core.updatedBy(), tslib.__metadata("design:type", String) ], exports.FabricIdentifiedBaseModel.prototype, "updatedBy", void 0);
|
|
1208
|
+
exports.FabricIdentifiedBaseModel = tslib.__decorate([ decoration.uses(FabricFlavour), tslib.__metadata("design:paramtypes", [ Object ]) ], exports.FabricIdentifiedBaseModel);
|
|
1209
|
+
decoratorValidation.Model.prototype.isShared = function isShared() {
|
|
1210
|
+
return decoratorValidation.Model.isShared(this.constructor);
|
|
1211
|
+
};
|
|
1212
|
+
decoratorValidation.Model.prototype.isPrivate = function isPrivate() {
|
|
1213
|
+
return decoratorValidation.Model.isPrivate(this.constructor);
|
|
1214
|
+
};
|
|
1215
|
+
decoratorValidation.Model.prototype.segregate = function segregate() {
|
|
1216
|
+
return decoratorValidation.Model.segregate(this);
|
|
1217
|
+
};
|
|
1218
|
+
decoratorValidation.Model.segregate = function segregate(model) {
|
|
1219
|
+
if (!decoratorValidation.Model.isTransient(model)) return {
|
|
1220
|
+
model: model
|
|
1221
|
+
};
|
|
1222
|
+
const decoratedProperties = decoration.Metadata.validatableProperties(model.constructor);
|
|
1223
|
+
const transientProps = decoration.Metadata.get(model.constructor, dbDecorators.DBKeys.TRANSIENT);
|
|
1224
|
+
const privateProperties = decoration.Metadata.get(model.constructor, exports.FabricModelKeys.PRIVATE);
|
|
1225
|
+
const sharedProperties = decoration.Metadata.get(model.constructor, exports.FabricModelKeys.PRIVATE);
|
|
1226
|
+
const result = {
|
|
1227
|
+
model: {},
|
|
1228
|
+
transient: {},
|
|
1229
|
+
private: {},
|
|
1230
|
+
shared: {}
|
|
1231
|
+
};
|
|
1232
|
+
const transientKeys = Object.keys(transientProps);
|
|
1233
|
+
const privateKeys = Object.keys(privateProperties);
|
|
1234
|
+
const sharedKeys = Object.keys(sharedProperties);
|
|
1235
|
+
for (const key of decoratedProperties) {
|
|
1236
|
+
const isTransient = transientKeys.includes(key);
|
|
1237
|
+
const isPrivate = privateKeys.includes(key);
|
|
1238
|
+
const isShared = sharedKeys.includes(key);
|
|
1239
|
+
if (isTransient) {
|
|
1240
|
+
result.transient = result.transient || {};
|
|
1241
|
+
result.transient[key] = model[key];
|
|
1242
|
+
if (isPrivate) {
|
|
1243
|
+
result.private = result.private || {};
|
|
1244
|
+
result.private[key] = model[key];
|
|
1245
|
+
}
|
|
1246
|
+
if (isShared) {
|
|
1247
|
+
result.shared = result.shared || {};
|
|
1248
|
+
result.shared[key] = model[key];
|
|
1249
|
+
}
|
|
1250
|
+
} else {
|
|
1251
|
+
result.model = result.model || {};
|
|
1252
|
+
result.model[key] = model[key];
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
result.model = decoratorValidation.Model.build(result.model, model.constructor.name);
|
|
1256
|
+
return result;
|
|
1257
|
+
}.bind(decoratorValidation.Model);
|
|
1258
|
+
decoratorValidation.Model.isPrivate = function isPrivate(model) {
|
|
1259
|
+
return !!decoration.Metadata.get(typeof model !== "function" ? model.constructor : model, exports.FabricModelKeys.PRIVATE);
|
|
1260
|
+
}.bind(decoratorValidation.Model);
|
|
1261
|
+
decoratorValidation.Model.isShared = function isShared(model) {
|
|
1262
|
+
return !!decoration.Metadata.get(typeof model !== "function" ? model.constructor : model, exports.FabricModelKeys.SHARED);
|
|
1263
|
+
}.bind(decoratorValidation.Model);
|
|
1264
|
+
decoratorValidation.Model.mirrored = function mirrored(model) {
|
|
1265
|
+
return decoration.Metadata.get(typeof model !== "function" ? model.constructor : model, decoration.Metadata.key(exports.FabricModelKeys.FABRIC, exports.FabricModelKeys.MIRROR));
|
|
1266
|
+
}.bind(decoratorValidation.Model);
|
|
1267
|
+
decoratorValidation.Model.ownerOf = function ownerOf(model) {
|
|
1268
|
+
const meta = decoration.Metadata.get(model.constructor, decoration.Metadata.key(exports.FabricModelKeys.FABRIC, exports.FabricModelKeys.OWNED_BY));
|
|
1269
|
+
if (!meta) return undefined;
|
|
1270
|
+
return model[meta];
|
|
1271
|
+
}.bind(decoratorValidation.Model);
|
|
1272
|
+
decoratorValidation.Model.mirroredAt = function mirroredAt(model) {
|
|
1273
|
+
model = typeof model !== "function" ? model.constructor : model;
|
|
1274
|
+
return decoration.Metadata.get(model, decoration.Metadata.key(exports.FabricModelKeys.FABRIC, exports.FabricModelKeys.MIRROR));
|
|
1275
|
+
}.bind(decoratorValidation.Model);
|
|
1276
|
+
decoratorValidation.Model.collectionsFor = function collectionsFor(model) {
|
|
1277
|
+
const privateKeys = [ exports.FabricModelKeys.PRIVATE ];
|
|
1278
|
+
const sharedKeys = [ exports.FabricModelKeys.SHARED ];
|
|
1279
|
+
const privateKey = decoration.Metadata.key(...privateKeys);
|
|
1280
|
+
const sharedKey = decoration.Metadata.key(...sharedKeys);
|
|
1281
|
+
const constr = typeof model === "function" ? model : model.constructor;
|
|
1282
|
+
const privateMeta = decoration.Metadata.get(constr, privateKey);
|
|
1283
|
+
const sharedMeta = decoration.Metadata.get(constr, sharedKey);
|
|
1284
|
+
return {
|
|
1285
|
+
privateCols: privateMeta?.collections || [],
|
|
1286
|
+
sharedCols: sharedMeta?.collections || []
|
|
1287
|
+
};
|
|
1288
|
+
}.bind(decoratorValidation.Model);
|
|
1289
|
+
function Owner() {
|
|
1290
|
+
return function(target, propertyKey, descriptor) {
|
|
1291
|
+
const originalMethod = descriptor.value;
|
|
1292
|
+
descriptor.value = async function(...args) {
|
|
1293
|
+
const ctx = args[0];
|
|
1294
|
+
const acountId = ctx.clientIdentity.getID();
|
|
1295
|
+
const select = await this["tokenRepository"].select();
|
|
1296
|
+
const tokens = await select.execute(ctx);
|
|
1297
|
+
if (tokens.length == 0) {
|
|
1298
|
+
throw new dbDecorators.NotFoundError("No tokens avaialble");
|
|
1299
|
+
}
|
|
1300
|
+
if (tokens.length > 1) {
|
|
1301
|
+
throw new dbDecorators.NotFoundError(`To many token available : ${tokens.length}`);
|
|
1302
|
+
}
|
|
1303
|
+
if (tokens[0].owner != acountId) {
|
|
1304
|
+
throw new core.AuthorizationError(`User not authorized to run ${propertyKey} on the token`);
|
|
1305
|
+
}
|
|
1306
|
+
return await originalMethod.apply(this, args);
|
|
1307
|
+
};
|
|
1308
|
+
return descriptor;
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
async function ownedByOnCreate(context, data, key, model) {
|
|
1312
|
+
const {stub: stub} = context;
|
|
1313
|
+
const creator = await stub.getCreator();
|
|
1314
|
+
const owner = creator.mspid;
|
|
1315
|
+
const setOwnedByKeyValue = function(target, propertyKey, value) {
|
|
1316
|
+
Object.defineProperty(target, propertyKey, {
|
|
1317
|
+
enumerable: true,
|
|
1318
|
+
writable: false,
|
|
1319
|
+
configurable: true,
|
|
1320
|
+
value: value
|
|
1321
|
+
});
|
|
1322
|
+
};
|
|
1323
|
+
setOwnedByKeyValue(model, key, owner);
|
|
1324
|
+
}
|
|
1325
|
+
function ownedBy() {
|
|
1326
|
+
function ownedBy() {
|
|
1327
|
+
return function(obj, attribute) {
|
|
1328
|
+
return decoration.apply(decoratorValidation.required(), dbDecorators.readonly(), dbDecorators.onCreate(ownedByOnCreate), decoration.propMetadata(decoration.Metadata.key(exports.FabricModelKeys.FABRIC, exports.FabricModelKeys.OWNED_BY), attribute))(obj, attribute);
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
return decoration.Decoration.for(exports.FabricModelKeys.OWNED_BY).define({
|
|
1332
|
+
decorator: ownedBy,
|
|
1333
|
+
args: []
|
|
1334
|
+
}).apply();
|
|
1335
|
+
}
|
|
1336
|
+
async function transactionIdOnCreate(context, data, key, model) {
|
|
1337
|
+
const {stub: stub} = context;
|
|
1338
|
+
model[key] = stub.getTxID();
|
|
1339
|
+
}
|
|
1340
|
+
function transactionId() {
|
|
1341
|
+
function transactionId() {
|
|
1342
|
+
return function(obj, attribute) {
|
|
1343
|
+
return decoration.apply(decoratorValidation.required(), dbDecorators.readonly(), dbDecorators.onCreate(transactionIdOnCreate), dbDecorators.onUpdate(transactionIdOnCreate), decoration.propMetadata(decoration.Metadata.key(exports.FabricModelKeys.FABRIC, attribute, exports.FabricModelKeys.TRANSACTION_ID), attribute))(obj, attribute);
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
return decoration.Decoration.for(exports.FabricModelKeys.TRANSACTION_ID).define({
|
|
1347
|
+
decorator: transactionId,
|
|
1348
|
+
args: []
|
|
1349
|
+
}).apply();
|
|
1350
|
+
}
|
|
1351
|
+
async function evalMirrorMetadata(model, resolver, ctx) {
|
|
1352
|
+
let collection = resolver;
|
|
1353
|
+
if (typeof collection !== "string") {
|
|
1354
|
+
try {
|
|
1355
|
+
const owner = decoratorValidation.Model.ownerOf(model) || ctx.get("stub").getCreator().toString();
|
|
1356
|
+
if (resolver && typeof resolver === "function") collection = await resolver(model, owner, ctx);
|
|
1357
|
+
} catch (e) {
|
|
1358
|
+
throw new dbDecorators.InternalError(`Failed to resolve collection mirror name: ${e}`);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
if (!collection || typeof collection !== "string") throw new dbDecorators.InternalError(`No collection found model ${model.constructor.name}`);
|
|
1362
|
+
return collection;
|
|
1363
|
+
}
|
|
1364
|
+
async function createMirrorHandler(context, data, key, model) {
|
|
1365
|
+
const collection = await evalMirrorMetadata(model, data.resolver, context);
|
|
1366
|
+
const repo = this.override(Object.assign({}, this._overrides, {
|
|
1367
|
+
segregate: collection,
|
|
1368
|
+
ignoreValidation: true,
|
|
1369
|
+
ignoreHandlers: true
|
|
1370
|
+
}));
|
|
1371
|
+
const mirror = await repo.create(model, context);
|
|
1372
|
+
context.logger.info(`Mirror for ${decoratorValidation.Model.tableName(this.class)} created with ${decoratorValidation.Model.pk(model)}: ${mirror[decoratorValidation.Model.pk(model)]}`);
|
|
1373
|
+
}
|
|
1374
|
+
async function updateMirrorHandler(context, data, key, model) {
|
|
1375
|
+
const collection = await evalMirrorMetadata(model, data.resolver, context);
|
|
1376
|
+
const repo = this.override(Object.assign({}, this._overrides, {
|
|
1377
|
+
segregate: collection,
|
|
1378
|
+
ignoreValidation: true,
|
|
1379
|
+
ignoreHandlers: true
|
|
1380
|
+
}));
|
|
1381
|
+
const mirror = await repo.update(model, context);
|
|
1382
|
+
context.logger.info(`Mirror for ${decoratorValidation.Model.tableName(this.class)} updated with ${decoratorValidation.Model.pk(model)}: ${mirror[decoratorValidation.Model.pk(model)]}`);
|
|
1383
|
+
}
|
|
1384
|
+
async function deleteMirrorHandler(context, data, key, model) {
|
|
1385
|
+
const collection = await evalMirrorMetadata(model, data.resolver, context);
|
|
1386
|
+
const repo = this.override(Object.assign({}, this._overrides, {
|
|
1387
|
+
segregate: collection,
|
|
1388
|
+
ignoreValidation: true,
|
|
1389
|
+
ignoreHandlers: true
|
|
1390
|
+
}));
|
|
1391
|
+
const mirror = await repo.delete(decoratorValidation.Model.pk(model), context);
|
|
1392
|
+
context.logger.info(`Mirror for ${decoratorValidation.Model.tableName(this.class)} deleted with ${decoratorValidation.Model.pk(model)}: ${mirror[decoratorValidation.Model.pk(model)]}`);
|
|
1393
|
+
}
|
|
1394
|
+
function mirror(collection, condition) {
|
|
1395
|
+
function mirror(resolver, condition) {
|
|
1396
|
+
const meta = {
|
|
1397
|
+
condition: condition,
|
|
1398
|
+
resolver: resolver
|
|
1399
|
+
};
|
|
1400
|
+
return decoration.apply(decoration.metadata(decoration.Metadata.key(exports.FabricModelKeys.FABRIC, exports.FabricModelKeys.MIRROR), meta), privateData(collection), dbDecorators.afterCreate(createMirrorHandler, meta, {
|
|
1401
|
+
priority: 95
|
|
1402
|
+
}), dbDecorators.afterUpdate(updateMirrorHandler, meta, {
|
|
1403
|
+
priority: 95
|
|
1404
|
+
}), dbDecorators.afterDelete(deleteMirrorHandler, meta, {
|
|
1405
|
+
priority: 95
|
|
1406
|
+
}));
|
|
1407
|
+
}
|
|
1408
|
+
return decoration.Decoration.for(exports.FabricModelKeys.MIRROR).define({
|
|
1409
|
+
decorator: mirror,
|
|
1410
|
+
args: [ collection, condition ]
|
|
1411
|
+
}).apply();
|
|
1412
|
+
}
|
|
1413
|
+
const ModelCollection = (model, mspId) => {
|
|
1414
|
+
const orgName = mspId || (typeof model !== "function" ? decoratorValidation.Model.ownerOf(model) : undefined);
|
|
1415
|
+
const constr = typeof model === "function" ? model : model.constructor;
|
|
1416
|
+
if (!orgName) throw new dbDecorators.InternalError(`Model ${constr.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);
|
|
1417
|
+
return `${logging.toPascalCase(constr.name)}${mspId ? logging.toPascalCase(mspId) : ""}`;
|
|
1418
|
+
};
|
|
1419
|
+
const ImplicitPrivateCollection = (model, mspId) => {
|
|
1420
|
+
const orgName = mspId || (typeof model !== "function" ? decoratorValidation.Model.ownerOf(model) : undefined);
|
|
1421
|
+
if (!orgName) throw new dbDecorators.InternalError(`Model ${model.constructor.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);
|
|
1422
|
+
return `__${logging.toPascalCase(orgName)}PrivateCollection`;
|
|
1423
|
+
};
|
|
1424
|
+
async function segregatedDataOnCreate(context, data, keys, model) {
|
|
1425
|
+
if (keys.length !== data.length) throw new dbDecorators.InternalError(`Segregated data keys and metadata length mismatch`);
|
|
1426
|
+
const msp = decoratorValidation.Model.ownerOf(model);
|
|
1427
|
+
if (!msp) throw new dbDecorators.ValidationError(`There's no assigned organization for model ${model.constructor.name}`);
|
|
1428
|
+
const collectionResolver = data[0].collections;
|
|
1429
|
+
const collection = typeof collectionResolver === "string" ? collectionResolver : collectionResolver(model, msp, context);
|
|
1430
|
+
const rebuilt = keys.reduce((acc, k, i) => {
|
|
1431
|
+
const c = typeof data[i].collections === "string" ? data[i].collections : data[i].collections(model, msp, context);
|
|
1432
|
+
if (c !== collection) throw new core.UnsupportedError(`Segregated data collection mismatch: ${c} vs ${collection}`);
|
|
1433
|
+
acc[k] = model[k];
|
|
1434
|
+
return acc;
|
|
1435
|
+
}, {});
|
|
1436
|
+
const toCreate = new this.class(rebuilt);
|
|
1437
|
+
const created = await this.override({
|
|
1438
|
+
segregated: collection,
|
|
1439
|
+
mergeModel: false,
|
|
1440
|
+
ignoreHandlers: true,
|
|
1441
|
+
ignoreValidation: true
|
|
1442
|
+
}).create(toCreate, context);
|
|
1443
|
+
Object.assign(model, created);
|
|
1444
|
+
}
|
|
1445
|
+
async function segregatedDataOnRead(context, data, keys, model) {
|
|
1446
|
+
if (keys.length !== data.length) throw new dbDecorators.InternalError(`Segregated data keys and metadata length mismatch`);
|
|
1447
|
+
const msp = decoratorValidation.Model.ownerOf(model);
|
|
1448
|
+
if (!msp) throw new dbDecorators.ValidationError(`There's no assigned organization for model ${model.constructor.name}`);
|
|
1449
|
+
const collectionResolver = data[0].collections;
|
|
1450
|
+
const collection = typeof collectionResolver === "string" ? collectionResolver : await collectionResolver(model, msp, context);
|
|
1451
|
+
const rebuilt = keys.reduce((acc, k, i) => {
|
|
1452
|
+
const c = typeof data[i].collections === "string" ? data[i].collections : data[i].collections(model, msp, context);
|
|
1453
|
+
if (c !== collection) return acc;
|
|
1454
|
+
acc[k] = model[k];
|
|
1455
|
+
return acc;
|
|
1456
|
+
}, {});
|
|
1457
|
+
}
|
|
1458
|
+
async function segregatedDataOnUpdate(context, data, key, model, oldModel) {}
|
|
1459
|
+
async function segregatedDataOnDelete(context, data, key, model) {}
|
|
1460
|
+
function segregated(collection, type, filter) {
|
|
1461
|
+
return function innerSegregated(target, propertyKey) {
|
|
1462
|
+
function segregatedDec(target, propertyKey) {
|
|
1463
|
+
const key = decoration.Metadata.key(type, propertyKey);
|
|
1464
|
+
const constr = target.constructor;
|
|
1465
|
+
const meta = decoration.Metadata.get(constr, key) || {};
|
|
1466
|
+
const collections = new Set(meta.collections || []);
|
|
1467
|
+
collections.add(collection);
|
|
1468
|
+
meta.collections = [ ...collections ];
|
|
1469
|
+
decoration.Metadata.set(constr, key, meta);
|
|
1470
|
+
const constrMeta = decoration.Metadata.get(constr, type) || {};
|
|
1471
|
+
const constrCollections = new Set(constrMeta.collections || []);
|
|
1472
|
+
constrCollections.add(collection);
|
|
1473
|
+
meta.collections = [ ...collections ];
|
|
1474
|
+
decoration.Metadata.set(constr, type, meta);
|
|
1475
|
+
}
|
|
1476
|
+
const decs = [];
|
|
1477
|
+
if (!propertyKey) {
|
|
1478
|
+
decoration.Metadata.properties(target)?.forEach(p => {
|
|
1479
|
+
if (!filter || filter(p)) {
|
|
1480
|
+
segregated(collection, type)(target.prototype, p);
|
|
1481
|
+
}
|
|
1482
|
+
});
|
|
1483
|
+
} else {
|
|
1484
|
+
decs.push(decoration.prop(), dbDecorators.transient(), segregatedDec, dbDecorators.onCreate(segregatedDataOnCreate, {
|
|
1485
|
+
collections: collection
|
|
1486
|
+
}, {
|
|
1487
|
+
priority: 95,
|
|
1488
|
+
group: typeof collection === "string" ? collection : collection.toString()
|
|
1489
|
+
}), dbDecorators.onRead(segregatedDataOnRead, {
|
|
1490
|
+
collections: collection
|
|
1491
|
+
}, {
|
|
1492
|
+
priority: 95,
|
|
1493
|
+
group: typeof collection === "string" ? collection : collection.toString()
|
|
1494
|
+
}), dbDecorators.onUpdate(segregatedDataOnUpdate, {
|
|
1495
|
+
collections: collection
|
|
1496
|
+
}, {
|
|
1497
|
+
priority: 95,
|
|
1498
|
+
group: typeof collection === "string" ? collection : collection.toString()
|
|
1499
|
+
}), dbDecorators.onDelete(segregatedDataOnDelete, {
|
|
1500
|
+
collections: collection
|
|
1501
|
+
}, {
|
|
1502
|
+
priority: 95,
|
|
1503
|
+
group: typeof collection === "string" ? collection : collection.toString()
|
|
1504
|
+
}));
|
|
1505
|
+
}
|
|
1506
|
+
return decoration.apply(...decs)(target, propertyKey);
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
function privateData(collection = ImplicitPrivateCollection) {
|
|
1510
|
+
function privateData(collection) {
|
|
1511
|
+
return segregated(collection, exports.FabricModelKeys.PRIVATE);
|
|
1512
|
+
}
|
|
1513
|
+
return decoration.Decoration.for(exports.FabricModelKeys.PRIVATE).define({
|
|
1514
|
+
decorator: privateData,
|
|
1515
|
+
args: [ collection ]
|
|
1516
|
+
}).apply();
|
|
1517
|
+
}
|
|
1518
|
+
function sharedData(collection) {
|
|
1519
|
+
function sharedData(collection) {
|
|
1520
|
+
return segregated(collection, exports.FabricModelKeys.SHARED);
|
|
1521
|
+
}
|
|
1522
|
+
return decoration.Decoration.for(exports.FabricModelKeys.SHARED).define({
|
|
1523
|
+
decorator: sharedData,
|
|
1524
|
+
args: [ collection ]
|
|
1525
|
+
}).apply();
|
|
1526
|
+
}
|
|
1527
|
+
class DeterministicSerializer extends decoratorValidation.JSONSerializer {
|
|
1528
|
+
constructor() {
|
|
1529
|
+
super();
|
|
1530
|
+
}
|
|
1531
|
+
preSerialize(model) {
|
|
1532
|
+
const toSerialize = Object.assign({}, model);
|
|
1533
|
+
let metadata;
|
|
1534
|
+
try {
|
|
1535
|
+
metadata = decoration.Metadata.modelName(model.constructor);
|
|
1536
|
+
} catch (error) {
|
|
1537
|
+
metadata = undefined;
|
|
1538
|
+
}
|
|
1539
|
+
toSerialize[decoratorValidation.ModelKeys.ANCHOR] = metadata || model.constructor.name;
|
|
1540
|
+
const preSerialize = function preSerialize(obj) {
|
|
1541
|
+
const self = this;
|
|
1542
|
+
if (typeof obj !== "object") return obj;
|
|
1543
|
+
if (Array.isArray(obj)) return obj.map(o => preSerialize.call(self, o));
|
|
1544
|
+
return this.preSerialize.call(this, obj);
|
|
1545
|
+
}.bind(this);
|
|
1546
|
+
decoratorValidation.Model.relations(model).forEach(r => {
|
|
1547
|
+
toSerialize[r] = preSerialize(toSerialize[r]);
|
|
1548
|
+
});
|
|
1549
|
+
return toSerialize;
|
|
1550
|
+
}
|
|
1551
|
+
deserialize(str) {
|
|
1552
|
+
const deserialization = JSON.parse(str);
|
|
1553
|
+
const className = deserialization[decoratorValidation.ModelKeys.ANCHOR];
|
|
1554
|
+
if (!className) throw new Error("Could not find class reference in serialized model");
|
|
1555
|
+
const model = decoratorValidation.Model.build(deserialization, className);
|
|
1556
|
+
return model;
|
|
1557
|
+
}
|
|
1558
|
+
serialize(model) {
|
|
1559
|
+
const stringify = require("json-stringify-deterministic");
|
|
1560
|
+
const sortKeysRecursive = require("sort-keys-recursive");
|
|
1561
|
+
return stringify(sortKeysRecursive(this.preSerialize(model)));
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
function generateFabricEventName(table, event, owner) {
|
|
1565
|
+
const params = [ table, event ];
|
|
1566
|
+
if (owner) params.push(owner);
|
|
1567
|
+
return params.join("_");
|
|
1568
|
+
}
|
|
1569
|
+
function parseEventName(name) {
|
|
1570
|
+
const parts = name.split("_");
|
|
1571
|
+
if (parts.length < 2 || parts.length > 3) return {
|
|
1572
|
+
table: undefined,
|
|
1573
|
+
event: name,
|
|
1574
|
+
owner: undefined
|
|
1575
|
+
};
|
|
1576
|
+
return {
|
|
1577
|
+
table: parts[0],
|
|
1578
|
+
event: parts[1],
|
|
1579
|
+
owner: parts[2]
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
function add(a, b) {
|
|
1583
|
+
const c = a + b;
|
|
1584
|
+
if (a !== c - b || b !== c - a) {
|
|
1585
|
+
throw new OverflowError(`Addition overflow: ${a} + ${b}`);
|
|
1586
|
+
}
|
|
1587
|
+
return c;
|
|
1588
|
+
}
|
|
1589
|
+
function sub(a, b) {
|
|
1590
|
+
const c = a - b;
|
|
1591
|
+
if (a !== c + b || b !== a - c) {
|
|
1592
|
+
throw new OverflowError(`Subtraction overflow: ${a} - ${b}`);
|
|
1593
|
+
}
|
|
1594
|
+
return c;
|
|
1595
|
+
}
|
|
1596
|
+
function safeParseInt(string) {
|
|
1597
|
+
const digitRegex = /^\d+$/;
|
|
1598
|
+
if (!digitRegex.test(string)) {
|
|
1599
|
+
throw new dbDecorators.ValidationError(decoratorValidation.stringFormat("Failed to parse: {0}", "string contains digits"));
|
|
1600
|
+
}
|
|
1601
|
+
const parsedint = parseInt(string);
|
|
1602
|
+
if (isNaN(parsedint)) {
|
|
1603
|
+
throw new dbDecorators.ValidationError(decoratorValidation.stringFormat("Failed to parse: {0}", "string is not a parsable integer"));
|
|
1604
|
+
}
|
|
1605
|
+
return parsedint;
|
|
1606
|
+
}
|
|
1607
|
+
class SimpleDeterministicSerializer extends decoratorValidation.JSONSerializer {
|
|
1608
|
+
constructor() {
|
|
1609
|
+
super();
|
|
1610
|
+
}
|
|
1611
|
+
deserialize(str, tableName) {
|
|
1612
|
+
const deserialization = JSON.parse(str);
|
|
1613
|
+
return deserialization;
|
|
1614
|
+
}
|
|
1615
|
+
serialize(model, putAnchor = true) {
|
|
1616
|
+
const stringify = require("json-stringify-deterministic");
|
|
1617
|
+
const sortKeysRecursive = require("sort-keys-recursive");
|
|
1618
|
+
const preSerialization = this.preSerialize(model, putAnchor);
|
|
1619
|
+
return stringify(sortKeysRecursive(preSerialization));
|
|
1620
|
+
}
|
|
1621
|
+
preSerialize(model, putAnchor = true) {
|
|
1622
|
+
const toSerialize = Object.assign({}, model);
|
|
1623
|
+
let metadata;
|
|
1624
|
+
try {
|
|
1625
|
+
metadata = decoration.Metadata.modelName(model.constructor);
|
|
1626
|
+
} catch (error) {
|
|
1627
|
+
metadata = undefined;
|
|
1628
|
+
}
|
|
1629
|
+
if (putAnchor) toSerialize[decoratorValidation.ModelKeys.ANCHOR] = metadata || model.constructor.name;
|
|
1630
|
+
function preSerialize(obj) {
|
|
1631
|
+
if (typeof obj !== "object") return obj;
|
|
1632
|
+
if (Array.isArray(obj)) return obj.map(preSerialize);
|
|
1633
|
+
return this.preSerialize(obj);
|
|
1634
|
+
}
|
|
1635
|
+
decoratorValidation.Model.relations(model).forEach(r => {
|
|
1636
|
+
toSerialize[r] = preSerialize.call(this, toSerialize[r]);
|
|
1637
|
+
});
|
|
1638
|
+
return toSerialize;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
class FabricIdentityService extends core.ClientBasedService {
|
|
1642
|
+
constructor() {
|
|
1643
|
+
super();
|
|
1644
|
+
}
|
|
1645
|
+
get rootClient() {
|
|
1646
|
+
return this.client["_FabricCaServices"];
|
|
1647
|
+
}
|
|
1648
|
+
get user() {
|
|
1649
|
+
if (!this._user) throw new dbDecorators.InternalError("Fabric identity service not properly setup: missing user");
|
|
1650
|
+
return this._user;
|
|
1651
|
+
}
|
|
1652
|
+
get certificates() {
|
|
1653
|
+
return this.rootClient.newCertificateService();
|
|
1654
|
+
}
|
|
1655
|
+
get affiliations() {
|
|
1656
|
+
return this.client.newAffiliationService();
|
|
1657
|
+
}
|
|
1658
|
+
get identities() {
|
|
1659
|
+
return this.client.newIdentityService();
|
|
1660
|
+
}
|
|
1661
|
+
async getUser(cfg, ctx) {
|
|
1662
|
+
const log = ctx.logger.for(this.getUser);
|
|
1663
|
+
const {caName: caName, caCert: caCert, caKey: caKey, url: url, hsm: hsm} = cfg;
|
|
1664
|
+
log.info(`Creating CA user for ${caName} at ${url}`);
|
|
1665
|
+
log.verbose(`Retrieving CA certificate from ${caCert}`);
|
|
1666
|
+
const certificate = await CoreUtils.getFirstDirFileNameContent(caCert);
|
|
1667
|
+
let key;
|
|
1668
|
+
if (!hsm) {
|
|
1669
|
+
if (!caKey) {
|
|
1670
|
+
throw new dbDecorators.InternalError(`Missing caKey configuration for CA ${caName}. Provide a key directory or configure HSM support.`);
|
|
1671
|
+
}
|
|
1672
|
+
log.debug(`Retrieving CA key from ${caKey}`);
|
|
1673
|
+
key = await CoreUtils.getFirstDirFileNameContent(caKey);
|
|
1674
|
+
} else {
|
|
1675
|
+
log.debug(`Using HSM configuration for CA ${caName} with library ${hsm.library}`);
|
|
1676
|
+
}
|
|
1677
|
+
log.debug(`Loading Admin user for ca ${caName}`);
|
|
1678
|
+
this._user = await CoreUtils.getCAUser("admin", key, certificate, caName, {
|
|
1679
|
+
hsm: hsm
|
|
1680
|
+
});
|
|
1681
|
+
return this._user;
|
|
1682
|
+
}
|
|
1683
|
+
async initialize(...args) {
|
|
1684
|
+
const {log: log, ctx: ctx} = await this.logCtx(args, this.initialize, true);
|
|
1685
|
+
const [config] = args;
|
|
1686
|
+
if (!config) throw new dbDecorators.InternalError("Missing Fabric CA configuration");
|
|
1687
|
+
const {url: url, tls: tls, caName: caName} = config;
|
|
1688
|
+
log.info(`Initializing CA Client for CA ${config.caName} at ${config.url}`);
|
|
1689
|
+
const {trustedRoots: trustedRoots, verify: verify} = tls;
|
|
1690
|
+
const root = trustedRoots[0];
|
|
1691
|
+
log.debug(`Retrieving CA certificate from ${root}. cwd: ${process.cwd()}`);
|
|
1692
|
+
const certificate = await CoreUtils.getFileContent(root);
|
|
1693
|
+
log.debug(`CA Certificate: ${certificate.toString()}`);
|
|
1694
|
+
const client = new FabricCAServices__default["default"](url, {
|
|
1695
|
+
trustedRoots: Buffer.from(certificate),
|
|
1696
|
+
verify: verify
|
|
1697
|
+
}, caName);
|
|
1698
|
+
const user = await this.getUser(config, ctx);
|
|
1699
|
+
log.debug(`CA user loaded: ${user.getName()}`);
|
|
1700
|
+
return {
|
|
1701
|
+
config: config,
|
|
1702
|
+
client: client
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1705
|
+
async getCertificates(request, doMap = true, ...args) {
|
|
1706
|
+
if (request instanceof core.Context) {
|
|
1707
|
+
args = [ request ];
|
|
1708
|
+
doMap = true;
|
|
1709
|
+
request = undefined;
|
|
1710
|
+
} else if (typeof request === "boolean") {
|
|
1711
|
+
doMap = request;
|
|
1712
|
+
request = undefined;
|
|
1713
|
+
} else if (typeof doMap !== "boolean") {
|
|
1714
|
+
args = [ doMap, ...args ];
|
|
1715
|
+
doMap = true;
|
|
1716
|
+
}
|
|
1717
|
+
const {log: log} = await this.logCtx(args, this.getCertificates, true);
|
|
1718
|
+
log.debug(`Retrieving certificates${request ? ` for ${request.id}` : ""} for CA ${this.config.caName}`);
|
|
1719
|
+
const response = (await this.certificates.getCertificates(request || {}, this.user)).result;
|
|
1720
|
+
log.verbose(`Found ${response.certs.length} certificates`);
|
|
1721
|
+
log.debug(response.certs);
|
|
1722
|
+
return doMap ? response.certs.map(c => c.PEM) : response;
|
|
1723
|
+
}
|
|
1724
|
+
async getIdentities(ctx) {
|
|
1725
|
+
const log = ctx.logger.for(this.getIdentities);
|
|
1726
|
+
log.verbose(`Retrieving Identities under CA ${this.config.caName}`);
|
|
1727
|
+
const response = (await this.identities.getAll(this.user)).result;
|
|
1728
|
+
log.verbose(`Found ${response.identities.length} Identities`);
|
|
1729
|
+
log.debug(response.identities);
|
|
1730
|
+
return response.identities;
|
|
1731
|
+
}
|
|
1732
|
+
async getAffiliations(ctx) {
|
|
1733
|
+
const log = ctx.logger.for(this.getAffiliations);
|
|
1734
|
+
log.verbose(`Retrieving Affiliations under CA ${this.config.caName}`);
|
|
1735
|
+
const response = (await this.affiliations.getAll(this.user)).result;
|
|
1736
|
+
log.verbose(`Found ${response.a.length} Affiliations`);
|
|
1737
|
+
log.debug(JSON.stringify(response));
|
|
1738
|
+
return response;
|
|
1739
|
+
}
|
|
1740
|
+
parseError(e) {
|
|
1741
|
+
const regexp = /.*code:\s(\d+).*?message:\s["'](.+)["']/gs;
|
|
1742
|
+
const match = regexp.exec(e.message);
|
|
1743
|
+
if (!match) return new RegistrationError(e);
|
|
1744
|
+
const [, code, message] = match;
|
|
1745
|
+
switch (code) {
|
|
1746
|
+
case "74":
|
|
1747
|
+
case "71":
|
|
1748
|
+
return new dbDecorators.ConflictError(message);
|
|
1749
|
+
|
|
1750
|
+
case "20":
|
|
1751
|
+
return new core.AuthorizationError(message);
|
|
1752
|
+
|
|
1753
|
+
default:
|
|
1754
|
+
return new RegistrationError(message);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
async read(enrollmentId, ...args) {
|
|
1758
|
+
const {log: log} = await this.logCtx(args, this.read, true);
|
|
1759
|
+
log.verbose(`Retrieving identity with enrollment ID ${enrollmentId}`);
|
|
1760
|
+
let result;
|
|
1761
|
+
try {
|
|
1762
|
+
result = await this.identities.getOne(enrollmentId, this.user);
|
|
1763
|
+
} catch (e) {
|
|
1764
|
+
throw new dbDecorators.NotFoundError(`Couldn't find enrollment with id ${enrollmentId}: ${e}`);
|
|
1765
|
+
}
|
|
1766
|
+
if (!result.success) throw new dbDecorators.NotFoundError(`Couldn't find enrollment with id ${enrollmentId}: ${result.errors.join("\n")}`);
|
|
1767
|
+
return result.result;
|
|
1768
|
+
}
|
|
1769
|
+
async register(model, isSuperUser = false, affiliation = "", userRole, attrs, maxEnrollments, ...args) {
|
|
1770
|
+
const {log: log} = await this.logCtx(args, this.register, true);
|
|
1771
|
+
let registration;
|
|
1772
|
+
try {
|
|
1773
|
+
const {userName: userName, password: password} = model;
|
|
1774
|
+
const props = {
|
|
1775
|
+
enrollmentID: userName,
|
|
1776
|
+
enrollmentSecret: password,
|
|
1777
|
+
affiliation: affiliation,
|
|
1778
|
+
userRole: userRole,
|
|
1779
|
+
attrs: attrs,
|
|
1780
|
+
maxEnrollments: maxEnrollments
|
|
1781
|
+
};
|
|
1782
|
+
registration = await this.client.register(props, this.user);
|
|
1783
|
+
log.info(`Registration for ${userName} created with user type ${userRole ?? "Undefined Role"} ${isSuperUser ? "as super user" : ""}`);
|
|
1784
|
+
} catch (e) {
|
|
1785
|
+
throw this.parseError(e);
|
|
1786
|
+
}
|
|
1787
|
+
return registration;
|
|
1788
|
+
}
|
|
1789
|
+
static identityFromEnrollment(enrollment, mspId, ctx) {
|
|
1790
|
+
const log = ctx.logger.for(this.identityFromEnrollment);
|
|
1791
|
+
const {certificate: certificate, key: key, rootCertificate: rootCertificate} = enrollment;
|
|
1792
|
+
log.verbose(`Generating Identity from certificate ${certificate} in msp ${mspId}`);
|
|
1793
|
+
const clientId = CryptoUtils.fabricIdFromCertificate(certificate);
|
|
1794
|
+
const id = CryptoUtils.encode(clientId);
|
|
1795
|
+
log.debug(`Identity ${clientId} and encodedId ${id}`);
|
|
1796
|
+
return new exports.Identity({
|
|
1797
|
+
id: id,
|
|
1798
|
+
credentials: {
|
|
1799
|
+
id: id,
|
|
1800
|
+
certificate: certificate,
|
|
1801
|
+
privateKey: key.toBytes(),
|
|
1802
|
+
rootCertificate: rootCertificate
|
|
1803
|
+
},
|
|
1804
|
+
mspId: mspId
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
async enroll(enrollmentId, registration, ...args) {
|
|
1808
|
+
const {log: log, ctx: ctx} = await this.logCtx(args, this.enroll, true);
|
|
1809
|
+
let identity;
|
|
1810
|
+
try {
|
|
1811
|
+
log.debug(`Enrolling ${enrollmentId}`);
|
|
1812
|
+
const enrollment = await this.client.enroll({
|
|
1813
|
+
enrollmentID: enrollmentId,
|
|
1814
|
+
enrollmentSecret: registration
|
|
1815
|
+
});
|
|
1816
|
+
identity = FabricIdentityService.identityFromEnrollment(enrollment, this.config.caName, ctx);
|
|
1817
|
+
log.info(`Successfully enrolled ${enrollmentId} under ${this.config.caName} as ${identity.id}`);
|
|
1818
|
+
} catch (e) {
|
|
1819
|
+
throw this.parseError(e);
|
|
1820
|
+
}
|
|
1821
|
+
return identity;
|
|
1822
|
+
}
|
|
1823
|
+
async registerAndEnroll(model, isSuperUser = false, affiliation = "", userRole, attrs, maxEnrollments, ...args) {
|
|
1824
|
+
const {ctx: ctx} = await this.logCtx(args, this.registerAndEnroll, true);
|
|
1825
|
+
const registration = await this.register(model, isSuperUser, affiliation, userRole, attrs, maxEnrollments, ctx);
|
|
1826
|
+
const {userName: userName} = model;
|
|
1827
|
+
return this.enroll(userName, registration, ctx);
|
|
1828
|
+
}
|
|
1829
|
+
async revoke(enrollmentId, ...args) {
|
|
1830
|
+
const {log: log} = await this.logCtx(args, this.revoke, true);
|
|
1831
|
+
log.verbose(`Revoking identity with enrollment ID ${enrollmentId}`);
|
|
1832
|
+
const identity = await this.read(enrollmentId);
|
|
1833
|
+
if (!identity) throw new dbDecorators.NotFoundError(`Could not find enrollment with id ${enrollmentId}`);
|
|
1834
|
+
let result;
|
|
1835
|
+
try {
|
|
1836
|
+
result = await this.client.revoke({
|
|
1837
|
+
enrollmentID: identity.id,
|
|
1838
|
+
reason: "User Deletion"
|
|
1839
|
+
}, this.user);
|
|
1840
|
+
} catch (e) {
|
|
1841
|
+
throw new dbDecorators.InternalError(`Could not revoke enrollment with id ${enrollmentId}: ${e}`);
|
|
1842
|
+
}
|
|
1843
|
+
if (!result.success) throw new dbDecorators.InternalError(`Could not revoke enrollment with id ${enrollmentId}: ${result.errors.join("\n")}`);
|
|
1844
|
+
return result;
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
const DefaultFabricClientFlags = Object.assign({
|
|
1848
|
+
evaluateTimeout: 5,
|
|
1849
|
+
endorseTimeout: 15,
|
|
1850
|
+
submitTimeout: 5,
|
|
1851
|
+
commitTimeout: 60
|
|
1852
|
+
}, core.DefaultAdapterFlags);
|
|
1853
|
+
const log = new logging.MiniLogger("fabric-fs");
|
|
1854
|
+
async function contentOfLoadFile(contentOrPath, fileReader) {
|
|
1855
|
+
if (contentOrPath instanceof Uint8Array) return contentOrPath;
|
|
1856
|
+
if (contentOrPath.match(/-----BEGIN (CERTIFICATE|KEY|PRIVATE KEY)-----.+?-----END \1-----$/gms)) return contentOrPath;
|
|
1857
|
+
return await fileReader(contentOrPath);
|
|
1858
|
+
}
|
|
1859
|
+
async function readFile(contentOrPath) {
|
|
1860
|
+
if (typeof contentOrPath !== "string") return contentOrPath;
|
|
1861
|
+
const fileReader = async path => {
|
|
1862
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
1863
|
+
return await promises.readFile(path);
|
|
1864
|
+
};
|
|
1865
|
+
return await fileReader(contentOrPath);
|
|
1866
|
+
}
|
|
1867
|
+
async function getCAUser(userName, privateKey, certificate, mspId) {
|
|
1868
|
+
log.debug(`Creating a CA ${mspId} user ${userName} with certificate ${certificate}`);
|
|
1869
|
+
const user = new fabricCommon.User(userName);
|
|
1870
|
+
const cryptoSuite = fabricCommon.User.newCryptoSuite();
|
|
1871
|
+
user.setCryptoSuite(cryptoSuite);
|
|
1872
|
+
const importedKey = cryptoSuite.createKeyFromRaw(privateKey);
|
|
1873
|
+
await user.setEnrollment(importedKey, certificate, mspId);
|
|
1874
|
+
return user;
|
|
1875
|
+
}
|
|
1876
|
+
async function getIdentity(mspId, certDirectoryPath) {
|
|
1877
|
+
const identityFileReader = async path => {
|
|
1878
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
1879
|
+
const certPath = await getFirstDirFileName(path);
|
|
1880
|
+
const credentials = await promises.readFile(certPath);
|
|
1881
|
+
return credentials;
|
|
1882
|
+
};
|
|
1883
|
+
const credentials = await contentOfLoadFile(certDirectoryPath, identityFileReader);
|
|
1884
|
+
return {
|
|
1885
|
+
mspId: mspId,
|
|
1886
|
+
credentials: credentials
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
async function getFirstDirFileName(dirPath) {
|
|
1890
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
1891
|
+
const {join: join} = await core.normalizeImport(import("path"));
|
|
1892
|
+
const files = await promises.readdir(dirPath);
|
|
1893
|
+
return join(dirPath, files[0]);
|
|
1894
|
+
}
|
|
1895
|
+
async function getFirstDirFileNameContent(dirPath) {
|
|
1896
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
1897
|
+
const {join: join} = await core.normalizeImport(import("path"));
|
|
1898
|
+
const files = await promises.readdir(dirPath);
|
|
1899
|
+
return (await promises.readFile(join(dirPath, files[0]))).toString();
|
|
1900
|
+
}
|
|
1901
|
+
async function getSigner(keyDirectoryPath) {
|
|
1902
|
+
const signerFileReader = async path => {
|
|
1903
|
+
const {promises: promises} = await core.normalizeImport(import("fs"));
|
|
1904
|
+
const keyPath = await getFirstDirFileName(path);
|
|
1905
|
+
return await promises.readFile(keyPath);
|
|
1906
|
+
};
|
|
1907
|
+
const privateKeyPem = await contentOfLoadFile(keyDirectoryPath, signerFileReader);
|
|
1908
|
+
const privateKey = await extractPrivateKey(privateKeyPem);
|
|
1909
|
+
const keys = Object.getOwnPropertySymbols(privateKey);
|
|
1910
|
+
const k = privateKey[keys[0]];
|
|
1911
|
+
return fabricGateway.signers.newPrivateKeySigner(k);
|
|
1912
|
+
}
|
|
1913
|
+
async function extractPrivateKey(pem) {
|
|
1914
|
+
const libName = "crypto";
|
|
1915
|
+
let subtle;
|
|
1916
|
+
if (logging.isBrowser()) {
|
|
1917
|
+
subtle = globalThis.crypto.subtle;
|
|
1918
|
+
} else {
|
|
1919
|
+
const lib = await core.normalizeImport(import(libName));
|
|
1920
|
+
subtle = lib.subtle || lib.webcrypto.subtle;
|
|
1921
|
+
}
|
|
1922
|
+
if (!subtle) throw new Error("Could not load SubtleCrypto module");
|
|
1923
|
+
function str2ab(str) {
|
|
1924
|
+
const buf = new ArrayBuffer(str.length);
|
|
1925
|
+
const bufView = new Uint8Array(buf);
|
|
1926
|
+
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
1927
|
+
bufView[i] = str.charCodeAt(i);
|
|
1928
|
+
}
|
|
1929
|
+
return buf;
|
|
1930
|
+
}
|
|
1931
|
+
const str = pem.toString("utf8").replace("-----BEGIN PRIVATE KEY-----", "").replaceAll("\n", "").replace("-----END PRIVATE KEY-----", "");
|
|
1932
|
+
const decoded = Buffer.from(str, "base64").toString("binary");
|
|
1933
|
+
const binaryDer = str2ab(decoded);
|
|
1934
|
+
try {
|
|
1935
|
+
const key = await subtle.importKey("pkcs8", binaryDer, {
|
|
1936
|
+
name: "ECDSA",
|
|
1937
|
+
namedCurve: "P-256"
|
|
1938
|
+
}, true, [ "sign" ]);
|
|
1939
|
+
return key;
|
|
1940
|
+
} catch (e) {
|
|
1941
|
+
throw new dbDecorators.InternalError(e);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
class HSMSignerFactoryCustom {
|
|
1945
|
+
static #pkcs11=null;
|
|
1946
|
+
static #initialized=false;
|
|
1947
|
+
constructor(library) {
|
|
1948
|
+
if (!HSMSignerFactoryCustom.#pkcs11) {
|
|
1949
|
+
HSMSignerFactoryCustom.#pkcs11 = new pkcs11__default["default"].PKCS11;
|
|
1950
|
+
HSMSignerFactoryCustom.#pkcs11.load(this.findHSMPKCS11Lib(library));
|
|
1951
|
+
}
|
|
1952
|
+
if (!HSMSignerFactoryCustom.#initialized) {
|
|
1953
|
+
try {
|
|
1954
|
+
HSMSignerFactoryCustom.#pkcs11.C_Initialize();
|
|
1955
|
+
} catch (e) {
|
|
1956
|
+
if (e.code !== pkcs11__default["default"].CKR_CRYPTOKI_ALREADY_INITIALIZED) {
|
|
1957
|
+
throw e;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
HSMSignerFactoryCustom.#initialized = true;
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
findHSMPKCS11Lib(lib) {
|
|
1964
|
+
const commonSoftHSMPathNames = [ "/usr/lib/softhsm/libsofthsm2.so", "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so", "/usr/local/lib/softhsm/libsofthsm2.so", "/usr/lib/libacsp-pkcs11.so", "/opt/homebrew/lib/softhsm/libsofthsm2.so" ];
|
|
1965
|
+
if (lib) commonSoftHSMPathNames.push(lib);
|
|
1966
|
+
for (const pathnameToTry of commonSoftHSMPathNames) {
|
|
1967
|
+
if (fs__default["default"].existsSync(pathnameToTry)) {
|
|
1968
|
+
return pathnameToTry;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
throw new MissingPKCSS11Lib("Unable to find PKCS11 library");
|
|
1972
|
+
}
|
|
1973
|
+
dispose() {
|
|
1974
|
+
HSMSignerFactoryCustom.#pkcs11.C_Finalize();
|
|
1975
|
+
}
|
|
1976
|
+
sanitizeOptions(hsmSignerOptions) {
|
|
1977
|
+
const options = Object.assign({
|
|
1978
|
+
userType: pkcs11__default["default"].CKU_USER
|
|
1979
|
+
}, hsmSignerOptions);
|
|
1980
|
+
this.assertNotEmpty(options.label, "label");
|
|
1981
|
+
this.assertNotEmpty(options.pin, "pin");
|
|
1982
|
+
this.assertNotEmpty(options.identifier, "identifier");
|
|
1983
|
+
return options;
|
|
1984
|
+
}
|
|
1985
|
+
assertNotEmpty(property, name) {
|
|
1986
|
+
if (!property || property.toString().trim().length === 0) {
|
|
1987
|
+
throw new Error(`${name} property must be provided`);
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
findSlotForLabel(pkcs11Label) {
|
|
1991
|
+
const slots = HSMSignerFactoryCustom.#pkcs11.C_GetSlotList(true);
|
|
1992
|
+
if (slots.length === 0) {
|
|
1993
|
+
throw new Error("No pkcs11 slots can be found");
|
|
1994
|
+
}
|
|
1995
|
+
const slot = slots.find(slotToCheck => {
|
|
1996
|
+
const tokenInfo = HSMSignerFactoryCustom.#pkcs11.C_GetTokenInfo(slotToCheck);
|
|
1997
|
+
return tokenInfo.label.trim() === pkcs11Label;
|
|
1998
|
+
});
|
|
1999
|
+
if (!slot) {
|
|
2000
|
+
throw new Error(`label ${pkcs11Label} cannot be found in the pkcs11 slot list`);
|
|
2001
|
+
}
|
|
2002
|
+
return slot;
|
|
2003
|
+
}
|
|
2004
|
+
login(session, userType, pin) {
|
|
2005
|
+
try {
|
|
2006
|
+
HSMSignerFactoryCustom.#pkcs11.C_Login(session, userType, pin);
|
|
2007
|
+
} catch (err) {
|
|
2008
|
+
const pkcs11err = err;
|
|
2009
|
+
if (pkcs11err.code !== pkcs11__default["default"].CKR_USER_ALREADY_LOGGED_IN) {
|
|
2010
|
+
throw err;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
findObjectInHSM(session, keytype, identifier) {
|
|
2015
|
+
const pkcs11Template = [ {
|
|
2016
|
+
type: pkcs11__default["default"].CKA_ID,
|
|
2017
|
+
value: identifier
|
|
2018
|
+
}, {
|
|
2019
|
+
type: pkcs11__default["default"].CKA_CLASS,
|
|
2020
|
+
value: keytype
|
|
2021
|
+
}, {
|
|
2022
|
+
type: pkcs11__default["default"].CKA_KEY_TYPE,
|
|
2023
|
+
value: pkcs11__default["default"].CKK_EC
|
|
2024
|
+
} ];
|
|
2025
|
+
HSMSignerFactoryCustom.#pkcs11.C_FindObjectsInit(session, pkcs11Template);
|
|
2026
|
+
const hsmObject = HSMSignerFactoryCustom.#pkcs11.C_FindObjects(session, 1)[0];
|
|
2027
|
+
if (!hsmObject) {
|
|
2028
|
+
HSMSignerFactoryCustom.#pkcs11.C_FindObjectsFinal(session);
|
|
2029
|
+
throw new Error(`Unable to find object in HSM with ID ${identifier.toString()}`);
|
|
2030
|
+
}
|
|
2031
|
+
HSMSignerFactoryCustom.#pkcs11.C_FindObjectsFinal(session);
|
|
2032
|
+
return hsmObject;
|
|
2033
|
+
}
|
|
2034
|
+
newSigner(hsmSignerOptions) {
|
|
2035
|
+
const options = this.sanitizeOptions(hsmSignerOptions);
|
|
2036
|
+
const pkcs = HSMSignerFactoryCustom.#pkcs11;
|
|
2037
|
+
const slot = this.findSlotForLabel(options.label);
|
|
2038
|
+
const session = pkcs.C_OpenSession(slot, pkcs11__default["default"].CKF_SERIAL_SESSION);
|
|
2039
|
+
let privateKeyHandle;
|
|
2040
|
+
try {
|
|
2041
|
+
this.login(session, options.userType, options.pin);
|
|
2042
|
+
privateKeyHandle = this.findObjectInHSM(session, pkcs11__default["default"].CKO_PRIVATE_KEY, options.identifier);
|
|
2043
|
+
} catch (err) {
|
|
2044
|
+
HSMSignerFactoryCustom.#pkcs11.C_CloseSession(session);
|
|
2045
|
+
throw err;
|
|
2046
|
+
}
|
|
2047
|
+
return {
|
|
2048
|
+
signer: async digest => {
|
|
2049
|
+
HSMSignerFactoryCustom.#pkcs11.C_SignInit(session, {
|
|
2050
|
+
mechanism: pkcs11__default["default"].CKM_ECDSA
|
|
2051
|
+
}, privateKeyHandle);
|
|
2052
|
+
const compactSignature = await HSMSignerFactoryCustom.#pkcs11.C_SignAsync(session, Buffer.from(digest), Buffer.alloc(nist.p256.Point.Fn.BYTES * 2));
|
|
2053
|
+
return nist.p256.Signature.fromBytes(compactSignature, "compact").normalizeS().toBytes("der");
|
|
2054
|
+
},
|
|
2055
|
+
close: () => {
|
|
2056
|
+
HSMSignerFactoryCustom.#pkcs11.C_CloseSession(session);
|
|
2057
|
+
}
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
assertDefined(value) {
|
|
2061
|
+
if (value === undefined) {
|
|
2062
|
+
throw new Error("required value was undefined");
|
|
2063
|
+
}
|
|
2064
|
+
return value;
|
|
2065
|
+
}
|
|
2066
|
+
getUncompressedPointOnCurve(key) {
|
|
2067
|
+
const jwk = key.export({
|
|
2068
|
+
format: "jwk"
|
|
2069
|
+
});
|
|
2070
|
+
const x = Buffer.from(this.assertDefined(jwk.x), "base64url");
|
|
2071
|
+
const y = Buffer.from(this.assertDefined(jwk.y), "base64url");
|
|
2072
|
+
const prefix = Buffer.from("04", "hex");
|
|
2073
|
+
return Buffer.concat([ prefix, x, y ]);
|
|
2074
|
+
}
|
|
2075
|
+
getSKIFromCertificatePath(certPath) {
|
|
2076
|
+
const p = certPath.endsWith(".pem") ? certPath : path__default["default"].join(certPath, "cert.pem");
|
|
2077
|
+
const credentials = fs__default["default"].readFileSync(p);
|
|
2078
|
+
return this.getSKIFromCertificate(credentials);
|
|
2079
|
+
}
|
|
2080
|
+
getSKIFromCertificate(cert) {
|
|
2081
|
+
const certificate = new crypto__default["default"].X509Certificate(cert);
|
|
2082
|
+
const uncompressedPoint = this.getUncompressedPointOnCurve(certificate.publicKey);
|
|
2083
|
+
return crypto__default["default"].createHash("sha256").update(uncompressedPoint).digest();
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
class FabricClientStatement extends core.Statement {
|
|
2087
|
+
constructor(adapter, overrides) {
|
|
2088
|
+
super(adapter, overrides);
|
|
2089
|
+
}
|
|
2090
|
+
squash(ctx) {
|
|
2091
|
+
const squashed = super.squash(ctx);
|
|
2092
|
+
if (!squashed) return squashed;
|
|
2093
|
+
const {method: method, params: params, args: args} = squashed;
|
|
2094
|
+
const {direction: direction, limit: limit} = params;
|
|
2095
|
+
switch (method) {
|
|
2096
|
+
case core.PreparedStatementKeys.FIND_BY:
|
|
2097
|
+
break;
|
|
2098
|
+
|
|
2099
|
+
case core.PreparedStatementKeys.LIST_BY:
|
|
2100
|
+
args.push(direction);
|
|
2101
|
+
break;
|
|
2102
|
+
|
|
2103
|
+
case core.PreparedStatementKeys.PAGE_BY:
|
|
2104
|
+
args.push(direction, limit);
|
|
2105
|
+
break;
|
|
2106
|
+
|
|
2107
|
+
case core.PreparedStatementKeys.FIND_ONE_BY:
|
|
2108
|
+
break;
|
|
2109
|
+
|
|
2110
|
+
default:
|
|
2111
|
+
throw new dbDecorators.InternalError(`Unsupported method ${method}`);
|
|
2112
|
+
}
|
|
2113
|
+
return squashed;
|
|
2114
|
+
}
|
|
2115
|
+
async executePrepared(...argz) {
|
|
2116
|
+
const repo = core.Repository.forModel(this.fromSelector, this.adapter.alias);
|
|
2117
|
+
const {method: method, args: args} = this.prepared;
|
|
2118
|
+
return repo.statement(method, ...args, ...argz);
|
|
2119
|
+
}
|
|
2120
|
+
async prepare(ctx) {
|
|
2121
|
+
ctx = ctx || await this.adapter.context(core.PersistenceKeys.QUERY, this.overrides || {}, this.fromSelector);
|
|
2122
|
+
if (this.isSimpleQuery() && ctx.get("forcePrepareSimpleQueries")) {
|
|
2123
|
+
const squashed = this.squash(ctx);
|
|
2124
|
+
if (squashed) {
|
|
2125
|
+
this.prepared = squashed;
|
|
2126
|
+
return this;
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
const args = [];
|
|
2130
|
+
const params = {};
|
|
2131
|
+
const prepared = {
|
|
2132
|
+
class: this.fromSelector,
|
|
2133
|
+
args: args,
|
|
2134
|
+
params: params
|
|
2135
|
+
};
|
|
2136
|
+
const method = [ core.QueryClause.FIND_BY ];
|
|
2137
|
+
if (this.whereCondition) {
|
|
2138
|
+
const parsed = this.prepareCondition(this.whereCondition, ctx);
|
|
2139
|
+
method.push(parsed.method);
|
|
2140
|
+
if (parsed.args && parsed.args.length) args.push(...parsed.args);
|
|
2141
|
+
}
|
|
2142
|
+
if (this.selectSelector) method.push(core.QueryClause.SELECT, this.selectSelector.join(` ${core.QueryClause.AND.toLowerCase()} `));
|
|
2143
|
+
if (this.orderBySelector) {
|
|
2144
|
+
method.push(core.QueryClause.ORDER_BY, this.orderBySelector[0]);
|
|
2145
|
+
args.push(this.orderBySelector[1]);
|
|
2146
|
+
}
|
|
2147
|
+
prepared.method = logging.toCamelCase(method.join(" "));
|
|
2148
|
+
prepared.params = params;
|
|
2149
|
+
this.prepared = prepared;
|
|
2150
|
+
return this;
|
|
2151
|
+
}
|
|
2152
|
+
build() {
|
|
2153
|
+
throw new core.UnsupportedError(`This method is only called is prepared statements are not used. If so, a dedicated implementation for the native queries used is required`);
|
|
2154
|
+
}
|
|
2155
|
+
parseCondition(condition, ...args) {
|
|
2156
|
+
throw new core.UnsupportedError(`This method is only called is prepared statements are not used. Is so, a dedicated implementation for the native queries used is required`);
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
class FabricClientPaginator extends core.Paginator {
|
|
2160
|
+
constructor(adapter, query, size, clazz) {
|
|
2161
|
+
super(adapter, query, size, clazz);
|
|
2162
|
+
}
|
|
2163
|
+
prepare(rawStatement) {
|
|
2164
|
+
throw new core.UnsupportedError(`Raw query access must be implemented by a subclass. only prepared statements are natively available`);
|
|
2165
|
+
}
|
|
2166
|
+
page(page = 1, ...args) {
|
|
2167
|
+
return super.page(page, ...args);
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
var _a;
|
|
2171
|
+
class FabricClientAdapter extends core.Adapter {
|
|
2172
|
+
static {
|
|
2173
|
+
this.decoder = new TextDecoder("utf8");
|
|
2174
|
+
}
|
|
2175
|
+
static {
|
|
2176
|
+
this.serializer = new ClientSerializer;
|
|
2177
|
+
}
|
|
2178
|
+
static {
|
|
2179
|
+
this.log = logging.Logging.for(FabricClientAdapter);
|
|
2180
|
+
}
|
|
2181
|
+
constructor(config, alias) {
|
|
2182
|
+
super(config, FabricFlavour, alias);
|
|
2183
|
+
this.serializer = FabricClientAdapter.serializer;
|
|
2184
|
+
}
|
|
2185
|
+
Statement(overrides) {
|
|
2186
|
+
return new FabricClientStatement(this, overrides);
|
|
2187
|
+
}
|
|
2188
|
+
Paginator(query, size, clazz) {
|
|
2189
|
+
return new FabricClientPaginator(this, query, size, clazz);
|
|
2190
|
+
}
|
|
2191
|
+
flags(operation, model, flags, ...args) {
|
|
2192
|
+
return super.flags(operation, model, flags, ...args);
|
|
2193
|
+
}
|
|
2194
|
+
async context(operation, overrides, model, ...args) {
|
|
2195
|
+
const log = this.log.for(this.context);
|
|
2196
|
+
log.silly(`creating new context for ${operation} operation on ${model ? Array.isArray(model) ? model.map(m => decoratorValidation.Model.tableName(m)) : decoratorValidation.Model.tableName(model) : "no"} table ${overrides && Object.keys(overrides) ? Object.keys(overrides).length : "no"} with flag overrides`);
|
|
2197
|
+
let ctx = args.pop();
|
|
2198
|
+
if (typeof ctx !== "undefined" && !(ctx instanceof core.Context)) {
|
|
2199
|
+
args.push(ctx);
|
|
2200
|
+
ctx = undefined;
|
|
2201
|
+
}
|
|
2202
|
+
overrides = ctx ? Object.assign({}, overrides, ctx.toOverrides()) : overrides;
|
|
2203
|
+
const flags = await this.flags(typeof operation === "string" ? operation : operation.name, model, overrides, ...args, ctx);
|
|
2204
|
+
if (ctx) {
|
|
2205
|
+
if (!(ctx instanceof this.Context)) {
|
|
2206
|
+
return (new this.Context).accumulate({
|
|
2207
|
+
...ctx["cache"],
|
|
2208
|
+
...flags,
|
|
2209
|
+
parentContext: ctx
|
|
2210
|
+
});
|
|
2211
|
+
}
|
|
2212
|
+
const currentOp = ctx.get("operation");
|
|
2213
|
+
const currentModel = ctx.get("affectedTables");
|
|
2214
|
+
if (currentOp !== operation || model !== currentModel) return (new this.Context).accumulate({
|
|
2215
|
+
...ctx["cache"],
|
|
2216
|
+
...flags,
|
|
2217
|
+
parentContext: ctx
|
|
2218
|
+
});
|
|
2219
|
+
return ctx.accumulate(flags);
|
|
2220
|
+
}
|
|
2221
|
+
return (new this.Context).accumulate({
|
|
2222
|
+
...DefaultFabricClientFlags,
|
|
2223
|
+
...flags
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
decode(data) {
|
|
2227
|
+
return FabricClientAdapter.decoder.decode(data);
|
|
2228
|
+
}
|
|
2229
|
+
repository() {
|
|
2230
|
+
return FabricClientRepository;
|
|
2231
|
+
}
|
|
2232
|
+
createPrefix(clazz, id, model, ...args) {
|
|
2233
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.createPrefix);
|
|
2234
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2235
|
+
const record = {};
|
|
2236
|
+
record[forCouchdb.CouchDBKeys.TABLE] = tableName;
|
|
2237
|
+
Object.assign(record, model);
|
|
2238
|
+
return [ clazz, id, record, ...ctxArgs ];
|
|
2239
|
+
}
|
|
2240
|
+
createAllPrefix(clazz, ids, models, ...args) {
|
|
2241
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2242
|
+
if (ids.length !== models.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
|
|
2243
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.createAllPrefix);
|
|
2244
|
+
const records = ids.map((id, count) => {
|
|
2245
|
+
const record = {};
|
|
2246
|
+
record[forCouchdb.CouchDBKeys.TABLE] = tableName;
|
|
2247
|
+
Object.assign(record, models[count]);
|
|
2248
|
+
return record;
|
|
2249
|
+
});
|
|
2250
|
+
return [ clazz, ids, records, ...ctxArgs ];
|
|
2251
|
+
}
|
|
2252
|
+
updateAllPrefix(clazz, ids, models, ...args) {
|
|
2253
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2254
|
+
if (ids.length !== models.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
|
|
2255
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.updateAllPrefix);
|
|
2256
|
+
const records = ids.map(() => {
|
|
2257
|
+
const record = {};
|
|
2258
|
+
record[forCouchdb.CouchDBKeys.TABLE] = tableName;
|
|
2259
|
+
return record;
|
|
2260
|
+
});
|
|
2261
|
+
return [ clazz, ids, records, ...ctxArgs ];
|
|
2262
|
+
}
|
|
2263
|
+
async createAll(clazz, ids, models, ...args) {
|
|
2264
|
+
if (ids.length !== models.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
|
|
2265
|
+
const ctxArgs = [ ...args ];
|
|
2266
|
+
const transient = ctxArgs.shift();
|
|
2267
|
+
const {log: log, ctx: ctx} = this.logCtx(ctxArgs, this.createAll);
|
|
2268
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2269
|
+
log.info(`adding ${ids.length} entries to ${tableName} table`);
|
|
2270
|
+
log.verbose(`pks: ${ids}`);
|
|
2271
|
+
const result = await this.submitTransaction(ctx, dbDecorators.BulkCrudOperationKeys.CREATE_ALL, [ JSON.stringify(models.map(m => this.serializer.serialize(m, clazz.name))) ], transient, undefined, clazz.name);
|
|
2272
|
+
try {
|
|
2273
|
+
return JSON.parse(this.decode(result)).map(r => JSON.parse(r));
|
|
2274
|
+
} catch (e) {
|
|
2275
|
+
throw new dbDecorators.SerializationError(e);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
async readAll(clazz, ids, ...args) {
|
|
2279
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.readAll);
|
|
2280
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2281
|
+
log.info(`reading ${ids.length} entries to ${tableName} table`);
|
|
2282
|
+
log.verbose(`pks: ${ids}`);
|
|
2283
|
+
const result = await this.evaluateTransaction(ctx, dbDecorators.BulkCrudOperationKeys.READ_ALL, [ JSON.stringify(ids) ], undefined, undefined, clazz.name);
|
|
2284
|
+
try {
|
|
2285
|
+
return JSON.parse(this.decode(result)).map(r => JSON.parse(r));
|
|
2286
|
+
} catch (e) {
|
|
2287
|
+
throw new dbDecorators.SerializationError(e);
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
async updateAll(clazz, ids, models, ...args) {
|
|
2291
|
+
if (ids.length !== models.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
|
|
2292
|
+
const ctxArgs = [ ...args ];
|
|
2293
|
+
const transient = ctxArgs.shift();
|
|
2294
|
+
const {log: log, ctx: ctx} = this.logCtx(ctxArgs, this.updateAll);
|
|
2295
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2296
|
+
log.info(`updating ${ids.length} entries to ${tableName} table`);
|
|
2297
|
+
log.verbose(`pks: ${ids}`);
|
|
2298
|
+
const result = await this.submitTransaction(ctx, dbDecorators.BulkCrudOperationKeys.UPDATE_ALL, [ JSON.stringify(models.map(m => this.serializer.serialize(m, clazz.name))) ], transient, undefined, clazz.name);
|
|
2299
|
+
try {
|
|
2300
|
+
return JSON.parse(this.decode(result)).map(r => JSON.parse(r));
|
|
2301
|
+
} catch (e) {
|
|
2302
|
+
throw new dbDecorators.SerializationError(e);
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
async deleteAll(clazz, ids, ...args) {
|
|
2306
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.deleteAll);
|
|
2307
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2308
|
+
log.info(`deleting ${ids.length} entries to ${tableName} table`);
|
|
2309
|
+
log.verbose(`pks: ${ids}`);
|
|
2310
|
+
const result = await this.submitTransaction(ctx, dbDecorators.BulkCrudOperationKeys.DELETE_ALL, [ JSON.stringify(ids) ], undefined, undefined, clazz.name);
|
|
2311
|
+
try {
|
|
2312
|
+
return JSON.parse(this.decode(result)).map(r => JSON.parse(r));
|
|
2313
|
+
} catch (e) {
|
|
2314
|
+
throw new dbDecorators.SerializationError(e);
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
prepare(model, ...args) {
|
|
2318
|
+
const {log: log} = this.logCtx(args, this.prepare);
|
|
2319
|
+
const split = decoratorValidation.Model.segregate(model);
|
|
2320
|
+
if (model[core.PersistenceKeys.METADATA]) {
|
|
2321
|
+
log.silly(`Passing along persistence metadata for ${model[core.PersistenceKeys.METADATA]}`);
|
|
2322
|
+
Object.defineProperty(split.model, core.PersistenceKeys.METADATA, {
|
|
2323
|
+
enumerable: false,
|
|
2324
|
+
writable: false,
|
|
2325
|
+
configurable: true,
|
|
2326
|
+
value: model[core.PersistenceKeys.METADATA]
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
2329
|
+
return {
|
|
2330
|
+
record: split.model,
|
|
2331
|
+
model: split.model,
|
|
2332
|
+
id: model[decoratorValidation.Model.pk(model.constructor)],
|
|
2333
|
+
transient: split.transient,
|
|
2334
|
+
private: split.private,
|
|
2335
|
+
shared: split.shared
|
|
2336
|
+
};
|
|
2337
|
+
}
|
|
2338
|
+
revert(obj, clazz, id, transient, ...args) {
|
|
2339
|
+
const {log: log} = this.logCtx(args, this.revert);
|
|
2340
|
+
if (transient) {
|
|
2341
|
+
log.verbose(`re-adding transient properties: ${Object.keys(transient).join(", ")}`);
|
|
2342
|
+
Object.entries(transient).forEach(([key, val]) => {
|
|
2343
|
+
if (key in obj) throw new dbDecorators.InternalError(`Transient property ${key} already exists on model ${typeof clazz === "string" ? clazz : clazz.name}. should be impossible`);
|
|
2344
|
+
obj[key] = val;
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2347
|
+
return new clazz(obj);
|
|
2348
|
+
}
|
|
2349
|
+
async create(clazz, id, model, transient = {}, ...args) {
|
|
2350
|
+
const ctxArgs = [ ...args ];
|
|
2351
|
+
const {log: log, ctx: ctx} = this.logCtx(ctxArgs, this.create);
|
|
2352
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2353
|
+
log.verbose(`adding entry to ${tableName} table`);
|
|
2354
|
+
log.debug(`pk: ${id}`);
|
|
2355
|
+
const result = await this.submitTransaction(ctx, dbDecorators.OperationKeys.CREATE, [ this.serializer.serialize(model, clazz.name) ], transient, undefined, clazz.name);
|
|
2356
|
+
return this.serializer.deserialize(this.decode(result));
|
|
2357
|
+
}
|
|
2358
|
+
async read(clazz, id, ...args) {
|
|
2359
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.readAll);
|
|
2360
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2361
|
+
log.verbose(`reading entry from ${tableName} table`);
|
|
2362
|
+
log.debug(`pk: ${id}`);
|
|
2363
|
+
const result = await this.evaluateTransaction(ctx, dbDecorators.OperationKeys.READ, [ id.toString() ], undefined, undefined, clazz.name);
|
|
2364
|
+
return this.serializer.deserialize(this.decode(result));
|
|
2365
|
+
}
|
|
2366
|
+
updatePrefix(clazz, id, model, ...args) {
|
|
2367
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2368
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.updatePrefix);
|
|
2369
|
+
const record = {};
|
|
2370
|
+
record[forCouchdb.CouchDBKeys.TABLE] = tableName;
|
|
2371
|
+
Object.assign(record, model);
|
|
2372
|
+
return [ clazz, id, record, ...ctxArgs ];
|
|
2373
|
+
}
|
|
2374
|
+
async update(clazz, id, model, transient = {}, ...args) {
|
|
2375
|
+
const ctxArgs = [ ...args ];
|
|
2376
|
+
const {log: log, ctx: ctx} = this.logCtx(ctxArgs, this.updateAll);
|
|
2377
|
+
log.info(`CLIENT UPDATE class : ${typeof clazz}`);
|
|
2378
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2379
|
+
log.verbose(`updating entry to ${tableName} table`);
|
|
2380
|
+
log.debug(`pk: ${id}`);
|
|
2381
|
+
const result = await this.submitTransaction(ctx, dbDecorators.OperationKeys.UPDATE, [ this.serializer.serialize(model, clazz.name || clazz) ], transient, undefined, clazz.name);
|
|
2382
|
+
return this.serializer.deserialize(this.decode(result));
|
|
2383
|
+
}
|
|
2384
|
+
async delete(clazz, id, ...args) {
|
|
2385
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.delete);
|
|
2386
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
2387
|
+
log.verbose(`deleting entry from ${tableName} table`);
|
|
2388
|
+
log.debug(`pk: ${id}`);
|
|
2389
|
+
const result = await this.submitTransaction(ctx, dbDecorators.OperationKeys.DELETE, [ id.toString() ], undefined, undefined, clazz.name);
|
|
2390
|
+
return this.serializer.deserialize(this.decode(result));
|
|
2391
|
+
}
|
|
2392
|
+
async raw(rawInput, docsOnly = true, clazz, ...args) {
|
|
2393
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.raw);
|
|
2394
|
+
const tableName = clazz.name;
|
|
2395
|
+
log.info(`Performing raw statement on table ${decoratorValidation.Model.tableName(clazz)}`);
|
|
2396
|
+
let transactionResult;
|
|
2397
|
+
try {
|
|
2398
|
+
transactionResult = await this.evaluateTransaction(ctx, "raw", [ JSON.stringify(rawInput), docsOnly ], undefined, undefined, tableName);
|
|
2399
|
+
} catch (e) {
|
|
2400
|
+
throw this.parseError(e);
|
|
2401
|
+
}
|
|
2402
|
+
let result;
|
|
2403
|
+
try {
|
|
2404
|
+
result = JSON.parse(this.decode(transactionResult));
|
|
2405
|
+
} catch (e) {
|
|
2406
|
+
throw new dbDecorators.SerializationError(`Failed to process result: ${e}`);
|
|
2407
|
+
}
|
|
2408
|
+
const parseRecord = record => {
|
|
2409
|
+
if (decoratorValidation.Model.isModel(record)) return decoratorValidation.Model.build(record);
|
|
2410
|
+
return record;
|
|
2411
|
+
};
|
|
2412
|
+
if (Array.isArray(result)) {
|
|
2413
|
+
if (!result.length) return result;
|
|
2414
|
+
const el = result[0];
|
|
2415
|
+
if (decoratorValidation.Model.isModel(el)) return result.map(el => decoratorValidation.Model.build(el));
|
|
2416
|
+
return result;
|
|
2417
|
+
}
|
|
2418
|
+
return parseRecord(result);
|
|
2419
|
+
}
|
|
2420
|
+
getClient() {
|
|
2421
|
+
if (!this._client) this._client = FabricClientAdapter.getClient(this.config);
|
|
2422
|
+
return this._client;
|
|
2423
|
+
}
|
|
2424
|
+
async Gateway(ctx) {
|
|
2425
|
+
return FabricClientAdapter.getGateway(ctx, this.config, this.client);
|
|
2426
|
+
}
|
|
2427
|
+
getContractName(className) {
|
|
2428
|
+
if (!className) return undefined;
|
|
2429
|
+
return `${className}Contract`;
|
|
2430
|
+
}
|
|
2431
|
+
async Contract(ctx, contractName) {
|
|
2432
|
+
return FabricClientAdapter.getContract(await this.Gateway(ctx), this.config, contractName);
|
|
2433
|
+
}
|
|
2434
|
+
async transaction(ctx, api, submit = true, args, transientData, endorsingOrganizations, className) {
|
|
2435
|
+
const log = this.log.for(this.transaction);
|
|
2436
|
+
const gateway = await this.Gateway(ctx);
|
|
2437
|
+
try {
|
|
2438
|
+
const contract = await this.Contract(ctx, this.getContractName(className));
|
|
2439
|
+
log.verbose(`${submit ? "Submit" : "Evaluate"}ting transaction ${this.getContractName(className) || this.config.contractName}.${api}`);
|
|
2440
|
+
log.debug(`args: ${args?.map(a => a.toString()).join("\n") || "none"}`);
|
|
2441
|
+
const method = submit ? contract.submit : contract.evaluate;
|
|
2442
|
+
endorsingOrganizations = endorsingOrganizations?.length ? endorsingOrganizations : undefined;
|
|
2443
|
+
const proposalOptions = {
|
|
2444
|
+
arguments: args || [],
|
|
2445
|
+
transientData: transientData
|
|
2446
|
+
};
|
|
2447
|
+
return await method.call(contract, api, proposalOptions);
|
|
2448
|
+
} catch (e) {
|
|
2449
|
+
if (e.code === 10) {
|
|
2450
|
+
throw new Error(`${e.details[0].message}`);
|
|
2451
|
+
}
|
|
2452
|
+
throw this.parseError(e);
|
|
2453
|
+
} finally {
|
|
2454
|
+
this.log.debug(`Closing ${this.config.mspId} gateway connection`);
|
|
2455
|
+
gateway.close();
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
parseError(err) {
|
|
2459
|
+
return FabricClientAdapter.parseError(err);
|
|
2460
|
+
}
|
|
2461
|
+
async submitTransaction(ctx, api, args, transientData, endorsingOrganizations, className) {
|
|
2462
|
+
return this.transaction(ctx, api, true, args, transientData, endorsingOrganizations, className);
|
|
2463
|
+
}
|
|
2464
|
+
async evaluateTransaction(ctx, api, args, transientData, endorsingOrganizations, className) {
|
|
2465
|
+
return this.transaction(ctx, api, false, args, transientData, endorsingOrganizations, className);
|
|
2466
|
+
}
|
|
2467
|
+
async close() {
|
|
2468
|
+
if (this.client) {
|
|
2469
|
+
this.log.verbose(`Closing ${this.config.mspId} gateway client`);
|
|
2470
|
+
this.client.close();
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
static getContract(gateway, config, contractName) {
|
|
2474
|
+
const log = this.log.for(this.getContract);
|
|
2475
|
+
const network = this.getNetwork(gateway, config.channel);
|
|
2476
|
+
let contract;
|
|
2477
|
+
try {
|
|
2478
|
+
log.debug(`Retrieving chaincode ${config.chaincodeName} contract ${contractName || config.contractName} from network ${config.channel}`);
|
|
2479
|
+
contractName = contractName ? contractName : config.contractName;
|
|
2480
|
+
contract = network.getContract(config.chaincodeName, contractName);
|
|
2481
|
+
} catch (e) {
|
|
2482
|
+
throw this.parseError(e);
|
|
2483
|
+
}
|
|
2484
|
+
return contract;
|
|
2485
|
+
}
|
|
2486
|
+
static getNetwork(gateway, channelName) {
|
|
2487
|
+
const log = logging.Logging.for(this.getNetwork);
|
|
2488
|
+
let network;
|
|
2489
|
+
try {
|
|
2490
|
+
log.debug(`Connecting to channel ${channelName}`);
|
|
2491
|
+
network = gateway.getNetwork(channelName);
|
|
2492
|
+
} catch (e) {
|
|
2493
|
+
throw this.parseError(e);
|
|
2494
|
+
}
|
|
2495
|
+
return network;
|
|
2496
|
+
}
|
|
2497
|
+
static async getGateway(ctx, config, client) {
|
|
2498
|
+
return await this.getConnection(client || await this.getClient(config), config, ctx);
|
|
2499
|
+
}
|
|
2500
|
+
static getClient(config) {
|
|
2501
|
+
const log = this.log.for(this.getClient);
|
|
2502
|
+
log.debug(`generating TLS credentials for msp ${config.mspId}`);
|
|
2503
|
+
let pathOrCert = config.tlsCert;
|
|
2504
|
+
if (typeof pathOrCert === "string") {
|
|
2505
|
+
if (pathOrCert.match(/-----BEGIN (CERTIFICATE|KEY|PRIVATE KEY)-----.+?-----END \1-----$/gms)) {
|
|
2506
|
+
pathOrCert = Buffer.from(pathOrCert, "utf8");
|
|
2507
|
+
} else {
|
|
2508
|
+
try {
|
|
2509
|
+
pathOrCert = Buffer.from(fs__default["default"].readFileSync(pathOrCert, "utf8"));
|
|
2510
|
+
} catch (e) {
|
|
2511
|
+
throw new dbDecorators.InternalError(`Failed to read the tls certificate from ${pathOrCert}: ${e}`);
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
const tlsCredentials = grpc__namespace.credentials.createSsl(pathOrCert);
|
|
2516
|
+
log.debug(`generating Gateway Client for url ${config.peerEndpoint}`);
|
|
2517
|
+
return new grpc.Client(config.peerEndpoint, tlsCredentials, {
|
|
2518
|
+
"grpc.max_receive_message_length": (config.sizeLimit || 15) * 1024 * 1024,
|
|
2519
|
+
"grpc.max_send_message_length": (config.sizeLimit || 15) * 1024 * 1024
|
|
2520
|
+
});
|
|
2521
|
+
}
|
|
2522
|
+
static async getConnection(client, config, ctx) {
|
|
2523
|
+
const log = logging.Logging.for(this.getConnection);
|
|
2524
|
+
log.debug(`Retrieving Peer Identity for ${config.mspId} under ${config.certCertOrDirectoryPath}`);
|
|
2525
|
+
const identity = await getIdentity(config.mspId, config.certCertOrDirectoryPath);
|
|
2526
|
+
log.debug(`Retrieving signer key from ${config.keyCertOrDirectoryPath}`);
|
|
2527
|
+
let signer, close = () => {};
|
|
2528
|
+
if (!config.hsm) {
|
|
2529
|
+
signer = await getSigner(config.keyCertOrDirectoryPath);
|
|
2530
|
+
} else {
|
|
2531
|
+
const hsm = new HSMSignerFactoryCustom(config.hsm.library);
|
|
2532
|
+
const identifier = hsm.getSKIFromCertificatePath(config.certCertOrDirectoryPath);
|
|
2533
|
+
const pkcs11Signer = hsm.newSigner({
|
|
2534
|
+
label: config.hsm.tokenLabel,
|
|
2535
|
+
pin: String(config.hsm.pin),
|
|
2536
|
+
identifier: identifier
|
|
2537
|
+
});
|
|
2538
|
+
signer = pkcs11Signer.signer;
|
|
2539
|
+
close = pkcs11Signer.close;
|
|
2540
|
+
}
|
|
2541
|
+
const options = {
|
|
2542
|
+
client: client,
|
|
2543
|
+
identity: identity,
|
|
2544
|
+
signer: signer,
|
|
2545
|
+
evaluateOptions: () => ({
|
|
2546
|
+
deadline: Date.now() + 1e3 * ctx.get("evaluateTimeout")
|
|
2547
|
+
}),
|
|
2548
|
+
endorseOptions: () => ({
|
|
2549
|
+
deadline: Date.now() + 1e3 * ctx.get("endorseTimeout")
|
|
2550
|
+
}),
|
|
2551
|
+
submitOptions: () => ({
|
|
2552
|
+
deadline: Date.now() + 1e3 * ctx.get("submitTimeout")
|
|
2553
|
+
}),
|
|
2554
|
+
commitStatusOptions: () => ({
|
|
2555
|
+
deadline: Date.now() + 1e3 * ctx.get("commitTimeout")
|
|
2556
|
+
})
|
|
2557
|
+
};
|
|
2558
|
+
log.debug(`Connecting to ${config.mspId}`);
|
|
2559
|
+
const gateway = fabricGateway.connect(options);
|
|
2560
|
+
if (config.hsm) {
|
|
2561
|
+
gateway.close = new Proxy(gateway.close, {
|
|
2562
|
+
apply(target, thisArg, argArray) {
|
|
2563
|
+
Reflect.apply(target, thisArg, argArray);
|
|
2564
|
+
close();
|
|
2565
|
+
}
|
|
2566
|
+
});
|
|
2567
|
+
}
|
|
2568
|
+
return gateway;
|
|
2569
|
+
}
|
|
2570
|
+
Dispatch() {
|
|
2571
|
+
return new FabricClientAdapter["_baseDispatch"];
|
|
2572
|
+
}
|
|
2573
|
+
static parseError(err) {
|
|
2574
|
+
const msg = typeof err === "string" ? err : err.message;
|
|
2575
|
+
if (msg.includes("MVCC_READ_CONFLICT")) return new MvccReadConflictError(err);
|
|
2576
|
+
if (msg.includes("ENDORSEMENT_POLICY_FAILURE")) return new EndorsementPolicyError(err);
|
|
2577
|
+
if (msg.includes("PHANTOM_READ_CONFLICT")) return new PhantomReadConflictError(err);
|
|
2578
|
+
if (err instanceof Error && err.code) {
|
|
2579
|
+
switch (err.code) {
|
|
2580
|
+
case 9:
|
|
2581
|
+
return new EndorsementError(err);
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
if (msg.includes(dbDecorators.NotFoundError.name)) return new dbDecorators.NotFoundError(err);
|
|
2585
|
+
if (msg.includes(dbDecorators.ConflictError.name)) return new dbDecorators.ConflictError(err);
|
|
2586
|
+
if (msg.includes(dbDecorators.BadRequestError.name)) return new dbDecorators.BadRequestError(err);
|
|
2587
|
+
if (msg.includes(core.QueryError.name)) return new core.QueryError(err);
|
|
2588
|
+
if (msg.includes(core.PagingError.name)) return new core.PagingError(err);
|
|
2589
|
+
if (msg.includes(core.UnsupportedError.name)) return new core.UnsupportedError(err);
|
|
2590
|
+
if (msg.includes(core.MigrationError.name)) return new core.MigrationError(err);
|
|
2591
|
+
if (msg.includes(core.ObserverError.name)) return new core.ObserverError(err);
|
|
2592
|
+
if (msg.includes(core.AuthorizationError.name)) return new core.AuthorizationError(err);
|
|
2593
|
+
if (msg.includes(core.ForbiddenError.name)) return new core.ForbiddenError(err);
|
|
2594
|
+
if (msg.includes(core.ConnectionError.name)) return new core.ConnectionError(err);
|
|
2595
|
+
if (msg.includes(dbDecorators.SerializationError.name)) return new dbDecorators.SerializationError(err);
|
|
2596
|
+
return new dbDecorators.InternalError(err);
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
tslib.__decorate([ logging.debug(), logging.final(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ Object, Object, Object, Object, core.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "create", null);
|
|
2600
|
+
tslib.__decorate([ logging.debug(), logging.final(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ Object, Object, core.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "read", null);
|
|
2601
|
+
tslib.__decorate([ logging.debug(), logging.final(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ Object, Object, Object, Object, core.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "update", null);
|
|
2602
|
+
tslib.__decorate([ logging.debug(), logging.final(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ Object, Object, core.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "delete", null);
|
|
2603
|
+
tslib.__decorate([ logging.debug(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ Object, typeof (_a = typeof D !== "undefined" && D) === "function" ? _a : Object, Object, core.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "raw", null);
|
|
2604
|
+
FabricClientAdapter.decoration();
|
|
2605
|
+
core.Adapter.setCurrent(FabricFlavour);
|
|
2606
|
+
class FabricClientDispatch extends core.Dispatch {
|
|
2607
|
+
constructor(client) {
|
|
2608
|
+
super();
|
|
2609
|
+
this.client = client;
|
|
2610
|
+
this.decoder = new TextDecoder("utf8");
|
|
2611
|
+
}
|
|
2612
|
+
async close() {
|
|
2613
|
+
if (this.listeningStack) this.listeningStack.close();
|
|
2614
|
+
}
|
|
2615
|
+
parsePayload(jsonBytes) {
|
|
2616
|
+
const json = this.decoder.decode(jsonBytes);
|
|
2617
|
+
return JSON.parse(json);
|
|
2618
|
+
}
|
|
2619
|
+
observe(observer) {
|
|
2620
|
+
if (!(observer instanceof FabricClientAdapter)) throw new core.UnsupportedError("Only FabricClientAdapter can be observed by dispatch");
|
|
2621
|
+
super.observe(observer);
|
|
2622
|
+
return () => this.unObserve(observer);
|
|
2623
|
+
}
|
|
2624
|
+
async updateObservers(model, event, id, ...args) {
|
|
2625
|
+
const {log: log, ctxArgs: ctxArgs} = core.Adapter.logCtx(this.updateObservers, event, false, ...args);
|
|
2626
|
+
if (!this.adapter) {
|
|
2627
|
+
log.verbose(`No adapter observed for dispatch; skipping observer update for ${typeof model === "string" ? model : decoratorValidation.Model.tableName(model)}:${event}`);
|
|
2628
|
+
return;
|
|
2629
|
+
}
|
|
2630
|
+
try {
|
|
2631
|
+
await this.adapter.refresh(model, event, id, ...ctxArgs);
|
|
2632
|
+
} catch (e) {
|
|
2633
|
+
throw new dbDecorators.InternalError(`Failed to refresh dispatch: ${e}`);
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
async handleEvents(ctxArg) {
|
|
2637
|
+
if (!this.listeningStack) throw new dbDecorators.InternalError(`Event stack not initialized. Ensure that "startListening" is called before attempting this operation.`);
|
|
2638
|
+
if (!this.adapter || !this.adapter.config) throw new dbDecorators.InternalError(`No adapter found. should be impossible`);
|
|
2639
|
+
const ctx = ctxArg || await this.adapter.context(dbDecorators.OperationKeys.READ, {
|
|
2640
|
+
correlationId: this.adapter.config.chaincodeName
|
|
2641
|
+
}, this.models && this.models[0] || decoratorValidation.Model);
|
|
2642
|
+
const log = this.log.for(this.handleEvents);
|
|
2643
|
+
log.info(`Listening for incoming events on chaincode "${this.adapter.config.chaincodeName}" on channel "${this.adapter.config.channel}"...`);
|
|
2644
|
+
try {
|
|
2645
|
+
for await (const evt of this.listeningStack) {
|
|
2646
|
+
const {table: table, event: event, owner: owner} = parseEventName(evt.eventName);
|
|
2647
|
+
if (owner && owner !== this.adapter.config?.mspId) continue;
|
|
2648
|
+
const payload = this.parsePayload(evt.payload);
|
|
2649
|
+
try {
|
|
2650
|
+
const targetModel = table ? decoratorValidation.Model.get(table) : decoratorValidation.Model.get(this.models[0].name);
|
|
2651
|
+
const modelRef = targetModel ?? (table || this.models[0]?.name);
|
|
2652
|
+
await this.updateObservers(modelRef, event, payload.id, ctx);
|
|
2653
|
+
} catch (e) {
|
|
2654
|
+
log.error(`Failed update observables for table ${table} event ${event} id: ${payload.id}: ${e}`);
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
} catch (e) {
|
|
2658
|
+
log.error(`Failed to read event for chaincode "${this.adapter.config.chaincodeName}" on channel "${this.adapter.config.channel}": ${e}`);
|
|
2659
|
+
await this.close();
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
async initialize() {
|
|
2663
|
+
if (!this.adapter) throw new dbDecorators.InternalError(`No adapter or config observed for dispatch`);
|
|
2664
|
+
const context = await this.adapter.context("dispatch", {
|
|
2665
|
+
correlationId: this.adapter.config.chaincodeName
|
|
2666
|
+
}, decoratorValidation.Model);
|
|
2667
|
+
const {ctx: ctx} = this.logCtx([ context ], this.initialize);
|
|
2668
|
+
const gateway = await FabricClientAdapter.getGateway(ctx, this.adapter.config, this.client);
|
|
2669
|
+
const network = gateway.getNetwork(this.adapter.config.channel);
|
|
2670
|
+
if (!this.adapter) throw new dbDecorators.InternalError(`No adapter observed for dispatch`);
|
|
2671
|
+
this.listeningStack = await network.getChaincodeEvents(this.adapter.config.chaincodeName);
|
|
2672
|
+
this.handleEvents(ctx);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
if (FabricClientAdapter) FabricClientAdapter["_baseDispatch"] = FabricClientDispatch;
|
|
2676
|
+
const VERSION = "0.1.62";
|
|
2677
|
+
const PACKAGE_NAME = "@decaf-ts/for-fabric";
|
|
2678
|
+
decoration.Metadata.registerLibrary(PACKAGE_NAME, VERSION);
|
|
2679
|
+
exports.AllowanceError = AllowanceError;
|
|
2680
|
+
exports.BalanceError = BalanceError;
|
|
2681
|
+
exports.BaseEncoder = BaseEncoder;
|
|
2682
|
+
exports.ClientSerializer = ClientSerializer;
|
|
2683
|
+
exports.CoreUtils = CoreUtils;
|
|
2684
|
+
exports.CryptoUtils = CryptoUtils;
|
|
2685
|
+
exports.DefaultFabricClientFlags = DefaultFabricClientFlags;
|
|
2686
|
+
exports.DeterministicSerializer = DeterministicSerializer;
|
|
2687
|
+
exports.EndorsementError = EndorsementError;
|
|
2688
|
+
exports.EndorsementPolicyError = EndorsementPolicyError;
|
|
2689
|
+
exports.FabricClientAdapter = FabricClientAdapter;
|
|
2690
|
+
exports.FabricClientDispatch = FabricClientDispatch;
|
|
2691
|
+
exports.FabricClientRepository = FabricClientRepository;
|
|
2692
|
+
exports.FabricERC20ClientRepository = FabricERC20ClientRepository;
|
|
2693
|
+
exports.FabricEnrollmentService = FabricEnrollmentService;
|
|
2694
|
+
exports.FabricFlavour = FabricFlavour;
|
|
2695
|
+
exports.FabricIdentityService = FabricIdentityService;
|
|
2696
|
+
exports.ImplicitPrivateCollection = ImplicitPrivateCollection;
|
|
2697
|
+
exports.MissingContextError = MissingContextError;
|
|
2698
|
+
exports.MissingPKCSS11Lib = MissingPKCSS11Lib;
|
|
2699
|
+
exports.ModelCollection = ModelCollection;
|
|
2700
|
+
exports.MvccReadConflictError = MvccReadConflictError;
|
|
2701
|
+
exports.NotInitializedError = NotInitializedError;
|
|
2702
|
+
exports.OverflowError = OverflowError;
|
|
2703
|
+
exports.Owner = Owner;
|
|
2704
|
+
exports.PACKAGE_NAME = PACKAGE_NAME;
|
|
2705
|
+
exports.PhantomReadConflictError = PhantomReadConflictError;
|
|
2706
|
+
exports.RegistrationError = RegistrationError;
|
|
2707
|
+
exports.RegistrationRequestBuilder = RegistrationRequestBuilder;
|
|
2708
|
+
exports.SimpleDeterministicSerializer = SimpleDeterministicSerializer;
|
|
2709
|
+
exports.UnauthorizedPrivateDataAccess = UnauthorizedPrivateDataAccess;
|
|
2710
|
+
exports.VERSION = VERSION;
|
|
2711
|
+
exports.add = add;
|
|
2712
|
+
exports.contentOfLoadFile = contentOfLoadFile;
|
|
2713
|
+
exports.createMirrorHandler = createMirrorHandler;
|
|
2714
|
+
exports.deleteMirrorHandler = deleteMirrorHandler;
|
|
2715
|
+
exports.evalMirrorMetadata = evalMirrorMetadata;
|
|
2716
|
+
exports.extractPrivateKey = extractPrivateKey;
|
|
2717
|
+
exports.generateFabricEventName = generateFabricEventName;
|
|
2718
|
+
exports.generateModelIndexes = generateModelIndexes;
|
|
2719
|
+
exports.getCAUser = getCAUser;
|
|
2720
|
+
exports.getFirstDirFileName = getFirstDirFileName;
|
|
2721
|
+
exports.getFirstDirFileNameContent = getFirstDirFileNameContent;
|
|
2722
|
+
exports.getIdentity = getIdentity;
|
|
2723
|
+
exports.getSigner = getSigner;
|
|
2724
|
+
exports.mirror = mirror;
|
|
2725
|
+
exports.ownedBy = ownedBy;
|
|
2726
|
+
exports.ownedByOnCreate = ownedByOnCreate;
|
|
2727
|
+
exports.parseEventName = parseEventName;
|
|
2728
|
+
exports.privateData = privateData;
|
|
2729
|
+
exports.readFile = readFile;
|
|
2730
|
+
exports.readModelFile = readModelFile;
|
|
2731
|
+
exports.readModelFolders = readModelFolders;
|
|
2732
|
+
exports.safeParseInt = safeParseInt;
|
|
2733
|
+
exports.segregatedDataOnCreate = segregatedDataOnCreate;
|
|
2734
|
+
exports.segregatedDataOnDelete = segregatedDataOnDelete;
|
|
2735
|
+
exports.segregatedDataOnRead = segregatedDataOnRead;
|
|
2736
|
+
exports.segregatedDataOnUpdate = segregatedDataOnUpdate;
|
|
2737
|
+
exports.sharedData = sharedData;
|
|
2738
|
+
exports.sub = sub;
|
|
2739
|
+
exports.transactionId = transactionId;
|
|
2740
|
+
exports.transactionIdOnCreate = transactionIdOnCreate;
|
|
2741
|
+
exports.updateMirrorHandler = updateMirrorHandler;
|
|
2742
|
+
exports.writeIndexes = writeIndexes;
|
|
2743
|
+
});
|
|
2744
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yLWZhYnJpYy5janMiLCJzb3VyY2VzIjpbIi4uL3NyYy9jbGllbnQvRmFicmljQ2xpZW50UmVwb3NpdG9yeS50cyIsIi4uL3NyYy9jb250cmFjdHMvZXJjMjAvbW9kZWxzLnRzIiwiLi4vc3JjL3NoYXJlZC9DbGllbnRTZXJpYWxpemVyLnRzIiwiLi4vc3JjL2NsaWVudC9lcmMyMC9GYWJyaWNFUkMyMENsaWVudFJlcG9zaXRvcnkudHMiLCIuLi9zcmMvY2xpZW50L2luZGV4ZXMvZ2VuZXJhdGlvbi50cyIsIi4uL3NyYy9zaGFyZWQvbW9kZWwvSWRlbnRpdHlDcmVkZW50aWFscy50cyIsIi4uL3NyYy9zaGFyZWQvY29uc3RhbnRzLnRzIiwiLi4vc3JjL3NoYXJlZC9tb2RlbC9JZGVudGl0eS50cyIsIi4uL3NyYy9jbGllbnQvdXRpbHMudHMiLCIuLi9zcmMvY2xpZW50L2NyeXB0by50cyIsIi4uL3NyYy9zaGFyZWQvZXJyb3JzLnRzIiwiLi4vc3JjL2NsaWVudC9zZXJ2aWNlcy9GYWJyaWNFbnJvbGxtZW50U2VydmljZS50cyIsIi4uL3NyYy9jbGllbnQvc2VydmljZXMvUmVnaXN0cmF0aW9uUmVxdWVzdEJ1aWxkZXIudHMiLCIuLi9zcmMvc2hhcmVkL2VyYzIwL2VyYzIwLWNvbnN0YW50cy50cyIsIi4uL3NyYy9zaGFyZWQvbW9kZWwvRmFicmljQmFzZU1vZGVsLnRzIiwiLi4vc3JjL3NoYXJlZC9tb2RlbC9GYWJyaWNJZGVudGlmaWVkQmFzZU1vZGVsLnRzIiwiLi4vc3JjL3NoYXJlZC9vdmVycmlkZXMvb3ZlcnJpZGVzLnRzIiwiLi4vc3JjL3NoYXJlZC9kZWNvcmF0b3JzLnRzIiwiLi4vc3JjL3NoYXJlZC9EZXRlcm1pbmlzdGljU2VyaWFsaXplci50cyIsIi4uL3NyYy9zaGFyZWQvZXZlbnRzLnRzIiwiLi4vc3JjL3NoYXJlZC9tYXRoLnRzIiwiLi4vc3JjL3NoYXJlZC9TaW1wbGVEZXRlcm1pbmlzdGljU2VyaWFsaXplci50cyIsIi4uL3NyYy9jbGllbnQvc2VydmljZXMvRmFicmljSWRlbnRpdHlTZXJ2aWNlLnRzIiwiLi4vc3JjL2NsaWVudC9jb25zdGFudHMudHMiLCIuLi9zcmMvY2xpZW50L2ZhYnJpYy1mcy50cyIsIi4uL3NyYy9jbGllbnQvZmFicmljLWhzbS50cyIsIi4uL3NyYy9jbGllbnQvRmFicmljQ2xpZW50U3RhdGVtZW50LnRzIiwiLi4vc3JjL2NsaWVudC9GYWJyaWNDbGllbnRQYWdpbmF0b3IudHMiLCIuLi9zcmMvY2xpZW50L0ZhYnJpY0NsaWVudEFkYXB0ZXIudHMiLCIuLi9zcmMvY2xpZW50L0ZhYnJpY0NsaWVudERpc3BhdGNoLnRzIiwiLi4vc3JjL3ZlcnNpb24udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgT3JkZXJEaXJlY3Rpb24sXG4gIFBlcnNpc3RlbmNlS2V5cyxcbiAgUmVwb3NpdG9yeSxcbiAgQ29udGV4dE9mLFxuICBQcmVwYXJlZFN0YXRlbWVudEtleXMsXG4gIFNlcmlhbGl6ZWRQYWdlLFxuICBEaXJlY3Rpb25MaW1pdE9mZnNldCxcbiAgUGFnaW5hdG9yLFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB0eXBlIHsgTWF5YmVDb250ZXh0dWFsQXJnIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBNb2RlbCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyB0eXBlIEZhYnJpY0NsaWVudEFkYXB0ZXIgfSBmcm9tIFwiLi9GYWJyaWNDbGllbnRBZGFwdGVyXCI7XG5pbXBvcnQge1xuICBPcGVyYXRpb25LZXlzLFxuICBQcmltYXJ5S2V5VHlwZSxcbiAgVmFsaWRhdGlvbkVycm9yLFxuICByZWR1Y2VFcnJvcnNUb1ByaW50LFxuICBlbmZvcmNlREJEZWNvcmF0b3JzLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IENvdWNoREJLZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXBvc2l0b3J5IGltcGxlbWVudGF0aW9uIGZvciBGYWJyaWMgY2xpZW50IG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IEV4dGVuZHMgdGhlIGdlbmVyaWMgUmVwb3NpdG9yeSB0byBwcmVwYXJlIGNvbnRleHQgYW5kIGFyZ3VtZW50cyBmb3IgQ1JVRCBvcGVyYXRpb25zIGV4ZWN1dGVkIHZpYSBhIEZhYnJpYyBjbGllbnQgQWRhcHRlciwgd2lyaW5nIFJlcG9zaXRvcnlGbGFncyBhbmQgRmFicmljLXNwZWNpZmljIG92ZXJyaWRlcy5cbiAqIEB0ZW1wbGF0ZSBNIGV4dGVuZHMgTW9kZWwgLSBUaGUgbW9kZWwgdHlwZSBoYW5kbGVkIGJ5IHRoaXMgcmVwb3NpdG9yeVxuICogQHBhcmFtIHtBZGFwdGVyPGFueSwgTWFuZ29RdWVyeSwgRmFicmljRmxhZ3MsIENvbnRleHQ8RmFicmljRmxhZ3M+Pn0gW2FkYXB0ZXJdIC0gT3B0aW9uYWwgYWRhcHRlciBpbnN0YW5jZSB1c2VkIHRvIGV4ZWN1dGUgb3BlcmF0aW9uc1xuICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gW2NsYXp6XSAtIE9wdGlvbmFsIG1vZGVsIGNvbnN0cnVjdG9yIHVzZWQgYnkgdGhlIHJlcG9zaXRvcnlcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgRmFicmljQ2xpZW50UmVwb3NpdG9yeVxuICogQGV4YW1wbGVcbiAqIGltcG9ydCB7IFJlcG9zaXRvcnkgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbiAqIGltcG9ydCB7IEZhYnJpY0NsaWVudFJlcG9zaXRvcnkgfSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1mYWJyaWNcIjtcbiAqXG4gKiBjbGFzcyBVc2VyIGV4dGVuZHMgTW9kZWwgeyBpZCE6IHN0cmluZzsgbmFtZSE6IHN0cmluZzsgfVxuICogY29uc3QgcmVwbyA9IG5ldyBGYWJyaWNDbGllbnRSZXBvc2l0b3J5PFVzZXI+KCk7XG4gKiBjb25zdCBjcmVhdGVkID0gYXdhaXQgcmVwby5jcmVhdGUobmV3IFVzZXIoeyBpZDogXCIxXCIsIG5hbWU6IFwiQWxpY2VcIiB9KSk7XG4gKiBjb25zdCBsb2FkZWQgPSBhd2FpdCByZXBvLnJlYWQoXCIxXCIpO1xuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQXBwXG4gKiAgIHBhcnRpY2lwYW50IFJlcG8gYXMgRmFicmljQ2xpZW50UmVwb3NpdG9yeVxuICogICBwYXJ0aWNpcGFudCBBZGFwdGVyXG4gKiAgIEFwcC0+PlJlcG86IGNyZWF0ZShtb2RlbClcbiAqICAgUmVwby0+PlJlcG86IGNyZWF0ZVByZWZpeChtb2RlbCwgLi4uYXJncylcbiAqICAgUmVwby0+PkFkYXB0ZXI6IGNyZWF0ZSh0YWJsZSwgaWQsIG1vZGVsLCBmbGFncylcbiAqICAgQWRhcHRlci0tPj5SZXBvOiByZXN1bHRcbiAqICAgUmVwby0tPj5BcHA6IG1vZGVsXG4gKi9cbmV4cG9ydCBjbGFzcyBGYWJyaWNDbGllbnRSZXBvc2l0b3J5PFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIEEgZXh0ZW5kcyBGYWJyaWNDbGllbnRBZGFwdGVyID0gRmFicmljQ2xpZW50QWRhcHRlcixcbj4gZXh0ZW5kcyBSZXBvc2l0b3J5PE0sIEE+IHtcbiAgcHJvdGVjdGVkIG92ZXJyaWRlIF9vdmVycmlkZXMgPSBPYmplY3QuYXNzaWduKHt9LCBzdXBlcltcIl9vdmVycmlkZXNcIl0sIHtcbiAgICBpZ25vcmVWYWxpZGF0aW9uOiB0cnVlLFxuICAgIGlnbm9yZUhhbmRsZXJzOiB0cnVlLFxuICAgIGFsbG93UmF3U3RhdGVtZW50czogZmFsc2UsXG4gICAgZm9yY2VQcmVwYXJlU2ltcGxlUXVlcmllczogdHJ1ZSxcbiAgICBmb3JjZVByZXBhcmVDb21wbGV4UXVlcmllczogdHJ1ZSxcbiAgICBhbGxvd0dlbmVyYXRpb25PdmVycmlkZTogZmFsc2UsXG4gIH0pO1xuXG4gIGNvbnN0cnVjdG9yKGFkYXB0ZXI/OiBBLCBjbGF6ej86IENvbnN0cnVjdG9yPE0+KSB7XG4gICAgc3VwZXIoYWRhcHRlciwgY2xhenopO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgcGFnaW5hdGVCeShcbiAgICBrZXk6IGtleW9mIE0sXG4gICAgb3JkZXI6IE9yZGVyRGlyZWN0aW9uLFxuICAgIHJlZjogT21pdDxEaXJlY3Rpb25MaW1pdE9mZnNldCwgXCJkaXJlY3Rpb25cIj4gPSB7XG4gICAgICBvZmZzZXQ6IDEsXG4gICAgICBsaW1pdDogMTAsXG4gICAgfSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPFNlcmlhbGl6ZWRQYWdlPE0+PiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IChcbiAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFByZXBhcmVkU3RhdGVtZW50S2V5cy5QQUdFX0JZLCB0cnVlKVxuICAgICkuZm9yKHRoaXMucGFnaW5hdGVCeSk7XG4gICAgbG9nLnZlcmJvc2UoXG4gICAgICBgcGFnaW5hdGluZyAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX0gd2l0aCBwYWdlIHNpemUgJHtyZWYubGltaXR9YFxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGVtZW50KFxuICAgICAgdGhpcy5wYWdpbmF0ZUJ5Lm5hbWUsXG4gICAgICBrZXksXG4gICAgICBvcmRlcixcbiAgICAgIHsgbGltaXQ6IHJlZi5saW1pdCwgb2Zmc2V0OiByZWYub2Zmc2V0LCBib29rbWFyazogcmVmLmJvb2ttYXJrIH0sXG4gICAgICAuLi5jdHhBcmdzXG4gICAgKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGxpc3RCeShcbiAgICBrZXk6IGtleW9mIE0sXG4gICAgb3JkZXI6IE9yZGVyRGlyZWN0aW9uLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICkge1xuICAgIGNvbnN0IHsgbG9nLCBjdHhBcmdzIH0gPSAoXG4gICAgICBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBQcmVwYXJlZFN0YXRlbWVudEtleXMuTElTVF9CWSwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLmxpc3RCeSk7XG4gICAgbG9nLnZlcmJvc2UoXG4gICAgICBgbGlzdGluZyAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX0gYnkgJHtrZXkgYXMgc3RyaW5nfSAke29yZGVyfWBcbiAgICApO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5zdGF0ZW1lbnQoXG4gICAgICB0aGlzLmxpc3RCeS5uYW1lLFxuICAgICAga2V5LFxuICAgICAgb3JkZXIsXG4gICAgICAuLi5jdHhBcmdzXG4gICAgKSkgYXMgYW55O1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgZmluZEJ5KFxuICAgIGtleToga2V5b2YgTSxcbiAgICB2YWx1ZTogYW55LFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8TVtdPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IChcbiAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZLCB0cnVlKVxuICAgICkuZm9yKHRoaXMuZmluZEJ5KTtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBmaW5kaW5nIGFsbCAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX0gd2l0aCAke2tleSBhcyBzdHJpbmd9ICR7dmFsdWV9YFxuICAgICk7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLnN0YXRlbWVudChcbiAgICAgIHRoaXMuZmluZEJ5Lm5hbWUsXG4gICAgICBrZXksXG4gICAgICB2YWx1ZSxcbiAgICAgIC4uLmN0eEFyZ3NcbiAgICApKSBhcyBhbnk7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBmaW5kT25lQnkoXG4gICAga2V5OiBrZXlvZiBNLFxuICAgIHZhbHVlOiBhbnksXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj5cbiAgKTogUHJvbWlzZTxNPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IChcbiAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX09ORV9CWSwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLmZpbmRPbmVCeSk7XG4gICAgbG9nLnZlcmJvc2UoXG4gICAgICBgZmluZGluZyBPbmUgJHtNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcyl9IHdpdGggJHtrZXkgYXMgc3RyaW5nfSAke3ZhbHVlfWBcbiAgICApO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5zdGF0ZW1lbnQoXG4gICAgICB0aGlzLmZpbmRPbmVCeS5uYW1lLFxuICAgICAga2V5LFxuICAgICAgdmFsdWUsXG4gICAgICAuLi5jdHhBcmdzXG4gICAgKSkgYXMgYW55O1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgc3RhdGVtZW50KFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHgsIGN0eEFyZ3MgfSA9IChcbiAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFBlcnNpc3RlbmNlS2V5cy5TVEFURU1FTlQsIHRydWUpXG4gICAgKS5mb3IodGhpcy5zdGF0ZW1lbnQpO1xuICAgIGxvZy52ZXJib3NlKGBFeGVjdXRpbmcgcHJlcGFyZWQgc3RhdGVtZW50ICR7bmFtZX1gKTtcbiAgICBjb25zdCBjYWxsQXJncyA9IGN0eEFyZ3Muc2xpY2UoMCwgLTEpO1xuICAgIGNvbnN0IHJlc3VsdCA9IEpTT04ucGFyc2UoXG4gICAgICB0aGlzLmFkYXB0ZXIuZGVjb2RlKFxuICAgICAgICBhd2FpdCB0aGlzLmFkYXB0ZXIuZXZhbHVhdGVUcmFuc2FjdGlvbihcbiAgICAgICAgICBjdHgsXG4gICAgICAgICAgUGVyc2lzdGVuY2VLZXlzLlNUQVRFTUVOVCxcbiAgICAgICAgICBbbmFtZSwgSlNPTi5zdHJpbmdpZnkoY2FsbEFyZ3MpXSxcbiAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgIHRoaXMuY2xhc3MubmFtZVxuICAgICAgICApXG4gICAgICApXG4gICAgKTtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KHJlc3VsdCkpIHtcbiAgICAgIHJldHVybiByZXN1bHQubWFwKChyOiBhbnkpID0+XG4gICAgICAgIChyIGFzIGFueSlbQ291Y2hEQktleXMuVEFCTEVdICYmXG4gICAgICAgIChyIGFzIGFueSlbQ291Y2hEQktleXMuVEFCTEVdID09PSBNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcylcbiAgICAgICAgICA/IG5ldyB0aGlzLmNsYXNzKHIpXG4gICAgICAgICAgOiByXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gKHJlc3VsdCBhcyBhbnkpW0NvdWNoREJLZXlzLlRBQkxFXSAmJlxuICAgICAgKHJlc3VsdCBhcyBhbnkpW0NvdWNoREJLZXlzLlRBQkxFXSA9PT0gTW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpXG4gICAgICA/IG5ldyB0aGlzLmNsYXNzKHJlc3VsdClcbiAgICAgIDogUGFnaW5hdG9yLmlzU2VyaWFsaXplZFBhZ2UocmVzdWx0KVxuICAgICAgICA/IE9iamVjdC5hc3NpZ24ocmVzdWx0LCB7XG4gICAgICAgICAgICBkYXRhOiByZXN1bHQuZGF0YS5tYXAoKGQ6IGFueSkgPT4gbmV3IHRoaXMuY2xhc3MoZCkpLFxuICAgICAgICAgIH0pXG4gICAgICAgIDogcmVzdWx0O1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlKFxuICAgIG1vZGVsOiBNLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8TT4ge1xuICAgIGNvbnN0IHsgY3R4LCBsb2csIGN0eEFyZ3MgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuY3JlYXRlKTtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgQ3JlYXRpbmcgbmV3ICR7dGhpcy5jbGFzcy5uYW1lfSBpbiB0YWJsZSAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX1gXG4gICAgKTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcHJlZmVyLWNvbnN0XG4gICAgbGV0IHsgcmVjb3JkLCBpZCwgdHJhbnNpZW50IH0gPSB0aGlzLmFkYXB0ZXIucHJlcGFyZShtb2RlbCwgY3R4KTtcbiAgICByZWNvcmQgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuY3JlYXRlKFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIGlkLFxuICAgICAgcmVjb3JkLFxuICAgICAgdHJhbnNpZW50LFxuICAgICAgLi4uY3R4QXJnc1xuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuYWRhcHRlci5yZXZlcnQ8TT4ocmVjb3JkLCB0aGlzLmNsYXNzLCBpZCwgdHJhbnNpZW50LCBjdHgpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgdXBkYXRlKFxuICAgIG1vZGVsOiBNLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8TT4ge1xuICAgIGNvbnN0IHsgY3R4QXJncywgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMudXBkYXRlKTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcHJlZmVyLWNvbnN0XG4gICAgbGV0IHsgcmVjb3JkLCBpZCwgdHJhbnNpZW50IH0gPSB0aGlzLmFkYXB0ZXIucHJlcGFyZShtb2RlbCwgY3R4KTtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgdXBkYXRpbmcgJHt0aGlzLmNsYXNzLm5hbWV9IGluIHRhYmxlICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfSB3aXRoIGlkICR7aWR9YFxuICAgICk7XG4gICAgcmVjb3JkID0gYXdhaXQgdGhpcy5hZGFwdGVyLnVwZGF0ZShcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBpZCxcbiAgICAgIHJlY29yZCxcbiAgICAgIHRyYW5zaWVudCxcbiAgICAgIC4uLmN0eEFyZ3NcbiAgICApO1xuICAgIHJldHVybiB0aGlzLmFkYXB0ZXIucmV2ZXJ0PE0+KHJlY29yZCwgdGhpcy5jbGFzcywgaWQsIHRyYW5zaWVudCwgY3R4KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvdmVycmlkZSBhc3luYyBjcmVhdGVBbGxQcmVmaXgoXG4gICAgbW9kZWxzOiBNW10sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj5cbiAgKTogUHJvbWlzZTxbTVtdLCAuLi5hbnlbXSwgQ29udGV4dE9mPEE+XT4ge1xuICAgIGNvbnN0IHsgY3R4LCBjdHhBcmdzIH0gPSAoXG4gICAgICBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBPcGVyYXRpb25LZXlzLkNSRUFURSwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLmNyZWF0ZUFsbFByZWZpeCk7XG4gICAgY29uc3QgaWdub3JlSGFuZGxlcnMgPSBjdHguZ2V0KFwiaWdub3JlSGFuZGxlcnNcIik7XG4gICAgY29uc3QgaWdub3JlVmFsaWRhdGUgPSBjdHguZ2V0KFwiaWdub3JlVmFsaWRhdGlvblwiKTtcbiAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHJldHVybiBbbW9kZWxzLCAuLi5jdHhBcmdzXSBhcyBhbnk7XG5cbiAgICBtb2RlbHMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIG1vZGVscy5tYXAoYXN5bmMgKG0pID0+IHtcbiAgICAgICAgbSA9IG5ldyB0aGlzLmNsYXNzKG0pO1xuICAgICAgICBpZiAoIWlnbm9yZUhhbmRsZXJzKVxuICAgICAgICAgIGF3YWl0IGVuZm9yY2VEQkRlY29yYXRvcnM8TSwgUmVwb3NpdG9yeTxNLCBBPiwgYW55PihcbiAgICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgICBjdHgsXG4gICAgICAgICAgICBtLFxuICAgICAgICAgICAgT3BlcmF0aW9uS2V5cy5DUkVBVEUsXG4gICAgICAgICAgICBPcGVyYXRpb25LZXlzLk9OXG4gICAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgICB9KVxuICAgICk7XG5cbiAgICBpZiAoIWlnbm9yZVZhbGlkYXRlKSB7XG4gICAgICBjb25zdCBpZ25vcmVkUHJvcHMgPSBjdHguZ2V0KFwiaWdub3JlZFZhbGlkYXRpb25Qcm9wZXJ0aWVzXCIpIHx8IFtdO1xuXG4gICAgICBjb25zdCBlcnJvcnMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgbW9kZWxzLm1hcCgobSkgPT4gUHJvbWlzZS5yZXNvbHZlKG0uaGFzRXJyb3JzKC4uLmlnbm9yZWRQcm9wcykpKVxuICAgICAgKTtcblxuICAgICAgY29uc3QgZXJyb3JNZXNzYWdlcyA9IHJlZHVjZUVycm9yc1RvUHJpbnQoZXJyb3JzKTtcblxuICAgICAgaWYgKGVycm9yTWVzc2FnZXMpIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoZXJyb3JNZXNzYWdlcyk7XG4gICAgfVxuICAgIHJldHVybiBbbW9kZWxzLCAuLi5jdHhBcmdzXSBhcyBhbnk7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBjcmVhdGVBbGwoXG4gICAgbW9kZWxzOiBNW10sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj5cbiAgKTogUHJvbWlzZTxNW10+IHtcbiAgICBpZiAoIW1vZGVscy5sZW5ndGgpIHJldHVybiBtb2RlbHM7XG4gICAgY29uc3QgeyBjdHgsIGxvZywgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5jcmVhdGVBbGwpO1xuICAgIGxvZy5kZWJ1ZyhcbiAgICAgIGBDcmVhdGluZyAke21vZGVscy5sZW5ndGh9IG5ldyAke3RoaXMuY2xhc3MubmFtZX0gaW4gdGFibGUgJHtNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcyl9YFxuICAgICk7XG5cbiAgICBjb25zdCBwcmVwYXJlZCA9IG1vZGVscy5tYXAoKG0pID0+IHRoaXMuYWRhcHRlci5wcmVwYXJlKG0sIGN0eCkpO1xuICAgIGNvbnN0IGlkcyA9IHByZXBhcmVkLm1hcCgocCkgPT4gcC5pZCk7XG4gICAgbGV0IHJlY29yZHMgPSBwcmVwYXJlZC5tYXAoKHApID0+IHAucmVjb3JkKTtcbiAgICBjb25zdCB0cmFuc2llbnQgPSBwcmVwYXJlZC5tYXAoKHApID0+IHAudHJhbnNpZW50KTtcbiAgICByZWNvcmRzID0gYXdhaXQgdGhpcy5hZGFwdGVyLmNyZWF0ZUFsbChcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBpZHMgYXMgUHJpbWFyeUtleVR5cGVbXSxcbiAgICAgIHJlY29yZHMsXG4gICAgICB0cmFuc2llbnQsXG4gICAgICAuLi5jdHhBcmdzXG4gICAgKTtcbiAgICByZXR1cm4gcmVjb3Jkcy5tYXAoKHIsIGkpID0+XG4gICAgICB0aGlzLmFkYXB0ZXIucmV2ZXJ0KFxuICAgICAgICByLFxuICAgICAgICB0aGlzLmNsYXNzLFxuICAgICAgICBpZHNbaV0sXG4gICAgICAgIGN0eC5nZXQoXCJyZWJ1aWxkV2l0aFRyYW5zaWVudFwiKSA/IHByZXBhcmVkW2ldLnRyYW5zaWVudCA6IHVuZGVmaW5lZCxcbiAgICAgICAgY3R4XG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIHVwZGF0ZUFsbChcbiAgICBtb2RlbHM6IE1bXSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPE1bXT4ge1xuICAgIGNvbnN0IHsgY3R4LCBsb2csIGN0eEFyZ3MgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMudXBkYXRlQWxsKTtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgVXBkYXRpbmcgJHttb2RlbHMubGVuZ3RofSBuZXcgJHt0aGlzLmNsYXNzLm5hbWV9IGluIHRhYmxlICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfWBcbiAgICApO1xuXG4gICAgY29uc3QgcmVjb3JkcyA9IG1vZGVscy5tYXAoKG0pID0+IHRoaXMuYWRhcHRlci5wcmVwYXJlKG0sIGN0eCkpO1xuICAgIGNvbnN0IHVwZGF0ZWQgPSBhd2FpdCB0aGlzLmFkYXB0ZXIudXBkYXRlQWxsKFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIHJlY29yZHMubWFwKChyKSA9PiByLmlkKSxcbiAgICAgIHJlY29yZHMubWFwKChyKSA9PiByLnJlY29yZCksXG4gICAgICByZWNvcmRzLm1hcCgocikgPT4gci50cmFuc2llbnQpLFxuICAgICAgLi4uY3R4QXJnc1xuICAgICk7XG4gICAgcmV0dXJuIHVwZGF0ZWQubWFwKCh1LCBpKSA9PlxuICAgICAgdGhpcy5hZGFwdGVyLnJldmVydChcbiAgICAgICAgdSxcbiAgICAgICAgdGhpcy5jbGFzcyxcbiAgICAgICAgcmVjb3Jkc1tpXS5pZCxcbiAgICAgICAgY3R4LmdldChcInJlYnVpbGRXaXRoVHJhbnNpZW50XCIpID8gcmVjb3Jkc1tpXS50cmFuc2llbnQgOiB1bmRlZmluZWQsXG4gICAgICAgIGN0eFxuICAgICAgKVxuICAgICk7XG4gIH1cbn1cbiIsImltcG9ydCB7IEJhc2VNb2RlbCwgY29sdW1uLCBwaywgdGFibGUgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IG1vZGVsLCB0eXBlIE1vZGVsQXJnLCByZXF1aXJlZCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRVJDMjAgdG9rZW4gbWV0YWRhdGEgbW9kZWxcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYW4gRVJDMjAgdG9rZW4gZGVmaW5pdGlvbiB3aXRoaW4gdGhlIEZhYnJpYyBFUkMyMCBzYW1wbGUsIGluY2x1ZGluZyBuYW1lLCBzeW1ib2wsIGRlY2ltYWxzLCBhbmQgdGhlIG93bmluZyBpZGVudGl0eS4gVXNlZCB0byBkZWZpbmUgdGhlIHVuaXF1ZSB0b2tlbiBtYW5hZ2VkIGJ5IHRoZSBjb250cmFjdC5cbiAqIEBwYXJhbSB7TW9kZWxBcmc8RVJDMjBUb2tlbj59IFttXSAtIE9wdGlvbmFsIHBhcnRpYWwgZGF0YSBvciBhbm90aGVyIGluc3RhbmNlIHRvIGluaXRpYWxpemUgdGhlIG1vZGVsXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGNsYXNzIEVSQzIwVG9rZW5cbiAqIEBleGFtcGxlXG4gKiBjb25zdCB0b2tlbiA9IG5ldyBFUkMyMFRva2VuKHsgbmFtZTogXCJNeVRva2VuXCIsIHN5bWJvbDogXCJNVEtcIiwgZGVjaW1hbHM6IDE4LCBvd25lcjogXCJ4NTA5OjouLi5cIiB9KTtcbiAqIC8vIFBlcnNpc3QgdGhyb3VnaCBhIHJlcG9zaXRvcnk6IGF3YWl0IHJlcG8uY3JlYXRlKHRva2VuLCBjdHgpXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBSZXBvXG4gKiAgIHBhcnRpY2lwYW50IEFkYXB0ZXJcbiAqICAgQXBwLT4+UmVwbzogY3JlYXRlKG5ldyBFUkMyMFRva2VuKHsuLi59KSwgY3R4KVxuICogICBSZXBvLT4+QWRhcHRlcjogY3JlYXRlKHRhYmxlLCBpZD1uYW1lLCByZWNvcmQsIGZsYWdzKVxuICogICBBZGFwdGVyLS0+PlJlcG86IHN0b3JlZFxuICogICBSZXBvLS0+PkFwcDogbW9kZWxcbiAqL1xuQHRhYmxlKFwiZXJjMjBfdG9rZW5zXCIpXG5AbW9kZWwoKVxuZXhwb3J0IGNsYXNzIEVSQzIwVG9rZW4gZXh0ZW5kcyBCYXNlTW9kZWwge1xuICBAcGsoeyB0eXBlOiBTdHJpbmcgfSlcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUb2tlbiB1bmlxdWUgbmFtZVxuICAgKiBAc3VtbWFyeSBTZXJ2ZXMgYXMgdGhlIHByaW1hcnkga2V5IGZvciB0aGUgRVJDMjAgdG9rZW4gZGVmaW5pdGlvbjsgdHlwaWNhbGx5IGEgaHVtYW4tcmVhZGFibGUgaWRlbnRpZmllclxuICAgKi9cbiAgbmFtZSE6IHN0cmluZztcblxuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBPd25pbmcgaWRlbnRpdHkgb2YgdGhlIHRva2VuXG4gICAqIEBzdW1tYXJ5IFguNTA5IHN1YmplY3Qgb3IgTVNQIGlkZW50aXR5IHN0cmluZyB0aGF0IGRlbm90ZXMgd2hvIG93bnMvY29udHJvbHMgdGhlIHRva2VuIGRlZmluaXRpb25cbiAgICovXG4gIG93bmVyITogc3RyaW5nO1xuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUb2tlbiBzeW1ib2xcbiAgICogQHN1bW1hcnkgU2hvcnQgdGlja2VyLWxpa2Ugc3ltYm9sIHVzZWQgdG8gcmVwcmVzZW50IHRoZSB0b2tlbiAoZS5nLiwgTVRLKVxuICAgKi9cbiAgc3ltYm9sITogc3RyaW5nO1xuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBEZWNpbWFsIHByZWNpc2lvbiBmb3IgdG9rZW4gYW1vdW50c1xuICAgKiBAc3VtbWFyeSBOdW1iZXIgb2YgZGlnaXRzIGFmdGVyIHRoZSBkZWNpbWFsIHNlcGFyYXRvciB1c2VkIHdoZW4gZm9ybWF0dGluZyB0b2tlbiBiYWxhbmNlc1xuICAgKi9cbiAgZGVjaW1hbHMhOiBudW1iZXI7XG5cbiAgY29uc3RydWN0b3IobT86IE1vZGVsQXJnPEVSQzIwV2FsbGV0Pikge1xuICAgIHN1cGVyKG0pO1xuICB9XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVSQzIwIHdhbGxldCBtb2RlbFxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBhIGhvbGRlciBhY2NvdW50IGZvciBhbiBFUkMyMCB0b2tlbiB3aXRoaW4gdGhlIEZhYnJpYyBuZXR3b3JrLCB0cmFja2luZyBiYWxhbmNlIGFuZCB0b2tlbiBhc3NvY2lhdGlvbi5cbiAqIEBwYXJhbSB7TW9kZWxBcmc8RVJDMjBXYWxsZXQ+fSBbbV0gLSBPcHRpb25hbCBwYXJ0aWFsIGRhdGEgb3IgYW5vdGhlciBpbnN0YW5jZSB0byBpbml0aWFsaXplIHRoZSBtb2RlbFxuICogQHJldHVybiB7dm9pZH1cbiAqIEBjbGFzcyBFUkMyMFdhbGxldFxuICogQGV4YW1wbGVcbiAqIGNvbnN0IHdhbGxldCA9IG5ldyBFUkMyMFdhbGxldCh7IGlkOiBcImFjY3QxXCIsIHRva2VuOiBcIk15VG9rZW5cIiwgYmFsYW5jZTogMTAwMCB9KTtcbiAqIC8vIFVwZGF0ZSBiYWxhbmNlIHZpYSByZXBvc2l0b3J5OiBhd2FpdCByZXBvLnVwZGF0ZSh3YWxsZXQsIGN0eClcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQXBwXG4gKiAgIHBhcnRpY2lwYW50IFJlcG9cbiAqICAgQXBwLT4+UmVwbzogcmVhZChcImFjY3QxXCIsIGN0eClcbiAqICAgUmVwby0tPj5BcHA6IEVSQzIwV2FsbGV0XG4gKi9cbkB0YWJsZShcImVyYzIwX3dhbGxldHNcIilcbkBtb2RlbCgpXG5leHBvcnQgY2xhc3MgRVJDMjBXYWxsZXQgZXh0ZW5kcyBCYXNlTW9kZWwge1xuICBAcGsoeyB0eXBlOiBTdHJpbmcgfSlcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBXYWxsZXQgdW5pcXVlIGlkZW50aWZpZXJcbiAgICogQHN1bW1hcnkgUHJpbWFyeSBrZXkgZm9yIHRoZSB3YWxsZXQ7IGNvbW1vbmx5IHJlZmVyZW5jZXMgYW4gYWNjb3VudCBvciBpZGVudGl0eVxuICAgKi9cbiAgaWQhOiBzdHJpbmc7XG5cbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQXNzb2NpYXRlZCB0b2tlbiBuYW1lXG4gICAqIEBzdW1tYXJ5IFJlZmVyZW5jZXMgdGhlIEVSQzIwVG9rZW4gdGhpcyB3YWxsZXQgaG9sZHM7IG1haW50YWluZWQgYXMgYSByZWxhdGlvbnNoaXAgZm9yIGNhc2NhZGluZyB1cGRhdGVzL2RlbGV0ZXNcbiAgICovXG4gIHRva2VuITogc3RyaW5nO1xuXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRva2VuIGJhbGFuY2UgZm9yIHRoaXMgd2FsbGV0XG4gICAqIEBzdW1tYXJ5IEN1cnJlbnQgYW1vdW50IG9mIHRoZSBhc3NvY2lhdGVkIHRva2VuIGhlbGQgYnkgdGhpcyB3YWxsZXRcbiAgICovXG4gIGJhbGFuY2UhOiBudW1iZXI7XG5cbiAgQGNvbHVtbigpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ2FwdGl2ZSBmbGFnIG9yIGlkZW50aWZpZXJcbiAgICogQHN1bW1hcnkgT3B0aW9uYWwgZmllbGQgdXNlZCBieSBzb21lIGZsb3dzIHRvIG1hcmsgbm9uLXRyYW5zZmVyYWJsZSBmdW5kcyBvciBtYW5hZ2VkIGN1c3RvZHlcbiAgICovXG4gIGNhcHRpdmUhOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IobT86IE1vZGVsQXJnPEVSQzIwV2FsbGV0Pikge1xuICAgIHN1cGVyKG0pO1xuICB9XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVSQzIwIGFsbG93YW5jZSBtb2RlbFxuICogQHN1bW1hcnkgQ2FwdHVyZXMgYW4gYXBwcm92YWwgcmVsYXRpb25zaGlwIHdoZXJlIGFuIG93bmVyIGFsbG93cyBhIHNwZW5kZXIgdG8gdHJhbnNmZXIgdXAgdG8gYSBjZXJ0YWluIHZhbHVlIGZyb20gdGhlIG93bmVyJ3Mgd2FsbGV0LlxuICogQHBhcmFtIHtNb2RlbEFyZzxBbGxvd2FuY2U+fSBbbV0gLSBPcHRpb25hbCBwYXJ0aWFsIGRhdGEgb3IgYW5vdGhlciBpbnN0YW5jZSB0byBpbml0aWFsaXplIHRoZSBtb2RlbFxuICogQHJldHVybiB7dm9pZH1cbiAqIEBjbGFzcyBBbGxvd2FuY2VcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBhbGxvd2FuY2UgPSBuZXcgQWxsb3dhbmNlKHsgb3duZXI6IFwiYWNjdDFcIiwgc3BlbmRlcjogXCJhY2N0MlwiLCB2YWx1ZTogNTAgfSk7XG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBBcHAtPj5BcHA6IG5ldyBBbGxvd2FuY2UoeyBvd25lciwgc3BlbmRlciwgdmFsdWUgfSlcbiAqL1xuQHRhYmxlKFwiZXJjMjBfYWxsb3dhbmNlc1wiKVxuQG1vZGVsKClcbmV4cG9ydCBjbGFzcyBBbGxvd2FuY2UgZXh0ZW5kcyBCYXNlTW9kZWwge1xuICBAcGsoeyB0eXBlOiBTdHJpbmcgfSlcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBbGxvd2FuY2UgdW5pcXVlIGlkZW50aWZpZXJcbiAgICogQHN1bW1hcnkgUHJpbWFyeSBrZXkgZm9yIHRoZSBhbGxvd2FuY2U7IHR5cGljYWxseSBhIHVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgYXBwcm92YWwgcmVsYXRpb25zaGlwXG4gICAqL1xuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBPd25lciB3YWxsZXQgaWRlbnRpZmllclxuICAgKiBAc3VtbWFyeSBXYWxsZXQgdGhhdCBhdXRob3JpemVzIHRoZSBhbGxvd2FuY2VcbiAgICovXG4gIG93bmVyITogc3RyaW5nO1xuXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNwZW5kZXIgd2FsbGV0IGlkZW50aWZpZXJcbiAgICogQHN1bW1hcnkgV2FsbGV0IGFsbG93ZWQgdG8gc3BlbmQgdXAgdG8gdGhlIGFwcHJvdmVkIHZhbHVlIGZyb20gdGhlIG93bmVyXG4gICAqL1xuICBzcGVuZGVyITogc3RyaW5nO1xuXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFwcHJvdmVkIHZhbHVlXG4gICAqIEBzdW1tYXJ5IE1heGltdW0gdG9rZW4gYW1vdW50IHRoZSBzcGVuZGVyIG1heSB0cmFuc2ZlciBvbiBiZWhhbGYgb2YgdGhlIG93bmVyXG4gICAqL1xuICB2YWx1ZSE6IG51bWJlcjtcblxuICBjb25zdHJ1Y3RvcihtPzogTW9kZWxBcmc8QWxsb3dhbmNlPikge1xuICAgIHN1cGVyKG0pO1xuICB9XG59XG4iLCJpbXBvcnQge1xuICBKU09OU2VyaWFsaXplcixcbiAgTW9kZWwsXG4gIE1vZGVsS2V5cyxcbn0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgU2VyaWFsaXphdGlvbkVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ2xpZW50LXNpZGUgSlNPTiBzZXJpYWxpemVyIGZvciBEZWNhZiBtb2RlbHMgdGFyZ2V0aW5nIEh5cGVybGVkZ2VyIEZhYnJpY1xuICogQHN1bW1hcnkgRXh0ZW5kcyB0aGUgYmFzZSBKU09OU2VyaWFsaXplciB0byBlbWJlZCBtb2RlbCBtZXRhZGF0YSAoYW5jaG9yKSByZXF1aXJlZCB0byByZWNvbnN0cnVjdCBpbnN0YW5jZXMgb24gdGhlIGNsaWVudCwgYW5kIHRvIHNhZmVseSBzZXJpYWxpemUvZGVzZXJpYWxpemUgRmFicmljLWJvdW5kIG1vZGVscy5cbiAqIEB0ZW1wbGF0ZSBNIGV4dGVuZHMgTW9kZWwgLSBUaGUgRGVjYWYgbW9kZWwgdHlwZSBoYW5kbGVkIGJ5IHRoaXMgc2VyaWFsaXplclxuICogQHBhcmFtIHt2b2lkfSBbY29uc3RydWN0b3JdIE5vIHB1YmxpYyBjb25zdHJ1Y3RvciBhcmd1bWVudHM7IHByb3ZpZGVkIGZvciBkb2N1bWVudGF0aW9uIGNvbXBsZXRlbmVzc1xuICogQHJldHVybiB7dm9pZH1cbiAqIEBjbGFzcyBDbGllbnRTZXJpYWxpemVyXG4gKiBAZXhhbXBsZVxuICogY29uc3Qgc2VyaWFsaXplciA9IG5ldyBDbGllbnRTZXJpYWxpemVyPFVzZXI+KCk7XG4gKiBjb25zdCBqc29uID0gc2VyaWFsaXplci5zZXJpYWxpemUobmV3IFVzZXIoeyBpZDogXCIxXCIsIG5hbWU6IFwiQWxpY2VcIiB9KSk7XG4gKiBjb25zdCB1c2VyID0gc2VyaWFsaXplci5kZXNlcmlhbGl6ZShqc29uKTtcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQXBwXG4gKiAgIHBhcnRpY2lwYW50IFNlcmlhbGl6ZXIgYXMgQ2xpZW50U2VyaWFsaXplclxuICogICBwYXJ0aWNpcGFudCBNb2RlbFxuICogICBBcHAtPj5TZXJpYWxpemVyOiBzZXJpYWxpemUobW9kZWwpXG4gKiAgIFNlcmlhbGl6ZXItPj5TZXJpYWxpemVyOiBwcmVTZXJpYWxpemUobW9kZWwpXG4gKiAgIFNlcmlhbGl6ZXItLT4+QXBwOiBKU09OIHN0cmluZ1xuICogICBBcHAtPj5TZXJpYWxpemVyOiBkZXNlcmlhbGl6ZShqc29uKVxuICogICBTZXJpYWxpemVyLT4+U2VyaWFsaXplcjogSlNPTi5wYXJzZShqc29uKVxuICogICBTZXJpYWxpemVyLT4+TW9kZWw6IE1vZGVsLmJ1aWxkKHBhcnNlZCwgYW5jaG9yKVxuICogICBNb2RlbC0tPj5BcHA6IGluc3RhbmNlXG4gKi9cbmV4cG9ydCBjbGFzcyBDbGllbnRTZXJpYWxpemVyPE0gZXh0ZW5kcyBNb2RlbD4gZXh0ZW5kcyBKU09OU2VyaWFsaXplcjxNPiB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcmVwYXJlIGEgbW9kZWwgZm9yIEpTT04gc2VyaWFsaXphdGlvbiBlbWJlZGRpbmcgY2xhc3MgYW5jaG9yXG4gICAqIEBzdW1tYXJ5IENsb25lcyB0aGUgbW9kZWwgYW5kIGluamVjdHMgdGhlIGNsYXNzIG1ldGFkYXRhIGFuY2hvciBzbyBpdCBjYW4gYmUgcmVjb25zdHJ1Y3RlZCBkdXJpbmcgZGVzZXJpYWxpemF0aW9uLiBGYWxscyBiYWNrIHRvIHByb3ZpZGVkIHRhYmxlIG5hbWUgaWYgbWV0YWRhdGEgaXMgbm90IGF2YWlsYWJsZS5cbiAgICogQHRlbXBsYXRlIE0gLSBNb2RlbCB0eXBlIGhhbmRsZWQgYnkgdGhpcyBzZXJpYWxpemVyXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgdG8gc2VyaWFsaXplXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbbW9kZWxOYW1lXSAtIE9wdGlvbmFsIHRhYmxlIG5hbWUgdG8gdXNlIHdoZW4gbWV0YWRhdGEgY2Fubm90IGJlIGRlcml2ZWRcbiAgICogQHJldHVybiB7UmVjb3JkPHN0cmluZywgYW55Pn0gQSBwbGFpbiBvYmplY3QgcmVhZHkgdG8gYmUgSlNPTi5zdHJpbmdpZnknZFxuICAgKi9cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHByZVNlcmlhbGl6ZShtb2RlbDogTSwgbW9kZWxOYW1lPzogc3RyaW5nKSB7XG4gICAgLy8gVE9ETzogbmVzdGVkIHByZXNlcmlhbGl6YXRpb24gKHNvIGluY3JlYXNlIHBlcmZvcm1hbmNlIHdoZW4gZGVzZXJpYWxpemluZylcbiAgICBjb25zdCB0b1NlcmlhbGl6ZTogUmVjb3JkPHN0cmluZywgYW55PiA9IE9iamVjdC5hc3NpZ24oe30sIG1vZGVsKTtcbiAgICBsZXQgbWV0YWRhdGEgPSBNZXRhZGF0YS5tb2RlbE5hbWUobW9kZWwuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3I8TT4pO1xuXG4gICAgaWYgKCFtZXRhZGF0YSB8fCBtZXRhZGF0YSA9PT0gXCJPYmplY3RcIilcbiAgICAgIGlmIChtb2RlbE5hbWUpIG1ldGFkYXRhID0gbW9kZWxOYW1lO1xuICAgICAgZWxzZVxuICAgICAgICB0aHJvdyBuZXcgU2VyaWFsaXphdGlvbkVycm9yKFxuICAgICAgICAgIGBDb3VsZCBub3QgZmluZCBtZXRhZGF0YSBmb3IgJHttb2RlbC5jb25zdHJ1Y3Rvci5uYW1lfWBcbiAgICAgICAgKTtcbiAgICB0b1NlcmlhbGl6ZVtNb2RlbEtleXMuQU5DSE9SXSA9IG1ldGFkYXRhO1xuICAgIHJldHVybiB0b1NlcmlhbGl6ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVidWlsZHMgYSBtb2RlbCBmcm9tIGl0cyBKU09OIHNlcmlhbGl6YXRpb25cbiAgICogQHN1bW1hcnkgUGFyc2VzIHRoZSBKU09OIHN0cmluZywgcmV0cmlldmVzIHRoZSBlbWJlZGRlZCBtb2RlbCBhbmNob3IsIGFuZCB1c2VzIE1vZGVsLmJ1aWxkIHRvIHJlY29uc3RydWN0IHRoZSBvcmlnaW5hbCBpbnN0YW5jZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyIC0gVGhlIEpTT04gc3RyaW5nIHByZXZpb3VzbHkgcHJvZHVjZWQgYnkgc2VyaWFsaXplXG4gICAqIEByZXR1cm4ge019IFRoZSByZWNvbnN0cnVjdGVkIG1vZGVsIGluc3RhbmNlXG4gICAqL1xuICBvdmVycmlkZSBkZXNlcmlhbGl6ZShzdHI6IHN0cmluZyk6IE0ge1xuICAgIGNvbnN0IGRlc2VyaWFsaXphdGlvbiA9IEpTT04ucGFyc2Uoc3RyKTtcbiAgICBjb25zdCBjbGFzc05hbWUgPSBkZXNlcmlhbGl6YXRpb25bTW9kZWxLZXlzLkFOQ0hPUl07XG4gICAgaWYgKCFjbGFzc05hbWUpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgZmluZCBjbGFzcyByZWZlcmVuY2UgaW4gc2VyaWFsaXplZCBtb2RlbFwiKTtcbiAgICBjb25zdCBtb2RlbDogTSA9IE1vZGVsLmJ1aWxkKGRlc2VyaWFsaXphdGlvbiwgY2xhc3NOYW1lKSBhcyB1bmtub3duIGFzIE07XG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTZXJpYWxpemVzIGEgbW9kZWwgdG8gYSBKU09OIHN0cmluZ1xuICAgKiBAc3VtbWFyeSBQcmVwYXJlcyB0aGUgbW9kZWwgdmlhIHByZVNlcmlhbGl6ZSwgZW1iZWRkaW5nIG1ldGFkYXRhIG5lZWRlZCBmb3IgcmVjb25zdHJ1Y3Rpb24sIGFuZCByZXR1cm5zIGEgSlNPTiBzdHJpbmcgcmVwcmVzZW50YXRpb25cbiAgICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZSB0byBzZXJpYWxpemVcbiAgICogQHBhcmFtIHtzdHJpbmd9IFt0YWJsZV0gLSBPcHRpb25hbCB0YWJsZSBuYW1lIHRvIGluY2x1ZGUgYXMgYW5jaG9yIHdoZW4gbWV0YWRhdGEgaXMgdW5hdmFpbGFibGVcbiAgICogQHJldHVybiB7c3RyaW5nfSBBIEpTT04gc3RyaW5nIGNvbnRhaW5pbmcgdGhlIHNlcmlhbGl6ZWQgbW9kZWwgd2l0aCBhbmNob3IgbWV0YWRhdGFcbiAgICovXG4gIG92ZXJyaWRlIHNlcmlhbGl6ZShtb2RlbDogTSwgbW9kZWxOYW1lPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodGhpcy5wcmVTZXJpYWxpemUobW9kZWwsIG1vZGVsTmFtZSkpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBGYWJyaWNDbGllbnRSZXBvc2l0b3J5IH0gZnJvbSBcIi4uL0ZhYnJpY0NsaWVudFJlcG9zaXRvcnlcIjtcbmltcG9ydCB7IEVSQzIwVG9rZW4sIEVSQzIwV2FsbGV0IH0gZnJvbSBcIi4uLy4uL2NvbnRyYWN0cy9lcmMyMC9tb2RlbHNcIjtcbmltcG9ydCB7IE1vZGVsLCBTZXJpYWxpemVyIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljQ2xpZW50QWRhcHRlciB9IGZyb20gXCIuLi9GYWJyaWNDbGllbnRBZGFwdGVyXCI7XG5pbXBvcnQgeyBDbGllbnRTZXJpYWxpemVyIH0gZnJvbSBcIi4uLy4uL3NoYXJlZC9DbGllbnRTZXJpYWxpemVyXCI7XG5pbXBvcnQge1xuICBDb250ZXh0LFxuICBDb250ZXh0T2YsXG4gIENvbnRleHR1YWxBcmdzLFxuICBFdmVudElkcyxcbiAgTWF5YmVDb250ZXh0dWFsQXJnLFxuICBTZXF1ZW5jZSxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQge1xuICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMsXG4gIEludGVybmFsRXJyb3IsXG4gIE9wZXJhdGlvbktleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbi8qKlxuICogUmVwb3NpdG9yeSBmb3IgaW50ZXJhY3Rpbmcgd2l0aCBFUkMyMCBjb250cmFjdHMgb24gYSBIeXBlcmxlZGdlciBGYWJyaWMgbmV0d29yay5cbiAqIEV4dGVuZHMgdGhlIGJhc2UgRmFicmljQ2xpZW50UmVwb3NpdG9yeSBjbGFzcyBhbmQgdXRpbGl6ZXMgdGhlIENsaWVudFNlcmlhbGl6ZXIgZm9yIGRhdGEgc2VyaWFsaXphdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIEZhYnJpY0VSQzIwQ2xpZW50UmVwb3NpdG9yeTxcbiAgQSBleHRlbmRzIEZhYnJpY0NsaWVudEFkYXB0ZXIsXG4+IGV4dGVuZHMgRmFicmljQ2xpZW50UmVwb3NpdG9yeTxFUkMyMFdhbGxldCwgQT4ge1xuICBwcml2YXRlIHN0YXRpYyBzZXJpYWxpemVyID0gbmV3IENsaWVudFNlcmlhbGl6ZXIoKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2VyaWFsaXplcjogU2VyaWFsaXplcjxhbnk+ID1cbiAgICBGYWJyaWNFUkMyMENsaWVudFJlcG9zaXRvcnkuc2VyaWFsaXplcjtcblxuICBwcml2YXRlIHN0YXRpYyBkZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKFwidXRmOFwiKTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIE5vdGlmaWVzIGFsbCBvYnNlcnZlcnMgb2YgYW4gZXZlbnQuXG4gICAqIEBzdW1tYXJ5IFVwZGF0ZXMgYWxsIHJlZ2lzdGVyZWQgb2JzZXJ2ZXJzIHdpdGggaW5mb3JtYXRpb24gYWJvdXQgYSBkYXRhYmFzZSBldmVudC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlIC0gVGhlIHRhYmxlIG5hbWUgd2hlcmUgdGhlIGV2ZW50IG9jY3VycmVkLlxuICAgKiBAcGFyYW0ge09wZXJhdGlvbktleXN8QnVsa0NydWRPcGVyYXRpb25LZXlzfHN0cmluZ30gZXZlbnQgLSBUaGUgdHlwZSBvZiBldmVudCB0aGF0IG9jY3VycmVkLlxuICAgKiBAcGFyYW0ge0V2ZW50SWRzfSBpZCAtIFRoZSBJRCBvciBJRHMgb2YgdGhlIGFmZmVjdGVkIHJlY29yZHMuXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cy5cbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBhbGwgb2JzZXJ2ZXJzIGhhdmUgYmVlbiBub3RpZmllZC5cbiAgICogQHRocm93cyB7SW50ZXJuYWxFcnJvcn0gSWYgdGhlIG9ic2VydmVyIGhhbmRsZXIgaXMgbm90IGluaXRpYWxpemVkLlxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgdXBkYXRlT2JzZXJ2ZXJzPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgdGFibGU6IENvbnN0cnVjdG9yPE0+IHwgc3RyaW5nLFxuICAgIGV2ZW50OiBPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nLFxuICAgIGlkOiBFdmVudElkcyxcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5vYnNlcnZlckhhbmRsZXIpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgXCJPYnNlcnZlckhhbmRsZXIgbm90IGluaXRpYWxpemVkLiBEaWQgeW91IHJlZ2lzdGVyIGFueSBvYnNlcnZhYmxlcz9cIlxuICAgICAgKTtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy51cGRhdGVPYnNlcnZlcnMpO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYFVwZGF0aW5nICR7dGhpcy5vYnNlcnZlckhhbmRsZXIuY291bnQoKX0gb2JzZXJ2ZXJzIGZvciAke3RoaXN9YFxuICAgICk7XG5cbiAgICB0YWJsZSA9IChcbiAgICAgIHR5cGVvZiB0YWJsZSA9PT0gXCJzdHJpbmdcIiA/IE1vZGVsLmdldCh0YWJsZSkgOiB0YWJsZVxuICAgICkgYXMgQ29uc3RydWN0b3I8TT47XG4gICAgbGV0IHBhcnNlZElkOiBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcblxuICAgIGlmIChpZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBwYXJzZWRJZCA9IHVuZGVmaW5lZDtcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoaWQpKSB7XG4gICAgICBwYXJzZWRJZCA9IGlkLm1hcChcbiAgICAgICAgKGkpID0+IFNlcXVlbmNlLnBhcnNlVmFsdWUoTW9kZWwuc2VxdWVuY2VGb3IodGFibGUpLnR5cGUsIGkpIGFzIHN0cmluZ1xuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcGFyc2VkSWQgPSBTZXF1ZW5jZS5wYXJzZVZhbHVlKFxuICAgICAgICBNb2RlbC5zZXF1ZW5jZUZvcih0YWJsZSkudHlwZSxcbiAgICAgICAgaWRcbiAgICAgICkgYXMgc3RyaW5nO1xuICAgIH1cbiAgICBhd2FpdCB0aGlzLm9ic2VydmVySGFuZGxlci51cGRhdGVPYnNlcnZlcnMoXG4gICAgICB0YWJsZSxcbiAgICAgIGV2ZW50LFxuICAgICAgcGFyc2VkSWQhLFxuICAgICAgLi4uY3R4QXJnc1xuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogRGVjb2RlcyBhIFVpbnQ4QXJyYXkgaW50byBhIHN0cmluZyB1c2luZyB0aGUgVGV4dERlY29kZXIuXG4gICAqXG4gICAqIEBwYXJhbSBkYXRhIC0gVGhlIFVpbnQ4QXJyYXkgdG8gZGVjb2RlLlxuICAgKiBAcmV0dXJucyBUaGUgZGVjb2RlZCBzdHJpbmcuXG4gICAqL1xuICBkZWNvZGUoZGF0YTogVWludDhBcnJheSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIEZhYnJpY0VSQzIwQ2xpZW50UmVwb3NpdG9yeS5kZWNvZGVyLmRlY29kZShkYXRhKTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKGFkYXB0ZXI/OiBBKSB7XG4gICAgc3VwZXIoYWRhcHRlciwgRVJDMjBXYWxsZXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyB0aGUgbmFtZSBvZiB0aGUgRVJDMjAgdG9rZW4uXG4gICAqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gZmV0Y2ggdGhlIG5hbWUgb2YgdGhlIEVSQzIwIHRva2VuLlxuICAgKiBJdCBjYWxscyB0aGUgXCJUb2tlbk5hbWVcIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3QgYW5kIGRlY29kZXMgdGhlIHJldHVybmVkIGRhdGEuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIG5hbWUgb2YgdGhlIEVSQzIwIHRva2VuLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzIG9yIHRoZSBkZWNvZGluZyBwcm9jZXNzIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgdG9rZW5OYW1lKC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gKGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFwidG9rZW5OYW1lXCIsIHRydWUpKS5mb3IoXG4gICAgICB0aGlzLnRva2VuTmFtZVxuICAgICk7XG4gICAgY29uc3QgbmFtZSA9IGF3YWl0IHRoaXMuYWRhcHRlci5ldmFsdWF0ZVRyYW5zYWN0aW9uKGN0eCwgXCJUb2tlbk5hbWVcIik7XG4gICAgcmV0dXJuIHRoaXMuZGVjb2RlKG5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyB0aGUgc3ltYm9sIG9mIHRoZSBFUkMyMCB0b2tlbi5cbiAgICpcbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIGZldGNoIHRoZSBzeW1ib2wgb2YgdGhlIEVSQzIwIHRva2VuLlxuICAgKiBJdCBjYWxscyB0aGUgXCJTeW1ib2xcIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3QgYW5kIGRlY29kZXMgdGhlIHJldHVybmVkIGRhdGEuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHN5bWJvbCBvZiB0aGUgRVJDMjAgdG9rZW4uXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZmFpbHMgb3IgdGhlIGRlY29kaW5nIHByb2Nlc3MgZmFpbHMuXG4gICAqL1xuICBhc3luYyBzeW1ib2woLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj4pOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSAoYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgXCJzeW1ib2xcIiwgdHJ1ZSkpLmZvcih0aGlzLnN5bWJvbCk7XG4gICAgY29uc3Qgc3ltYm9sID0gYXdhaXQgdGhpcy5hZGFwdGVyLmV2YWx1YXRlVHJhbnNhY3Rpb24oY3R4LCBcIlN5bWJvbFwiKTtcbiAgICByZXR1cm4gdGhpcy5kZWNvZGUoc3ltYm9sKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgdGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyBmb3IgdGhlIEVSQzIwIHRva2VuLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gZmV0Y2ggdGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyBmb3IgdGhlIEVSQzIwIHRva2VuLlxuICAgKiBJdCBjYWxscyB0aGUgXCJEZWNpbWFsc1wiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCBhbmQgZGVjb2RlcyB0aGUgcmV0dXJuZWQgZGF0YS5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8bnVtYmVyPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIGZvciB0aGUgRVJDMjAgdG9rZW4uXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZmFpbHMgb3IgdGhlIGRlY29kaW5nIHByb2Nlc3MgZmFpbHMuXG4gICAqL1xuICBhc3luYyBkZWNpbWFscyguLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+Pik6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IChhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBcImRlY2ltYWxzXCIsIHRydWUpKS5mb3IoXG4gICAgICB0aGlzLmRlY2ltYWxzXG4gICAgKTtcbiAgICBjb25zdCBkZWNpbWFscyA9IGF3YWl0IHRoaXMuYWRhcHRlci5ldmFsdWF0ZVRyYW5zYWN0aW9uKGN0eCwgXCJEZWNpbWFsc1wiKTtcbiAgICByZXR1cm4gTnVtYmVyKHRoaXMuZGVjb2RlKGRlY2ltYWxzKSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHRoZSB0b3RhbCBzdXBwbHkgb2YgdGhlIEVSQzIwIHRva2VuLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gZmV0Y2ggdGhlIHRvdGFsIHN1cHBseSBvZiB0aGUgRVJDMjAgdG9rZW4uXG4gICAqIEl0IGNhbGxzIHRoZSBcIlRvdGFsU3VwcGx5XCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0IGFuZCBkZWNvZGVzIHRoZSByZXR1cm5lZCBkYXRhLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxudW1iZXI+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSB0b3RhbCBzdXBwbHkgb2YgdGhlIEVSQzIwIHRva2VuLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzIG9yIHRoZSBkZWNvZGluZyBwcm9jZXNzIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgdG90YWxTdXBwbHkoXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj5cbiAgKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gKGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFwidG90YWxTdXBwbHlcIiwgdHJ1ZSkpLmZvcihcbiAgICAgIHRoaXMudG90YWxTdXBwbHlcbiAgICApO1xuICAgIGNvbnN0IHRvdGFsID0gYXdhaXQgdGhpcy5hZGFwdGVyLmV2YWx1YXRlVHJhbnNhY3Rpb24oY3R4LCBcIlRvdGFsU3VwcGx5XCIpO1xuICAgIHJldHVybiBOdW1iZXIodGhpcy5kZWNvZGUodG90YWwpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgdGhlIGJhbGFuY2Ugb2YgdGhlIEVSQzIwIHRva2VuIGZvciBhIHNwZWNpZmllZCBvd25lci5cbiAgICpcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byBmZXRjaCB0aGUgYmFsYW5jZSBvZiB0aGUgRVJDMjAgdG9rZW4gZm9yIGEgZ2l2ZW4gb3duZXIuXG4gICAqIEl0IGNhbGxzIHRoZSBcIkJhbGFuY2VPZlwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCB3aXRoIHRoZSBwcm92aWRlZCBvd25lcidzIGFkZHJlc3MgYXMgYSBwYXJhbWV0ZXIuXG4gICAqIFRoZSByZXR1cm5lZCBkYXRhIGlzIHRoZW4gZGVjb2RlZCBhbmQgY29udmVydGVkIHRvIGEgbnVtYmVyLlxuICAgKlxuICAgKiBAcGFyYW0gb3duZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgRVJDMjAgdG9rZW4gb3duZXIuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGJhbGFuY2Ugb2YgdGhlIEVSQzIwIHRva2VuIGZvciB0aGUgc3BlY2lmaWVkIG93bmVyLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzIG9yIHRoZSBkZWNvZGluZyBwcm9jZXNzIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgYmFsYW5jZU9mKFxuICAgIG93bmVyOiBzdHJpbmcsXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj5cbiAgKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gKGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFwiYmFsYW5jZVwiLCB0cnVlKSkuZm9yKFxuICAgICAgdGhpcy5iYWxhbmNlT2ZcbiAgICApO1xuICAgIGNvbnN0IGJhbGFuY2UgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuZXZhbHVhdGVUcmFuc2FjdGlvbihjdHgsIFwiQmFsYW5jZU9mXCIsIFtcbiAgICAgIG93bmVyLFxuICAgIF0pO1xuICAgIHJldHVybiBOdW1iZXIodGhpcy5kZWNvZGUoYmFsYW5jZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYW5zZmVycyBhIHNwZWNpZmllZCBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIHRvIGEgcmVjaXBpZW50LlxuICAgKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIHRyYW5zZmVyIGEgc3BlY2lmaWVkIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMgdG8gYSByZWNpcGllbnQuXG4gICAqIEl0IGNhbGxzIHRoZSBcIlRyYW5zZmVyXCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0IHdpdGggdGhlIHJlY2lwaWVudCdzIGFkZHJlc3MgYW5kIHRoZSB0cmFuc2ZlciBhbW91bnQgYXMgcGFyYW1ldGVycy5cbiAgICogVGhlIHJldHVybmVkIGRhdGEgaXMgdGhlbiBkZWNvZGVkIGFuZCBjaGVja2VkIHRvIGRldGVybWluZSBpZiB0aGUgdHJhbnNmZXIgd2FzIHN1Y2Nlc3NmdWwuXG4gICAqXG4gICAqIEBwYXJhbSB0byAtIFRoZSBhZGRyZXNzIG9mIHRoZSByZWNpcGllbnQuXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIHRvIHRyYW5zZmVyLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCBgdHJ1ZWAgaWYgdGhlIHRyYW5zZmVyIHdhcyBzdWNjZXNzZnVsLCBhbmQgYGZhbHNlYCBvdGhlcndpc2UuXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZmFpbHMgb3IgdGhlIGRlY29kaW5nIHByb2Nlc3MgZmFpbHMuXG4gICAqL1xuICBhc3luYyB0cmFuc2ZlcihcbiAgICB0bzogc3RyaW5nLFxuICAgIHZhbHVlOiBudW1iZXIsXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj5cbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IChhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBcInRyYW5zZmVyXCIsIHRydWUpKS5mb3IoXG4gICAgICB0aGlzLnRyYW5zZmVyXG4gICAgKTtcbiAgICBjb25zdCB0cmFuc2ZlcnJlZCA9IGF3YWl0IHRoaXMuYWRhcHRlci5zdWJtaXRUcmFuc2FjdGlvbihjdHgsIFwiVHJhbnNmZXJcIiwgW1xuICAgICAgdG8sXG4gICAgICB2YWx1ZS50b1N0cmluZygpLFxuICAgIF0pO1xuICAgIHJldHVybiB0aGlzLmRlY29kZSh0cmFuc2ZlcnJlZCkgPT09IFwidHJ1ZVwiID8gdHJ1ZSA6IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYW5zZmVycyBhIHNwZWNpZmllZCBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIGZyb20gb25lIGFjY291bnQgdG8gYW5vdGhlci5cbiAgICpcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byB0cmFuc2ZlciBhIHNwZWNpZmllZCBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIGZyb20gb25lIGFjY291bnQgdG8gYW5vdGhlci5cbiAgICogRm9yIHRoaXMgdHJhbnNmZXIgdG8gd29yayB0aGUgc3BlbmRlciAoIGFjY291bnQgdGhhdCB3aWxsIHRyaWdnZXIgdGhpcyBmdW5jdGlvbiApIG5lZWQgdG8gaGF2ZSB0aGUgdmFsdWUgYXBwcm92ZWQgYXMgYW4gYWxsb3dhbmNlIGJ5IHRoZSBzZW5kZXIuXG4gICAqIEl0IGNhbGxzIHRoZSBcIlRyYW5zZmVyRnJvbVwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCB3aXRoIHRoZSBzZW5kZXIncyBhZGRyZXNzLCByZWNpcGllbnQncyBhZGRyZXNzLCBhbmQgdGhlIHRyYW5zZmVyIGFtb3VudCBhcyBwYXJhbWV0ZXJzLlxuICAgKiBUaGUgcmV0dXJuZWQgZGF0YSBpcyB0aGVuIGRlY29kZWQgYW5kIGNoZWNrZWQgdG8gZGV0ZXJtaW5lIGlmIHRoZSB0cmFuc2ZlciB3YXMgc3VjY2Vzc2Z1bC5cbiAgICpcbiAgICogQHBhcmFtIGZyb20gLSBUaGUgYWRkcmVzcyBvZiB0aGUgc2VuZGVyLlxuICAgKiBAcGFyYW0gdG8gLSBUaGUgYWRkcmVzcyBvZiB0aGUgcmVjaXBpZW50LlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgYW1vdW50IG9mIEVSQzIwIHRva2VucyB0byB0cmFuc2Zlci5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggYHRydWVgIGlmIHRoZSB0cmFuc2ZlciB3YXMgc3VjY2Vzc2Z1bCwgYW5kIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzIG9yIHRoZSBkZWNvZGluZyBwcm9jZXNzIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgdHJhbnNmZXJGcm9tKFxuICAgIGZyb206IHN0cmluZyxcbiAgICB0bzogc3RyaW5nLFxuICAgIHZhbHVlOiBudW1iZXJcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3MoXG4gICAgICBcInRyYW5zZmVyRnJvbVwiLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIFtdLFxuICAgICAgdGhpcy5hZGFwdGVyLFxuICAgICAgdGhpcy5fb3ZlcnJpZGVzIHx8IHt9XG4gICAgKTtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcy5sb2dDdHgoY29udGV4dEFyZ3MuYXJncywgdGhpcy50cmFuc2ZlckZyb20pO1xuICAgIGNvbnN0IHRyYW5zZmVycmVkID0gYXdhaXQgdGhpcy5hZGFwdGVyLnN1Ym1pdFRyYW5zYWN0aW9uKFxuICAgICAgY3R4LFxuICAgICAgXCJUcmFuc2ZlckZyb21cIixcbiAgICAgIFtmcm9tLCB0bywgdmFsdWUudG9TdHJpbmcoKV1cbiAgICApO1xuXG4gICAgcmV0dXJuIHRoaXMuZGVjb2RlKHRyYW5zZmVycmVkKSA9PT0gXCJ0cnVlXCIgPyB0cnVlIDogZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQXBwcm92ZXMgYSBzcGVjaWZpZWQgYW1vdW50IG9mIEVSQzIwIHRva2VucyB0byBiZSBzcGVudCBieSBhIHNwZWNpZmllZCBzcGVuZGVyLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gYXBwcm92ZSBhIHNwZWNpZmllZCBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIHRvIGJlIHNwZW50IGJ5IGEgc3BlY2lmaWVkIHNwZW5kZXIuXG4gICAqIEl0IGNhbGxzIHRoZSBcIkFwcHJvdmVcIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3Qgd2l0aCB0aGUgc3BlbmRlcidzIGFkZHJlc3MgYW5kIHRoZSBhcHByb3ZhbCBhbW91bnQgYXMgcGFyYW1ldGVycy5cbiAgICogVGhlIHJldHVybmVkIGRhdGEgaXMgdGhlbiBkZWNvZGVkIGFuZCBjaGVja2VkIHRvIGRldGVybWluZSBpZiB0aGUgYXBwcm92YWwgd2FzIHN1Y2Nlc3NmdWwuXG4gICAqXG4gICAqIEBwYXJhbSBzcGVuZGVyIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHNwZW5kZXIuXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIHRvIGFwcHJvdmUgZm9yIHRoZSBzcGVuZGVyLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCBgdHJ1ZWAgaWYgdGhlIGFwcHJvdmFsIHdhcyBzdWNjZXNzZnVsLCBhbmQgYGZhbHNlYCBvdGhlcndpc2UuXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZmFpbHMgb3IgdGhlIGRlY29kaW5nIHByb2Nlc3MgZmFpbHMuXG4gICAqL1xuICBhc3luYyBhcHByb3ZlKHNwZW5kZXI6IHN0cmluZywgdmFsdWU6IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgXCJhcHByb3ZlXCIsXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgW10sXG4gICAgICB0aGlzLmFkYXB0ZXIsXG4gICAgICB0aGlzLl9vdmVycmlkZXMgfHwge31cbiAgICApO1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzLmxvZ0N0eChjb250ZXh0QXJncy5hcmdzLCB0aGlzLmFwcHJvdmUpO1xuICAgIGNvbnN0IGFwcHJvdmVkID0gYXdhaXQgdGhpcy5hZGFwdGVyLnN1Ym1pdFRyYW5zYWN0aW9uKGN0eCwgXCJBcHByb3ZlXCIsIFtcbiAgICAgIHNwZW5kZXIsXG4gICAgICB2YWx1ZS50b1N0cmluZygpLFxuICAgIF0pO1xuICAgIHJldHVybiB0aGlzLmRlY29kZShhcHByb3ZlZCkgPT09IFwidHJ1ZVwiID8gdHJ1ZSA6IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyB0aGUgYWxsb3dhbmNlIG9mIEVSQzIwIHRva2VucyB0aGF0IHRoZSBzcGVjaWZpZWQgb3duZXIgaGFzIGFwcHJvdmVkIGZvciBhIHNwZW5kZXIuXG4gICAqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gZmV0Y2ggdGhlIGFsbG93YW5jZSBvZiBFUkMyMCB0b2tlbnMgdGhhdCB0aGUgc3BlY2lmaWVkIG93bmVyIGhhcyBhcHByb3ZlZCBmb3IgYSBzcGVuZGVyLlxuICAgKiBJdCBjYWxscyB0aGUgXCJBbGxvd2FuY2VcIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3Qgd2l0aCB0aGUgb3duZXIncyBhZGRyZXNzIGFuZCB0aGUgc3BlbmRlcidzIGFkZHJlc3MgYXMgcGFyYW1ldGVycy5cbiAgICogVGhlIHJldHVybmVkIGRhdGEgaXMgdGhlbiBkZWNvZGVkIGFuZCBjb252ZXJ0ZWQgdG8gYSBudW1iZXIuXG4gICAqXG4gICAqIEBwYXJhbSBvd25lciAtIFRoZSBhZGRyZXNzIG9mIHRoZSBFUkMyMCB0b2tlbiBvd25lci5cbiAgICogQHBhcmFtIHNwZW5kZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgc3BlbmRlci5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8bnVtYmVyPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgYWxsb3dhbmNlIG9mIEVSQzIwIHRva2VucyB0aGF0IHRoZSBzcGVjaWZpZWQgb3duZXIgaGFzIGFwcHJvdmVkIGZvciB0aGUgc3BlbmRlci5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscyBvciB0aGUgZGVjb2RpbmcgcHJvY2VzcyBmYWlscy5cbiAgICovXG4gIGFzeW5jIGFsbG93YW5jZShvd25lcjogc3RyaW5nLCBzcGVuZGVyOiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgXCJhbGxvd2FuY2VcIixcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBbXSxcbiAgICAgIHRoaXMuYWRhcHRlcixcbiAgICAgIHRoaXMuX292ZXJyaWRlcyB8fCB7fVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGNvbnRleHRBcmdzLmFyZ3MsIHRoaXMuYWxsb3dhbmNlKTtcbiAgICBjb25zdCBhbGxvd2FuY2UgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuc3VibWl0VHJhbnNhY3Rpb24oY3R4LCBcIkFsbG93YW5jZVwiLCBbXG4gICAgICBvd25lcixcbiAgICAgIHNwZW5kZXIsXG4gICAgXSk7XG4gICAgcmV0dXJuIE51bWJlcih0aGlzLmRlY29kZShhbGxvd2FuY2UpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplcyB0aGUgRVJDMjAgY29udHJhY3Qgd2l0aCB0aGUgcHJvdmlkZWQgdG9rZW4gaW5mb3JtYXRpb24uXG4gICAqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gaW5pdGlhbGl6ZSB0aGUgRVJDMjAgY29udHJhY3Qgd2l0aCB0aGUgZ2l2ZW4gdG9rZW4gaW5mb3JtYXRpb24uXG4gICAqIEl0IGNhbGxzIHRoZSBcIkluaXRpYWxpemVcIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3Qgd2l0aCB0aGUgc2VyaWFsaXplZCB0b2tlbiBkYXRhIGFzIGEgcGFyYW1ldGVyLlxuICAgKiBUaGUgcmV0dXJuZWQgZGF0YSBpcyB0aGVuIGRlY29kZWQgYW5kIGNoZWNrZWQgdG8gZGV0ZXJtaW5lIGlmIHRoZSBpbml0aWFsaXphdGlvbiB3YXMgc3VjY2Vzc2Z1bC5cbiAgICpcbiAgICogQHBhcmFtIHRva2VuIC0gVGhlIEVSQzIwIHRva2VuIGluZm9ybWF0aW9uIHRvIGluaXRpYWxpemUgdGhlIGNvbnRyYWN0IHdpdGguXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIGB0cnVlYCBpZiB0aGUgaW5pdGlhbGl6YXRpb24gd2FzIHN1Y2Nlc3NmdWwsIGFuZCBgZmFsc2VgIG90aGVyd2lzZS5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscyBvciB0aGUgZGVjb2RpbmcgcHJvY2VzcyBmYWlscy5cbiAgICovXG4gIGFzeW5jIGluaXRpYWxpemUodG9rZW46IEVSQzIwVG9rZW4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJncyhcbiAgICAgIFwiaW5pdGlhbGl6ZVwiLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIFtdLFxuICAgICAgdGhpcy5hZGFwdGVyLFxuICAgICAgdGhpcy5fb3ZlcnJpZGVzIHx8IHt9XG4gICAgKTtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcy5sb2dDdHgoY29udGV4dEFyZ3MuYXJncywgdGhpcy5pbml0aWFsaXplKTtcbiAgICBjb25zdCBpbml0aWxpYXplZCA9IGF3YWl0IHRoaXMuYWRhcHRlci5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIFwiSW5pdGlhbGl6ZVwiLFxuICAgICAgW0ZhYnJpY0VSQzIwQ2xpZW50UmVwb3NpdG9yeS5zZXJpYWxpemVyLnNlcmlhbGl6ZSh0b2tlbildXG4gICAgKTtcblxuICAgIHJldHVybiB0aGlzLmRlY29kZShpbml0aWxpYXplZCkgPT09IFwidHJ1ZVwiID8gdHJ1ZSA6IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgRVJDMjAgY29udHJhY3QgaGFzIGJlZW4gaW5pdGlhbGl6ZWQuXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byB2ZXJpZnkgaWYgdGhlIEVSQzIwIGNvbnRyYWN0IGhhcyBiZWVuIGluaXRpYWxpemVkLlxuICAgKiBJdCBjYWxscyB0aGUgXCJDaGVja0luaXRpYWxpemVkXCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0LCB3aGljaCBkb2VzIG5vdCByZXF1aXJlIGFueSBwYXJhbWV0ZXJzLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgaW5pdGlhbGl6YXRpb24gY2hlY2sgaXMgY29tcGxldGVkLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgY2hlY2tJbml0aWFsaXplZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJncyhcbiAgICAgIFwiY2hlY2tJbml0aWFsaXplZFwiLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIFtdLFxuICAgICAgdGhpcy5hZGFwdGVyLFxuICAgICAgdGhpcy5fb3ZlcnJpZGVzIHx8IHt9XG4gICAgKTtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcy5sb2dDdHgoY29udGV4dEFyZ3MuYXJncywgdGhpcy5jaGVja0luaXRpYWxpemVkKTtcbiAgICBhd2FpdCB0aGlzLmFkYXB0ZXIuZXZhbHVhdGVUcmFuc2FjdGlvbihjdHgsIFwiQ2hlY2tJbml0aWFsaXplZFwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNaW50cyBhIHNwZWNpZmllZCBhbW91bnQgb2YgRVJDMjAgdG9rZW5zLlxuICAgKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIG1pbnQgYSBzcGVjaWZpZWQgYW1vdW50IG9mIEVSQzIwIHRva2Vucy5cbiAgICogSXQgY2FsbHMgdGhlIFwiTWludFwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCB3aXRoIHRoZSBtaW50aW5nIGFtb3VudCBhcyBhIHBhcmFtZXRlci5cbiAgICogVGhlIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhbnkgdmFsdWUsIGJ1dCBpdCB1cGRhdGVzIHRoZSBtaW50ZXIncyBudW1iZXIgb2YgdG9rZW5zLlxuICAgKlxuICAgKiBAcGFyYW0gYW1vdW50IC0gVGhlIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMgdG8gbWludC5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIG1pbnRpbmcgcHJvY2VzcyBpcyBjb21wbGV0ZWQuXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZmFpbHMuXG4gICAqL1xuICBhc3luYyBtaW50KGFtb3VudDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3MoXG4gICAgICBcIm1pbnRcIixcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBbXSxcbiAgICAgIHRoaXMuYWRhcHRlcixcbiAgICAgIHRoaXMuX292ZXJyaWRlcyB8fCB7fVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGNvbnRleHRBcmdzLmFyZ3MsIHRoaXMubWludCk7XG4gICAgYXdhaXQgdGhpcy5hZGFwdGVyLnN1Ym1pdFRyYW5zYWN0aW9uKGN0eCwgXCJNaW50XCIsIFthbW91bnQudG9TdHJpbmcoKV0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1cm5zIGEgc3BlY2lmaWVkIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMgZnJvbSB0aGUgbWludGVyJ3MgYWNjb3VudC5cbiAgICpcbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIGJ1cm4gYSBzcGVjaWZpZWQgYW1vdW50IG9mIEVSQzIwIHRva2Vucy5cbiAgICogSXQgY2FsbHMgdGhlIFwiQnVyblwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCB3aXRoIHRoZSBidXJuaW5nIGFtb3VudCBhcyBhIHBhcmFtZXRlci5cbiAgICogVGhlIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhbnkgdmFsdWUsIGJ1dCBpdCBkZWNyZWFzZXMgdGhlIG1pbnRlcidzIG51bWJlciBvZiB0b2tlbnMuXG4gICAqXG4gICAqIEBwYXJhbSBhbW91bnQgLSBUaGUgYW1vdW50IG9mIEVSQzIwIHRva2VucyB0byBidXJuLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgYnVybmluZyBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscy5cbiAgICovXG4gIGFzeW5jIGJ1cm4oYW1vdW50OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJncyhcbiAgICAgIFwiYnVyblwiLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIFtdLFxuICAgICAgdGhpcy5hZGFwdGVyLFxuICAgICAgdGhpcy5fb3ZlcnJpZGVzIHx8IHt9XG4gICAgKTtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcy5sb2dDdHgoY29udGV4dEFyZ3MuYXJncywgdGhpcy5idXJuKTtcbiAgICBhd2FpdCB0aGlzLmFkYXB0ZXIuc3VibWl0VHJhbnNhY3Rpb24oY3R4LCBcIkJ1cm5cIiwgW2Ftb3VudC50b1N0cmluZygpXSk7XG4gIH1cblxuICAvKipcbiAgICogQnVybnMgYSBzcGVjaWZpZWQgYW1vdW50IG9mIEVSQzIwIHRva2VucyBmcm9tIGEgc3BlY2lmaWVkIGFjY291bnQuXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byBidXJuIGEgc3BlY2lmaWVkIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMgZnJvbSBhIGdpdmVuIGFjY291bnQuXG4gICAqIEl0IGNhbGxzIHRoZSBcIkJ1cm5Gcm9tXCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0IHdpdGggdGhlIGFjY291bnQncyBhZGRyZXNzIGFuZCB0aGUgYnVybmluZyBhbW91bnQgYXMgcGFyYW1ldGVycy5cbiAgICogVGhlIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhbnkgdmFsdWUsIGJ1dCBpdCBkZWNyZWFzZXMgdGhlIHNwZWNpZmllZCBhY2NvdW50J3MgbnVtYmVyIG9mIHRva2Vucy5cbiAgICpcbiAgICogQHBhcmFtIGFjY291bnQgLSBUaGUgYWRkcmVzcyBvZiB0aGUgYWNjb3VudCBmcm9tIHdoaWNoIHRvIGJ1cm4gdGhlIEVSQzIwIHRva2Vucy5cbiAgICogQHBhcmFtIGFtb3VudCAtIFRoZSBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIHRvIGJ1cm4uXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBidXJuaW5nIHByb2Nlc3MgaXMgY29tcGxldGVkLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgYnVybkZyb20oYWNjb3VudDogc3RyaW5nLCBhbW91bnQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgXCJidXJuRnJvbVwiLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIFtdLFxuICAgICAgdGhpcy5hZGFwdGVyLFxuICAgICAgdGhpcy5fb3ZlcnJpZGVzIHx8IHt9XG4gICAgKTtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcy5sb2dDdHgoY29udGV4dEFyZ3MuYXJncywgdGhpcy5idXJuRnJvbSk7XG4gICAgYXdhaXQgdGhpcy5hZGFwdGVyLnN1Ym1pdFRyYW5zYWN0aW9uKGN0eCwgXCJCdXJuRnJvbVwiLCBbXG4gICAgICBhY2NvdW50LFxuICAgICAgYW1vdW50LnRvU3RyaW5nKCksXG4gICAgXSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHRoZSBiYWxhbmNlIG9mIEVSQzIwIHRva2VucyBhc3NvY2lhdGVkIHdpdGggdGhlIGNsaWVudCdzIGFjY291bnQuXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byBmZXRjaCB0aGUgYmFsYW5jZSBvZiBFUkMyMCB0b2tlbnMgYXNzb2NpYXRlZCB3aXRoIHRoZSBjbGllbnQncyBhY2NvdW50LlxuICAgKiBJdCBjYWxscyB0aGUgXCJDbGllbnRBY2NvdW50QmFsYW5jZVwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCwgd2hpY2ggZG9lcyBub3QgcmVxdWlyZSBhbnkgcGFyYW1ldGVycy5cbiAgICogVGhlIHJldHVybmVkIGRhdGEgaXMgdGhlbiBkZWNvZGVkIGFuZCBjb252ZXJ0ZWQgdG8gYSBudW1iZXIuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGJhbGFuY2Ugb2YgRVJDMjAgdG9rZW5zIGFzc29jaWF0ZWQgd2l0aCB0aGUgY2xpZW50J3MgYWNjb3VudC5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscyBvciB0aGUgZGVjb2RpbmcgcHJvY2VzcyBmYWlscy5cbiAgICovXG4gIGFzeW5jIGNsaWVudEFjY291bnRCYWxhbmNlKCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3MoXG4gICAgICBcImFjY291bnRCYWxhbmNlXCIsXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgW10sXG4gICAgICB0aGlzLmFkYXB0ZXIsXG4gICAgICB0aGlzLl9vdmVycmlkZXMgfHwge31cbiAgICApO1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzLmxvZ0N0eChjb250ZXh0QXJncy5hcmdzLCB0aGlzLmNsaWVudEFjY291bnRCYWxhbmNlKTtcbiAgICBjb25zdCBzZXJpYWxpemVkQWNjb3VudEJhbGFuY2UgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuZXZhbHVhdGVUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIFwiQ2xpZW50QWNjb3VudEJhbGFuY2VcIlxuICAgICk7XG5cbiAgICByZXR1cm4gTnVtYmVyKHRoaXMuZGVjb2RlKHNlcmlhbGl6ZWRBY2NvdW50QmFsYW5jZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyB0aGUgY2xpZW50J3MgYWNjb3VudCBJRCBmcm9tIHRoZSBibG9ja2NoYWluIG5ldHdvcmsuXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byBmZXRjaCB0aGUgY2xpZW50J3MgYWNjb3VudCBJRC5cbiAgICogSXQgY2FsbHMgdGhlIFwiQ2xpZW50QWNjb3VudElEXCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0LCB3aGljaCBkb2VzIG5vdCByZXF1aXJlIGFueSBwYXJhbWV0ZXJzLlxuICAgKiBUaGUgcmV0dXJuZWQgZGF0YSBpcyB0aGVuIGRlY29kZWQgYW5kIHJldHVybmVkIGFzIGEgc3RyaW5nLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBjbGllbnQncyBhY2NvdW50IElELlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzIG9yIHRoZSBkZWNvZGluZyBwcm9jZXNzIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgY2xpZW50QWNjb3VudElEKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3MoXG4gICAgICBcImFjY291bnRJZFwiLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIFtdLFxuICAgICAgdGhpcy5hZGFwdGVyLFxuICAgICAgdGhpcy5fb3ZlcnJpZGVzIHx8IHt9XG4gICAgKTtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcy5sb2dDdHgoY29udGV4dEFyZ3MuYXJncywgdGhpcy5jbGllbnRBY2NvdW50SUQpO1xuICAgIGNvbnN0IGNsaWVudEFjY291bnRJRCA9IGF3YWl0IHRoaXMuYWRhcHRlci5ldmFsdWF0ZVRyYW5zYWN0aW9uKFxuICAgICAgY3R4LFxuICAgICAgXCJDbGllbnRBY2NvdW50SURcIlxuICAgICk7XG5cbiAgICByZXR1cm4gdGhpcy5kZWNvZGUoY2xpZW50QWNjb3VudElEKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgSW5kZXhNZXRhZGF0YSwgT3JkZXJEaXJlY3Rpb24gfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yLCBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgQ291Y2hEQktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1jb3VjaGRiXCI7XG5pbXBvcnQgeyBNb2RlbCwgTW9kZWxDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IEludGVybmFsRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuZXhwb3J0IHR5cGUgSW5kZXggPSB7XG4gIGluZGV4OiB7XG4gICAgZmllbGRzOiBzdHJpbmdbXSB8IHsgW2s6IHN0cmluZ106IE9yZGVyRGlyZWN0aW9uIH07XG4gIH07XG4gIGRkb2M/OiBzdHJpbmc7XG4gIG5hbWU6IHN0cmluZztcbiAgdHlwZTogXCJqc29uXCI7XG59O1xuXG5mdW5jdGlvbiBnZXRJbmRleFJlZmVyZW5jZShcbiAgbmFtZTogc3RyaW5nW10sXG4gIGRpcmVjdGlvbj86IE9yZGVyRGlyZWN0aW9uLFxuICBjb21wb3NpdGlvbnM/OiBzdHJpbmdbXVxuKSB7XG4gIHJldHVybiBbXG4gICAgLi4ubmFtZS5tYXAoKG4pID0+IChuID09PSBDb3VjaERCS2V5cy5UQUJMRSA/IFwidGFibGVcIiA6IG4pKSxcbiAgICAuLi4oY29tcG9zaXRpb25zIHx8IFtdKSxcbiAgICAuLi4oZGlyZWN0aW9uID8gW2RpcmVjdGlvbl0gOiBbXSksXG4gICAgXCJpbmRleFwiLFxuICBdLmpvaW4oTWV0YWRhdGEuc3BsaXR0ZXIpO1xufVxuXG5mdW5jdGlvbiBhZGRJbmRleChcbiAgYWNjdW06IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gIGZpZWxkczogc3RyaW5nW10sXG4gIGRpcmVjdGlvbj86IE9yZGVyRGlyZWN0aW9uLFxuICBjb21wb3NpdGlvbnM/OiBzdHJpbmdbXVxuKSB7XG4gIGNvbnN0IHRhYmxlRmllbGQgPSBmaWVsZHMucG9wKCk7XG4gIGlmICh0YWJsZUZpZWxkICYmIHRhYmxlRmllbGQgIT09IENvdWNoREJLZXlzLlRBQkxFKSB7XG4gICAgZmllbGRzLnB1c2godGFibGVGaWVsZCk7XG4gIH0gZWxzZSBpZiAodGFibGVGaWVsZCA9PT0gQ291Y2hEQktleXMuVEFCTEUpIHtcbiAgICBmaWVsZHMudW5zaGlmdCh0YWJsZUZpZWxkKTtcbiAgfVxuXG4gIGNvbnN0IG5hbWUgPSBnZXRJbmRleFJlZmVyZW5jZShmaWVsZHMsIGRpcmVjdGlvbiwgY29tcG9zaXRpb25zKTtcblxuICBsZXQgZjogc3RyaW5nW10gfCB7IFtrOiBzdHJpbmddOiBPcmRlckRpcmVjdGlvbiB9W10gPSBbXG4gICAgLi4uZmllbGRzLFxuICAgIC4uLihjb21wb3NpdGlvbnMgfHwgW10pLFxuICBdO1xuXG4gIGlmIChkaXJlY3Rpb24pXG4gICAgZiA9IGYucmVkdWNlKChhY2N1bTogeyBbazogc3RyaW5nXTogT3JkZXJEaXJlY3Rpb24gfVtdLCBlbDogc3RyaW5nKSA9PiB7XG4gICAgICBjb25zdCBlbnRyeTogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgICAgZW50cnlbZWxdID0gZGlyZWN0aW9uO1xuICAgICAgYWNjdW0ucHVzaChlbnRyeSk7XG4gICAgICByZXR1cm4gYWNjdW07XG4gICAgfSwgW10pO1xuXG4gIGNvbnN0IGluZGV4OiBJbmRleCA9IHtcbiAgICBpbmRleDoge1xuICAgICAgZmllbGRzOiBmLFxuICAgIH0sXG4gICAgbmFtZTogbmFtZSxcbiAgICBkZG9jOiBuYW1lLFxuICAgIHR5cGU6IFwianNvblwiLFxuICB9IGFzIEluZGV4O1xuXG4gIGFjY3VtW25hbWVdID0gaW5kZXg7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZU1vZGVsSW5kZXhlczxNIGV4dGVuZHMgTW9kZWw+KFxuICBtOiBDb25zdHJ1Y3RvcjxNPixcbiAgYWNjdW0/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+XG4pOiBJbmRleFtdIHtcbiAgY29uc3QgdGFibGVOYW1lID0gZ2V0SW5kZXhSZWZlcmVuY2UoW0NvdWNoREJLZXlzLlRBQkxFXSk7XG4gIGNvbnN0IGluZGV4ZXM6IFJlY29yZDxzdHJpbmcsIEluZGV4PiA9IGFjY3VtIHx8IHt9O1xuICBpbmRleGVzW3RhYmxlTmFtZV0gPSB7XG4gICAgaW5kZXg6IHtcbiAgICAgIGZpZWxkczogW0NvdWNoREJLZXlzLlRBQkxFXSxcbiAgICB9LFxuICAgIG5hbWU6IHRhYmxlTmFtZSxcbiAgICBkZG9jOiB0YWJsZU5hbWUsXG4gICAgdHlwZTogXCJqc29uXCIsXG4gIH07XG5cbiAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG5cbiAgY29uc3QgbW9kZWxJbmRleGVzID0gTW9kZWwuaW5kZXhlcyhtKTtcbiAgZm9yIChjb25zdCBwcm9wIG9mIE9iamVjdC5rZXlzKG1vZGVsSW5kZXhlcykpIHtcbiAgICBmb3IgKGNvbnN0IFssIGRlY10gb2YgT2JqZWN0LmVudHJpZXMobW9kZWxJbmRleGVzW3Byb3BdKSkge1xuICAgICAgY29uc3QgZGlyZWN0aW9ucyA9IChkZWMgYXMgSW5kZXhNZXRhZGF0YSlcbiAgICAgICAgLmRpcmVjdGlvbnMgYXMgdW5rbm93biBhcyBPcmRlckRpcmVjdGlvbltdO1xuICAgICAgY29uc3QgY29tcG9zaXRpb25zID0gKGRlYyBhcyBJbmRleE1ldGFkYXRhKS5jb21wb3NpdGlvbnM7XG4gICAgICBjb25zdCBmaWVsZHMgPSBbcHJvcCwgQ291Y2hEQktleXMuVEFCTEVdO1xuXG4gICAgICBhZGRJbmRleChyZXN1bHQsIGZpZWxkcyk7XG4gICAgICBpZiAoY29tcG9zaXRpb25zICYmIGNvbXBvc2l0aW9ucy5sZW5ndGgpXG4gICAgICAgIGFkZEluZGV4KHJlc3VsdCwgZmllbGRzLCB1bmRlZmluZWQsIGNvbXBvc2l0aW9ucyk7XG4gICAgICBpZiAoZGlyZWN0aW9ucyAmJiBkaXJlY3Rpb25zLmxlbmd0aCkge1xuICAgICAgICBkaXJlY3Rpb25zLmZvckVhY2goKGQpID0+IHtcbiAgICAgICAgICBhZGRJbmRleChyZXN1bHQsIGZpZWxkcywgZCk7XG4gICAgICAgICAgaWYgKGNvbXBvc2l0aW9ucyAmJiBjb21wb3NpdGlvbnMubGVuZ3RoKVxuICAgICAgICAgICAgYWRkSW5kZXgocmVzdWx0LCBmaWVsZHMsIGQsIGNvbXBvc2l0aW9ucyk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIE9iamVjdC5lbnRyaWVzKHJlc3VsdCkuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgaW5kZXhlc1trZXldID0gdmFsdWU7XG4gIH0pO1xuICByZXR1cm4gT2JqZWN0LnZhbHVlcyhyZXN1bHQpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVhZE1vZGVsRmlsZShmaWxlOiBhbnkpIHtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgY29uc3QgcGF0aCA9IHJlcXVpcmUoXCJwYXRoXCIpO1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICBjb25zdCBleHBvcnRzID0gcmVxdWlyZShwYXRoLmpvaW4ocHJvY2Vzcy5jd2QoKSwgZmlsZS5wYXJlbnRQYXRoLCBmaWxlLm5hbWUpKTtcblxuICBjb25zdCB2YWx1ZXMgPSBPYmplY3QudmFsdWVzKGV4cG9ydHMpLmZpbHRlcigoZSkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBtID0gbmV3IChlIGFzIENvbnN0cnVjdG9yKSgpO1xuICAgICAgcmV0dXJuIG0gaW5zdGFuY2VvZiBNb2RlbDtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9KSBhcyBNb2RlbENvbnN0cnVjdG9yPGFueT5bXTtcbiAgcmV0dXJuIHZhbHVlcztcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRNb2RlbEZvbGRlcnMoXG4gIC4uLmZvbGRlcnM6IHN0cmluZ1tdXG4pOiBQcm9taXNlPE1vZGVsQ29uc3RydWN0b3I8YW55PltdPiB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG4gIGNvbnN0IGZzID0gcmVxdWlyZShcImZzXCIpO1xuXG4gIGNvbnN0IHJlc3VsdDogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+W10gPSBbXTtcblxuICBmb3IgKGNvbnN0IGZvbGRlciBvZiBmb2xkZXJzKSB7XG4gICAgY29uc3QgZmlsZXMgPSBmc1xuICAgICAgLnJlYWRkaXJTeW5jKGZvbGRlciwge1xuICAgICAgICB3aXRoRmlsZVR5cGVzOiB0cnVlLFxuICAgICAgICByZWN1cnNpdmU6IHRydWUsXG4gICAgICB9KVxuICAgICAgLmZpbHRlcigoZjogYW55KSA9PiBmLmlzRmlsZSgpICYmIGYubmFtZS5lbmRzV2l0aChcImpzXCIpKTtcbiAgICBmb3IgKGNvbnN0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAgIHJlc3VsdC5wdXNoKC4uLnJlYWRNb2RlbEZpbGUoZmlsZSkpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gd3JpdGVJbmRleGVzKFxuICBpbmRleGVzOiBJbmRleFtdLFxuICBwOiBzdHJpbmcgPSBwcm9jZXNzLmN3ZCgpLFxuICBjb2xsZWN0aW9uPzogc3RyaW5nXG4pIHtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgY29uc3QgZnMgPSByZXF1aXJlKFwiZnNcIik7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG4gIGNvbnN0IHBhdGggPSByZXF1aXJlKFwicGF0aFwiKTtcblxuICBmdW5jdGlvbiBlbnN1cmVEaXJlY3RvcnlFeGlzdGVuY2UoZmlsZVBhdGg6IHN0cmluZykge1xuICAgIGNvbnN0IGRpcm5hbWU6IHN0cmluZyA9IHBhdGguZGlybmFtZShmaWxlUGF0aCkgYXMgc3RyaW5nO1xuICAgIGlmIChmcy5leGlzdHNTeW5jKGRpcm5hbWUpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgZW5zdXJlRGlyZWN0b3J5RXhpc3RlbmNlKGRpcm5hbWUpO1xuICAgIGZzLm1rZGlyU3luYyhkaXJuYW1lKTtcbiAgfVxuXG4gIGluZGV4ZXMuZm9yRWFjaCgoaW5kZXgpID0+IHtcbiAgICBjb25zdCBmaWxlID0gcGF0aC5yZXNvbHZlKFxuICAgICAgcGF0aC5qb2luKFxuICAgICAgICBwLFxuICAgICAgICBgLi9NRVRBLUlORi9zdGF0ZWRiL2NvdWNoZGIvJHtjb2xsZWN0aW9uID8gYGNvbGxlY3Rpb25zLyR7Y29sbGVjdGlvbn0vYCA6IFwiXCJ9aW5kZXhlcy8ke2luZGV4Lm5hbWV9Lmpzb25gXG4gICAgICApXG4gICAgKTtcbiAgICBlbnN1cmVEaXJlY3RvcnlFeGlzdGVuY2UoZmlsZSk7XG4gICAgZnMud3JpdGVGaWxlU3luYyhmaWxlLCBKU09OLnN0cmluZ2lmeShpbmRleCwgdW5kZWZpbmVkLCAyKSk7XG4gIH0pO1xufVxuIiwiaW1wb3J0IHsgQmFzZU1vZGVsLCBjb2x1bW4sIHBrIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBtb2RlbCwgdHlwZSBNb2RlbEFyZywgcmVxdWlyZWQgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBkZXNjcmlwdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBJZGVudGl0eSBjcmVkZW50aWFsIG1vZGVsIHN0b3JpbmcgY3J5cHRvZ3JhcGhpYyBtYXRlcmlhbHNcbiAqIEBzdW1tYXJ5IEhvbGRzIGNlcnRpZmljYXRlIGNoYWluIGFuZCBwcml2YXRlIGtleSBpbmZvcm1hdGlvbiBmb3IgYSBGYWJyaWMgaWRlbnRpdHksIG1hbmFnZWQgYXMgYSBzZXBhcmF0ZSBlbnRpdHkgbGlua2VkIGZyb20gSWRlbnRpdHlcbiAqIEBwYXJhbSB7TW9kZWxBcmc8SWRlbnRpdHlDcmVkZW50aWFscz59IFthcmddIC0gT3B0aW9uYWwgaW5pdGlhbGl6YXRpb24gb2JqZWN0IHVzZWQgdG8gcG9wdWxhdGUgbW9kZWwgZmllbGRzXG4gKiBAY2xhc3MgSWRlbnRpdHlDcmVkZW50aWFsc1xuICogQGV4YW1wbGVcbiAqIC8vIENyZWF0ZSBjcmVkZW50aWFscyBlbnRyeVxuICogY29uc3QgY3JlZHMgPSBuZXcgSWRlbnRpdHlDcmVkZW50aWFscyh7IGlkOiBcImNyZWRzMVwiLCBjZXJ0aWZpY2F0ZTogXCIuLi5cIiwgcm9vdENlcnRpZmljYXRlOiBcIi4uLlwiLCBwcml2YXRlS2V5OiBcIi4uLlwiIH0pO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBBcHBcbiAqICAgcGFydGljaXBhbnQgTW9kZWwgYXMgSWRlbnRpdHlDcmVkZW50aWFsc1xuICogICBBcHAtPj5Nb2RlbDogbmV3IElkZW50aXR5Q3JlZGVudGlhbHMoeyBpZCwgY2VydGlmaWNhdGUsIHJvb3RDZXJ0aWZpY2F0ZSwgcHJpdmF0ZUtleSB9KVxuICogICBNb2RlbC0tPj5BcHA6IGluc3RhbmNlXG4gKiBAc2VlIG1vZGVsXG4gKi9cbkBtb2RlbCgpXG5leHBvcnQgY2xhc3MgSWRlbnRpdHlDcmVkZW50aWFscyBleHRlbmRzIEJhc2VNb2RlbCB7XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVW5pcXVlIGlkZW50aWZpZXIgb2YgdGhlIGNyZWRlbnRpYWxzIHJlY29yZFxuICAgKiBAc3VtbWFyeSBQcmltYXJ5IGtleSBmb3IgcmVmZXJlbmNpbmcgdGhpcyBjcmVkZW50aWFscyBlbnRyeVxuICAgKi9cbiAgQGRlc2NyaXB0aW9uKFwiVW5pcXVlIGlkZW50aWZpZXIgb2YgdGhlIGNyZWRlbnRpYWxzIHJlY29yZFwiKVxuICBAY29sdW1uKClcbiAgQHBrKClcbiAgaWQhOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQRU0tZW5jb2RlZCBYLjUwOSBjZXJ0aWZpY2F0ZSBmb3IgdGhlIGlkZW50aXR5XG4gICAqIEBzdW1tYXJ5IExlYWYgY2VydGlmaWNhdGUgYXNzb2NpYXRlZCB3aXRoIHRoZSBpZGVudGl0eVxuICAgKi9cbiAgQGRlc2NyaXB0aW9uKFwiUEVNLWVuY29kZWQgWC41MDkgY2VydGlmaWNhdGUgZm9yIHRoZSBpZGVudGl0eVwiKVxuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgY2VydGlmaWNhdGUhOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQRU0tZW5jb2RlZCByb290IG9yIGludGVybWVkaWF0ZSBjZXJ0aWZpY2F0ZVxuICAgKiBAc3VtbWFyeSBSb290IG9mIHRydXN0IHVzZWQgdG8gdmFsaWRhdGUgdGhlIGxlYWYgY2VydGlmaWNhdGVcbiAgICovXG4gIEBkZXNjcmlwdGlvbihcIlBFTS1lbmNvZGVkIHJvb3Qgb3IgaW50ZXJtZWRpYXRlIGNlcnRpZmljYXRlXCIpXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICByb290Q2VydGlmaWNhdGUhOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQRU0tZW5jb2RlZCBwcml2YXRlIGtleSBtYXRlcmlhbFxuICAgKiBAc3VtbWFyeSBQcml2YXRlIGtleSBjb3JyZXNwb25kaW5nIHRvIHRoZSBpZGVudGl0eSBjZXJ0aWZpY2F0ZVxuICAgKi9cbiAgQGRlc2NyaXB0aW9uKFwiUEVNLWVuY29kZWQgcHJpdmF0ZSBrZXlcIilcbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIHByaXZhdGVLZXkhOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IoYXJnPzogTW9kZWxBcmc8SWRlbnRpdHlDcmVkZW50aWFscz4pIHtcbiAgICBzdXBlcihhcmcpO1xuICB9XG59XG4iLCIvKipcbiAqIEBkZXNjcmlwdGlvbiBLZXlzIHVzZWQgdG8gbWFyayBGYWJyaWMtc3BlY2lmaWMgbW9kZWwgbWV0YWRhdGFcbiAqIEBzdW1tYXJ5IEVudW1lcmF0aW9uIG9mIHNwZWNpYWwga2V5cyB1c2VkIGJ5IHRoZSBzZXJpYWxpemF0aW9uIGxheWVyIHRvIHBlcnNpc3QgRmFicmljLXJlbGF0ZWQgZmxhZ3Mgb24gbW9kZWxzXG4gKiBAZW51bSB7c3RyaW5nfVxuICogQHJlYWRvbmx5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBlbnVtIEZhYnJpY01vZGVsS2V5cyB7XG4gIC8qKiBQcml2YXRlIGRhdGEgbWFya2VyIHVzZWQgdG8gdGFnIHByb3BlcnRpZXMgb3IgbW9kZWxzIGZvciBGYWJyaWMgcHJpdmF0ZSBjb2xsZWN0aW9ucyAqL1xuICBQUklWQVRFID0gXCJwcml2YXRlXCIsXG4gIFNIQVJFRCA9IFwic2hhcmVkXCIsXG4gIC8qKiBOYW1lc3BhY2UgcHJlZml4IHVzZWQgZm9yIEZhYnJpYy1zcGVjaWZpYyBtZXRhZGF0YSBrZXlzICovXG4gIEZBQlJJQyA9IFwiZmFicmljXCIsXG4gIE9XTkVEX0JZID0gXCJvd25lZC1ieVwiLFxuICBUUkFOU0FDVElPTl9JRCA9IFwidHJhbnNhY3Rpb24taWRcIixcbiAgTUlSUk9SID0gXCJtaXJyb3JcIixcbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIFN1cHBvcnRlZCBpZGVudGl0eSB0eXBlcyBmb3IgRmFicmljIGNyZWRlbnRpYWxzXG4gKiBAc3VtbWFyeSBFbnVtZXJhdGlvbiBvZiBpZGVudGl0eSBmb3JtYXRzIHJlY29nbml6ZWQgYnkgdGhpcyBsaWJyYXJ5XG4gKiBAZW51bSB7c3RyaW5nfVxuICogQHJlYWRvbmx5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBlbnVtIElkZW50aXR5VHlwZSB7XG4gIC8qKiBTdGFuZGFyZCBYLjUwOSBpZGVudGl0eSBmb3JtYXQgdXNlZCBieSBIeXBlcmxlZGdlciBGYWJyaWMgKi9cbiAgWDUwOSA9IFwiWC41MDlcIixcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU3RyaW5nIGlkZW50aWZpZXIgZm9yIHRoZSBGYWJyaWMgYWRhcHRlciBmbGF2b3VyXG4gKiBAc3VtbWFyeSBVc2VkIHRvIHRhZyBhZGFwdGVycy9yZXBvc2l0b3JpZXMgdGhhdCBvcGVyYXRlIGFnYWluc3QgSHlwZXJsZWRnZXIgRmFicmljXG4gKiBAY29uc3QgRmFicmljRmxhdm91clxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgY29uc3QgRmFicmljRmxhdm91ciA9IFwiaGxmLWZhYnJpY1wiO1xuIiwiaW1wb3J0IHtcbiAgQmFzZU1vZGVsLFxuICBDYXNjYWRlLFxuICBjb2x1bW4sXG4gIGluZGV4LFxuICBvbmVUb09uZSxcbiAgcGssXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgbW9kZWwsIHR5cGUgTW9kZWxBcmcsIHJlcXVpcmVkIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgSWRlbnRpdHlDcmVkZW50aWFscyB9IGZyb20gXCIuL0lkZW50aXR5Q3JlZGVudGlhbHNcIjtcbmltcG9ydCB7IElkZW50aXR5VHlwZSB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGRlc2NyaXB0aW9uIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIElkZW50aXR5IG1vZGVsIHJlcHJlc2VudGluZyBhIEZhYnJpYyB3YWxsZXQgZW50cnlcbiAqIEBzdW1tYXJ5IEVuY2Fwc3VsYXRlcyBhbiBpZGVudGl0eSBzdG9yZWQgaW4gYSBGYWJyaWMgd2FsbGV0LCBpbmNsdWRpbmcgaXRzIE1TUCBpZGVudGlmaWVyLCBjcmVkZW50aWFsIGxpbmthZ2UsIGFuZCB0eXBlIGluZm9ybWF0aW9uLiBCdWlsdCBvbiBCYXNlTW9kZWwgZm9yIGludGVncmF0aW9uIHdpdGggRGVjYWYgdmFsaWRhdGlvbiBhbmQgcGVyc2lzdGVuY2UuXG4gKiBAcGFyYW0ge01vZGVsQXJnPElkZW50aXR5Pn0gW2FyZ10gLSBPcHRpb25hbCBpbml0aWFsaXphdGlvbiBvYmplY3QgdXNlZCB0byBwb3B1bGF0ZSBtb2RlbCBmaWVsZHNcbiAqIEBjbGFzcyBJZGVudGl0eVxuICogQGV4YW1wbGVcbiAqIC8vIENyZWF0ZSBhIG5ldyBpZGVudGl0eSByZWZlcmVuY2luZyBleGlzdGluZyBjcmVkZW50aWFsc1xuICogY29uc3QgaWQgPSBuZXcgSWRlbnRpdHkoeyBpZDogXCJ1c2VyMVwiLCBtc3BJZDogXCJPcmcxTVNQXCIsIHR5cGU6IElkZW50aXR5VHlwZS5YNTA5IH0pO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBBcHBcbiAqICAgcGFydGljaXBhbnQgTW9kZWwgYXMgSWRlbnRpdHlcbiAqICAgQXBwLT4+TW9kZWw6IG5ldyBJZGVudGl0eSh7IGlkLCBtc3BJZCwgdHlwZSB9KVxuICogICBNb2RlbC0tPj5BcHA6IGluc3RhbmNlXG4gKi9cbkBtb2RlbCgpXG5leHBvcnQgY2xhc3MgSWRlbnRpdHkgZXh0ZW5kcyBCYXNlTW9kZWwge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVuaXF1ZSBpZGVudGlmaWVyIG9mIHRoZSBpZGVudGl0eSBpbiB0aGUgd2FsbGV0XG4gICAqIEBzdW1tYXJ5IFByaW1hcnkga2V5IHVzZWQgdG8gcmVmZXJlbmNlIHRoaXMgaWRlbnRpdHkgcmVjb3JkXG4gICAqL1xuICBAZGVzY3JpcHRpb24oXCJVbmlxdWUgaWRlbnRpZmllciBvZiB0aGUgaWRlbnRpdHlcIilcbiAgQHBrKClcbiAgaWQhOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMaW5rIHRvIHRoZSBpZGVudGl0eSBjcmVkZW50aWFscyBzdG9yZWQgc2VwYXJhdGVseVxuICAgKiBAc3VtbWFyeSBPbmUtdG8tb25lIHJlbGF0aW9uc2hpcCB0byB0aGUgY3JlZGVudGlhbHMgZW50aXR5OyBjYXNjYWRlcyBvbiB1cGRhdGUgYW5kIGRlbGV0ZVxuICAgKi9cbiAgQG9uZVRvT25lKElkZW50aXR5Q3JlZGVudGlhbHMsIHtcbiAgICB1cGRhdGU6IENhc2NhZGUuQ0FTQ0FERSxcbiAgICBkZWxldGU6IENhc2NhZGUuQ0FTQ0FERSxcbiAgfSlcbiAgY3JlZGVudGlhbHMhOiBJZGVudGl0eUNyZWRlbnRpYWxzO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gTWVtYmVyc2hpcCBTZXJ2aWNlIFByb3ZpZGVyIGlkZW50aWZpZXJcbiAgICogQHN1bW1hcnkgVGhlIE1TUCBJRCBjb3JyZXNwb25kaW5nIHRvIHRoZSBvcmdhbml6YXRpb24gdGhhdCBpc3N1ZWQgdGhpcyBpZGVudGl0eVxuICAgKi9cbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIEBpbmRleCgpXG4gIG1zcElkITogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVHlwZSBvZiBpZGVudGl0eVxuICAgKiBAc3VtbWFyeSBJbmRpY2F0ZXMgdGhlIGlkZW50aXR5IGVuY29kaW5nL2Zvcm1hdDsgZGVmYXVsdHMgdG8gWC41MDlcbiAgICovXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICB0eXBlOiBJZGVudGl0eVR5cGUgPSBJZGVudGl0eVR5cGUuWDUwOTtcblxuICBjb25zdHJ1Y3Rvcihhcmc6IE1vZGVsQXJnPElkZW50aXR5Pikge1xuICAgIHN1cGVyKGFyZyk7XG4gIH1cbn1cbiIsImltcG9ydCB7IHN0cmluZ0Zvcm1hdCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IExvZ2dlciwgTWluaUxvZ2dlciB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgSWRlbnRpdHksIFNpZ25lciwgc2lnbmVycyB9IGZyb20gXCJAaHlwZXJsZWRnZXIvZmFicmljLWdhdGV3YXlcIjtcbmltcG9ydCB7IENyeXB0b1NldHRpbmcsIElDcnlwdG9TdWl0ZSwgVXNlciB9IGZyb20gXCJmYWJyaWMtY29tbW9uXCI7XG5pbXBvcnQgeyBIU01PcHRpb25zIH0gZnJvbSBcIi4uL3NoYXJlZC90eXBlc1wiO1xuaW1wb3J0IHsgbm9ybWFsaXplSW1wb3J0IH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgY3J5cHRvLCB7IFg1MDlDZXJ0aWZpY2F0ZSB9IGZyb20gXCJjcnlwdG9cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ29yZSB1dGlsaXRpZXMgZm9yIGludGVyYWN0aW5nIHdpdGggZmlsZXMsIGNyeXB0byBpZGVudGl0aWVzLCBhbmQgRmFicmljIFNESyBoZWxwZXJzXG4gKiBAc3VtbWFyeSBQcm92aWRlcyBzdGF0aWMgaGVscGVyIG1ldGhvZHMgdG8gcmVhZCBjcmVkZW50aWFscyBhbmQga2V5cyBmcm9tIGRpc2sgb3IgcmF3IGNvbnRlbnQsIGNvbnN0cnVjdCBGYWJyaWMgZ2F0ZXdheSBJZGVudGl0aWVzIGFuZCBTaWduZXJzLCBhbmQgcGVyZm9ybSBjb21tb24gZmlsZXN5c3RlbSBvcGVyYXRpb25zIHVzZWQgYnkgdGhlIEZhYnJpYyBjbGllbnQgdG9vbGluZy5cbiAqIEBjbGFzcyBDb3JlVXRpbHNcbiAqIEBleGFtcGxlXG4gKiAvLyBSZWFkIGFuIGlkZW50aXR5IGFuZCBzaWduZXIgZnJvbSBkaXJlY3Rvcmllc1xuICogY29uc3QgaWRlbnRpdHkgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0SWRlbnRpdHkoJ09yZzFNU1AnLCAnL21zcC9zaWduY2VydHMnKTtcbiAqIGNvbnN0IHNpZ25lciA9IGF3YWl0IENvcmVVdGlscy5nZXRTaWduZXIoJy9tc3Ava2V5c3RvcmUnKTtcbiAqIC8vIEJ1aWxkIGEgQ0EgdXNlclxuICogY29uc3QgdXNlciA9IGF3YWl0IENvcmVVdGlscy5nZXRDQVVzZXIoJ2FwcFVzZXInLCBwZW1LZXksIHBlbUNlcnQsICdPcmcxTVNQJyk7XG4gKi9cbmV4cG9ydCBjbGFzcyBDb3JlVXRpbHMge1xuICBwcml2YXRlIHN0YXRpYyBsb2dnZXI6IExvZ2dlciA9IG5ldyBNaW5pTG9nZ2VyKENvcmVVdGlscy5uYW1lKTtcblxuICBwcml2YXRlIHN0YXRpYyBjcnlwdG9TdWl0ZTogSUNyeXB0b1N1aXRlO1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IoKSB7fVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVzb2x2ZSBmaWxlIGNvbnRlbnQgZnJvbSBhIHBhdGggb3IgcmV0dXJuIHByb3ZpZGVkIHJhdyBjb250ZW50XG4gICAqIEBzdW1tYXJ5IElmIHRoZSBpbnB1dCBpcyBhIFVpbnQ4QXJyYXkgb3IgUEVNIGNvbnRlbnQsIHJldHVybnMgaXQgYXMtaXM7IG90aGVyd2lzZSB1c2VzIGEgcHJvdmlkZWQgYXN5bmMgZmlsZVJlYWRlciB0byBsb2FkIHRoZSBjb250ZW50IGZyb20gZGlzay5cbiAgICogQHBhcmFtIHtzdHJpbmd8VWludDhBcnJheX0gY29udGVudE9yUGF0aCAtIEVpdGhlciBhIHJhdyBjb250ZW50IGJ1ZmZlci9zdHJpbmcgb3IgYSBmaWxlc3lzdGVtIHBhdGhcbiAgICogQHBhcmFtIHtmdW5jdGlvbihzdHJpbmcpOiBQcm9taXNlPHN0cmluZ3xVaW50OEFycmF5fEJ1ZmZlcj59IGZpbGVSZWFkZXIgLSBBc3luYyBmdW5jdGlvbiB0byByZWFkIGZpbGUgY29udGVudCB3aGVuIGEgcGF0aCBpcyBwcm92aWRlZFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZ3xVaW50OEFycmF5fEJ1ZmZlcj59IFRoZSBjb250ZW50IHRvIGJlIHVzZWQgZG93bnN0cmVhbVxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgYXN5bmMgY29udGVudE9mTG9hZEZpbGUoXG4gICAgY29udGVudE9yUGF0aDogc3RyaW5nIHwgVWludDhBcnJheSxcbiAgICBmaWxlUmVhZGVyOiAocGF0aDogc3RyaW5nKSA9PiBQcm9taXNlPHN0cmluZyB8IFVpbnQ4QXJyYXkgfCBCdWZmZXI+XG4gICkge1xuICAgIGlmIChjb250ZW50T3JQYXRoIGluc3RhbmNlb2YgVWludDhBcnJheSkgcmV0dXJuIGNvbnRlbnRPclBhdGg7XG4gICAgaWYgKFxuICAgICAgY29udGVudE9yUGF0aC5tYXRjaChcbiAgICAgICAgLy0tLS0tQkVHSU4gKENFUlRJRklDQVRFfEtFWXxQUklWQVRFIEtFWSktLS0tLS4rPy0tLS0tRU5EIFxcMS0tLS0tJC9nbXNcbiAgICAgIClcbiAgICApXG4gICAgICByZXR1cm4gY29udGVudE9yUGF0aDtcbiAgICByZXR1cm4gYXdhaXQgZmlsZVJlYWRlcihjb250ZW50T3JQYXRoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVhZCBmaWxlIGNvbnRlbnQgZnJvbSBhIHBhdGggb3IgcmV0dXJuIHByb3ZpZGVkIEJ1ZmZlclxuICAgKiBAc3VtbWFyeSBDb252ZW5pZW5jZSB3cmFwcGVyIHRoYXQgbG9hZHMgYSBmaWxlIHVzaW5nIGZzLnByb21pc2VzIHdoZW4gYSBwYXRoIHN0cmluZyBpcyBwcm92aWRlZDsgb3RoZXJ3aXNlIHJldHVybnMgdGhlIGdpdmVuIEJ1ZmZlciBkaXJlY3RseS5cbiAgICogQHBhcmFtIHtzdHJpbmd8QnVmZmVyfSBjb250ZW50T3JQYXRoIC0gUGF0aCB0byBhIGZpbGUgb24gZGlzayBvciBhbiBhbHJlYWR5LWxvYWRlZCBCdWZmZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmd8VWludDhBcnJheXxCdWZmZXI+fSBUaGUgZmlsZSBjb250ZW50IGFzIGEgQnVmZmVyL3N0cmluZyBkZXBlbmRpbmcgb24gcmVhZGVyXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgcmVhZEZpbGUoY29udGVudE9yUGF0aDogc3RyaW5nIHwgQnVmZmVyKSB7XG4gICAgaWYgKHR5cGVvZiBjb250ZW50T3JQYXRoICE9PSBcInN0cmluZ1wiKSByZXR1cm4gY29udGVudE9yUGF0aDtcblxuICAgIGNvbnN0IGZpbGVSZWFkZXIgPSBhc3luYyAocGF0aDogc3RyaW5nKSA9PiB7XG4gICAgICBjb25zdCB7IHByb21pc2VzIH0gPSBhd2FpdCBub3JtYWxpemVJbXBvcnQoaW1wb3J0KFwiZnNcIikpO1xuICAgICAgcmV0dXJuIGF3YWl0IHByb21pc2VzLnJlYWRGaWxlKHBhdGgpO1xuICAgIH07XG5cbiAgICByZXR1cm4gYXdhaXQgZmlsZVJlYWRlcihjb250ZW50T3JQYXRoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlIGEgRmFicmljIENBIFVzZXIgb2JqZWN0IHdpdGggZW5yb2xsbWVudFxuICAgKiBAc3VtbWFyeSBDb25zdHJ1Y3RzIGEgZmFicmljLWNvbW1vbiBVc2VyLCBzZXRzIGEgY3J5cHRvIHN1aXRlLCBpbXBvcnRzIHRoZSBwcm92aWRlZCBwcml2YXRlIGtleSwgYW5kIHNldHMgZW5yb2xsbWVudCB3aXRoIGNlcnRpZmljYXRlIGFuZCBNU1AgSUQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1c2VyTmFtZSAtIFRoZSB1c2VyIG5hbWUgZm9yIHRoZSBDQSB1c2VyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwcml2YXRlS2V5IC0gUEVNLWVuY29kZWQgcHJpdmF0ZSBrZXlcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNlcnRpZmljYXRlIC0gUEVNLWVuY29kZWQgWC41MDkgY2VydGlmaWNhdGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1zcElkIC0gTWVtYmVyc2hpcCBTZXJ2aWNlIFByb3ZpZGVyIGlkZW50aWZpZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTxVc2VyPn0gVGhlIGVucm9sbGVkIEZhYnJpYyBVc2VyIGluc3RhbmNlXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2V0Q0FVc2VyKFxuICAgIHVzZXJOYW1lOiBzdHJpbmcsXG4gICAgcHJpdmF0ZUtleTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIGNlcnRpZmljYXRlOiBzdHJpbmcsXG4gICAgbXNwSWQ6IHN0cmluZyxcbiAgICBvcHRpb25zPzogeyBoc20/OiBIU01PcHRpb25zIH1cbiAgKTogUHJvbWlzZTxVc2VyPiB7XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoXG4gICAgICBzdHJpbmdGb3JtYXQoXG4gICAgICAgIFwiQ3JlYXRpbmcgQ0EgezB9IHVzZXIgezF9IHdpdGggY2VydGlmaWNhdGUgezJ9XCIsXG4gICAgICAgIG1zcElkLFxuICAgICAgICB1c2VyTmFtZSxcbiAgICAgICAgY2VydGlmaWNhdGVcbiAgICAgIClcbiAgICApO1xuICAgIGNvbnN0IHVzZXIgPSBuZXcgVXNlcih1c2VyTmFtZSk7XG4gICAgY29uc3QgY29uZmlnID0gb3B0aW9ucz8uaHNtXG4gICAgICA/IHtcbiAgICAgICAgICBzb2Z0d2FyZTogZmFsc2UsXG4gICAgICAgICAgbGliOiBvcHRpb25zLmhzbS5saWJyYXJ5LFxuICAgICAgICAgIHNsb3Q6IG9wdGlvbnMuaHNtLnNsb3QsXG4gICAgICAgICAgbGFiZWw6IG9wdGlvbnMuaHNtLnRva2VuTGFiZWwsXG4gICAgICAgICAgcGluOiBTdHJpbmcob3B0aW9ucy5oc20ucGluKSxcbiAgICAgICAgfVxuICAgICAgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgY3J5cHRvU3VpdGUgPSB0aGlzLmdldENyeXB0b1N1aXRlKGNvbmZpZyk7XG5cbiAgICB1c2VyLnNldENyeXB0b1N1aXRlKGNyeXB0b1N1aXRlKTtcbiAgICBjb25zdCBlbnJvbGxtZW50S2V5ID0gb3B0aW9ucz8uaHNtXG4gICAgICA/IGF3YWl0IHRoaXMuZ2V0SFNNRW5yb2xsbWVudEtleShjcnlwdG9TdWl0ZSwgY2VydGlmaWNhdGUsIG9wdGlvbnMuaHNtKVxuICAgICAgOiB0aGlzLmdldFNvZnR3YXJlRW5yb2xsbWVudEtleShjcnlwdG9TdWl0ZSwgcHJpdmF0ZUtleSk7XG4gICAgYXdhaXQgdXNlci5zZXRFbnJvbGxtZW50KGVucm9sbG1lbnRLZXksIGNlcnRpZmljYXRlLCBtc3BJZCk7XG4gICAgcmV0dXJuIHVzZXI7XG4gIH1cblxuICBzdGF0aWMgZ2V0Q3J5cHRvU3VpdGUob3B0aW9ucz86IENyeXB0b1NldHRpbmcpOiBJQ3J5cHRvU3VpdGUge1xuICAgIGlmICghb3B0aW9ucykgcmV0dXJuIFVzZXIubmV3Q3J5cHRvU3VpdGUoKTtcbiAgICBpZiAoQ29yZVV0aWxzLmNyeXB0b1N1aXRlKSByZXR1cm4gQ29yZVV0aWxzLmNyeXB0b1N1aXRlO1xuXG4gICAgQ29yZVV0aWxzLmNyeXB0b1N1aXRlID0gVXNlci5uZXdDcnlwdG9TdWl0ZShvcHRpb25zKTtcbiAgICByZXR1cm4gQ29yZVV0aWxzLmNyeXB0b1N1aXRlO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0U29mdHdhcmVFbnJvbGxtZW50S2V5KFxuICAgIGNyeXB0b1N1aXRlOiBhbnksXG4gICAgcHJpdmF0ZUtleT86IHN0cmluZ1xuICApIHtcbiAgICBpZiAoIXByaXZhdGVLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJQcml2YXRlIGtleSBtdXN0IGJlIHByb3ZpZGVkIHdoZW4gSFNNIGNvbmZpZ3VyYXRpb24gaXMgbm90IHN1cHBsaWVkXCJcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBjcnlwdG9TdWl0ZS5jcmVhdGVLZXlGcm9tUmF3KHByaXZhdGVLZXkpO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgYXN5bmMgZ2V0SFNNRW5yb2xsbWVudEtleShcbiAgICBjcnlwdG9TdWl0ZTogYW55LFxuICAgIGNlcnRpZmljYXRlOiBzdHJpbmcsXG4gICAgaHNtOiBIU01PcHRpb25zXG4gICkge1xuICAgIGNvbnN0IHNraSA9XG4gICAgICBoc20ua2V5SWRIZXggJiYgaHNtLmtleUlkSGV4LnRyaW0oKS5sZW5ndGggPiAwXG4gICAgICAgID8gQnVmZmVyLmZyb20oaHNtLmtleUlkSGV4LCBcImhleFwiKVxuICAgICAgICA6IGF3YWl0IHRoaXMuZ2V0Q2VydGlmaWNhdGVTS0koY2VydGlmaWNhdGUpO1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IGNyeXB0b1N1aXRlLmdldEtleShza2kpO1xuICAgIGlmICgha2V5IHx8ICh0eXBlb2Yga2V5LmlzUHJpdmF0ZSA9PT0gXCJmdW5jdGlvblwiICYmICFrZXkuaXNQcml2YXRlKCkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbmFibGUgdG8gcmVzb2x2ZSBwcml2YXRlIGtleSBmcm9tIEhTTVwiKTtcbiAgICB9XG4gICAgcmV0dXJuIGtleTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBnZXRDZXJ0aWZpY2F0ZVNLSShjZXJ0aWZpY2F0ZTogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBjb25zdCB4NTA5ID0gbmV3IFg1MDlDZXJ0aWZpY2F0ZShjZXJ0aWZpY2F0ZSk7XG4gICAgY29uc3QgandrID0geDUwOS5wdWJsaWNLZXkuZXhwb3J0KHsgZm9ybWF0OiBcImp3a1wiIH0pO1xuICAgIGNvbnN0IHByZWZpeCA9IEJ1ZmZlci5mcm9tKFsweDA0XSk7XG4gICAgY29uc3QgeCA9IEJ1ZmZlci5mcm9tKGp3ay54IHx8IFwiXCIsIFwiYmFzZTY0dXJsXCIpO1xuICAgIGNvbnN0IHkgPSBCdWZmZXIuZnJvbShqd2sueSB8fCBcIlwiLCBcImJhc2U2NHVybFwiKTtcbiAgICByZXR1cm4gY3J5cHRvXG4gICAgICAuY3JlYXRlSGFzaChcInNoYTI1NlwiKVxuICAgICAgLnVwZGF0ZShCdWZmZXIuY29uY2F0KFtwcmVmaXgsIHgsIHldKSlcbiAgICAgIC5kaWdlc3QoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQnVpbGQgYSBGYWJyaWMgR2F0ZXdheSBJZGVudGl0eSBmcm9tIGFuIE1TUCBJRCBhbmQgY2VydGlmaWNhdGVcbiAgICogQHN1bW1hcnkgUmVhZHMgYSBjZXJ0aWZpY2F0ZSBmcm9tIGEgZGlyZWN0b3J5IHBhdGggb3IgYWNjZXB0cyByYXcgY29udGVudCBhbmQgcmV0dXJucyBhbiBJZGVudGl0eSBvYmplY3Qgc3VpdGFibGUgZm9yIHRoZSBGYWJyaWMgR2F0ZXdheS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG1zcElkIC0gTWVtYmVyc2hpcCBTZXJ2aWNlIFByb3ZpZGVyIElEXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjZXJ0RGlyZWN0b3J5UGF0aCAtIFBhdGggdG8gYSBkaXJlY3RvcnkgY29udGFpbmluZyB0aGUgY2VydGlmaWNhdGUgZmlsZSwgb3IgUEVNIGNvbnRlbnRcbiAgICogQHJldHVybiB7UHJvbWlzZTxJZGVudGl0eT59IFRoZSBpZGVudGl0eSBjb250YWluaW5nIG1zcElkIGFuZCBjZXJ0aWZpY2F0ZSBjcmVkZW50aWFsc1xuICAgKi9cbiAgc3RhdGljIGFzeW5jIGdldElkZW50aXR5KFxuICAgIG1zcElkOiBzdHJpbmcsXG4gICAgY2VydERpcmVjdG9yeVBhdGg6IHN0cmluZ1xuICApOiBQcm9taXNlPElkZW50aXR5PiB7XG4gICAgY29uc3QgaWRlbnRpdHlGaWxlUmVhZGVyID0gYXN5bmMgKHBhdGg6IHN0cmluZykgPT4ge1xuICAgICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICAgIGNvbnN0IGNlcnRQYXRoID0gYXdhaXQgdGhpcy5nZXRGaXJzdERpckZpbGVOYW1lKHBhdGgpO1xuICAgICAgY29uc3QgY3JlZGVudGlhbHMgPSBhd2FpdCBwcm9taXNlcy5yZWFkRmlsZShjZXJ0UGF0aCk7XG4gICAgICByZXR1cm4gY3JlZGVudGlhbHM7XG4gICAgfTtcblxuICAgIGNvbnN0IGNyZWRlbnRpYWxzOiBVaW50OEFycmF5ID0gKGF3YWl0IHRoaXMuY29udGVudE9mTG9hZEZpbGUoXG4gICAgICBjZXJ0RGlyZWN0b3J5UGF0aCxcbiAgICAgIGlkZW50aXR5RmlsZVJlYWRlclxuICAgICkpIGFzIFVpbnQ4QXJyYXk7XG5cbiAgICByZXR1cm4geyBtc3BJZCwgY3JlZGVudGlhbHMgfTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBnZXRGaXJzdERpckZpbGVOYW1lKGRpclBhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICBjb25zdCB7IGpvaW4gfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJwYXRoXCIpKTtcbiAgICBjb25zdCBmaWxlcyA9IGF3YWl0IHByb21pc2VzLnJlYWRkaXIoZGlyUGF0aCk7XG4gICAgcmV0dXJuIGpvaW4oZGlyUGF0aCwgZmlsZXNbMF0pO1xuICB9XG5cbiAgc3RhdGljIGFzeW5jIGdldEZpcnN0RGlyRmlsZU5hbWVDb250ZW50KGRpclBhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICBjb25zdCB7IGpvaW4gfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJwYXRoXCIpKTtcbiAgICBjb25zdCBmaWxlcyA9IGF3YWl0IHByb21pc2VzLnJlYWRkaXIoZGlyUGF0aCk7XG4gICAgcmV0dXJuIChhd2FpdCBwcm9taXNlcy5yZWFkRmlsZShqb2luKGRpclBhdGgsIGZpbGVzWzBdKSkpLnRvU3RyaW5nKCk7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgZ2V0RmlsZUNvbnRlbnQoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICByZXR1cm4gKGF3YWl0IHByb21pc2VzLnJlYWRGaWxlKGZpbGVQYXRoKSkudG9TdHJpbmcoKTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBnZXRTaWduZXIoa2V5RGlyZWN0b3J5UGF0aDogc3RyaW5nKTogUHJvbWlzZTxTaWduZXI+IHtcbiAgICBjb25zdCBzaWduZXJGaWxlUmVhZGVyID0gYXN5bmMgKHBhdGg6IHN0cmluZykgPT4ge1xuICAgICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICAgIGNvbnN0IGtleVBhdGggPSBhd2FpdCB0aGlzLmdldEZpcnN0RGlyRmlsZU5hbWUocGF0aCk7XG4gICAgICByZXR1cm4gYXdhaXQgcHJvbWlzZXMucmVhZEZpbGUoa2V5UGF0aCk7XG4gICAgfTtcblxuICAgIGNvbnN0IHByaXZhdGVLZXlQZW0gPSAoYXdhaXQgdGhpcy5jb250ZW50T2ZMb2FkRmlsZShcbiAgICAgIGtleURpcmVjdG9yeVBhdGgsXG4gICAgICBzaWduZXJGaWxlUmVhZGVyXG4gICAgKSkgYXMgQnVmZmVyO1xuICAgIGNvbnN0IHByaXZhdGVLZXkgPSBhd2FpdCB0aGlzLmV4dHJhY3RQcml2YXRlS2V5KHByaXZhdGVLZXlQZW0pO1xuICAgIGNvbnN0IGtleXMgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHByaXZhdGVLZXkpO1xuICAgIGNvbnN0IGsgPSAocHJpdmF0ZUtleSBhcyBhbnkpW2tleXNbMF1dO1xuICAgIC8vIC0tXG5cbiAgICByZXR1cm4gc2lnbmVycy5uZXdQcml2YXRlS2V5U2lnbmVyKGsgYXMgYW55KTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGFzeW5jIGV4dHJhY3RQcml2YXRlS2V5KHBlbTogQnVmZmVyKSB7XG4gICAgY29uc3QgbGliTmFtZSA9IFwiY3J5cHRvXCI7XG4gICAgbGV0IHN1YnRsZTogYW55O1xuICAgIGlmIChcbiAgICAgIChnbG9iYWxUaGlzIGFzIGFueSkud2luZG93ICYmXG4gICAgICAoKGdsb2JhbFRoaXMgYXMgYW55KS53aW5kb3cgYXMgeyBDcnlwdG86IGFueSB9KS5DcnlwdG9cbiAgICApIHtcbiAgICAgIHN1YnRsZSA9ICgoZ2xvYmFsVGhpcyBhcyBhbnkpLkNyeXB0byBhcyBhbnkpLnN1YnRsZTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbGliID0gKGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQobGliTmFtZSkpKSBhcyBhbnk7XG4gICAgICBzdWJ0bGUgPSBsaWIuc3VidGxlIHx8IGxpYi53ZWJjcnlwdG8uc3VidGxlO1xuICAgIH1cblxuICAgIGlmICghc3VidGxlKSB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgbG9hZCBTdWJ0bGVDcnlwdG8gbW9kdWxlXCIpO1xuXG4gICAgZnVuY3Rpb24gc3RyMmFiKHN0cjogc3RyaW5nKSB7XG4gICAgICBjb25zdCBidWYgPSBuZXcgQXJyYXlCdWZmZXIoc3RyLmxlbmd0aCk7XG4gICAgICBjb25zdCBidWZWaWV3ID0gbmV3IFVpbnQ4QXJyYXkoYnVmKTtcbiAgICAgIGZvciAobGV0IGkgPSAwLCBzdHJMZW4gPSBzdHIubGVuZ3RoOyBpIDwgc3RyTGVuOyBpKyspIHtcbiAgICAgICAgYnVmVmlld1tpXSA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1ZjtcbiAgICB9XG5cbiAgICBjb25zdCBzdHIgPSBwZW1cbiAgICAgIC50b1N0cmluZyhcInV0ZjhcIilcbiAgICAgIC5yZXBsYWNlKFwiLS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tXCIsIFwiXCIpXG4gICAgICAucmVwbGFjZUFsbChcIlxcblwiLCBcIlwiKVxuICAgICAgLnJlcGxhY2UoXCItLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXCIsIFwiXCIpO1xuICAgIGNvbnN0IGRlY29kZWQgPSBCdWZmZXIuZnJvbShzdHIsIFwiYmFzZTY0XCIpLnRvU3RyaW5nKFwiYmluYXJ5XCIpO1xuICAgIGNvbnN0IGJpbmFyeURlciA9IHN0cjJhYihkZWNvZGVkKTtcbiAgICBjb25zdCBrZXkgPSBhd2FpdCBzdWJ0bGUuaW1wb3J0S2V5KFxuICAgICAgXCJwa2NzOFwiLFxuICAgICAgYmluYXJ5RGVyLFxuICAgICAge1xuICAgICAgICBuYW1lOiBcIkVDRFNBXCIsXG4gICAgICAgIG5hbWVkQ3VydmU6IFwiUC0yNTZcIixcbiAgICAgIH0sXG4gICAgICB0cnVlLFxuICAgICAgW1wic2lnblwiXVxuICAgICk7XG5cbiAgICByZXR1cm4ga2V5O1xuICB9XG59XG4iLCJpbXBvcnQgKiBhcyB4NTA5IGZyb20gXCJAcGVjdWxpYXIveDUwOVwiO1xuaW1wb3J0IHsgQ3J5cHRvLCBDcnlwdG9LZXkgfSBmcm9tIFwiQHBlY3VsaWFyL3dlYmNyeXB0b1wiO1xuaW1wb3J0IHsgc3RyaW5nRm9ybWF0IH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgaXNCcm93c2VyLCBNaW5pTG9nZ2VyIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5cbmNvbnN0IGNyeXB0byA9IG5ldyBDcnlwdG8oKTtcbng1MDkuY3J5cHRvUHJvdmlkZXIuc2V0KGNyeXB0byk7XG5cbmV4cG9ydCBlbnVtIEJBU0VfQUxQSEFCRVQge1xuICBCQVNFMiA9IFwiMDFcIixcbiAgQkFTRTggPSBcIjAxMjM0NTY3XCIsXG4gIEJBU0UxMSA9IFwiMDEyMzQ1Njc4OWFcIixcbiAgQkFTRTE2ID0gXCIwMTIzNDU2Nzg5YWJjZGVmXCIsXG4gIEJBU0UzMiA9IFwiMDEyMzQ1Njc4OUFCQ0RFRkdISktNTlBRUlNUVldYWVpcIixcbiAgQkFTRTMyX1ogPSBcInlibmRyZmc4ZWprbWNwcXhvdDF1d2lzemEzNDVoNzY5XCIsXG4gIEJBU0UzNiA9IFwiMDEyMzQ1Njc4OWFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6XCIsXG4gIEJBU0U1OCA9IFwiMTIzNDU2Nzg5QUJDREVGR0hKS0xNTlBRUlNUVVZXWFlaYWJjZGVmZ2hpamttbm9wcXJzdHV2d3h5elwiLFxuICBCQVNFNjIgPSBcIjAxMjM0NTY3ODlhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaXCIsXG4gIEJBU0U2NCA9IFwiQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrL1wiLFxuICBCQVNFNjcgPSBcIkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5LV8uIX5cIixcbn1cblxuZXhwb3J0IHR5cGUga2V5T2JqZWN0ID0ge1xuICBpdjogQXJyYXlCdWZmZXI7XG4gIGtleTogQ3J5cHRvS2V5O1xufTtcblxuZXhwb3J0IGVudW0gQ1JZUFRPIHtcbiAgSEFTSCA9IFwiU0hBLTI1NlwiLFxuICBJVEVSQVRJT05TID0gMTAwMCxcbiAgS0VZTEVOR1RIID0gNDgsXG4gIERFUklWRURfSVZfTEVOR1RIID0gMTYsXG4gIERFUklWRURfS0VZX0xFTkdUSCA9IDMyLCAvLyBCZWNhdXNlIFNIQS0yNTYgdXNlZCBoYXMgYSBuYXRpdmUgc2l6ZSBvZiAzMiBieXRlc1xuICBBTEdPUllUSE0gPSBcIkFFUy1HQ01cIixcbiAgS0VZX0FMR09SWVRITSA9IFwiUEJLREYyXCIsXG59XG5cbmV4cG9ydCBjbGFzcyBCYXNlRW5jb2RlciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgYmFzZU1hcDogVWludDhBcnJheSA9IG5ldyBVaW50OEFycmF5KDI1Nik7XG4gIHByaXZhdGUgcmVhZG9ubHkgYmFzZTogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGxlYWRlcjogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IGZhY3RvcjogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGlGYWN0b3I6IG51bWJlcjtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGFscGhhYmV0OiBCQVNFX0FMUEhBQkVUKSB7XG4gICAgaWYgKHRoaXMuYWxwaGFiZXQubGVuZ3RoID49IDI1NSkgdGhyb3cgbmV3IEVycm9yKFwiQWxwaGFiZXQgdG9vIGxvbmdcIik7XG5cbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMuYmFzZU1hcC5sZW5ndGg7IGorKykgdGhpcy5iYXNlTWFwW2pdID0gMjU1O1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhbHBoYWJldC5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgeCA9IGFscGhhYmV0LmNoYXJBdChpKTtcbiAgICAgIGNvbnN0IHhjID0geC5jaGFyQ29kZUF0KDApO1xuICAgICAgaWYgKHRoaXMuYmFzZU1hcFt4Y10gIT09IDI1NSkgdGhyb3cgbmV3IEVycm9yKHggKyBcIiBpcyBhbWJpZ3VvdXNcIik7XG5cbiAgICAgIHRoaXMuYmFzZU1hcFt4Y10gPSBpO1xuICAgIH1cblxuICAgIHRoaXMuYmFzZSA9IHRoaXMuYWxwaGFiZXQubGVuZ3RoO1xuICAgIHRoaXMubGVhZGVyID0gdGhpcy5hbHBoYWJldC5jaGFyQXQoMCk7XG4gICAgdGhpcy5mYWN0b3IgPSBNYXRoLmxvZyh0aGlzLmJhc2UpIC8gTWF0aC5sb2coMjU2KTsgLy8gbG9nKEJBU0UpIC8gbG9nKDI1NiksIHJvdW5kZWQgdXBcbiAgICB0aGlzLmlGYWN0b3IgPSBNYXRoLmxvZygyNTYpIC8gTWF0aC5sb2codGhpcy5iYXNlKTsgLy8gbG9nKDI1NikgLyBsb2coQkFTRSksIHJvdW5kZWQgdXBcbiAgfVxuXG4gIGVuY29kZShzb3VyY2U6IFVpbnQ4QXJyYXkgfCBEYXRhVmlldyB8IGFueVtdIHwgc3RyaW5nKSB7XG4gICAgaWYgKHR5cGVvZiBzb3VyY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHNvdXJjZSA9IEJ1ZmZlci5mcm9tKHNvdXJjZSk7XG4gICAgfSBlbHNlIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcoc291cmNlKSkge1xuICAgICAgc291cmNlID0gbmV3IFVpbnQ4QXJyYXkoXG4gICAgICAgIHNvdXJjZS5idWZmZXIsXG4gICAgICAgIHNvdXJjZS5ieXRlT2Zmc2V0LFxuICAgICAgICBzb3VyY2UuYnl0ZUxlbmd0aFxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoc291cmNlKSkge1xuICAgICAgc291cmNlID0gVWludDhBcnJheS5mcm9tKHNvdXJjZSk7XG4gICAgfVxuXG4gICAgaWYgKHNvdXJjZS5sZW5ndGggPT09IDApIHJldHVybiBcIlwiO1xuXG4gICAgLy8gU2tpcCAmIGNvdW50IGxlYWRpbmcgemVyb2VzLlxuICAgIGxldCB6ZXJvZXMgPSAwO1xuICAgIGxldCBsZW5ndGggPSAwO1xuICAgIGxldCBwYmVnaW4gPSAwO1xuICAgIGNvbnN0IHBlbmQgPSBzb3VyY2UubGVuZ3RoO1xuICAgIHdoaWxlIChwYmVnaW4gIT09IHBlbmQgJiYgc291cmNlW3BiZWdpbl0gPT09IDApIHtcbiAgICAgIHBiZWdpbisrO1xuICAgICAgemVyb2VzKys7XG4gICAgfVxuICAgIC8vIEFsbG9jYXRlIGVub3VnaCBzcGFjZSBpbiBiaWctZW5kaWFuIGJhc2U1OCByZXByZXNlbnRhdGlvbi5cbiAgICBjb25zdCBzaXplID0gKChwZW5kIC0gcGJlZ2luKSAqIHRoaXMuaUZhY3RvciArIDEpID4+PiAwO1xuICAgIGNvbnN0IGI1OCA9IG5ldyBVaW50OEFycmF5KHNpemUpO1xuICAgIC8vIFByb2Nlc3MgdGhlIGJ5dGVzLlxuICAgIHdoaWxlIChwYmVnaW4gIT09IHBlbmQpIHtcbiAgICAgIGxldCBjYXJyeSA9IHNvdXJjZVtwYmVnaW5dO1xuICAgICAgLy8gQXBwbHkgXCJiNTggPSBiNTggKiAyNTYgKyBjaFwiLlxuICAgICAgbGV0IGkgPSAwO1xuICAgICAgZm9yIChcbiAgICAgICAgbGV0IGl0MSA9IHNpemUgLSAxO1xuICAgICAgICAoY2FycnkgIT09IDAgfHwgaSA8IGxlbmd0aCkgJiYgaXQxICE9PSAtMTtcbiAgICAgICAgaXQxLS0sIGkrK1xuICAgICAgKSB7XG4gICAgICAgIGNhcnJ5ICs9ICgyNTYgKiBiNThbaXQxXSkgPj4+IDA7XG4gICAgICAgIGI1OFtpdDFdID0gY2FycnkgJSB0aGlzLmJhc2UgPj4+IDA7XG4gICAgICAgIGNhcnJ5ID0gKGNhcnJ5IC8gdGhpcy5iYXNlKSA+Pj4gMDtcbiAgICAgIH1cbiAgICAgIGlmIChjYXJyeSAhPT0gMCkgdGhyb3cgbmV3IEVycm9yKFwiTm9uLXplcm8gY2FycnlcIik7XG5cbiAgICAgIGxlbmd0aCA9IGk7XG4gICAgICBwYmVnaW4rKztcbiAgICB9XG4gICAgLy8gU2tpcCBsZWFkaW5nIHplcm9lcyBpbiBiYXNlNTggcmVzdWx0LlxuICAgIGxldCBpdDIgPSBzaXplIC0gbGVuZ3RoO1xuICAgIHdoaWxlIChpdDIgIT09IHNpemUgJiYgYjU4W2l0Ml0gPT09IDApIGl0MisrO1xuXG4gICAgLy8gVHJhbnNsYXRlIHRoZSByZXN1bHQgaW50byBhIHN0cmluZy5cbiAgICBsZXQgc3RyID0gdGhpcy5sZWFkZXIucmVwZWF0KHplcm9lcyk7XG4gICAgZm9yICg7IGl0MiA8IHNpemU7ICsraXQyKSB7XG4gICAgICBzdHIgKz0gdGhpcy5hbHBoYWJldC5jaGFyQXQoYjU4W2l0Ml0pO1xuICAgIH1cbiAgICByZXR1cm4gc3RyO1xuICB9XG5cbiAgcHJpdmF0ZSBkZWNvZGVVbnNhZmUoc291cmNlOiBzdHJpbmcpOiBVaW50OEFycmF5IHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoc291cmNlLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG5ldyBVaW50OEFycmF5KDApO1xuXG4gICAgbGV0IHBzeiA9IDA7XG4gICAgLy8gU2tpcCBhbmQgY291bnQgbGVhZGluZyAnMSdzLlxuICAgIGxldCB6ZXJvZXMgPSAwO1xuICAgIGxldCBsZW5ndGggPSAwO1xuICAgIHdoaWxlIChzb3VyY2VbcHN6XSA9PT0gdGhpcy5sZWFkZXIpIHtcbiAgICAgIHplcm9lcysrO1xuICAgICAgcHN6Kys7XG4gICAgfVxuICAgIC8vIEFsbG9jYXRlIGVub3VnaCBzcGFjZSBpbiBiaWctZW5kaWFuIGJhc2UyNTYgcmVwcmVzZW50YXRpb24uXG4gICAgY29uc3Qgc2l6ZSA9ICgoc291cmNlLmxlbmd0aCAtIHBzeikgKiB0aGlzLmZhY3RvciArIDEpID4+PiAwOyAvLyBsb2coNTgpIC8gbG9nKDI1NiksIHJvdW5kZWQgdXAuXG4gICAgY29uc3QgYjI1NiA9IG5ldyBVaW50OEFycmF5KHNpemUpO1xuICAgIC8vIFByb2Nlc3MgdGhlIGNoYXJhY3RlcnMuXG4gICAgd2hpbGUgKHNvdXJjZVtwc3pdKSB7XG4gICAgICAvLyBEZWNvZGUgY2hhcmFjdGVyXG4gICAgICBsZXQgY2FycnkgPSB0aGlzLmJhc2VNYXBbc291cmNlLmNoYXJDb2RlQXQocHN6KV07XG4gICAgICAvLyBJbnZhbGlkIGNoYXJhY3RlclxuICAgICAgaWYgKGNhcnJ5ID09PSAyNTUpIHJldHVybjtcblxuICAgICAgbGV0IGkgPSAwO1xuICAgICAgZm9yIChcbiAgICAgICAgbGV0IGl0MyA9IHNpemUgLSAxO1xuICAgICAgICAoY2FycnkgIT09IDAgfHwgaSA8IGxlbmd0aCkgJiYgaXQzICE9PSAtMTtcbiAgICAgICAgaXQzLS0sIGkrK1xuICAgICAgKSB7XG4gICAgICAgIGNhcnJ5ICs9ICh0aGlzLmJhc2UgKiBiMjU2W2l0M10pID4+PiAwO1xuICAgICAgICBiMjU2W2l0M10gPSBjYXJyeSAlIDI1NiA+Pj4gMDtcbiAgICAgICAgY2FycnkgPSAoY2FycnkgLyAyNTYpID4+PiAwO1xuICAgICAgfVxuICAgICAgaWYgKGNhcnJ5ICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoXCJOb24temVybyBjYXJyeVwiKTtcblxuICAgICAgbGVuZ3RoID0gaTtcbiAgICAgIHBzeisrO1xuICAgIH1cbiAgICAvLyBTa2lwIGxlYWRpbmcgemVyb2VzIGluIGIyNTYuXG4gICAgbGV0IGl0NCA9IHNpemUgLSBsZW5ndGg7XG4gICAgd2hpbGUgKGl0NCAhPT0gc2l6ZSAmJiBiMjU2W2l0NF0gPT09IDApIGl0NCsrO1xuXG4gICAgY29uc3QgdmNoID0gbmV3IFVpbnQ4QXJyYXkoemVyb2VzICsgKHNpemUgLSBpdDQpKTtcbiAgICBsZXQgaiA9IHplcm9lcztcbiAgICB3aGlsZSAoaXQ0ICE9PSBzaXplKSB2Y2hbaisrXSA9IGIyNTZbaXQ0KytdO1xuXG4gICAgcmV0dXJuIHZjaDtcbiAgfVxuXG4gIGRlY29kZShzb3VyY2U6IHN0cmluZykge1xuICAgIGNvbnN0IGJ1ZmZlciA9IHRoaXMuZGVjb2RlVW5zYWZlKHNvdXJjZSk7XG4gICAgaWYgKGJ1ZmZlcikgcmV0dXJuIGJ1ZmZlcjtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJOb24tYmFzZVwiICsgdGhpcy5iYXNlICsgXCIgY2hhcmFjdGVyXCIpO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBDcnlwdG9VdGlscyB7XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IGI1OGVuY29kZXIgPSBuZXcgQmFzZUVuY29kZXIoQkFTRV9BTFBIQUJFVC5CQVNFNTgpO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBsb2dnZXIgPSBuZXcgTWluaUxvZ2dlcihDcnlwdG9VdGlscy5uYW1lKTtcbiAgcHJpdmF0ZSBjb25zdHJ1Y3RvcigpIHt9XG5cbiAgc3RhdGljIGZhYnJpY0lkRnJvbUNlcnRpZmljYXRlKGNlcnRpZmljYXRlOiBzdHJpbmcpIHtcbiAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhzdHJpbmdGb3JtYXQoXCJQYXJzaW5nIGNlcnRpZmljYXRlOiB7MH1cIiwgY2VydGlmaWNhdGUpKTtcbiAgICBjb25zdCBjZXJ0ID0gbmV3IHg1MDkuWDUwOUNlcnRpZmljYXRlKGNlcnRpZmljYXRlKTtcbiAgICBjb25zdCB7IHN1YmplY3QsIGlzc3VlciB9ID0gY2VydDtcbiAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcbiAgICAgIHN0cmluZ0Zvcm1hdChcbiAgICAgICAgXCJDZXJ0aWZpY2F0ZSBwYXJzZWQgd2l0aCBzdWJqZWN0IHswfSBhbmQgaXNzdWVyIHsxfVwiLFxuICAgICAgICBzdWJqZWN0LFxuICAgICAgICBpc3N1ZXJcbiAgICAgIClcbiAgICApO1xuICAgIHJldHVybiBgeDUwOTo6LyR7c3ViamVjdC5yZXBsYWNlQWxsKFwiLCBcIiwgXCIvXCIpfTo6LyR7aXNzdWVyLnJlcGxhY2VBbGwoXCIsIFwiLCBcIi9cIil9YDtcbiAgfVxuXG4gIHN0YXRpYyBlbmNvZGUoc3RyOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmI1OGVuY29kZXIuZW5jb2RlKHN0cik7XG4gIH1cbiAgc3RhdGljIGRlY29kZShzdHI6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgZGVjb2RlZCA9IHRoaXMuYjU4ZW5jb2Rlci5kZWNvZGUoc3RyKTtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoZGVjb2RlZCk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHN0YXRpYyBzdHJpbmdUb0FycmF5QnVmZmVyKHN0cjogc3RyaW5nKSB7XG4gICAgY29uc3QgYnVmID0gbmV3IEFycmF5QnVmZmVyKHN0ci5sZW5ndGgpO1xuICAgIGNvbnN0IGJ1ZlZpZXcgPSBuZXcgVWludDhBcnJheShidWYpO1xuICAgIGZvciAobGV0IGkgPSAwLCBzdHJMZW4gPSBzdHIubGVuZ3RoOyBpIDwgc3RyTGVuOyBpKyspIHtcbiAgICAgIGJ1ZlZpZXdbaV0gPSBzdHIuY2hhckNvZGVBdChpKTtcbiAgICB9XG4gICAgcmV0dXJuIGJ1ZjtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGFzeW5jIGV4dHJhY3RLZXkoXG4gICAgdHlwZTogXCJwcml2YXRlXCIgfCBcInB1YmxpY1wiLFxuICAgIHBlbTogQnVmZmVyIHwgc3RyaW5nLFxuICAgIHVzYWdlcz86IGFueVtdXG4gICkge1xuICAgIGNvbnN0IHN1YnRsZSA9IGNyeXB0by5zdWJ0bGU7XG5cbiAgICBjb25zdCBzdHIgPSBwZW1cbiAgICAgIC50b1N0cmluZyhcInV0ZjhcIilcbiAgICAgIC5yZXBsYWNlKFxuICAgICAgICBuZXcgUmVnRXhwKGAtLS0tLUJFR0lOICgke3R5cGUudG9VcHBlckNhc2UoKX0gS0VZfENFUlRJRklDQVRFKS0tLS0tYCksXG4gICAgICAgIFwiXCJcbiAgICAgIClcbiAgICAgIC5yZXBsYWNlQWxsKFwiXFxuXCIsIFwiXCIpXG4gICAgICAucmVwbGFjZShcbiAgICAgICAgbmV3IFJlZ0V4cChgLS0tLS1FTkQgKCR7dHlwZS50b1VwcGVyQ2FzZSgpfSBLRVl8Q0VSVElGSUNBVEUpLS0tLS1gKSxcbiAgICAgICAgXCJcIlxuICAgICAgKTtcbiAgICBjb25zdCBkZWNvZGVkID0gQnVmZmVyLmZyb20oc3RyLCBcImJhc2U2NFwiKS50b1N0cmluZyhcImJpbmFyeVwiKTtcbiAgICBjb25zdCBiaW5hcnlEZXIgPSB0aGlzLnN0cmluZ1RvQXJyYXlCdWZmZXIoZGVjb2RlZCk7XG4gICAgY29uc3Qga2V5ID0gYXdhaXQgc3VidGxlLmltcG9ydEtleShcbiAgICAgIFwicGtjczhcIixcbiAgICAgIGJpbmFyeURlcixcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJFQ0RTQVwiLFxuICAgICAgICBuYW1lZEN1cnZlOiBcIlAtMjU2XCIsXG4gICAgICB9LFxuICAgICAgdHJ1ZSxcbiAgICAgIHVzYWdlcyA/IHVzYWdlcyA6IFtcInNpZ25cIl1cbiAgICApO1xuXG4gICAgcmV0dXJuIGtleTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBleHRyYWN0UHJpdmF0ZUtleShwZW06IEJ1ZmZlciB8IHN0cmluZywgdXNhZ2VzPzogYW55W10pIHtcbiAgICByZXR1cm4gdGhpcy5leHRyYWN0S2V5KFwicHJpdmF0ZVwiLCBwZW0sIHVzYWdlcyk7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgZXh0cmFjdFB1YmxpY0tleShwZW06IEJ1ZmZlciB8IHN0cmluZywgdXNhZ2VzPzogYW55W10pIHtcbiAgICByZXR1cm4gdGhpcy5leHRyYWN0S2V5KFwicHVibGljXCIsIHBlbSwgdXNhZ2VzKTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBzaWduKHByaXZhdGVLZXk6IHN0cmluZywgZGF0YTogQnVmZmVyKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBrZXkgPSBhd2FpdCB0aGlzLmV4dHJhY3RQcml2YXRlS2V5KHByaXZhdGVLZXkpO1xuICAgIGNvbnN0IGJ1ZmYgPSAoYXdhaXQgY3J5cHRvLnN1YnRsZS5zaWduKFxuICAgICAge1xuICAgICAgICBuYW1lOiBcIkVDRFNBXCIsXG4gICAgICAgIGhhc2g6IFwiU0hBLTI1NlwiLFxuICAgICAgfSxcbiAgICAgIGtleSxcbiAgICAgIGRhdGFcbiAgICApKSBhcyBBcnJheUJ1ZmZlcjtcblxuICAgIHJldHVybiBBcnJheS5mcm9tKG5ldyBVaW50OEFycmF5KGJ1ZmYpKVxuICAgICAgLm1hcCgoYikgPT4gYi50b1N0cmluZygxNikucGFkU3RhcnQoMiwgXCIwXCIpKVxuICAgICAgLmpvaW4oXCJcIik7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgdmVyaWZ5KFxuICAgIGNlcnRpZmljYXRlOiBzdHJpbmcsXG4gICAgc2lnbmF0dXJlOiBCdWZmZXIgfCBzdHJpbmcsXG4gICAgZGF0YTogQnVmZmVyIHwgc3RyaW5nXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGNlcnQgPSBuZXcgeDUwOS5YNTA5Q2VydGlmaWNhdGUoY2VydGlmaWNhdGUpO1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IGNlcnQucHVibGljS2V5LmV4cG9ydCgpO1xuICAgIHNpZ25hdHVyZSA9IChcbiAgICAgIHR5cGVvZiBzaWduYXR1cmUgPT09IFwic3RyaW5nXCIgPyBCdWZmZXIuZnJvbShzaWduYXR1cmUsIFwiaGV4XCIpIDogc2lnbmF0dXJlXG4gICAgKSBhcyBCdWZmZXI7XG4gICAgZGF0YSA9ICh0eXBlb2YgZGF0YSA9PT0gXCJzdHJpbmdcIiA/IEJ1ZmZlci5mcm9tKGRhdGEpIDogZGF0YSkgYXMgQnVmZmVyO1xuICAgIHJldHVybiBjcnlwdG8uc3VidGxlLnZlcmlmeShcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJFQ0RTQVwiLFxuICAgICAgICBoYXNoOiBcIlNIQS0yNTZcIixcbiAgICAgIH0sXG4gICAgICBrZXksXG4gICAgICBzaWduYXR1cmUsXG4gICAgICBkYXRhXG4gICAgKTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBlbmNyeXB0KGNlcnRpZmljYXRlOiBzdHJpbmcsIGRhdGE6IHN0cmluZyB8IEJ1ZmZlcikge1xuICAgIGNvbnN0IGNlcnQgPSBuZXcgeDUwOS5YNTA5Q2VydGlmaWNhdGUoY2VydGlmaWNhdGUpO1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IGNlcnQucHVibGljS2V5LmV4cG9ydCgpO1xuICAgIGRhdGEgPSAodHlwZW9mIGRhdGEgPT09IFwic3RyaW5nXCIgPyBCdWZmZXIuZnJvbShkYXRhKSA6IGRhdGEpIGFzIEJ1ZmZlcjtcbiAgICBjb25zdCBidWZmID0gYXdhaXQgdGhpcy5nZXRTdWJ0bGVDcnlwdG8oKS5lbmNyeXB0KFxuICAgICAge1xuICAgICAgICBuYW1lOiBcIkVDRFNBXCIsXG4gICAgICB9LFxuICAgICAga2V5LFxuICAgICAgZGF0YVxuICAgICk7XG5cbiAgICByZXR1cm4gQXJyYXkuZnJvbShuZXcgVWludDhBcnJheShidWZmKSlcbiAgICAgIC5tYXAoKGIpID0+IGIudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsIFwiMFwiKSlcbiAgICAgIC5qb2luKFwiXCIpO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0U3VidGxlQ3J5cHRvKCkge1xuICAgIHJldHVybiBpc0Jyb3dzZXIoKVxuICAgICAgPyAoZ2xvYmFsVGhpcyBhcyBhbnkpLndpbmRvdy5jcnlwdG8uc3VidGxlXG4gICAgICA6IGNyeXB0by5zdWJ0bGU7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgZGVjcnlwdChwcml2YXRlS2V5OiBzdHJpbmcsIGRhdGE6IHN0cmluZyB8IEJ1ZmZlcikge1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IHRoaXMuZXh0cmFjdFByaXZhdGVLZXkocHJpdmF0ZUtleSk7XG4gICAgZGF0YSA9IChcbiAgICAgIHR5cGVvZiBkYXRhID09PSBcInN0cmluZ1wiID8gQnVmZmVyLmZyb20oZGF0YSwgXCJoZXhcIikgOiBkYXRhXG4gICAgKSBhcyBCdWZmZXI7XG4gICAgcmV0dXJuIHRoaXMuZ2V0U3VidGxlQ3J5cHRvKCkuZGVjcnlwdChcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJFQ0RTQVwiLFxuICAgICAgfSxcbiAgICAgIGtleSxcbiAgICAgIGRhdGFcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gZ2V0IGEgcmFuZG9tIG1hc3RlciBrZXlcbiAgICpcbiAgICogQGRlc2NyaXB0aW9uIElmIGRhdGEgaXMgbm90IHBhc3NlZCwgYSByYW5kb20gQXJyYXlCdWZmZXIgd2lsbCBiZSBnZW5lcmF0ZWRcbiAgICpcbiAgICogQHBhcmFtIHtBcnJheUJ1ZmZlcn0gZGF0YSBlbmNyeXRpb24gZGF0YVxuICAgKlxuICAgKiBAZnVuY3Rpb24gZ2V0TWFzdGVyXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2V0TWFzdGVyKGRhdGE/OiBBcnJheUJ1ZmZlcik6IFByb21pc2U8a2V5T2JqZWN0PiB7XG4gICAgY29uc3QgdGV4dEVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKTtcbiAgICBpZiAoZGF0YSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBnZW5HZW5lc2lzID0gY3J5cHRvLnJhbmRvbVVVSUQoKTtcbiAgICAgIGRhdGEgPSB0ZXh0RW5jb2Rlci5lbmNvZGUoZ2VuR2VuZXNpcykuYnVmZmVyO1xuICAgIH1cblxuICAgIGNvbnN0IGltcG9ydGVkS2V5ID0gYXdhaXQgdGhpcy5nZXRTdWJ0bGVDcnlwdG8oKS5pbXBvcnRLZXkoXG4gICAgICBcInJhd1wiLFxuICAgICAgZGF0YSxcbiAgICAgIENSWVBUTy5LRVlfQUxHT1JZVEhNIGFzIHN0cmluZyxcbiAgICAgIGZhbHNlLFxuICAgICAgW1wiZGVyaXZlQml0c1wiXVxuICAgICk7XG5cbiAgICByZXR1cm4ge1xuICAgICAga2V5OiBpbXBvcnRlZEtleSxcbiAgICAgIGl2OiBkYXRhISxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gZGVyaXZlIGEga2V5IGZyb20gYW5vdGhlciBrZXlcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNhbHRcbiAgICogQHBhcmFtIHtDcnlwdG9LZXl9IGtleSBPcmlnaW5hbCBrZXlcbiAgICpcbiAgICogQGZ1bmN0aW9uIGdldERlcml2YXRpb25LZXlcbiAgICovXG4gIHN0YXRpYyBhc3luYyBnZXREZXJpdmF0aW9uS2V5KHNhbHQ6IHN0cmluZywga2V5OiBDcnlwdG9LZXkpIHtcbiAgICBjb25zdCB0ZXh0RW5jb2RlciA9IG5ldyBUZXh0RW5jb2RlcigpO1xuICAgIGNvbnN0IHNhbHRCdWZmZXIgPSB0ZXh0RW5jb2Rlci5lbmNvZGUoc2FsdCk7XG4gICAgY29uc3Qgc2FsdEhhc2hlZCA9IGF3YWl0IHRoaXMuZ2V0U3VidGxlQ3J5cHRvKCkuZGlnZXN0KFxuICAgICAgXCJTSEEtMjU2XCIsXG4gICAgICBzYWx0QnVmZmVyXG4gICAgKTtcbiAgICBjb25zdCBwYXJhbXMgPSB7XG4gICAgICBuYW1lOiBDUllQVE8uS0VZX0FMR09SWVRITSBhcyBzdHJpbmcsXG4gICAgICBoYXNoOiBDUllQVE8uSEFTSCxcbiAgICAgIHNhbHQ6IHNhbHRIYXNoZWQsXG4gICAgICBpdGVyYXRpb25zOiBDUllQVE8uSVRFUkFUSU9OUyxcbiAgICB9O1xuICAgIGNvbnN0IGRlcml2YXRpb24gPSBhd2FpdCB0aGlzLmdldFN1YnRsZUNyeXB0bygpLmRlcml2ZUJpdHMoXG4gICAgICBwYXJhbXMsXG4gICAgICBrZXksXG4gICAgICBDUllQVE8uS0VZTEVOR1RIICogOFxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuZ2V0S2V5KGRlcml2YXRpb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gZ2V0IHRoZSBrZXkgYW5kIElWIGZyb20gdGhlIENyeXRvS2V5IGFycmF5XG4gICAqXG4gICAqIEBwYXJhbSB7QXJyYXlCdWZmZXJ9IGRlcml2YXRpb25cbiAgICpcbiAgICogQGZ1bmN0aW9uIGdldEtleVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGdldEtleShkZXJpdmF0aW9uOiBBcnJheUJ1ZmZlcikge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBjb25zdCBpdmxlbiA9IDE2O1xuICAgIGNvbnN0IGtleWxlbiA9IDMyO1xuICAgIGNvbnN0IGRlcml2ZWRLZXkgPSBkZXJpdmF0aW9uLnNsaWNlKDAsIGtleWxlbik7XG4gICAgY29uc3QgaXYgPSBkZXJpdmF0aW9uLnNsaWNlKGtleWxlbik7XG4gICAgY29uc3QgaW1wb3J0ZWRFbmNyeXB0aW9uS2V5ID0gYXdhaXQgdGhpcy5nZXRTdWJ0bGVDcnlwdG8oKS5pbXBvcnRLZXkoXG4gICAgICBcInJhd1wiLFxuICAgICAgZGVyaXZlZEtleSxcbiAgICAgIHsgbmFtZTogQ1JZUFRPLkFMR09SWVRITSBhcyBzdHJpbmcgfSxcbiAgICAgIGZhbHNlLFxuICAgICAgW1wiZW5jcnlwdFwiLCBcImRlY3J5cHRcIl1cbiAgICApO1xuICAgIHJldHVybiB7XG4gICAgICBrZXk6IGltcG9ydGVkRW5jcnlwdGlvbktleSxcbiAgICAgIGl2OiBpdixcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gZGVjcnlwdCBkYXRhXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0XG4gICAqIEBwYXJhbSB7a2V5T2JqZWN0fSBrZXlPYmplY3RcbiAgICpcbiAgICogQGZ1bmN0aW9uIGVuY3J5cHRcbiAgICovXG4gIHN0YXRpYyBhc3luYyBlbmNyeXB0UGluKFxuICAgIHRleHQ6IHN0cmluZyxcbiAgICBrZXlPYmplY3Q6IGtleU9iamVjdFxuICApOiBQcm9taXNlPEFycmF5QnVmZmVyPiB7XG4gICAgY29uc3QgdGV4dEVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKTtcbiAgICBjb25zdCB0ZXh0QnVmZmVyID0gdGV4dEVuY29kZXIuZW5jb2RlKHRleHQpO1xuICAgIGNvbnN0IGVuY3J5cHRlZFRleHQgPSBhd2FpdCB0aGlzLmdldFN1YnRsZUNyeXB0bygpLmVuY3J5cHQoXG4gICAgICB7IG5hbWU6IENSWVBUTy5BTEdPUllUSE0gYXMgc3RyaW5nLCBpdjoga2V5T2JqZWN0Lml2IH0sXG4gICAgICBrZXlPYmplY3Qua2V5LFxuICAgICAgdGV4dEJ1ZmZlclxuICAgICk7XG4gICAgcmV0dXJuIGVuY3J5cHRlZFRleHQ7XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgVXRpbCBmdW5jdGlvbiB0byBkZWNyeXB0IGRhdGFcbiAgICpcbiAgICogQHBhcmFtIHtCdWZmZXJTb3VyY2V9IGVuY3J5cHRlZFRleHRcbiAgICogQHBhcmFtIHtrZXlPYmplY3R9IGtleU9iamVjdFxuICAgKlxuICAgKiBAZnVuY3Rpb24gZGVjcnlwdFxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGRlY3J5cHRQaW4oXG4gICAgZW5jcnlwdGVkVGV4dDogQXJyYXlCdWZmZXIsXG4gICAga2V5T2JqZWN0OiBrZXlPYmplY3RcbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB0ZXh0RGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlcigpO1xuICAgIGNvbnN0IGRlY3J5cHRlZFRleHQgPSBhd2FpdCB0aGlzLmdldFN1YnRsZUNyeXB0bygpLmRlY3J5cHQoXG4gICAgICB7IG5hbWU6IENSWVBUTy5BTEdPUllUSE0gYXMgc3RyaW5nLCBpdjoga2V5T2JqZWN0Lml2IH0sXG4gICAgICBrZXlPYmplY3Qua2V5LFxuICAgICAgZW5jcnlwdGVkVGV4dFxuICAgICk7XG4gICAgcmV0dXJuIHRleHREZWNvZGVyLmRlY29kZShkZWNyeXB0ZWRUZXh0KTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgQmFzZUVycm9yLCBJbnRlcm5hbEVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBBdXRob3JpemF0aW9uRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbi8vIGltcG9ydCB7IE1JU1NJTkdfUFJJVkFURV9EQVRBX0VSUk9SX01FU1NBR0UgfSBmcm9tIFwiLi4vY29udHJhY3RzL3ByaXZhdGUtZGF0YVwiO1xuLyoqXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGFuIG92ZXJmbG93IGVycm9yIGluIGFyaXRobWV0aWMgb3BlcmF0aW9ucyBpbiBTbWFydCBDb250cmFjdHNcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbXNnIHRoZSBlcnJvciBtZXNzYWdlXG4gKlxuICogQGNsYXNzIE92ZXJmbG93RXJyb3JcbiAqIEBleHRlbmRzIEludGVybmFsRXJyb3JcbiAqXG4gKiBAY2F0ZWdvcnkgRXJyb3JzXG4gKi9cbmV4cG9ydCBjbGFzcyBPdmVyZmxvd0Vycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIE92ZXJmbG93RXJyb3IubmFtZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGEgZmFpbHVyZSBpbiBiYWxhbmNlIHRvIHBlcmZvcm0gYSB0cmFuc2FjdGlvbiBpbiBTbWFydCBDb250cmFjdHNcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbXNnIHRoZSBlcnJvciBtZXNzYWdlXG4gKlxuICogQGNsYXNzIEJhbGFuY2VFcnJvclxuICogQGV4dGVuZHMgSW50ZXJuYWxFcnJvclxuICpcbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIEJhbGFuY2VFcnJvciBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBCYWxhbmNlRXJyb3IubmFtZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGEgZmFpbHVyZSBpbiBiYWxhbmNlIHRvIHBlcmZvcm0gYSB0cmFuc2FjdGlvbiBpbiBTbWFydCBDb250cmFjdHNcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbXNnIHRoZSBlcnJvciBtZXNzYWdlXG4gKlxuICogQGNsYXNzIEJhbGFuY2VFcnJvclxuICogQGV4dGVuZHMgSW50ZXJuYWxFcnJvclxuICpcbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIEFsbG93YW5jZUVycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIEFsbG93YW5jZUVycm9yLm5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBhIGZhaWx1cmUgcmVnaXN0cmF0aW5nIG5ldyBlbnRpdGllc1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBtc2cgdGhlIGVycm9yIG1lc3NhZ2VcbiAqXG4gKiBAY2xhc3MgUmVnaXN0cmF0aW9uRXJyb3JcbiAqXG4gKiBAY2F0ZWdvcnQgRXJyb3JzXG4gKi9cbmV4cG9ydCBjbGFzcyBSZWdpc3RyYXRpb25FcnJvciBleHRlbmRzIEF1dGhvcml6YXRpb25FcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIFJlZ2lzdHJhdGlvbkVycm9yLm5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVycm9yIHRocm93biB3aGVuIGFuIHVuc3VwcG9ydGVkIG9wZXJhdGlvbiBpcyBhdHRlbXB0ZWRcbiAqIEBzdW1tYXJ5IFRoaXMgZXJyb3IgaXMgdGhyb3duIHdoZW4gYW4gb3BlcmF0aW9uIGlzIHJlcXVlc3RlZCB0aGF0IGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGN1cnJlbnRcbiAqIHBlcnNpc3RlbmNlIGFkYXB0ZXIgb3IgY29uZmlndXJhdGlvbi4gSXQgZXh0ZW5kcyB0aGUgQmFzZUVycm9yIGNsYXNzIGFuZCBzZXRzIGEgNTAwIHN0YXR1cyBjb2RlLlxuICogQHBhcmFtIHtzdHJpbmd8RXJyb3J9IG1zZyAtIFRoZSBlcnJvciBtZXNzYWdlIG9yIGFuIEVycm9yIG9iamVjdCB0byB3cmFwXG4gKiBAY2xhc3MgVW5zdXBwb3J0ZWRFcnJvclxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIFRocm93aW5nIGFuIFVuc3VwcG9ydGVkRXJyb3JcbiAqIGlmICghYWRhcHRlci5zdXBwb3J0c1RyYW5zYWN0aW9ucygpKSB7XG4gKiAgIHRocm93IG5ldyBVbnN1cHBvcnRlZEVycm9yKCdUcmFuc2FjdGlvbnMgYXJlIG5vdCBzdXBwb3J0ZWQgYnkgdGhpcyBhZGFwdGVyJyk7XG4gKiB9XG4gKlxuICogLy8gQ2F0Y2hpbmcgYW4gVW5zdXBwb3J0ZWRFcnJvclxuICogdHJ5IHtcbiAqICAgYXdhaXQgYWRhcHRlci5iZWdpblRyYW5zYWN0aW9uKCk7XG4gKiB9IGNhdGNoIChlcnJvcikge1xuICogICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBVbnN1cHBvcnRlZEVycm9yKSB7XG4gKiAgICAgY29uc29sZS5lcnJvcignT3BlcmF0aW9uIG5vdCBzdXBwb3J0ZWQ6JywgZXJyb3IubWVzc2FnZSk7XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIE1pc3NpbmdDb250ZXh0RXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1zZywgTWlzc2luZ0NvbnRleHRFcnJvci5uYW1lLCA1MDApO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBVbmF1dGhvcml6ZWRQcml2YXRlRGF0YUFjY2VzcyBleHRlbmRzIEJhc2VFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IgPSBcIk1JU1NJTkdfUFJJVkFURV9EQVRBX0VSUk9SX01FU1NBR0VcIikge1xuICAgIHN1cGVyKFVuYXV0aG9yaXplZFByaXZhdGVEYXRhQWNjZXNzLm5hbWUsIG1zZywgNDAzKTtcbiAgfVxufVxuXG4vKipcbiAqIFJlcHJlc2VudHMgYW4gZXJyb3IgdGhhdCBvY2N1cnMgd2hlbiBhIHJlcXVpcmVkIGluaXRpYWxpemF0aW9uIHN0ZXAgaXMgbm90IHBlcmZvcm1lZC5cbiAqXG4gKiBAY2xhc3MgTm90SW5pdGlhbGl6ZWRFcnJvclxuICogQGV4dGVuZHMgQmFzZUVycm9yXG4gKlxuICogQGNhdGVnb3J5IEVycm9yc1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nIHwgRXJyb3J9IG1zZyAtIFRoZSBlcnJvciBtZXNzYWdlIG9yIGFuIEVycm9yIG9iamVjdCB0byB3cmFwLlxuICpcbiAqIEB0aHJvd3Mge05vdEluaXRpYWxpemVkRXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIHdoZW4gYSByZXF1aXJlZCBpbml0aWFsaXphdGlvbiBzdGVwIGlzIG5vdCBwZXJmb3JtZWQuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIEluaXRpYWxpemUgdGhlIGFwcGxpY2F0aW9uXG4gKiBpZiAoIWlzSW5pdGlhbGl6ZWQpIHtcbiAqICAgdGhyb3cgbmV3IE5vdEluaXRpYWxpemVkRXJyb3IoJ0FwcGxpY2F0aW9uIGlzIG5vdCBpbml0aWFsaXplZCcpO1xuICogfVxuICpcbiAqIC8vIENhdGNoaW5nIGFuIE5vdEluaXRpYWxpemVkRXJyb3JcbiAqIHRyeSB7XG4gKiAgIC8vIFBlcmZvcm0gb3BlcmF0aW9ucyB0aGF0IHJlcXVpcmUgaW5pdGlhbGl6YXRpb25cbiAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gKiAgIGlmIChlcnJvciBpbnN0YW5jZW9mIE5vdEluaXRpYWxpemVkRXJyb3IpIHtcbiAqICAgICBjb25zb2xlLmVycm9yKCdJbml0aWFsaXphdGlvbiBlcnJvcjonLCBlcnJvci5tZXNzYWdlKTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBOb3RJbml0aWFsaXplZEVycm9yIGV4dGVuZHMgQmFzZUVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKE5vdEluaXRpYWxpemVkRXJyb3IubmFtZSwgbXNnLCA0MDkpO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBNaXNzaW5nUEtDU1MxMUxpYiBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBNaXNzaW5nUEtDU1MxMUxpYi5uYW1lLCA1MDApO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBFbmRvcnNlbWVudEVycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobWVzc2FnZSwgRW5kb3JzZW1lbnRFcnJvci5uYW1lLCA1MDApO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBNdmNjUmVhZENvbmZsaWN0RXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtZXNzYWdlLCBNdmNjUmVhZENvbmZsaWN0RXJyb3IubmFtZSwgNTAwKTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgUGhhbnRvbVJlYWRDb25mbGljdEVycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobWVzc2FnZSwgUGhhbnRvbVJlYWRDb25mbGljdEVycm9yLm5hbWUsIDUwMCk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIEVuZG9yc2VtZW50UG9saWN5RXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtZXNzYWdlLCBFbmRvcnNlbWVudFBvbGljeUVycm9yLm5hbWUsIDUwMCk7XG4gIH1cbn1cbiIsImltcG9ydCBGYWJyaWNDQVNlcnZpY2VzIGZyb20gXCJmYWJyaWMtY2EtY2xpZW50XCI7XG5pbXBvcnQge1xuICBBZmZpbGlhdGlvblNlcnZpY2UsXG4gIElkZW50aXR5U2VydmljZSxcbiAgSUVucm9sbFJlc3BvbnNlLFxuICBJUmVnaXN0ZXJSZXF1ZXN0LFxuICBJU2VydmljZVJlc3BvbnNlLFxuICBUTFNPcHRpb25zLFxufSBmcm9tIFwiZmFicmljLWNhLWNsaWVudFwiO1xuaW1wb3J0IHsgVXNlciB9IGZyb20gXCJmYWJyaWMtY29tbW9uXCI7XG5pbXBvcnQgeyBDQUNvbmZpZywgQ3JlZGVudGlhbHMgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL3R5cGVzXCI7XG5pbXBvcnQgeyBJZGVudGl0eSB9IGZyb20gXCIuLi8uLi9zaGFyZWQvbW9kZWwvSWRlbnRpdHlcIjtcbmltcG9ydCB7IEF1dGhvcml6YXRpb25FcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHtcbiAgQ29uZmxpY3RFcnJvcixcbiAgSW50ZXJuYWxFcnJvcixcbiAgTm90Rm91bmRFcnJvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDb3JlVXRpbHMgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IENBX1JPTEUgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IENyeXB0b1V0aWxzIH0gZnJvbSBcIi4uL2NyeXB0b1wiO1xuaW1wb3J0IHtcbiAgQ2VydGlmaWNhdGVSZXNwb25zZSxcbiAgRmFicmljSWRlbnRpdHksXG4gIEdldENlcnRpZmljYXRlc1JlcXVlc3QsXG4gIElkZW50aXR5UmVzcG9uc2UsXG59IGZyb20gXCIuLi8uLi9zaGFyZWQvZmFicmljLXR5cGVzXCI7XG5pbXBvcnQgeyBSZWdpc3RyYXRpb25FcnJvciB9IGZyb20gXCIuLi8uLi9zaGFyZWQvZXJyb3JzXCI7XG5pbXBvcnQgeyBMb2dnZWRDbGFzcywgTG9nZ2luZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBIeXBlcmxlZGdlciBGYWJyaWMgQ0EgaWRlbnRpdHkgdHlwZXMuXG4gKiBAc3VtbWFyeSBFbnVtZXJhdGVzIHRoZSBzdXBwb3J0ZWQgaWRlbnRpdHkgdHlwZXMgcmVjb2duaXplZCBieSBGYWJyaWMgQ0EgZm9yIHJlZ2lzdHJhdGlvbiBhbmQgaWRlbnRpdHkgbWFuYWdlbWVudC5cbiAqIEBlbnVtIHtzdHJpbmd9XG4gKiBAcmVhZG9ubHlcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGVudW0gSEZDQUlkZW50aXR5VHlwZSB7XG4gIFBFRVIgPSBcInBlZXJcIixcbiAgT1JERVJFUiA9IFwib3JkZXJlclwiLFxuICBDTElFTlQgPSBcImNsaWVudFwiLFxuICBVU0VSID0gXCJ1c2VyXCIsXG4gIEFETUlOID0gXCJhZG1pblwiLFxufVxuLyoqXG4gKiBAZGVzY3JpcHRpb24gS2V5L3ZhbHVlIGF0dHJpYnV0ZSB1c2VkIGR1cmluZyBDQSByZWdpc3RyYXRpb24uXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGFuIGF0dHJpYnV0ZSBlbnRyeSB0aGF0IGNhbiBiZSBhdHRhY2hlZCB0byBhIEZhYnJpYyBDQSBpZGVudGl0eSBkdXJpbmcgcmVnaXN0cmF0aW9uLCBvcHRpb25hbGx5IG1hcmtpbmcgaXQgZm9yIGluY2x1c2lvbiBpbiBlY2VydC5cbiAqIEBpbnRlcmZhY2UgSUtleVZhbHVlQXR0cmlidXRlXG4gKiBAdGVtcGxhdGUgVFxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBBdHRyaWJ1dGUgbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIEF0dHJpYnV0ZSB2YWx1ZS5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2VjZXJ0XSAtIFdoZXRoZXIgdGhlIGF0dHJpYnV0ZSBzaG91bGQgYmUgaW5jbHVkZWQgaW4gdGhlIGVucm9sbG1lbnQgY2VydGlmaWNhdGUgKEVDZXJ0KS5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJS2V5VmFsdWVBdHRyaWJ1dGUge1xuICBuYW1lOiBzdHJpbmc7XG4gIHZhbHVlOiBzdHJpbmc7XG4gIGVjZXJ0PzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU3RhbmRhcmQgRmFicmljIENBIGlkZW50aXR5IGF0dHJpYnV0ZSBrZXlzLlxuICogQHN1bW1hcnkgRW51bWVyYXRlcyB3ZWxsLWtub3duIEZhYnJpYyBDQSBhdHRyaWJ1dGUga2V5cyB0aGF0IGNhbiBiZSBhc3NpZ25lZCB0byBpZGVudGl0aWVzIGZvciBkZWxlZ2F0aW9ucyBhbmQgcGVybWlzc2lvbnMuXG4gKiBAZW51bSB7c3RyaW5nfVxuICogQHJlYWRvbmx5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuY2xpZW50XG4gKi9cbmV4cG9ydCBlbnVtIEhGQ0FJZGVudGl0eUF0dHJpYnV0ZXMge1xuICBIRlJFR0lTVFJBUlJPTEVTID0gXCJoZi5SZWdpc3RyYXIuUm9sZXNcIixcbiAgSEZSRUdJU1RSQVJERUxFR0FURVJPTEVTID0gXCJoZi5SZWdpc3RyYXIuRGVsZWdhdGVSb2xlc1wiLFxuICBIRlJFR0lTVFJBUkFUVFJJQlVURVMgPSBcImhmLlJlZ2lzdHJhci5BdHRyaWJ1dGVzXCIsXG4gIEhGSU5URVJNRURJQVRFQ0EgPSBcImhmLkludGVybWVkaWF0ZUNBXCIsXG4gIEhGUkVWT0tFUiA9IFwiaGYuUmV2b2tlclwiLFxuICBIRkFGRklMSUFUSU9OTUdSID0gXCJoZi5BZmZpbGlhdGlvbk1nclwiLFxuICBIRkdFTkNSTCA9IFwiaGYuR2VuQ1JMXCIsXG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFNlcnZpY2Ugd3JhcHBlciBmb3IgaW50ZXJhY3Rpbmcgd2l0aCBhIEZhYnJpYyBDQS5cbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIGhpZ2gtbGV2ZWwgb3BlcmF0aW9ucyBmb3IgbWFuYWdpbmcgaWRlbnRpdGllcyBhZ2FpbnN0IGEgSHlwZXJsZWRnZXIgRmFicmljIENlcnRpZmljYXRlIEF1dGhvcml0eSwgaW5jbHVkaW5nIHJlZ2lzdHJhdGlvbiwgZW5yb2xsbWVudCwgcmV2b2NhdGlvbiwgYW5kIGFkbWluaXN0cmF0aXZlIHF1ZXJpZXMuIEVuY2Fwc3VsYXRlcyBsb3dlci1sZXZlbCBGYWJyaWMgQ0EgY2xpZW50IGNhbGxzIHdpdGggY29uc2lzdGVudCBsb2dnaW5nIGFuZCBlcnJvciBtYXBwaW5nLlxuICogQHBhcmFtIHtDQUNvbmZpZ30gY2FDb25maWcgLSBDb25uZWN0aW9uIGFuZCBUTFMgY29uZmlndXJhdGlvbiBmb3IgdGhlIHRhcmdldCBDQS5cbiAqIEBjbGFzcyBGYWJyaWNFbnJvbGxtZW50U2VydmljZVxuICogQGV4YW1wbGVcbiAqIC8vIFJlZ2lzdGVyIGFuZCBlbnJvbGwgYSBuZXcgdXNlclxuICogY29uc3Qgc3ZjID0gbmV3IEZhYnJpY0Vucm9sbG1lbnRTZXJ2aWNlKHtcbiAqICAgdXJsOiAnaHR0cHM6Ly9sb2NhbGhvc3Q6NzA1NCcsXG4gKiAgIGNhTmFtZTogJ09yZzFDQScsXG4gKiAgIHRsczogeyB0cnVzdGVkUm9vdHM6IFsnL3BhdGgvdG8vY2EucGVtJ10sIHZlcmlmeTogZmFsc2UgfSxcbiAqICAgY2FDZXJ0OiAnL3BhdGgvdG8vYWRtaW4vY2VydERpcicsXG4gKiAgIGNhS2V5OiAnL3BhdGgvdG8vYWRtaW4va2V5RGlyJ1xuICogfSk7XG4gKiBhd2FpdCBzdmMucmVnaXN0ZXIoeyB1c2VyTmFtZTogJ2FsaWNlJywgcGFzc3dvcmQ6ICdzM2NyM3QnIH0sIGZhbHNlLCAnb3JnMS5kZXBhcnRtZW50MScsIENBX1JPTEUuVVNFUik7XG4gKiBjb25zdCBpZCA9IGF3YWl0IHN2Yy5lbnJvbGwoJ2FsaWNlJywgJ3MzY3IzdCcpO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBhdXRvbnVtYmVyXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBTdmMgYXMgRmFicmljRW5yb2xsbWVudFNlcnZpY2VcbiAqICAgcGFydGljaXBhbnQgQ0EgYXMgRmFicmljIENBXG4gKiAgIEFwcC0+PlN2YzogcmVnaXN0ZXIoY3JlZGVudGlhbHMsIC4uLilcbiAqICAgU3ZjLT4+Q0E6IHJlZ2lzdGVyKHJlcXVlc3QsIGFkbWluVXNlcilcbiAqICAgQ0EtLT4+U3ZjOiBlbnJvbGxtZW50U2VjcmV0XG4gKiAgIFN2Yy0tPj5BcHA6IHNlY3JldFxuICogICBBcHAtPj5TdmM6IGVucm9sbChlbnJvbGxtZW50SWQsIHNlY3JldClcbiAqICAgU3ZjLT4+Q0E6IGVucm9sbCh7ZW5yb2xsbWVudElELCBzZWNyZXR9KVxuICogICBDQS0tPj5TdmM6IGNlcnRpZmljYXRlc1xuICogICBTdmMtLT4+QXBwOiBJZGVudGl0eVxuICovXG5leHBvcnQgY2xhc3MgRmFicmljRW5yb2xsbWVudFNlcnZpY2UgZXh0ZW5kcyBMb2dnZWRDbGFzcyB7XG4gIHByaXZhdGUgY2E/OiBGYWJyaWNDQVNlcnZpY2VzO1xuXG4gIHByaXZhdGUgY2VydGlmaWNhdGVTZXJ2aWNlPzogYW55O1xuXG4gIHByaXZhdGUgYWZmaWxpYXRpb25TZXJ2aWNlPzogQWZmaWxpYXRpb25TZXJ2aWNlO1xuXG4gIHByaXZhdGUgaWRlbnRpdHlTZXJ2aWNlPzogSWRlbnRpdHlTZXJ2aWNlO1xuXG4gIHByaXZhdGUgY2xpZW50PzogYW55O1xuXG4gIHByaXZhdGUgdXNlcj86IFVzZXI7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjYUNvbmZpZzogQ0FDb25maWcpIHtcbiAgICBDb3JlVXRpbHMuZ2V0Q3J5cHRvU3VpdGUoXG4gICAgICBjYUNvbmZpZy5oc21cbiAgICAgICAgPyB7XG4gICAgICAgICAgICBzb2Z0d2FyZTogZmFsc2UsXG4gICAgICAgICAgICBsaWI6IGNhQ29uZmlnLmhzbS5saWJyYXJ5LFxuICAgICAgICAgICAgc2xvdDogY2FDb25maWcuaHNtLnNsb3QsXG4gICAgICAgICAgICBsYWJlbDogY2FDb25maWcuaHNtLnRva2VuTGFiZWwsXG4gICAgICAgICAgICBwaW46IFN0cmluZyhjYUNvbmZpZy5oc20ucGluKSxcbiAgICAgICAgICB9XG4gICAgICAgIDogdW5kZWZpbmVkXG4gICAgKTtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIFVzZXIoKTogUHJvbWlzZTxVc2VyPiB7XG4gICAgaWYgKHRoaXMudXNlcikgcmV0dXJuIHRoaXMudXNlcjtcbiAgICBjb25zdCB7IGNhTmFtZSwgY2FDZXJ0LCBjYUtleSwgdXJsLCBoc20gfSA9IHRoaXMuY2FDb25maWc7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuVXNlcik7XG4gICAgbG9nLmRlYnVnKGBDcmVhdGluZyBDQSB1c2VyIGZvciAke2NhTmFtZX0gYXQgJHt1cmx9YCk7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIENBIGNlcnRpZmljYXRlIGZyb20gJHtjYUNlcnR9YCk7XG4gICAgY29uc3QgY2VydGlmaWNhdGUgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0Rmlyc3REaXJGaWxlTmFtZUNvbnRlbnQoY2FDZXJ0KTtcbiAgICBsZXQga2V5OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgaWYgKCFoc20pIHtcbiAgICAgIGlmICghY2FLZXkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgICAgYE1pc3NpbmcgY2FLZXkgY29uZmlndXJhdGlvbiBmb3IgQ0EgJHtjYU5hbWV9LiBQcm92aWRlIGEga2V5IGRpcmVjdG9yeSBvciBjb25maWd1cmUgSFNNIHN1cHBvcnQuYFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIENBIGtleSBmcm9tICR7Y2FLZXl9YCk7XG4gICAgICBrZXkgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0Rmlyc3REaXJGaWxlTmFtZUNvbnRlbnQoY2FLZXkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBVc2luZyBIU00gY29uZmlndXJhdGlvbiBmb3IgQ0EgJHtjYU5hbWV9IHdpdGggbGlicmFyeSAke2hzbS5saWJyYXJ5fWBcbiAgICAgICk7XG4gICAgfVxuICAgIGxvZy5kZWJ1ZyhgTG9hZGluZyBBZG1pbiB1c2VyIGZvciBjYSAke2NhTmFtZX1gKTtcbiAgICB0aGlzLnVzZXIgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0Q0FVc2VyKFwiYWRtaW5cIiwga2V5LCBjZXJ0aWZpY2F0ZSwgY2FOYW1lLCB7XG4gICAgICBoc20sXG4gICAgfSk7XG4gICAgcmV0dXJuIHRoaXMudXNlcjtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBDQSgpOiBQcm9taXNlPEZhYnJpY0NBU2VydmljZXM+IHtcbiAgICBpZiAodGhpcy5jYSkgcmV0dXJuIHRoaXMuY2E7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuQ0EpO1xuICAgIGNvbnN0IHsgdXJsLCB0bHMsIGNhTmFtZSB9ID0gdGhpcy5jYUNvbmZpZztcblxuICAgIC8vIEZPUiBTb21lIFJlYXNvbiB0aGUgdmVyaWZpY2F0aW9uIGZhaWxzIG5lZWQgdG8gaW52ZXN0aWdhdGUgdGhpcyB3b3JrcyBmb3Igbm93XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHByZWZlci1jb25zdFxuICAgIGxldCB7IHRydXN0ZWRSb290cywgdmVyaWZ5IH0gPSB0bHMgYXMgVExTT3B0aW9ucztcblxuICAgIGNvbnN0IHJvb3QgPSAodHJ1c3RlZFJvb3RzIGFzIHN0cmluZ1tdKVswXSBhcyBzdHJpbmc7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIENBIGNlcnRpZmljYXRlIGZyb20gJHtyb290fS4gY3dkOiAke3Byb2Nlc3MuY3dkKCl9YCk7XG5cbiAgICBjb25zdCBjZXJ0aWZpY2F0ZSA9IGF3YWl0IENvcmVVdGlscy5nZXRGaWxlQ29udGVudChyb290KTtcbiAgICBsb2cuZGVidWcoYENyZWF0aW5nIENBIENsaWVudCBmb3IgQ0EgJHtjYU5hbWV9IHVuZGVyICR7dXJsfWApO1xuICAgIHRoaXMuY2EgPSBuZXcgRmFicmljQ0FTZXJ2aWNlcyhcbiAgICAgIHVybCxcbiAgICAgIHtcbiAgICAgICAgdHJ1c3RlZFJvb3RzOiBCdWZmZXIuZnJvbShjZXJ0aWZpY2F0ZSksXG4gICAgICAgIHZlcmlmeSxcbiAgICAgIH0gYXMgVExTT3B0aW9ucyxcbiAgICAgIGNhTmFtZVxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuY2E7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgQ2xpZW50KCk6IFByb21pc2U8eyBuZXdDZXJ0aWZpY2F0ZVNlcnZpY2U6IGFueSB9PiB7XG4gICAgaWYgKHRoaXMuY2xpZW50KSByZXR1cm4gdGhpcy5jbGllbnQ7XG4gICAgY29uc3QgY2EgPSBhd2FpdCB0aGlzLkNBKCk7XG4gICAgdGhpcy5jbGllbnQgPSAoY2EgYXMgYW55KVtcIl9GYWJyaWNDQVNlcnZpY2VzXCJdO1xuICAgIHJldHVybiB0aGlzLmNsaWVudDtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBDZXJ0aWZpY2F0ZSgpIHtcbiAgICBpZiAoIXRoaXMuY2VydGlmaWNhdGVTZXJ2aWNlKVxuICAgICAgdGhpcy5jZXJ0aWZpY2F0ZVNlcnZpY2UgPSAoYXdhaXQgdGhpcy5DbGllbnQoKSkubmV3Q2VydGlmaWNhdGVTZXJ2aWNlKCk7XG4gICAgcmV0dXJuIHRoaXMuY2VydGlmaWNhdGVTZXJ2aWNlO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIEFmZmlsaWF0aW9ucygpIHtcbiAgICBpZiAoIXRoaXMuYWZmaWxpYXRpb25TZXJ2aWNlKVxuICAgICAgdGhpcy5hZmZpbGlhdGlvblNlcnZpY2UgPSAoYXdhaXQgdGhpcy5DQSgpKS5uZXdBZmZpbGlhdGlvblNlcnZpY2UoKTtcbiAgICByZXR1cm4gdGhpcy5hZmZpbGlhdGlvblNlcnZpY2U7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgSWRlbnRpdGllcygpIHtcbiAgICBpZiAoIXRoaXMuaWRlbnRpdHlTZXJ2aWNlKVxuICAgICAgdGhpcy5pZGVudGl0eVNlcnZpY2UgPSAoYXdhaXQgdGhpcy5DQSgpKS5uZXdJZGVudGl0eVNlcnZpY2UoKTtcbiAgICByZXR1cm4gdGhpcy5pZGVudGl0eVNlcnZpY2U7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJldHJpZXZlIGNlcnRpZmljYXRlcyBmcm9tIHRoZSBDQS5cbiAgICogQHN1bW1hcnkgQ2FsbHMgdGhlIENBIGNlcnRpZmljYXRlIHNlcnZpY2UgdG8gbGlzdCBjZXJ0aWZpY2F0ZXMsIG9wdGlvbmFsbHkgbWFwcGluZyB0byBQRU0gc3RyaW5ncyBvbmx5LlxuICAgKiBAcGFyYW0ge0dldENlcnRpZmljYXRlc1JlcXVlc3R9IFtyZXF1ZXN0XSAtIE9wdGlvbmFsIGZpbHRlciByZXF1ZXN0IGZvciBjZXJ0aWZpY2F0ZSBsb29rdXAuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2RvTWFwPXRydWVdIC0gV2hlbiB0cnVlLCByZXR1cm5zIGFycmF5IG9mIFBFTSBzdHJpbmdzOyBvdGhlcndpc2UgcmV0dXJucyBmdWxsIHJlc3BvbnNlIG9iamVjdC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmdbXSB8IENlcnRpZmljYXRlUmVzcG9uc2U+fSBBcnJheSBvZiBQRU0gc3RyaW5ncyBvciB0aGUgZnVsbCBjZXJ0aWZpY2F0ZSByZXNwb25zZS5cbiAgICovXG4gIGFzeW5jIGdldENlcnRpZmljYXRlcyhcbiAgICByZXF1ZXN0PzogR2V0Q2VydGlmaWNhdGVzUmVxdWVzdCxcbiAgICBkb01hcCA9IHRydWVcbiAgKTogUHJvbWlzZTxzdHJpbmdbXSB8IENlcnRpZmljYXRlUmVzcG9uc2U+IHtcbiAgICBjb25zdCBjZXJ0aWZpY2F0ZVNlcnZpY2UgPSBhd2FpdCB0aGlzLkNlcnRpZmljYXRlKCk7XG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuVXNlcigpO1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmdldENlcnRpZmljYXRlcyk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYFJldHJpZXZpbmcgY2VydGlmaWNhdGVzJHtyZXF1ZXN0ID8gYCBmb3IgJHtyZXF1ZXN0LmlkfWAgOiBcIlwifSBmb3IgQ0EgJHt0aGlzLmNhQ29uZmlnLmNhTmFtZX1gXG4gICAgKTtcbiAgICBjb25zdCByZXNwb25zZTogQ2VydGlmaWNhdGVSZXNwb25zZSA9IChcbiAgICAgIGF3YWl0IGNlcnRpZmljYXRlU2VydmljZS5nZXRDZXJ0aWZpY2F0ZXMocmVxdWVzdCB8fCB7fSwgdXNlcilcbiAgICApLnJlc3VsdDtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgRm91bmQgJHtyZXNwb25zZS5jZXJ0cy5sZW5ndGh9IGNlcnRpZmljYXRlczogJHtKU09OLnN0cmluZ2lmeShyZXNwb25zZSl9YFxuICAgICk7XG4gICAgcmV0dXJuIGRvTWFwID8gcmVzcG9uc2UuY2VydHMubWFwKChjKSA9PiBjLlBFTSkgOiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gTGlzdCBpZGVudGl0aWVzIHJlZ2lzdGVyZWQgaW4gdGhlIENBLlxuICAgKiBAc3VtbWFyeSBRdWVyaWVzIHRoZSBDQSBpZGVudGl0eSBzZXJ2aWNlIHRvIGZldGNoIGFsbCBpZGVudGl0aWVzIGFuZCByZXR1cm5zIHRoZSBsaXN0IGFzIEZhYnJpY0lkZW50aXR5IG9iamVjdHMuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8RmFicmljSWRlbnRpdHlbXT59IFRoZSBsaXN0IG9mIGlkZW50aXRpZXMgcmVnaXN0ZXJlZCBpbiB0aGUgQ0EuXG4gICAqL1xuICBhc3luYyBnZXRJZGVudGl0aWVzKCk6IFByb21pc2U8RmFicmljSWRlbnRpdHlbXT4ge1xuICAgIGNvbnN0IGlkZW50aXRpZXNTZXJ2aWNlID0gYXdhaXQgdGhpcy5JZGVudGl0aWVzKCk7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuZ2V0SWRlbnRpdGllcyk7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIElkZW50aXRpZXMgdW5kZXIgQ0EgJHt0aGlzLmNhQ29uZmlnLmNhTmFtZX1gKTtcbiAgICBjb25zdCByZXNwb25zZTogSWRlbnRpdHlSZXNwb25zZSA9IChcbiAgICAgIGF3YWl0IGlkZW50aXRpZXNTZXJ2aWNlLmdldEFsbChhd2FpdCB0aGlzLlVzZXIoKSlcbiAgICApLnJlc3VsdDtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgRm91bmQgJHtyZXNwb25zZS5pZGVudGl0aWVzLmxlbmd0aH0gSWRlbnRpdGllczogJHtKU09OLnN0cmluZ2lmeShyZXNwb25zZSl9YFxuICAgICk7XG4gICAgcmV0dXJuIHJlc3BvbnNlLmlkZW50aXRpZXM7XG4gIH1cblxuICBwcm90ZWN0ZWQgcGFyc2VFcnJvcihlOiBFcnJvcikge1xuICAgIGNvbnN0IHJlZ2V4cCA9IC8uKmNvZGU6XFxzKFxcZCspLio/bWVzc2FnZTpcXHNbXCInXSguKylbXCInXS9ncztcbiAgICBjb25zdCBtYXRjaCA9IHJlZ2V4cC5leGVjKGUubWVzc2FnZSk7XG4gICAgaWYgKCFtYXRjaCkgcmV0dXJuIG5ldyBSZWdpc3RyYXRpb25FcnJvcihlKTtcbiAgICBjb25zdCBbLCBjb2RlLCBtZXNzYWdlXSA9IG1hdGNoO1xuICAgIHN3aXRjaCAoY29kZSkge1xuICAgICAgY2FzZSBcIjc0XCI6XG4gICAgICBjYXNlIFwiNzFcIjpcbiAgICAgICAgcmV0dXJuIG5ldyBDb25mbGljdEVycm9yKG1lc3NhZ2UpO1xuICAgICAgY2FzZSBcIjIwXCI6XG4gICAgICAgIHJldHVybiBuZXcgQXV0aG9yaXphdGlvbkVycm9yKG1lc3NhZ2UpO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIG5ldyBSZWdpc3RyYXRpb25FcnJvcihtZXNzYWdlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJldHJpZXZlIGFmZmlsaWF0aW9ucyBmcm9tIHRoZSBDQS5cbiAgICogQHN1bW1hcnkgUXVlcmllcyB0aGUgQ0EgZm9yIHRoZSBsaXN0IG9mIGFmZmlsaWF0aW9ucyBhdmFpbGFibGUgdW5kZXIgdGhlIGNvbmZpZ3VyZWQgQ0EuXG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGFmZmlsaWF0aW9ucyByZXN1bHQgcGF5bG9hZC5cbiAgICovXG4gIGFzeW5jIGdldEFmZmlsaWF0aW9ucygpIHtcbiAgICBjb25zdCBhZmZpbGlhdGlvblNlcnZpY2UgPSBhd2FpdCB0aGlzLkFmZmlsaWF0aW9ucygpO1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmdldEFmZmlsaWF0aW9ucyk7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIEFmZmlsaWF0aW9ucyB1bmRlciBDQSAke3RoaXMuY2FDb25maWcuY2FOYW1lfWApO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gKGF3YWl0IGFmZmlsaWF0aW9uU2VydmljZS5nZXRBbGwoYXdhaXQgdGhpcy5Vc2VyKCkpKVxuICAgICAgLnJlc3VsdDtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgRm91bmQgJHtyZXNwb25zZS5hLmxlbmd0aH0gQWZmaWxpYXRpb25zOiAke0pTT04uc3RyaW5naWZ5KHJlc3BvbnNlKX1gXG4gICAgKTtcbiAgICByZXR1cm4gcmVzcG9uc2U7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlYWQgaWRlbnRpdHkgZGV0YWlscyBmcm9tIHRoZSBDQSBieSBlbnJvbGxtZW50IElELlxuICAgKiBAc3VtbWFyeSBSZXRyaWV2ZXMgYW5kIHZhbGlkYXRlcyBhIHNpbmdsZSBpZGVudGl0eSwgdGhyb3dpbmcgTm90Rm91bmRFcnJvciB3aGVuIG1pc3NpbmcuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBlbnJvbGxtZW50SWQgLSBFbnJvbGxtZW50IElEIHRvIGxvb2t1cC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxGYWJyaWNJZGVudGl0eT59IFRoZSBpZGVudGl0eSBkZXRhaWxzIHN0b3JlZCBpbiB0aGUgQ0EuXG4gICAqL1xuICBhc3luYyByZWFkKGVucm9sbG1lbnRJZDogc3RyaW5nKSB7XG4gICAgY29uc3QgY2EgPSBhd2FpdCB0aGlzLkNBKCk7XG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuVXNlcigpO1xuICAgIGxldCByZXN1bHQ6IElTZXJ2aWNlUmVzcG9uc2U7XG4gICAgdHJ5IHtcbiAgICAgIHJlc3VsdCA9IGF3YWl0IGNhLm5ld0lkZW50aXR5U2VydmljZSgpLmdldE9uZShlbnJvbGxtZW50SWQsIHVzZXIpO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXJyb3IoXG4gICAgICAgIGBDb3VsZG4ndCBmaW5kIGVucm9sbG1lbnQgd2l0aCBpZCAke2Vucm9sbG1lbnRJZH06ICR7ZX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICghcmVzdWx0LnN1Y2Nlc3MpXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihcbiAgICAgICAgYENvdWxkbid0IGZpbmQgZW5yb2xsbWVudCB3aXRoIGlkICR7ZW5yb2xsbWVudElkfTogJHtyZXN1bHQuZXJyb3JzLmpvaW4oXCJcXG5cIil9YFxuICAgICAgKTtcblxuICAgIHJldHVybiByZXN1bHQucmVzdWx0IGFzIEZhYnJpY0lkZW50aXR5O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWdpc3RlciBhIG5ldyBpZGVudGl0eSB3aXRoIHRoZSBDQS5cbiAgICogQHN1bW1hcnkgU3VibWl0cyBhIHJlZ2lzdHJhdGlvbiByZXF1ZXN0IGZvciBhIG5ldyBlbnJvbGxtZW50IElELCByZXR1cm5pbmcgdGhlIGVucm9sbG1lbnQgc2VjcmV0IHVwb24gc3VjY2Vzcy5cbiAgICogQHBhcmFtIHtDcmVkZW50aWFsc30gbW9kZWwgLSBDcmVkZW50aWFscyBjb250YWluaW5nIHVzZXJOYW1lIGFuZCBwYXNzd29yZCBmb3IgdGhlIG5ldyBpZGVudGl0eS5cbiAgICogQHBhcmFtIHtib29sZWFufSBbaXNTdXBlclVzZXI9ZmFsc2VdIC0gV2hldGhlciB0byByZWdpc3RlciB0aGUgaWRlbnRpdHkgYXMgYSBzdXBlciB1c2VyLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FmZmlsaWF0aW9uPVwiXCJdIC0gQWZmaWxpYXRpb24gc3RyaW5nIChlLmcuLCBvcmcxLmRlcGFydG1lbnQxKS5cbiAgICogQHBhcmFtIHtDQV9ST0xFIHwgc3RyaW5nfSBbdXNlclJvbGVdIC0gUm9sZSB0byBhc3NpZ24gdG8gdGhlIGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge0lLZXlWYWx1ZUF0dHJpYnV0ZX0gW2F0dHJzXSAtIE9wdGlvbmFsIGF0dHJpYnV0ZXMgdG8gYXR0YWNoIHRvIHRoZSBpZGVudGl0eS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhFbnJvbGxtZW50c10gLSBNYXhpbXVtIG51bWJlciBvZiBlbnJvbGxtZW50cyBhbGxvd2VkIGZvciB0aGUgaWRlbnRpdHkuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gVGhlIGVucm9sbG1lbnQgc2VjcmV0IGZvciB0aGUgcmVnaXN0ZXJlZCBpZGVudGl0eS5cbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyKFxuICAgIG1vZGVsOiBDcmVkZW50aWFscyxcbiAgICBpc1N1cGVyVXNlcjogYm9vbGVhbiA9IGZhbHNlLFxuICAgIGFmZmlsaWF0aW9uOiBzdHJpbmcgPSBcIlwiLFxuICAgIHVzZXJSb2xlPzogQ0FfUk9MRSB8IHN0cmluZyxcbiAgICBhdHRycz86IElLZXlWYWx1ZUF0dHJpYnV0ZSxcbiAgICBtYXhFbnJvbGxtZW50cz86IG51bWJlclxuICApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGxldCByZWdpc3RyYXRpb246IHN0cmluZztcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5yZWdpc3Rlcik7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgdXNlck5hbWUsIHBhc3N3b3JkIH0gPSBtb2RlbDtcbiAgICAgIGNvbnN0IGNhID0gYXdhaXQgdGhpcy5DQSgpO1xuICAgICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuVXNlcigpO1xuICAgICAgY29uc3QgcHJvcHMgPSB7XG4gICAgICAgIGVucm9sbG1lbnRJRDogdXNlck5hbWUgYXMgc3RyaW5nLFxuICAgICAgICBlbnJvbGxtZW50U2VjcmV0OiBwYXNzd29yZCxcbiAgICAgICAgYWZmaWxpYXRpb246IGFmZmlsaWF0aW9uLFxuICAgICAgICB1c2VyUm9sZTogdXNlclJvbGUsXG4gICAgICAgIGF0dHJzOiBhdHRycyxcbiAgICAgICAgbWF4RW5yb2xsbWVudHM6IG1heEVucm9sbG1lbnRzLFxuICAgICAgfSBhcyBJUmVnaXN0ZXJSZXF1ZXN0O1xuICAgICAgcmVnaXN0cmF0aW9uID0gYXdhaXQgY2EucmVnaXN0ZXIocHJvcHMsIHVzZXIpO1xuICAgICAgbG9nLmluZm8oXG4gICAgICAgIGBSZWdpc3RyYXRpb24gZm9yICR7dXNlck5hbWV9IGNyZWF0ZWQgd2l0aCB1c2VyIHR5cGUgJHt1c2VyUm9sZSA/PyBcIlVuZGVmaW5lZCBSb2xlXCJ9ICR7aXNTdXBlclVzZXIgPyBcImFzIHN1cGVyIHVzZXJcIiA6IFwiXCJ9YFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlZ2lzdHJhdGlvbjtcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGF0aWMgaWRlbnRpdHlGcm9tRW5yb2xsbWVudChcbiAgICBlbnJvbGxtZW50OiBJRW5yb2xsUmVzcG9uc2UsXG4gICAgbXNwSWQ6IHN0cmluZ1xuICApOiBJZGVudGl0eSB7XG4gICAgY29uc3QgeyBjZXJ0aWZpY2F0ZSwga2V5LCByb290Q2VydGlmaWNhdGUgfSA9IGVucm9sbG1lbnQ7XG4gICAgY29uc3QgbG9nID0gTG9nZ2luZy5mb3IoRmFicmljRW5yb2xsbWVudFNlcnZpY2UsIHt9KS5mb3IoXG4gICAgICB0aGlzLmlkZW50aXR5RnJvbUVucm9sbG1lbnRcbiAgICApO1xuICAgIGxvZy5kZWJ1ZyhcbiAgICAgIGBHZW5lcmF0aW5nIElkZW50aXR5IGZyb20gY2VydGlmaWNhdGUgJHtjZXJ0aWZpY2F0ZX0gaW4gbXNwICR7bXNwSWR9YFxuICAgICk7XG4gICAgY29uc3QgY2xpZW50SWQgPSBDcnlwdG9VdGlscy5mYWJyaWNJZEZyb21DZXJ0aWZpY2F0ZShjZXJ0aWZpY2F0ZSk7XG4gICAgY29uc3QgaWQgPSBDcnlwdG9VdGlscy5lbmNvZGUoY2xpZW50SWQpO1xuICAgIGxvZy5kZWJ1ZyhgSWRlbnRpdHkgJHtjbGllbnRJZH0gYW5kIGVuY29kZWRJZCAke2lkfWApO1xuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgcmV0dXJuIG5ldyBJZGVudGl0eSh7XG4gICAgICBpZDogaWQsXG4gICAgICBjcmVkZW50aWFsczoge1xuICAgICAgICBpZDogaWQsXG4gICAgICAgIGNlcnRpZmljYXRlOiBjZXJ0aWZpY2F0ZSxcbiAgICAgICAgcHJpdmF0ZUtleToga2V5LnRvQnl0ZXMoKSxcbiAgICAgICAgcm9vdENlcnRpZmljYXRlOiByb290Q2VydGlmaWNhdGUsXG4gICAgICAgIGNyZWF0ZWRPbjogbm93LFxuICAgICAgICB1cGRhdGVkT246IG5vdyxcbiAgICAgIH0sXG4gICAgICBtc3BJZDogbXNwSWQsXG4gICAgICBjcmVhdGVkT246IG5vdyxcbiAgICAgIHVwZGF0ZWRPbjogbm93LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFbnJvbGwgYW4gaWRlbnRpdHkgd2l0aCB0aGUgQ0EgdXNpbmcgYSByZWdpc3RyYXRpb24gc2VjcmV0LlxuICAgKiBAc3VtbWFyeSBFeGNoYW5nZXMgdGhlIGVucm9sbG1lbnQgSUQgYW5kIHNlY3JldCBmb3IgY2VydGlmaWNhdGVzLCByZXR1cm5pbmcgYSBjb25zdHJ1Y3RlZCBJZGVudGl0eSBtb2RlbC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGVucm9sbG1lbnRJZCAtIEVucm9sbG1lbnQgSUQgdG8gZW5yb2xsLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVnaXN0cmF0aW9uIC0gRW5yb2xsbWVudCBzZWNyZXQgcmV0dXJuZWQgYXQgcmVnaXN0cmF0aW9uIHRpbWUuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8SWRlbnRpdHk+fSBUaGUgZW5yb2xsZWQgaWRlbnRpdHkgb2JqZWN0IHdpdGggY3JlZGVudGlhbHMuXG4gICAqL1xuICBhc3luYyBlbnJvbGwoZW5yb2xsbWVudElkOiBzdHJpbmcsIHJlZ2lzdHJhdGlvbjogc3RyaW5nKSB7XG4gICAgbGV0IGlkZW50aXR5OiBJZGVudGl0eTtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5lbnJvbGwpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjYSA9IGF3YWl0IHRoaXMuQ0EoKTtcbiAgICAgIGxvZy5kZWJ1ZyhgRW5yb2xsaW5nICR7ZW5yb2xsbWVudElkfWApO1xuICAgICAgY29uc3QgZW5yb2xsbWVudDogSUVucm9sbFJlc3BvbnNlID0gYXdhaXQgY2EuZW5yb2xsKHtcbiAgICAgICAgZW5yb2xsbWVudElEOiBlbnJvbGxtZW50SWQsXG4gICAgICAgIGVucm9sbG1lbnRTZWNyZXQ6IHJlZ2lzdHJhdGlvbixcbiAgICAgIH0pO1xuICAgICAgaWRlbnRpdHkgPSBGYWJyaWNFbnJvbGxtZW50U2VydmljZS5pZGVudGl0eUZyb21FbnJvbGxtZW50KFxuICAgICAgICBlbnJvbGxtZW50LFxuICAgICAgICB0aGlzLmNhQ29uZmlnLmNhTmFtZVxuICAgICAgKTtcbiAgICAgIGxvZy5pbmZvKFxuICAgICAgICBgU3VjY2Vzc2Z1bGx5IGVucm9sbGVkICR7ZW5yb2xsbWVudElkfSB1bmRlciAke3RoaXMuY2FDb25maWcuY2FOYW1lfSBhcyAke2lkZW50aXR5LmlkfWBcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSk7XG4gICAgfVxuICAgIHJldHVybiBpZGVudGl0eTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVnaXN0ZXIgYW5kIGVucm9sbCBhIG5ldyBpZGVudGl0eSBpbiBvbmUgc3RlcC5cbiAgICogQHN1bW1hcnkgUmVnaXN0ZXJzIGEgbmV3IGVucm9sbG1lbnQgSUQgd2l0aCB0aGUgQ0EgYW5kIGltbWVkaWF0ZWx5IGV4Y2hhbmdlcyB0aGUgc2VjcmV0IHRvIGVucm9sbCwgcmV0dXJuaW5nIHRoZSBjcmVhdGVkIElkZW50aXR5LlxuICAgKiBAcGFyYW0ge0NyZWRlbnRpYWxzfSBtb2RlbCAtIENyZWRlbnRpYWxzIGZvciB0aGUgbmV3IGlkZW50aXR5IGNvbnRhaW5pbmcgdXNlck5hbWUgYW5kIHBhc3N3b3JkLlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtpc1N1cGVyVXNlcj1mYWxzZV0gLSBXaGV0aGVyIHRvIHJlZ2lzdGVyIHRoZSBpZGVudGl0eSBhcyBhIHN1cGVyIHVzZXIuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYWZmaWxpYXRpb249XCJcIl0gLSBBZmZpbGlhdGlvbiBzdHJpbmcgKGUuZy4sIG9yZzEuZGVwYXJ0bWVudDEpLlxuICAgKiBAcGFyYW0ge0NBX1JPTEUgfCBzdHJpbmd9IFt1c2VyUm9sZV0gLSBSb2xlIHRvIGFzc2lnbiB0byB0aGUgaWRlbnRpdHkuXG4gICAqIEBwYXJhbSB7SUtleVZhbHVlQXR0cmlidXRlfSBbYXR0cnNdIC0gT3B0aW9uYWwgYXR0cmlidXRlcyB0byBhdHRhY2ggdG8gdGhlIGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge251bWJlcn0gW21heEVucm9sbG1lbnRzXSAtIE1heGltdW0gbnVtYmVyIG9mIGVucm9sbG1lbnRzIGFsbG93ZWQgZm9yIHRoZSBpZGVudGl0eS5cbiAgICogQHJldHVybiB7UHJvbWlzZTxJZGVudGl0eT59IFRoZSBlbnJvbGxlZCBpZGVudGl0eS5cbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyQW5kRW5yb2xsKFxuICAgIG1vZGVsOiBDcmVkZW50aWFscyxcbiAgICBpc1N1cGVyVXNlcjogYm9vbGVhbiA9IGZhbHNlLFxuICAgIGFmZmlsaWF0aW9uOiBzdHJpbmcgPSBcIlwiLFxuICAgIHVzZXJSb2xlPzogQ0FfUk9MRSB8IHN0cmluZyxcbiAgICBhdHRycz86IElLZXlWYWx1ZUF0dHJpYnV0ZSxcbiAgICBtYXhFbnJvbGxtZW50cz86IG51bWJlclxuICApOiBQcm9taXNlPElkZW50aXR5PiB7XG4gICAgY29uc3QgcmVnaXN0cmF0aW9uID0gYXdhaXQgdGhpcy5yZWdpc3RlcihcbiAgICAgIG1vZGVsLFxuICAgICAgaXNTdXBlclVzZXIsXG4gICAgICBhZmZpbGlhdGlvbixcbiAgICAgIHVzZXJSb2xlLFxuICAgICAgYXR0cnMsXG4gICAgICBtYXhFbnJvbGxtZW50c1xuICAgICk7XG4gICAgY29uc3QgeyB1c2VyTmFtZSB9ID0gbW9kZWw7XG4gICAgcmV0dXJuIHRoaXMuZW5yb2xsKHVzZXJOYW1lIGFzIHN0cmluZywgcmVnaXN0cmF0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXZva2VzIHRoZSBlbnJvbGxtZW50IG9mIGFuIGlkZW50aXR5IHdpdGggdGhlIHNwZWNpZmllZCBlbnJvbGxtZW50IElELlxuICAgKlxuICAgKiBAcGFyYW0gZW5yb2xsbWVudElkIC0gVGhlIGVucm9sbG1lbnQgSUQgb2YgdGhlIGlkZW50aXR5IHRvIGJlIHJldm9rZWQuXG4gICAqXG4gICAqIEByZXR1cm5zIEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXN1bHQgb2YgdGhlIHJldm9jYXRpb24gb3BlcmF0aW9uLlxuICAgKlxuICAgKiBAdGhyb3dzIHtOb3RGb3VuZEVycm9yfSBJZiB0aGUgZW5yb2xsbWVudCB3aXRoIHRoZSBzcGVjaWZpZWQgSUQgZG9lcyBub3QgZXhpc3QuXG4gICAqIEB0aHJvd3Mge0ludGVybmFsRXJyb3J9IElmIHRoZXJlIGlzIGFuIGVycm9yIGR1cmluZyB0aGUgcmV2b2NhdGlvbiBwcm9jZXNzLlxuICAgKi9cbiAgYXN5bmMgcmV2b2tlKGVucm9sbG1lbnRJZDogc3RyaW5nKSB7XG4gICAgY29uc3QgY2EgPSBhd2FpdCB0aGlzLkNBKCk7XG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuVXNlcigpO1xuICAgIGNvbnN0IGlkZW50aXR5ID0gYXdhaXQgdGhpcy5yZWFkKGVucm9sbG1lbnRJZCk7XG4gICAgaWYgKCFpZGVudGl0eSlcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEVycm9yKFxuICAgICAgICBgQ291bGQgbm90IGZpbmQgZW5yb2xsbWVudCB3aXRoIGlkICR7ZW5yb2xsbWVudElkfWBcbiAgICAgICk7XG4gICAgbGV0IHJlc3VsdDogSVNlcnZpY2VSZXNwb25zZTtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gYXdhaXQgY2EucmV2b2tlKFxuICAgICAgICB7IGVucm9sbG1lbnRJRDogaWRlbnRpdHkuaWQsIHJlYXNvbjogXCJVc2VyIERlbGV0YXRpb25cIiB9LFxuICAgICAgICB1c2VyXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBgQ291bGQgbm90IHJldm9rZSBlbnJvbGxtZW50IHdpdGggaWQgJHtlbnJvbGxtZW50SWR9OiAke2V9YFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCFyZXN1bHQuc3VjY2VzcylcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBgQ291bGQgbm90IHJldm9rZSBlbnJvbGxtZW50IHdpdGggaWQgJHtlbnJvbGxtZW50SWR9OiAke3Jlc3VsdC5lcnJvcnMuam9pbihcIlxcblwiKX1gXG4gICAgICApO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbn1cbiIsImltcG9ydCB7IElSZWdpc3RlclJlcXVlc3QsIElLZXlWYWx1ZUF0dHJpYnV0ZSB9IGZyb20gXCJmYWJyaWMtY2EtY2xpZW50XCI7XG5pbXBvcnQgeyBDQV9ST0xFIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQge1xuICBtaW4sXG4gIG1pbmxlbmd0aCxcbiAgTW9kZWwsXG4gIHJlcXVpcmVkLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBWYWxpZGF0aW9uRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuZXhwb3J0IGNsYXNzIFJlZ2lzdHJhdGlvblJlcXVlc3RCdWlsZGVyIGV4dGVuZHMgTW9kZWwge1xuICBAcmVxdWlyZWQoKVxuICBhZmZpbGlhdGlvbjogc3RyaW5nID0gXCJcIjtcbiAgQG1pbmxlbmd0aCgxKVxuICBhdHRycz86IElLZXlWYWx1ZUF0dHJpYnV0ZVtdO1xuICBAcmVxdWlyZWQoKVxuICBlbnJvbGxtZW50SUQhOiBzdHJpbmc7XG4gIEByZXF1aXJlZCgpXG4gIGVucm9sbG1lbnRTZWNyZXQhOiBzdHJpbmc7XG4gIEBtaW4oMClcbiAgbWF4RW5yb2xsbWVudHM/OiBudW1iZXI7XG4gIEByZXF1aXJlZCgpXG4gIHJvbGUhOiBzdHJpbmc7XG5cbiAgYnVpbGQoKTogSVJlZ2lzdGVyUmVxdWVzdCB7XG4gICAgY29uc3QgZXJycyA9IHRoaXMuaGFzRXJyb3JzKCk7XG4gICAgaWYgKGVycnMpIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoZXJycy50b1N0cmluZygpKTtcbiAgICBjb25zdCByZXNwb25zZTogSVJlZ2lzdGVyUmVxdWVzdCA9IHtcbiAgICAgIGVucm9sbG1lbnRJRDogdGhpcy5lbnJvbGxtZW50SUQsXG4gICAgICBlbnJvbGxtZW50U2VjcmV0OiB0aGlzLmVucm9sbG1lbnRTZWNyZXQsXG4gICAgICByb2xlOiB0aGlzLnJvbGUsXG4gICAgICBhZmZpbGlhdGlvbjogdGhpcy5hZmZpbGlhdGlvbixcbiAgICB9O1xuICAgIGlmICh0eXBlb2YgdGhpcy5tYXhFbnJvbGxtZW50cyAhPT0gXCJ1bmRlZmluZWRcIilcbiAgICAgIHJlc3BvbnNlLm1heEVucm9sbG1lbnRzID0gdGhpcy5tYXhFbnJvbGxtZW50cztcbiAgICBpZiAodGhpcy5hdHRycykgcmVzcG9uc2UuYXR0cnMgPSB0aGlzLmF0dHJzO1xuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIHNldEFmZmlsaWF0aW9uKHZhbHVlOiBzdHJpbmcpIHtcbiAgICB0aGlzLmFmZmlsaWF0aW9uID0gdmFsdWU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBhZGRBdHRyKGF0dHI6IElLZXlWYWx1ZUF0dHJpYnV0ZSkge1xuICAgIHRoaXMuYXR0cnMgPSB0aGlzLmF0dHJzIHx8IFtdO1xuICAgIHRoaXMuYXR0cnMucHVzaChhdHRyKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEF0dHJzKHZhbHVlOiBJS2V5VmFsdWVBdHRyaWJ1dGVbXSkge1xuICAgIHRoaXMuYXR0cnMgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEVucm9sbG1lbnRJRCh2YWx1ZTogc3RyaW5nKSB7XG4gICAgdGhpcy5lbnJvbGxtZW50SUQgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEVucm9sbG1lbnRTZWNyZXQodmFsdWU6IHN0cmluZykge1xuICAgIHRoaXMuZW5yb2xsbWVudFNlY3JldCA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0TWF4RW5yb2xsbWVudHModmFsdWU6IG51bWJlcikge1xuICAgIHRoaXMubWF4RW5yb2xsbWVudHMgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFJvbGUodmFsdWU6IENBX1JPTEUgfCBzdHJpbmcpIHtcbiAgICB0aGlzLnJvbGUgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuIiwiLyoqXG4gKiBFbnVtIHJlcHJlc2VudGluZyB0aGUgZXZlbnRzIGVtaXR0ZWQgYnkgYW4gRVJDMjAgY29udHJhY3QuXG4gKlxuICogQHJlbWFya3NcbiAqIFRoaXMgZW51bSBpcyB1c2VkIHRvIGlkZW50aWZ5IHRoZSBzcGVjaWZpYyBldmVudHMgdGhhdCBjYW4gYmUgZW1pdHRlZCBieSBhbiBFUkMyMCBjb250cmFjdC5cbiAqIFRoZSBldmVudHMgYXJlIG5hbWVkIGFjY29yZGluZyB0byB0aGUgRUlQLTIwIHN0YW5kYXJkLlxuICovXG5leHBvcnQgZW51bSBFUkMyMEV2ZW50cyB7XG4gIC8qKlxuICAgKiBFbWl0dGVkIHdoZW4gYSBgdHJhbnNmZXJgIGZ1bmN0aW9uIGlzIGNhbGxlZCBzdWNjZXNzZnVsbHkuXG4gICAqXG4gICAqIEBwYXJhbSBmcm9tIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHNlbmRlci5cbiAgICogQHBhcmFtIHRvIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHJlY2lwaWVudC5cbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGFtb3VudCBvZiB0b2tlbnMgdHJhbnNmZXJyZWQuXG4gICAqL1xuICBUUkFOU0ZFUiA9IFwiVHJhbnNmZXJcIixcblxuICAvKipcbiAgICogRW1pdHRlZCB3aGVuIGFuIGBhcHByb3ZlYCBmdW5jdGlvbiBpcyBjYWxsZWQgc3VjY2Vzc2Z1bGx5LlxuICAgKlxuICAgKiBAcGFyYW0gb3duZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgdG9rZW4gb3duZXIuXG4gICAqIEBwYXJhbSBzcGVuZGVyIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIGFwcHJvdmVkIHNwZW5kZXIuXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBhbW91bnQgb2YgdG9rZW5zIGFwcHJvdmVkIGZvciB0aGUgc3BlbmRlci5cbiAgICovXG4gIEFQUFJPVkFMID0gXCJBcHByb3ZhbFwiLFxufVxuIiwiaW1wb3J0IHsgTW9kZWwsIHR5cGUgTW9kZWxBcmcgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBjb2x1bW4sIGNyZWF0ZWRBdCwgdXBkYXRlZEF0IH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyB2ZXJzaW9uIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBkZXNjcmlwdGlvbiwgdXNlcyB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljRmxhdm91ciB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IFByb3BlcnR5IH0gZnJvbSBcImZhYnJpYy1jb250cmFjdC1hcGlcIjtcblxuQHVzZXMoRmFicmljRmxhdm91cilcbmV4cG9ydCBjbGFzcyBGYWJyaWNCYXNlTW9kZWwgZXh0ZW5kcyBNb2RlbCB7XG4gIEBkZXNjcmlwdGlvbihcIlN0b3JlcyB0aGUgb3JpZ2luYWwgdGltZXN0YW1wIG9mIGNyZWF0aW9uXCIpXG4gIEBjb2x1bW4oKVxuICBAY3JlYXRlZEF0KClcbiAgY3JlYXRlZEF0ITogRGF0ZTtcblxuICBAZGVzY3JpcHRpb24oXCJTdG9yZXMgdGhlIHRpbWVzdGFtcCBvZiB0aGUgbGFzdCB1cGRhdGVcIilcbiAgQGNvbHVtbigpXG4gIEB1cGRhdGVkQXQoKVxuICB1cGRhdGVkQXQhOiBEYXRlO1xuXG4gIEBkZXNjcmlwdGlvbihcIlN0b3JlcyB0aGUgdmVyc2lvbiBvZiB0aGUgbW9kZWxcIilcbiAgQGNvbHVtbigpXG4gIEB2ZXJzaW9uKClcbiAgdmVyc2lvbiE6IG51bWJlcjtcblxuICBjb25zdHJ1Y3Rvcihhcmc/OiBNb2RlbEFyZzxGYWJyaWNCYXNlTW9kZWw+KSB7XG4gICAgc3VwZXIoYXJnKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgdHlwZSBNb2RlbEFyZyB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IGNvbHVtbiwgY3JlYXRlZEJ5LCB1cGRhdGVkQnkgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IGRlc2NyaXB0aW9uLCB1c2VzIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBGYWJyaWNGbGF2b3VyIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgRmFicmljQmFzZU1vZGVsIH0gZnJvbSBcIi4vRmFicmljQmFzZU1vZGVsXCI7XG5cbkB1c2VzKEZhYnJpY0ZsYXZvdXIpXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRmFicmljSWRlbnRpZmllZEJhc2VNb2RlbCBleHRlbmRzIEZhYnJpY0Jhc2VNb2RlbCB7XG4gIEBkZXNjcmlwdGlvbihcIlN0b3JlcyB0aGUgY3JlYXRvclwiKVxuICBAY29sdW1uKClcbiAgQGNyZWF0ZWRCeSgpXG4gIGNyZWF0ZWRCeSE6IHN0cmluZztcblxuICBAZGVzY3JpcHRpb24oXCJTdG9yZXMgdGhlIHVzZXIgdGhhdCBsYXN0IHVwZGF0ZWQgdGhlIG1vZGVsXCIpXG4gIEBjb2x1bW4oKVxuICBAdXBkYXRlZEJ5KClcbiAgdXBkYXRlZEJ5ITogc3RyaW5nO1xuXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3Rvcihhcmc/OiBNb2RlbEFyZzxGYWJyaWNJZGVudGlmaWVkQmFzZU1vZGVsPikge1xuICAgIHN1cGVyKGFyZyk7XG4gIH1cbn1cbiIsImltcG9ydCB7IE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IsIE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBGYWJyaWNNb2RlbEtleXMgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBTZWdyZWdhdGVkTW9kZWwgfSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IERCS2V5cywgSW50ZXJuYWxFcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQ29udGV4dCB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgQ29sbGVjdGlvblJlc29sdmVyLCBNaXJyb3JNZXRhZGF0YSB9IGZyb20gXCIuLi9kZWNvcmF0b3JzXCI7XG5cbk1vZGVsLnByb3RvdHlwZS5pc1NoYXJlZCA9IGZ1bmN0aW9uIGlzU2hhcmVkPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIHRoaXM6IE1cbik6IGJvb2xlYW4ge1xuICByZXR1cm4gTW9kZWwuaXNTaGFyZWQodGhpcy5jb25zdHJ1Y3RvciBhcyBDb25zdHJ1Y3RvcjxNPik7XG59O1xuXG5Nb2RlbC5wcm90b3R5cGUuaXNQcml2YXRlID0gZnVuY3Rpb24gaXNQcml2YXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIHRoaXM6IE1cbik6IGJvb2xlYW4ge1xuICByZXR1cm4gTW9kZWwuaXNQcml2YXRlKHRoaXMuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3I8TT4pO1xufTtcblxuTW9kZWwucHJvdG90eXBlLnNlZ3JlZ2F0ZSA9IGZ1bmN0aW9uIHNlZ3JlZ2F0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICB0aGlzOiBNXG4pOiBTZWdyZWdhdGVkTW9kZWw8TT4ge1xuICByZXR1cm4gTW9kZWwuc2VncmVnYXRlKHRoaXMpO1xufTtcblxuKE1vZGVsIGFzIGFueSkuc2VncmVnYXRlID0gZnVuY3Rpb24gc2VncmVnYXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNXG4pOiBTZWdyZWdhdGVkTW9kZWw8TT4ge1xuICBpZiAoIU1vZGVsLmlzVHJhbnNpZW50KG1vZGVsKSkgcmV0dXJuIHsgbW9kZWw6IG1vZGVsIH07XG4gIGNvbnN0IGRlY29yYXRlZFByb3BlcnRpZXMgPSBNZXRhZGF0YS52YWxpZGF0YWJsZVByb3BlcnRpZXMoXG4gICAgbW9kZWwuY29uc3RydWN0b3IgYXMgYW55XG4gICk7XG5cbiAgY29uc3QgdHJhbnNpZW50UHJvcHMgPSBNZXRhZGF0YS5nZXQoXG4gICAgbW9kZWwuY29uc3RydWN0b3IgYXMgYW55LFxuICAgIERCS2V5cy5UUkFOU0lFTlRcbiAgKTtcbiAgY29uc3QgcHJpdmF0ZVByb3BlcnRpZXMgPSBNZXRhZGF0YS5nZXQoXG4gICAgbW9kZWwuY29uc3RydWN0b3IgYXMgYW55LFxuICAgIEZhYnJpY01vZGVsS2V5cy5QUklWQVRFXG4gICk7XG4gIGNvbnN0IHNoYXJlZFByb3BlcnRpZXMgPSBNZXRhZGF0YS5nZXQoXG4gICAgbW9kZWwuY29uc3RydWN0b3IgYXMgYW55LFxuICAgIEZhYnJpY01vZGVsS2V5cy5QUklWQVRFXG4gICk7XG5cbiAgY29uc3QgcmVzdWx0OiBTZWdyZWdhdGVkTW9kZWw8TT4gPSB7XG4gICAgbW9kZWw6IHt9IGFzIFJlY29yZDxrZXlvZiBNLCBhbnk+LFxuICAgIHRyYW5zaWVudDoge30gYXMgUmVjb3JkPGtleW9mIE0sIGFueT4sXG4gICAgcHJpdmF0ZToge30gYXMgUmVjb3JkPGtleW9mIE0sIGFueT4sXG4gICAgc2hhcmVkOiB7fSBhcyBSZWNvcmQ8a2V5b2YgTSwgYW55PixcbiAgfTtcblxuICBjb25zdCB0cmFuc2llbnRLZXlzID0gT2JqZWN0LmtleXModHJhbnNpZW50UHJvcHMpO1xuICBjb25zdCBwcml2YXRlS2V5cyA9IE9iamVjdC5rZXlzKHByaXZhdGVQcm9wZXJ0aWVzKTtcbiAgY29uc3Qgc2hhcmVkS2V5cyA9IE9iamVjdC5rZXlzKHNoYXJlZFByb3BlcnRpZXMpO1xuXG4gIGZvciAoY29uc3Qga2V5IG9mIGRlY29yYXRlZFByb3BlcnRpZXMpIHtcbiAgICBjb25zdCBpc1RyYW5zaWVudCA9IHRyYW5zaWVudEtleXMuaW5jbHVkZXMoa2V5KTtcbiAgICBjb25zdCBpc1ByaXZhdGUgPSBwcml2YXRlS2V5cy5pbmNsdWRlcyhrZXkpO1xuICAgIGNvbnN0IGlzU2hhcmVkID0gc2hhcmVkS2V5cy5pbmNsdWRlcyhrZXkpO1xuICAgIGlmIChpc1RyYW5zaWVudCkge1xuICAgICAgcmVzdWx0LnRyYW5zaWVudCA9IHJlc3VsdC50cmFuc2llbnQgfHwgKHt9IGFzIGFueSk7XG4gICAgICAocmVzdWx0LnRyYW5zaWVudCBhcyBhbnkpW2tleV0gPSBtb2RlbFtrZXkgYXMga2V5b2YgTV07XG4gICAgICBpZiAoaXNQcml2YXRlKSB7XG4gICAgICAgIHJlc3VsdC5wcml2YXRlID0gcmVzdWx0LnByaXZhdGUgfHwgKHt9IGFzIGFueSk7XG4gICAgICAgIChyZXN1bHQucHJpdmF0ZSBhcyBhbnkpW2tleV0gPSBtb2RlbFtrZXkgYXMga2V5b2YgTV07XG4gICAgICB9XG4gICAgICBpZiAoaXNTaGFyZWQpIHtcbiAgICAgICAgcmVzdWx0LnNoYXJlZCA9IHJlc3VsdC5zaGFyZWQgfHwgKHt9IGFzIGFueSk7XG4gICAgICAgIChyZXN1bHQuc2hhcmVkIGFzIGFueSlba2V5XSA9IG1vZGVsW2tleSBhcyBrZXlvZiBNXTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmVzdWx0Lm1vZGVsID0gcmVzdWx0Lm1vZGVsIHx8IHt9O1xuICAgICAgKHJlc3VsdC5tb2RlbCBhcyBhbnkpW2tleV0gPSAobW9kZWwgYXMgUmVjb3JkPHN0cmluZywgYW55Pilba2V5XTtcbiAgICB9XG4gIH1cblxuICByZXN1bHQubW9kZWwgPSBNb2RlbC5idWlsZChyZXN1bHQubW9kZWwsIG1vZGVsLmNvbnN0cnVjdG9yLm5hbWUpO1xuICByZXR1cm4gcmVzdWx0IGFzIFNlZ3JlZ2F0ZWRNb2RlbDxNPjtcbn0uYmluZChNb2RlbCk7XG5cbihNb2RlbCBhcyBhbnkpLmlzUHJpdmF0ZSA9IGZ1bmN0aW9uIGlzUHJpdmF0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICBtb2RlbDogTSB8IENvbnN0cnVjdG9yPE0+XG4pOiBib29sZWFuIHtcbiAgcmV0dXJuICEhTWV0YWRhdGEuZ2V0KFxuICAgIHR5cGVvZiBtb2RlbCAhPT0gXCJmdW5jdGlvblwiID8gKG1vZGVsLmNvbnN0cnVjdG9yIGFzIGFueSkgOiBtb2RlbCxcbiAgICBGYWJyaWNNb2RlbEtleXMuUFJJVkFURVxuICApO1xufS5iaW5kKE1vZGVsKTtcblxuKE1vZGVsIGFzIGFueSkuaXNTaGFyZWQgPSBmdW5jdGlvbiBpc1NoYXJlZDxNIGV4dGVuZHMgTW9kZWw+KFxuICBtb2RlbDogTSB8IENvbnN0cnVjdG9yPE0+XG4pOiBib29sZWFuIHtcbiAgcmV0dXJuICEhTWV0YWRhdGEuZ2V0KFxuICAgIHR5cGVvZiBtb2RlbCAhPT0gXCJmdW5jdGlvblwiID8gKG1vZGVsLmNvbnN0cnVjdG9yIGFzIGFueSkgOiBtb2RlbCxcbiAgICBGYWJyaWNNb2RlbEtleXMuU0hBUkVEXG4gICk7XG59LmJpbmQoTW9kZWwpO1xuXG4oTW9kZWwgYXMgYW55KS5taXJyb3JlZCA9IGZ1bmN0aW9uIG1pcnJvcmVkPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNIHwgQ29uc3RydWN0b3I8TT5cbik6IGJvb2xlYW4ge1xuICByZXR1cm4gTWV0YWRhdGEuZ2V0KFxuICAgIHR5cGVvZiBtb2RlbCAhPT0gXCJmdW5jdGlvblwiID8gKG1vZGVsLmNvbnN0cnVjdG9yIGFzIGFueSkgOiBtb2RlbCxcbiAgICBNZXRhZGF0YS5rZXkoRmFicmljTW9kZWxLZXlzLkZBQlJJQywgRmFicmljTW9kZWxLZXlzLk1JUlJPUilcbiAgKTtcbn0uYmluZChNb2RlbCk7XG5cbihNb2RlbCBhcyBhbnkpLm93bmVyT2YgPSBmdW5jdGlvbiBvd25lck9mPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNXG4pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBtZXRhID0gTWV0YWRhdGEuZ2V0KFxuICAgIG1vZGVsLmNvbnN0cnVjdG9yIGFzIGFueSxcbiAgICBNZXRhZGF0YS5rZXkoRmFicmljTW9kZWxLZXlzLkZBQlJJQywgRmFicmljTW9kZWxLZXlzLk9XTkVEX0JZKVxuICApO1xuICBpZiAoIW1ldGEpIHJldHVybiB1bmRlZmluZWQ7XG4gIHJldHVybiBtb2RlbFttZXRhIGFzIGtleW9mIE1dIGFzIHN0cmluZztcbn0uYmluZChNb2RlbCk7XG5cbihNb2RlbCBhcyBhbnkpLm1pcnJvcmVkQXQgPSBmdW5jdGlvbiBtaXJyb3JlZEF0PE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNIHwgQ29uc3RydWN0b3I8TT5cbik6IE1pcnJvck1ldGFkYXRhIHwgdW5kZWZpbmVkIHtcbiAgbW9kZWwgPSB0eXBlb2YgbW9kZWwgIT09IFwiZnVuY3Rpb25cIiA/IChtb2RlbC5jb25zdHJ1Y3RvciBhcyBhbnkpIDogbW9kZWw7XG4gIHJldHVybiBNZXRhZGF0YS5nZXQoXG4gICAgbW9kZWwgYXMgYW55LFxuICAgIE1ldGFkYXRhLmtleShGYWJyaWNNb2RlbEtleXMuRkFCUklDLCBGYWJyaWNNb2RlbEtleXMuTUlSUk9SKVxuICApO1xufS5iaW5kKE1vZGVsKTtcblxuKE1vZGVsIGFzIGFueSkuY29sbGVjdGlvbnNGb3IgPSBmdW5jdGlvbiBjb2xsZWN0aW9uc0ZvcjxNIGV4dGVuZHMgTW9kZWw+KFxuICBtb2RlbDogTSB8IENvbnN0cnVjdG9yPE0+XG4pOiB7XG4gIHByaXZhdGVDb2xzOiAoc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyKVtdO1xuICBzaGFyZWRDb2xzOiAoc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyKVtdO1xufSB7XG4gIGNvbnN0IHByaXZhdGVLZXlzOiBzdHJpbmdbXSA9IFtGYWJyaWNNb2RlbEtleXMuUFJJVkFURV0gYXMgc3RyaW5nW107XG4gIGNvbnN0IHNoYXJlZEtleXM6IHN0cmluZ1tdID0gW0ZhYnJpY01vZGVsS2V5cy5TSEFSRURdIGFzIHN0cmluZ1tdO1xuXG4gIGNvbnN0IHByaXZhdGVLZXkgPSBNZXRhZGF0YS5rZXkoLi4ucHJpdmF0ZUtleXMpO1xuICBjb25zdCBzaGFyZWRLZXkgPSBNZXRhZGF0YS5rZXkoLi4uc2hhcmVkS2V5cyk7XG5cbiAgY29uc3QgY29uc3RyID0gdHlwZW9mIG1vZGVsID09PSBcImZ1bmN0aW9uXCIgPyBtb2RlbCA6IG1vZGVsLmNvbnN0cnVjdG9yO1xuXG4gIGNvbnN0IHByaXZhdGVNZXRhOiB7IGNvbGxlY3Rpb25zOiBzdHJpbmdbXSB9ID0gTWV0YWRhdGEuZ2V0KFxuICAgIGNvbnN0ciBhcyBhbnksXG4gICAgcHJpdmF0ZUtleVxuICApO1xuICBjb25zdCBzaGFyZWRNZXRhOiB7IGNvbGxlY3Rpb25zOiBzdHJpbmdbXSB9ID0gTWV0YWRhdGEuZ2V0KFxuICAgIGNvbnN0ciBhcyBhbnksXG4gICAgc2hhcmVkS2V5XG4gICk7XG5cbiAgcmV0dXJuIHtcbiAgICBwcml2YXRlQ29sczogcHJpdmF0ZU1ldGE/LmNvbGxlY3Rpb25zIHx8IFtdLFxuICAgIHNoYXJlZENvbHM6IHNoYXJlZE1ldGE/LmNvbGxlY3Rpb25zIHx8IFtdLFxuICB9O1xufS5iaW5kKE1vZGVsKTtcbiIsImltcG9ydCB7XG4gIEF1dGhvcml6YXRpb25FcnJvcixcbiAgUmVwbyxcbiAgQ29udGV4dCxcbiAgVW5zdXBwb3J0ZWRFcnJvcixcbiAgUmVwb3NpdG9yeSxcbiAgQ29udGV4dE9mLFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7XG4gIGFmdGVyQ3JlYXRlLFxuICBhZnRlckRlbGV0ZSxcbiAgYWZ0ZXJVcGRhdGUsXG4gIEludGVybmFsRXJyb3IsXG4gIE5vdEZvdW5kRXJyb3IsXG4gIG9uQ3JlYXRlLFxuICBvbkRlbGV0ZSxcbiAgb25SZWFkLFxuICBvblVwZGF0ZSxcbiAgcmVhZG9ubHksXG4gIHRyYW5zaWVudCxcbiAgVmFsaWRhdGlvbkVycm9yLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IE1vZGVsLCByZXF1aXJlZCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY01vZGVsS2V5cyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0IGFzIEhMQ29udGV4dCB9IGZyb20gXCJmYWJyaWMtY29udHJhY3QtYXBpXCI7XG5pbXBvcnQgeyBGYWJyaWNFUkMyMENvbnRyYWN0IH0gZnJvbSBcIi4uL2NvbnRyYWN0cy9lcmMyMC9lcmMyMGNvbnRyYWN0XCI7XG5pbXBvcnQge1xuICBhcHBseSxcbiAgQ29uc3RydWN0b3IsXG4gIERlY29yYXRpb24sXG4gIG1ldGFkYXRhLFxuICBNZXRhZGF0YSxcbiAgcHJvcCxcbiAgcHJvcE1ldGFkYXRhLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0ZsYWdzIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IHRvUGFzY2FsQ2FzZSB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RGbGFncyB9IGZyb20gXCIuLi9jb250cmFjdHMvdHlwZXNcIjtcbmltcG9ydCBcIi4uL3NoYXJlZC9vdmVycmlkZXNcIjtcblxuLyoqXG4gKiBEZWNvcmF0b3IgZm9yIG1hcmtpbmcgbWV0aG9kcyB0aGF0IHJlcXVpcmUgb3duZXJzaGlwIGF1dGhvcml6YXRpb24uXG4gKiBDaGVja3MgdGhlIG93bmVyIG9mIHRoZSB0b2tlbiBiZWZvcmUgYWxsb3dpbmcgdGhlIG1ldGhvZCB0byBiZSBleGVjdXRlZC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY2xhc3MgVG9rZW5Db250cmFjdCBleHRlbmRzIENvbnRyYWN0IHtcbiAqICAgQE93bmVyKClcbiAqICAgYXN5bmMgTWludChjdHg6IENvbnRleHQsIGFtb3VudDogbnVtYmVyKSB7XG4gKiAgICAgLy8gTWludCB0b2tlbiBsb2dpY1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAcmV0dXJucyB7TWV0aG9kRGVjb3JhdG9yfSBBIG1ldGhvZCBkZWNvcmF0b3IgdGhhdCBjaGVja3Mgb3duZXJzaGlwIGF1dGhvcml6YXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPd25lcigpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBwcm9wZXJ0eUtleTogc3RyaW5nLFxuICAgIGRlc2NyaXB0b3I6IFByb3BlcnR5RGVzY3JpcHRvclxuICApIHtcbiAgICBjb25zdCBvcmlnaW5hbE1ldGhvZCA9IGRlc2NyaXB0b3IudmFsdWU7XG5cbiAgICBkZXNjcmlwdG9yLnZhbHVlID0gYXN5bmMgZnVuY3Rpb24gKFxuICAgICAgdGhpczogRmFicmljRVJDMjBDb250cmFjdCxcbiAgICAgIC4uLmFyZ3M6IGFueVtdXG4gICAgKSB7XG4gICAgICBjb25zdCBjdHg6IEhMQ29udGV4dCA9IGFyZ3NbMF07XG4gICAgICBjb25zdCBhY291bnRJZCA9IGN0eC5jbGllbnRJZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgICBjb25zdCBzZWxlY3QgPSBhd2FpdCAodGhpcyBhcyBGYWJyaWNFUkMyMENvbnRyYWN0KVtcbiAgICAgICAgXCJ0b2tlblJlcG9zaXRvcnlcIlxuICAgICAgXS5zZWxlY3QoKTtcblxuICAgICAgY29uc3QgdG9rZW5zID0gYXdhaXQgc2VsZWN0LmV4ZWN1dGUoY3R4KTtcblxuICAgICAgaWYgKHRva2Vucy5sZW5ndGggPT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihcIk5vIHRva2VucyBhdmFpYWxibGVcIik7XG4gICAgICB9XG5cbiAgICAgIGlmICh0b2tlbnMubGVuZ3RoID4gMSkge1xuICAgICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihgVG8gbWFueSB0b2tlbiBhdmFpbGFibGUgOiAke3Rva2Vucy5sZW5ndGh9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0b2tlbnNbMF0ub3duZXIgIT0gYWNvdW50SWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEF1dGhvcml6YXRpb25FcnJvcihcbiAgICAgICAgICBgVXNlciBub3QgYXV0aG9yaXplZCB0byBydW4gJHtwcm9wZXJ0eUtleX0gb24gdGhlIHRva2VuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gYXdhaXQgb3JpZ2luYWxNZXRob2QuYXBwbHkodGhpcywgYXJncyk7XG4gICAgfTtcblxuICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICB9O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gb3duZWRCeU9uQ3JlYXRlPFxuICBNIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4sXG4gIFIgZXh0ZW5kcyBSZXBvPE0+LFxuICBWLFxuPihcbiAgdGhpczogUixcbiAgY29udGV4dDogQ29udGV4dE9mPFI+LFxuICBkYXRhOiBWLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgeyBzdHViIH0gPSBjb250ZXh0IGFzIGFueTtcblxuICBjb25zdCBjcmVhdG9yID0gYXdhaXQgc3R1Yi5nZXRDcmVhdG9yKCk7XG4gIGNvbnN0IG93bmVyID0gY3JlYXRvci5tc3BpZDtcblxuICBjb25zdCBzZXRPd25lZEJ5S2V5VmFsdWUgPSBmdW5jdGlvbiA8TSBleHRlbmRzIE1vZGVsPihcbiAgICB0YXJnZXQ6IE0sXG4gICAgcHJvcGVydHlLZXk6IHN0cmluZyxcbiAgICB2YWx1ZTogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50XG4gICkge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIHByb3BlcnR5S2V5LCB7XG4gICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgdmFsdWU6IHZhbHVlLFxuICAgIH0pO1xuICB9O1xuXG4gIHNldE93bmVkQnlLZXlWYWx1ZShtb2RlbCwga2V5IGFzIHN0cmluZywgb3duZXIpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gb3duZWRCeSgpIHtcbiAgZnVuY3Rpb24gb3duZWRCeSgpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKG9iajogYW55LCBhdHRyaWJ1dGU/OiBhbnkpIHtcbiAgICAgIHJldHVybiBhcHBseShcbiAgICAgICAgcmVxdWlyZWQoKSxcbiAgICAgICAgcmVhZG9ubHkoKSxcbiAgICAgICAgb25DcmVhdGUob3duZWRCeU9uQ3JlYXRlKSxcbiAgICAgICAgcHJvcE1ldGFkYXRhKFxuICAgICAgICAgIE1ldGFkYXRhLmtleShGYWJyaWNNb2RlbEtleXMuRkFCUklDLCBGYWJyaWNNb2RlbEtleXMuT1dORURfQlkpLFxuICAgICAgICAgIGF0dHJpYnV0ZVxuICAgICAgICApXG4gICAgICApKG9iaiwgYXR0cmlidXRlKTtcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKEZhYnJpY01vZGVsS2V5cy5PV05FRF9CWSlcbiAgICAuZGVmaW5lKHtcbiAgICAgIGRlY29yYXRvcjogb3duZWRCeSxcbiAgICAgIGFyZ3M6IFtdLFxuICAgIH0pXG4gICAgLmFwcGx5KCk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB0cmFuc2FjdGlvbklkT25DcmVhdGU8XG4gIE0gZXh0ZW5kcyBNb2RlbDxib29sZWFuPixcbiAgUiBleHRlbmRzIFJlcG88TT4sXG4gIFYsXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBDb250ZXh0T2Y8Uj4sXG4gIGRhdGE6IFYsXG4gIGtleToga2V5b2YgTSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB7IHN0dWIgfSA9IGNvbnRleHQgYXMgYW55O1xuICBtb2RlbFtrZXldID0gc3R1Yi5nZXRUeElEKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0cmFuc2FjdGlvbklkKCkge1xuICBmdW5jdGlvbiB0cmFuc2FjdGlvbklkKCkge1xuICAgIHJldHVybiBmdW5jdGlvbiAob2JqOiBhbnksIGF0dHJpYnV0ZT86IGFueSkge1xuICAgICAgcmV0dXJuIGFwcGx5KFxuICAgICAgICByZXF1aXJlZCgpLFxuICAgICAgICByZWFkb25seSgpLFxuICAgICAgICBvbkNyZWF0ZSh0cmFuc2FjdGlvbklkT25DcmVhdGUpLFxuICAgICAgICBvblVwZGF0ZSh0cmFuc2FjdGlvbklkT25DcmVhdGUpLFxuICAgICAgICBwcm9wTWV0YWRhdGEoXG4gICAgICAgICAgTWV0YWRhdGEua2V5KFxuICAgICAgICAgICAgRmFicmljTW9kZWxLZXlzLkZBQlJJQyxcbiAgICAgICAgICAgIGF0dHJpYnV0ZSxcbiAgICAgICAgICAgIEZhYnJpY01vZGVsS2V5cy5UUkFOU0FDVElPTl9JRFxuICAgICAgICAgICksXG4gICAgICAgICAgYXR0cmlidXRlXG4gICAgICAgIClcbiAgICAgICkob2JqLCBhdHRyaWJ1dGUpO1xuICAgIH07XG4gIH1cblxuICByZXR1cm4gRGVjb3JhdGlvbi5mb3IoRmFicmljTW9kZWxLZXlzLlRSQU5TQUNUSU9OX0lEKVxuICAgIC5kZWZpbmUoe1xuICAgICAgZGVjb3JhdG9yOiB0cmFuc2FjdGlvbklkLFxuICAgICAgYXJnczogW10sXG4gICAgfSlcbiAgICAuYXBwbHkoKTtcbn1cblxuZXhwb3J0IHR5cGUgTWlycm9yQ29uZGl0aW9uID0gKG1zcDogc3RyaW5nKSA9PiBib29sZWFuO1xuXG5leHBvcnQgdHlwZSBNaXJyb3JNZXRhZGF0YSA9IHtcbiAgY29uZGl0aW9uOiBNaXJyb3JDb25kaXRpb247XG4gIHJlc29sdmVyOiBDb2xsZWN0aW9uUmVzb2x2ZXIgfCBzdHJpbmc7XG59O1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXZhbE1pcnJvck1ldGFkYXRhPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNLFxuICByZXNvbHZlcjogdW5kZWZpbmVkIHwgc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyLFxuICBjdHg6IENvbnRleHQ8RmFicmljQ29udHJhY3RGbGFncz5cbikge1xuICBsZXQgY29sbGVjdGlvbjogQ29sbGVjdGlvblJlc29sdmVyIHwgc3RyaW5nIHwgdW5kZWZpbmVkID0gcmVzb2x2ZXI7XG4gIGlmICh0eXBlb2YgY29sbGVjdGlvbiAhPT0gXCJzdHJpbmdcIikge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBvd25lciA9XG4gICAgICAgIE1vZGVsLm93bmVyT2YobW9kZWwpIHx8IGN0eC5nZXQoXCJzdHViXCIpLmdldENyZWF0b3IoKS50b1N0cmluZygpO1xuICAgICAgaWYgKHJlc29sdmVyICYmIHR5cGVvZiByZXNvbHZlciA9PT0gXCJmdW5jdGlvblwiKVxuICAgICAgICBjb2xsZWN0aW9uID0gYXdhaXQgcmVzb2x2ZXIobW9kZWwsIG93bmVyLCBjdHgpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBGYWlsZWQgdG8gcmVzb2x2ZSBjb2xsZWN0aW9uIG1pcnJvciBuYW1lOiAke2V9YCk7XG4gICAgfVxuICB9XG5cbiAgaWYgKCFjb2xsZWN0aW9uIHx8IHR5cGVvZiBjb2xsZWN0aW9uICE9PSBcInN0cmluZ1wiKVxuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgYE5vIGNvbGxlY3Rpb24gZm91bmQgbW9kZWwgJHttb2RlbC5jb25zdHJ1Y3Rvci5uYW1lfWBcbiAgICApO1xuICByZXR1cm4gY29sbGVjdGlvbjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZU1pcnJvckhhbmRsZXI8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIFJlcG9zaXRvcnk8TSwgYW55Pixcbj4oXG4gIHRoaXM6IFIsXG4gIGNvbnRleHQ6IENvbnRleHQ8RmFicmljQ29udHJhY3RGbGFncz4sXG4gIGRhdGE6IE1pcnJvck1ldGFkYXRhLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgY29sbGVjdGlvbiA9IGF3YWl0IGV2YWxNaXJyb3JNZXRhZGF0YShtb2RlbCwgZGF0YS5yZXNvbHZlciwgY29udGV4dCk7XG5cbiAgY29uc3QgcmVwbyA9IHRoaXMub3ZlcnJpZGUoXG4gICAgT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5fb3ZlcnJpZGVzLCB7XG4gICAgICBzZWdyZWdhdGU6IGNvbGxlY3Rpb24sXG4gICAgICBpZ25vcmVWYWxpZGF0aW9uOiB0cnVlLFxuICAgICAgaWdub3JlSGFuZGxlcnM6IHRydWUsXG4gICAgfSBhcyBhbnkpXG4gICk7XG5cbiAgY29uc3QgbWlycm9yID0gYXdhaXQgcmVwby5jcmVhdGUobW9kZWwsIGNvbnRleHQpO1xuICBjb250ZXh0LmxvZ2dlci5pbmZvKFxuICAgIGBNaXJyb3IgZm9yICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfSBjcmVhdGVkIHdpdGggJHtNb2RlbC5wayhtb2RlbCkgYXMgc3RyaW5nfTogJHttaXJyb3JbTW9kZWwucGsobW9kZWwpXX1gXG4gICk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB1cGRhdGVNaXJyb3JIYW5kbGVyPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBSZXBvc2l0b3J5PE0sIGFueT4sXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBDb250ZXh0PEZhYnJpY0NvbnRyYWN0RmxhZ3M+LFxuICBkYXRhOiBNaXJyb3JNZXRhZGF0YSxcbiAga2V5OiBrZXlvZiBNLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGNvbGxlY3Rpb24gPSBhd2FpdCBldmFsTWlycm9yTWV0YWRhdGEobW9kZWwsIGRhdGEucmVzb2x2ZXIsIGNvbnRleHQpO1xuXG4gIGNvbnN0IHJlcG8gPSB0aGlzLm92ZXJyaWRlKFxuICAgIE9iamVjdC5hc3NpZ24oe30sIHRoaXMuX292ZXJyaWRlcywge1xuICAgICAgc2VncmVnYXRlOiBjb2xsZWN0aW9uLFxuICAgICAgaWdub3JlVmFsaWRhdGlvbjogdHJ1ZSxcbiAgICAgIGlnbm9yZUhhbmRsZXJzOiB0cnVlLFxuICAgIH0gYXMgYW55KVxuICApO1xuXG4gIGNvbnN0IG1pcnJvciA9IGF3YWl0IHJlcG8udXBkYXRlKG1vZGVsLCBjb250ZXh0KTtcbiAgY29udGV4dC5sb2dnZXIuaW5mbyhcbiAgICBgTWlycm9yIGZvciAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX0gdXBkYXRlZCB3aXRoICR7TW9kZWwucGsobW9kZWwpIGFzIHN0cmluZ306ICR7bWlycm9yW01vZGVsLnBrKG1vZGVsKV19YFxuICApO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGVsZXRlTWlycm9ySGFuZGxlcjxcbiAgTSBleHRlbmRzIE1vZGVsLFxuICBSIGV4dGVuZHMgUmVwb3NpdG9yeTxNLCBhbnk+LFxuPihcbiAgdGhpczogUixcbiAgY29udGV4dDogQ29udGV4dDxGYWJyaWNDb250cmFjdEZsYWdzPixcbiAgZGF0YTogTWlycm9yTWV0YWRhdGEsXG4gIGtleToga2V5b2YgTSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBjb2xsZWN0aW9uID0gYXdhaXQgZXZhbE1pcnJvck1ldGFkYXRhKG1vZGVsLCBkYXRhLnJlc29sdmVyLCBjb250ZXh0KTtcblxuICBjb25zdCByZXBvID0gdGhpcy5vdmVycmlkZShcbiAgICBPYmplY3QuYXNzaWduKHt9LCB0aGlzLl9vdmVycmlkZXMsIHtcbiAgICAgIHNlZ3JlZ2F0ZTogY29sbGVjdGlvbixcbiAgICAgIGlnbm9yZVZhbGlkYXRpb246IHRydWUsXG4gICAgICBpZ25vcmVIYW5kbGVyczogdHJ1ZSxcbiAgICB9IGFzIGFueSlcbiAgKTtcblxuICBjb25zdCBtaXJyb3IgPSBhd2FpdCByZXBvLmRlbGV0ZShNb2RlbC5wayhtb2RlbCkgYXMgc3RyaW5nLCBjb250ZXh0KTtcbiAgY29udGV4dC5sb2dnZXIuaW5mbyhcbiAgICBgTWlycm9yIGZvciAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX0gZGVsZXRlZCB3aXRoICR7TW9kZWwucGsobW9kZWwpIGFzIHN0cmluZ306ICR7bWlycm9yW01vZGVsLnBrKG1vZGVsKV19YFxuICApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbWlycm9yKFxuICBjb2xsZWN0aW9uOiBDb2xsZWN0aW9uUmVzb2x2ZXIgfCBzdHJpbmcsXG4gIGNvbmRpdGlvbj86IE1pcnJvckNvbmRpdGlvblxuKSB7XG4gIGZ1bmN0aW9uIG1pcnJvcihcbiAgICByZXNvbHZlcjogQ29sbGVjdGlvblJlc29sdmVyIHwgc3RyaW5nLFxuICAgIGNvbmRpdGlvbjogTWlycm9yQ29uZGl0aW9uXG4gICkge1xuICAgIGNvbnN0IG1ldGE6IE1pcnJvck1ldGFkYXRhID0ge1xuICAgICAgY29uZGl0aW9uOiBjb25kaXRpb24sXG4gICAgICByZXNvbHZlcjogcmVzb2x2ZXIsXG4gICAgfTtcbiAgICByZXR1cm4gYXBwbHkoXG4gICAgICBtZXRhZGF0YShcbiAgICAgICAgTWV0YWRhdGEua2V5KEZhYnJpY01vZGVsS2V5cy5GQUJSSUMsIEZhYnJpY01vZGVsS2V5cy5NSVJST1IpLFxuICAgICAgICBtZXRhXG4gICAgICApLFxuICAgICAgcHJpdmF0ZURhdGEoY29sbGVjdGlvbiksXG4gICAgICBhZnRlckNyZWF0ZShjcmVhdGVNaXJyb3JIYW5kbGVyIGFzIGFueSwgbWV0YSwgeyBwcmlvcml0eTogOTUgfSksXG4gICAgICBhZnRlclVwZGF0ZSh1cGRhdGVNaXJyb3JIYW5kbGVyIGFzIGFueSwgbWV0YSwgeyBwcmlvcml0eTogOTUgfSksXG4gICAgICBhZnRlckRlbGV0ZShkZWxldGVNaXJyb3JIYW5kbGVyIGFzIGFueSwgbWV0YSwgeyBwcmlvcml0eTogOTUgfSlcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKEZhYnJpY01vZGVsS2V5cy5NSVJST1IpXG4gICAgLmRlZmluZSh7XG4gICAgICBkZWNvcmF0b3I6IG1pcnJvcixcbiAgICAgIGFyZ3M6IFtjb2xsZWN0aW9uLCBjb25kaXRpb25dLFxuICAgIH0pXG4gICAgLmFwcGx5KCk7XG59XG5cbmV4cG9ydCB0eXBlIENvbGxlY3Rpb25SZXNvbHZlciA9IDxNIGV4dGVuZHMgTW9kZWw+KFxuICBtb2RlbDogTSB8IENvbnN0cnVjdG9yPE0+LFxuICBtc3A/OiBzdHJpbmcsXG4gIC4uLmFyZ3M6IGFueVtdXG4pID0+IHN0cmluZztcblxuZXhwb3J0IGNvbnN0IE1vZGVsQ29sbGVjdGlvbjogQ29sbGVjdGlvblJlc29sdmVyID0gPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNIHwgQ29uc3RydWN0b3I8TT4sXG4gIG1zcElkPzogc3RyaW5nXG4pID0+IHtcbiAgY29uc3Qgb3JnTmFtZSA9XG4gICAgbXNwSWQgfHwgKHR5cGVvZiBtb2RlbCAhPT0gXCJmdW5jdGlvblwiID8gTW9kZWwub3duZXJPZihtb2RlbCkgOiB1bmRlZmluZWQpO1xuICBjb25zdCBjb25zdHIgPSB0eXBlb2YgbW9kZWwgPT09IFwiZnVuY3Rpb25cIiA/IG1vZGVsIDogbW9kZWwuY29uc3RydWN0b3I7XG4gIGlmICghb3JnTmFtZSlcbiAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgIGBNb2RlbCAke2NvbnN0ci5uYW1lfSBpcyBub3Qgb3duZWQgYnkgYW55IG9yZ2FuaXphdGlvbi4gZGlkIHlvdSB1c2UgQG93bmVkQnkoKSAob3IgcHJvdmlkZSB0aGUgbmFtZSk/YFxuICAgICk7XG4gIHJldHVybiBgJHt0b1Bhc2NhbENhc2UoY29uc3RyLm5hbWUpfSR7bXNwSWQgPyB0b1Bhc2NhbENhc2UobXNwSWQpIDogXCJcIn1gO1xufTtcblxuZXhwb3J0IGNvbnN0IEltcGxpY2l0UHJpdmF0ZUNvbGxlY3Rpb246IENvbGxlY3Rpb25SZXNvbHZlciA9IDxNIGV4dGVuZHMgTW9kZWw+KFxuICBtb2RlbDogTSB8IENvbnN0cnVjdG9yPE0+LFxuICBtc3BJZD86IHN0cmluZ1xuKSA9PiB7XG4gIGNvbnN0IG9yZ05hbWUgPVxuICAgIG1zcElkIHx8ICh0eXBlb2YgbW9kZWwgIT09IFwiZnVuY3Rpb25cIiA/IE1vZGVsLm93bmVyT2YobW9kZWwpIDogdW5kZWZpbmVkKTtcbiAgaWYgKCFvcmdOYW1lKVxuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgYE1vZGVsICR7bW9kZWwuY29uc3RydWN0b3IubmFtZX0gaXMgbm90IG93bmVkIGJ5IGFueSBvcmdhbml6YXRpb24uIGRpZCB5b3UgdXNlIEBvd25lZEJ5KCkgKG9yIHByb3ZpZGUgdGhlIG5hbWUpP2BcbiAgICApO1xuICByZXR1cm4gYF9fJHt0b1Bhc2NhbENhc2Uob3JnTmFtZSl9UHJpdmF0ZUNvbGxlY3Rpb25gO1xufTtcblxuZXhwb3J0IHR5cGUgU2VncmVnYXRlZERhdGFNZXRhZGF0YSA9IHtcbiAgY29sbGVjdGlvbnM6IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlcjtcbn07XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWdyZWdhdGVkRGF0YU9uQ3JlYXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIHRoaXM6IFJlcG9zaXRvcnk8TSwgYW55PixcbiAgY29udGV4dDogQ29udGV4dE9mPHR5cGVvZiB0aGlzPixcbiAgZGF0YTogU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdLFxuICBrZXlzOiAoa2V5b2YgTSlbXSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoa2V5cy5sZW5ndGggIT09IGRhdGEubGVuZ3RoKVxuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgYFNlZ3JlZ2F0ZWQgZGF0YSBrZXlzIGFuZCBtZXRhZGF0YSBsZW5ndGggbWlzbWF0Y2hgXG4gICAgKTtcblxuICBjb25zdCBtc3AgPSBNb2RlbC5vd25lck9mKG1vZGVsKTtcbiAgaWYgKCFtc3ApXG4gICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihcbiAgICAgIGBUaGVyZSdzIG5vIGFzc2lnbmVkIG9yZ2FuaXphdGlvbiBmb3IgbW9kZWwgJHttb2RlbC5jb25zdHJ1Y3Rvci5uYW1lfWBcbiAgICApO1xuXG4gIGNvbnN0IGNvbGxlY3Rpb25SZXNvbHZlciA9IGRhdGFbMF0uY29sbGVjdGlvbnM7XG4gIGNvbnN0IGNvbGxlY3Rpb24gPVxuICAgIHR5cGVvZiBjb2xsZWN0aW9uUmVzb2x2ZXIgPT09IFwic3RyaW5nXCJcbiAgICAgID8gY29sbGVjdGlvblJlc29sdmVyXG4gICAgICA6IGNvbGxlY3Rpb25SZXNvbHZlcihtb2RlbCwgbXNwLCBjb250ZXh0KTtcblxuICBjb25zdCByZWJ1aWx0ID0ga2V5cy5yZWR1Y2UoXG4gICAgKGFjYzogUmVjb3JkPGtleW9mIE0sIGFueT4sIGssIGkpID0+IHtcbiAgICAgIGNvbnN0IGMgPVxuICAgICAgICB0eXBlb2YgZGF0YVtpXS5jb2xsZWN0aW9ucyA9PT0gXCJzdHJpbmdcIlxuICAgICAgICAgID8gZGF0YVtpXS5jb2xsZWN0aW9uc1xuICAgICAgICAgIDogZGF0YVtpXS5jb2xsZWN0aW9ucyhtb2RlbCwgbXNwLCBjb250ZXh0KTtcbiAgICAgIGlmIChjICE9PSBjb2xsZWN0aW9uKVxuICAgICAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgICAgICBgU2VncmVnYXRlZCBkYXRhIGNvbGxlY3Rpb24gbWlzbWF0Y2g6ICR7Y30gdnMgJHtjb2xsZWN0aW9ufWBcbiAgICAgICAgKTtcbiAgICAgIGFjY1trXSA9IG1vZGVsW2tdO1xuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LFxuICAgIHt9IGFzIFJlY29yZDxrZXlvZiBNLCBhbnk+XG4gICk7XG5cbiAgY29uc3QgdG9DcmVhdGUgPSBuZXcgdGhpcy5jbGFzcyhyZWJ1aWx0KTtcblxuICAvLyBjb25zdCBzZWdyZWdhdGVkID0gTW9kZWwuc2VncmVnYXRlKG1vZGVsKTtcblxuICBjb25zdCBjcmVhdGVkID0gYXdhaXQgdGhpcy5vdmVycmlkZSh7XG4gICAgc2VncmVnYXRlZDogY29sbGVjdGlvbixcbiAgICBtZXJnZU1vZGVsOiBmYWxzZSxcbiAgICBpZ25vcmVIYW5kbGVyczogdHJ1ZSxcbiAgICBpZ25vcmVWYWxpZGF0aW9uOiB0cnVlLFxuICB9IGFzIGFueSkuY3JlYXRlKHRvQ3JlYXRlLCBjb250ZXh0KTtcbiAgT2JqZWN0LmFzc2lnbihtb2RlbCwgY3JlYXRlZCk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWdyZWdhdGVkRGF0YU9uUmVhZDxNIGV4dGVuZHMgTW9kZWw+KFxuICB0aGlzOiBSZXBvc2l0b3J5PE0sIGFueT4sXG4gIGNvbnRleHQ6IENvbnRleHQ8RmFicmljRmxhZ3M+LFxuICBkYXRhOiBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhW10sXG4gIGtleXM6IChrZXlvZiBNKVtdLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChrZXlzLmxlbmd0aCAhPT0gZGF0YS5sZW5ndGgpXG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICBgU2VncmVnYXRlZCBkYXRhIGtleXMgYW5kIG1ldGFkYXRhIGxlbmd0aCBtaXNtYXRjaGBcbiAgICApO1xuXG4gIGNvbnN0IG1zcCA9IE1vZGVsLm93bmVyT2YobW9kZWwpO1xuICBpZiAoIW1zcClcbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFxuICAgICAgYFRoZXJlJ3Mgbm8gYXNzaWduZWQgb3JnYW5pemF0aW9uIGZvciBtb2RlbCAke21vZGVsLmNvbnN0cnVjdG9yLm5hbWV9YFxuICAgICk7XG5cbiAgY29uc3QgY29sbGVjdGlvblJlc29sdmVyID0gZGF0YVswXS5jb2xsZWN0aW9ucztcbiAgY29uc3QgY29sbGVjdGlvbiA9XG4gICAgdHlwZW9mIGNvbGxlY3Rpb25SZXNvbHZlciA9PT0gXCJzdHJpbmdcIlxuICAgICAgPyBjb2xsZWN0aW9uUmVzb2x2ZXJcbiAgICAgIDogYXdhaXQgY29sbGVjdGlvblJlc29sdmVyKG1vZGVsLCBtc3AsIGNvbnRleHQpO1xuXG4gIGNvbnN0IHJlYnVpbHQgPSBrZXlzLnJlZHVjZShcbiAgICAoYWNjOiBSZWNvcmQ8a2V5b2YgTSwgYW55PiwgaywgaSkgPT4ge1xuICAgICAgY29uc3QgYyA9XG4gICAgICAgIHR5cGVvZiBkYXRhW2ldLmNvbGxlY3Rpb25zID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgPyBkYXRhW2ldLmNvbGxlY3Rpb25zXG4gICAgICAgICAgOiBkYXRhW2ldLmNvbGxlY3Rpb25zKG1vZGVsLCBtc3AsIGNvbnRleHQpO1xuICAgICAgaWYgKGMgIT09IGNvbGxlY3Rpb24pIHJldHVybiBhY2M7XG4gICAgICBhY2Nba10gPSBtb2RlbFtrXTtcbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSxcbiAgICB7fSBhcyBSZWNvcmQ8a2V5b2YgTSwgYW55PlxuICApO1xuXG4gIC8vIGNvbnN0IHNlZ3JlZ2F0ZWQgPSBNb2RlbC5zZWdyZWdhdGUobW9kZWwpO1xuICAvL1xuICAvLyBjb25zdCBjcmVhdGVkID0gYXdhaXQgdGhpcy5vdmVycmlkZSh7IHNlZ3JlZ2F0ZWQ6IGNvbGxlY3Rpb24gfSBhcyBhbnkpLnJlYWRBbGwoXG4gIC8vICAgdG9DcmVhdGUsXG4gIC8vICAgY29udGV4dFxuICAvLyApO1xuICAvLyBPYmplY3QuYXNzaWduKG1vZGVsLCBjcmVhdGVkKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlZ3JlZ2F0ZWREYXRhT25VcGRhdGU8TSBleHRlbmRzIE1vZGVsPihcbiAgdGhpczogUmVwb3NpdG9yeTxNLCBhbnk+LFxuICBjb250ZXh0OiBDb250ZXh0T2Y8dHlwZW9mIHRoaXM+LFxuICBkYXRhOiBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhW10sXG4gIGtleToga2V5b2YgTVtdLFxuICBtb2RlbDogTSxcbiAgb2xkTW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge31cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlZ3JlZ2F0ZWREYXRhT25EZWxldGU8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIFJlcG9zaXRvcnk8TSwgYW55PixcbiAgViBleHRlbmRzIFNlZ3JlZ2F0ZWREYXRhTWV0YWRhdGEsXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBDb250ZXh0T2Y8Uj4sXG4gIGRhdGE6IFZbXSxcbiAga2V5OiBrZXlvZiBNW10sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHt9XG5cbmZ1bmN0aW9uIHNlZ3JlZ2F0ZWQoXG4gIGNvbGxlY3Rpb246IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlcixcbiAgdHlwZTogRmFicmljTW9kZWxLZXlzLlBSSVZBVEUgfCBGYWJyaWNNb2RlbEtleXMuU0hBUkVELFxuICBmaWx0ZXI/OiAocHJvcE5hbWU6IHN0cmluZykgPT4gYm9vbGVhblxuKSB7XG4gIHJldHVybiBmdW5jdGlvbiBpbm5lclNlZ3JlZ2F0ZWQodGFyZ2V0OiBvYmplY3QsIHByb3BlcnR5S2V5PzogYW55KSB7XG4gICAgZnVuY3Rpb24gc2VncmVnYXRlZERlYyh0YXJnZXQ6IG9iamVjdCwgcHJvcGVydHlLZXk/OiBhbnkpIHtcbiAgICAgIGNvbnN0IGtleSA9IE1ldGFkYXRhLmtleSh0eXBlLCBwcm9wZXJ0eUtleSk7XG4gICAgICBjb25zdCBjb25zdHI6IENvbnN0cnVjdG9yID0gdGFyZ2V0LmNvbnN0cnVjdG9yIGFzIENvbnN0cnVjdG9yO1xuXG4gICAgICBjb25zdCBtZXRhID0gTWV0YWRhdGEuZ2V0KGNvbnN0ciBhcyBDb25zdHJ1Y3Rvciwga2V5KSB8fCB7fTtcbiAgICAgIGNvbnN0IGNvbGxlY3Rpb25zID0gbmV3IFNldChtZXRhLmNvbGxlY3Rpb25zIHx8IFtdKTtcbiAgICAgIGNvbGxlY3Rpb25zLmFkZChjb2xsZWN0aW9uKTtcbiAgICAgIG1ldGEuY29sbGVjdGlvbnMgPSBbLi4uY29sbGVjdGlvbnNdO1xuICAgICAgTWV0YWRhdGEuc2V0KGNvbnN0ciBhcyBDb25zdHJ1Y3Rvciwga2V5LCBtZXRhKTtcblxuICAgICAgY29uc3QgY29uc3RyTWV0YSA9IE1ldGFkYXRhLmdldChjb25zdHIgYXMgQ29uc3RydWN0b3IsIHR5cGUpIHx8IHt9O1xuICAgICAgY29uc3QgY29uc3RyQ29sbGVjdGlvbnMgPSBuZXcgU2V0KGNvbnN0ck1ldGEuY29sbGVjdGlvbnMgfHwgW10pO1xuICAgICAgY29uc3RyQ29sbGVjdGlvbnMuYWRkKGNvbGxlY3Rpb24pO1xuICAgICAgbWV0YS5jb2xsZWN0aW9ucyA9IFsuLi5jb2xsZWN0aW9uc107XG4gICAgICBNZXRhZGF0YS5zZXQoY29uc3RyIGFzIENvbnN0cnVjdG9yLCB0eXBlLCBtZXRhKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZWNzOiBhbnlbXSA9IFtdO1xuICAgIGlmICghcHJvcGVydHlLZXkpIHtcbiAgICAgIC8vIGRlY29yYXRlZCBhdCB0aGUgY2xhc3MgbGV2ZWxcbiAgICAgIE1ldGFkYXRhLnByb3BlcnRpZXModGFyZ2V0IGFzIENvbnN0cnVjdG9yKT8uZm9yRWFjaCgocCkgPT4ge1xuICAgICAgICBpZiAoIWZpbHRlciB8fCBmaWx0ZXIocCkpIHtcbiAgICAgICAgICBzZWdyZWdhdGVkKGNvbGxlY3Rpb24sIHR5cGUpKCh0YXJnZXQgYXMgYW55KS5wcm90b3R5cGUsIHApO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgZGVjcy5wdXNoKFxuICAgICAgICBwcm9wKCksXG4gICAgICAgIHRyYW5zaWVudCgpLFxuICAgICAgICBzZWdyZWdhdGVkRGVjLFxuICAgICAgICBvbkNyZWF0ZShcbiAgICAgICAgICBzZWdyZWdhdGVkRGF0YU9uQ3JlYXRlLFxuICAgICAgICAgIHsgY29sbGVjdGlvbnM6IGNvbGxlY3Rpb24gfSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBwcmlvcml0eTogOTUsXG4gICAgICAgICAgICBncm91cDpcbiAgICAgICAgICAgICAgdHlwZW9mIGNvbGxlY3Rpb24gPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICAgICA/IGNvbGxlY3Rpb25cbiAgICAgICAgICAgICAgICA6IGNvbGxlY3Rpb24udG9TdHJpbmcoKSxcbiAgICAgICAgICB9XG4gICAgICAgICksXG4gICAgICAgIG9uUmVhZChcbiAgICAgICAgICBzZWdyZWdhdGVkRGF0YU9uUmVhZCBhcyBhbnksXG4gICAgICAgICAgeyBjb2xsZWN0aW9uczogY29sbGVjdGlvbiB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHByaW9yaXR5OiA5NSxcbiAgICAgICAgICAgIGdyb3VwOlxuICAgICAgICAgICAgICB0eXBlb2YgY29sbGVjdGlvbiA9PT0gXCJzdHJpbmdcIlxuICAgICAgICAgICAgICAgID8gY29sbGVjdGlvblxuICAgICAgICAgICAgICAgIDogY29sbGVjdGlvbi50b1N0cmluZygpLFxuICAgICAgICAgIH1cbiAgICAgICAgKSxcbiAgICAgICAgb25VcGRhdGUoXG4gICAgICAgICAgc2VncmVnYXRlZERhdGFPblVwZGF0ZSBhcyBhbnksXG4gICAgICAgICAgeyBjb2xsZWN0aW9uczogY29sbGVjdGlvbiB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHByaW9yaXR5OiA5NSxcbiAgICAgICAgICAgIGdyb3VwOlxuICAgICAgICAgICAgICB0eXBlb2YgY29sbGVjdGlvbiA9PT0gXCJzdHJpbmdcIlxuICAgICAgICAgICAgICAgID8gY29sbGVjdGlvblxuICAgICAgICAgICAgICAgIDogY29sbGVjdGlvbi50b1N0cmluZygpLFxuICAgICAgICAgIH1cbiAgICAgICAgKSxcbiAgICAgICAgb25EZWxldGUoXG4gICAgICAgICAgc2VncmVnYXRlZERhdGFPbkRlbGV0ZSBhcyBhbnksXG4gICAgICAgICAgeyBjb2xsZWN0aW9uczogY29sbGVjdGlvbiB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHByaW9yaXR5OiA5NSxcbiAgICAgICAgICAgIGdyb3VwOlxuICAgICAgICAgICAgICB0eXBlb2YgY29sbGVjdGlvbiA9PT0gXCJzdHJpbmdcIlxuICAgICAgICAgICAgICAgID8gY29sbGVjdGlvblxuICAgICAgICAgICAgICAgIDogY29sbGVjdGlvbi50b1N0cmluZygpLFxuICAgICAgICAgIH1cbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGFwcGx5KC4uLmRlY3MpKHRhcmdldCwgcHJvcGVydHlLZXkpO1xuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcHJpdmF0ZURhdGEoXG4gIGNvbGxlY3Rpb246IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlciA9IEltcGxpY2l0UHJpdmF0ZUNvbGxlY3Rpb25cbikge1xuICBmdW5jdGlvbiBwcml2YXRlRGF0YShjb2xsZWN0aW9uOiBzdHJpbmcgfCBDb2xsZWN0aW9uUmVzb2x2ZXIpIHtcbiAgICByZXR1cm4gc2VncmVnYXRlZChjb2xsZWN0aW9uLCBGYWJyaWNNb2RlbEtleXMuUFJJVkFURSk7XG4gIH1cblxuICByZXR1cm4gRGVjb3JhdGlvbi5mb3IoRmFicmljTW9kZWxLZXlzLlBSSVZBVEUpXG4gICAgLmRlZmluZSh7XG4gICAgICBkZWNvcmF0b3I6IHByaXZhdGVEYXRhLFxuICAgICAgYXJnczogW2NvbGxlY3Rpb25dLFxuICAgIH0pXG4gICAgLmFwcGx5KCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzaGFyZWREYXRhKGNvbGxlY3Rpb246IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlcikge1xuICBmdW5jdGlvbiBzaGFyZWREYXRhKGNvbGxlY3Rpb246IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlcikge1xuICAgIHJldHVybiBzZWdyZWdhdGVkKGNvbGxlY3Rpb24sIEZhYnJpY01vZGVsS2V5cy5TSEFSRUQpO1xuICB9XG5cbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKEZhYnJpY01vZGVsS2V5cy5TSEFSRUQpXG4gICAgLmRlZmluZSh7XG4gICAgICBkZWNvcmF0b3I6IHNoYXJlZERhdGEsXG4gICAgICBhcmdzOiBbY29sbGVjdGlvbl0sXG4gICAgfSlcbiAgICAuYXBwbHkoKTtcbn1cbiIsIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHMgKi9cbmltcG9ydCB7IENvbnN0cnVjdG9yLCBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHtcbiAgSlNPTlNlcmlhbGl6ZXIsXG4gIE1vZGVsLFxuICBNb2RlbEtleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGV0ZXJtaW5pc3RpYyBKU09OIHNlcmlhbGl6ZXIgZm9yIEZhYnJpYyBtb2RlbHNcbiAqIEBzdW1tYXJ5IEVuc3VyZXMgc3RhYmxlLCBkZXRlcm1pbmlzdGljIEpTT04gb3V0cHV0IGJ5IHNvcnRpbmcgb2JqZWN0IGtleXMgcmVjdXJzaXZlbHkgYmVmb3JlIHN0cmluZ2lmaWNhdGlvbiwgd2hpY2ggaXMgaW1wb3J0YW50IGZvciBGYWJyaWMgZW5kb3JzZW1lbnQgYW5kIGhhc2hpbmcuIEV4dGVuZHMgSlNPTlNlcmlhbGl6ZXIgdG8gcGx1ZyBpbnRvIGV4aXN0aW5nIERlY2FmIG1vZGVsIHNlcmlhbGl6YXRpb24gZmxvdy5cbiAqIEB0ZW1wbGF0ZSBNIC0gVGhlIERlY2FmIE1vZGVsIHN1YnR5cGUgc2VyaWFsaXplZCBieSB0aGlzIGluc3RhbmNlXG4gKiBAcGFyYW0ge3ZvaWR9IFtjb25zdHJ1Y3Rvcl0gTm8gcHVibGljIGNvbnN0cnVjdG9yIGFyZ3VtZW50c1xuICogQGNsYXNzIERldGVybWluaXN0aWNTZXJpYWxpemVyXG4gKiBAZXhhbXBsZVxuICogY29uc3Qgc2VyaWFsaXplciA9IG5ldyBEZXRlcm1pbmlzdGljU2VyaWFsaXplcjxNeU1vZGVsPigpO1xuICogY29uc3QganNvbiA9IHNlcmlhbGl6ZXIuc2VyaWFsaXplKG1vZGVsKTtcbiAqIGNvbnN0IHJlYnVpbHQgPSBzZXJpYWxpemVyLmRlc2VyaWFsaXplKGpzb24pO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgRFMgYXMgRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXJcbiAqICAgQ2FsbGVyLT4+RFM6IHNlcmlhbGl6ZShtb2RlbClcbiAqICAgRFMtPj5EUzogcHJlU2VyaWFsaXplKG1vZGVsKVxuICogICBEUy0+PkRTOiBzb3J0LWtleXMtcmVjdXJzaXZlXG4gKiAgIERTLT4+RFM6IGpzb24tc3RyaW5naWZ5LWRldGVybWluaXN0aWNcbiAqICAgRFMtLT4+Q2FsbGVyOiBzdHJpbmdcbiAqICAgQ2FsbGVyLT4+RFM6IGRlc2VyaWFsaXplKHN0cmluZylcbiAqICAgRFMtLT4+Q2FsbGVyOiBtb2RlbFxuICovXG5leHBvcnQgY2xhc3MgRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbj4gZXh0ZW5kcyBKU09OU2VyaWFsaXplcjxNPiB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHByZVNlcmlhbGl6ZShtb2RlbDogTSkge1xuICAgIC8vIFRPRE86IG5lc3RlZCBwcmVzZXJpYWxpemF0aW9uIChzbyBpbmNyZWFzZSBwZXJmb3JtYW5jZSB3aGVuIGRlc2VyaWFsaXppbmcpXG4gICAgLy8gVE9ETzogVmVyaWZ5IHdoeSB0aGVyZSBpcyBubyBtZXRhZGF0YVxuICAgIGNvbnN0IHRvU2VyaWFsaXplOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gT2JqZWN0LmFzc2lnbih7fSwgbW9kZWwpO1xuICAgIGxldCBtZXRhZGF0YTtcbiAgICB0cnkge1xuICAgICAgbWV0YWRhdGEgPSBNZXRhZGF0YS5tb2RlbE5hbWUobW9kZWwuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICBtZXRhZGF0YSA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgdG9TZXJpYWxpemVbTW9kZWxLZXlzLkFOQ0hPUl0gPSBtZXRhZGF0YSB8fCBtb2RlbC5jb25zdHJ1Y3Rvci5uYW1lO1xuXG4gICAgY29uc3QgcHJlU2VyaWFsaXplID0gZnVuY3Rpb24gcHJlU2VyaWFsaXplKFxuICAgICAgdGhpczogRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8YW55PixcbiAgICAgIG9iajogYW55XG4gICAgKTogYW55IHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdGhpcy1hbGlhc1xuICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICBpZiAodHlwZW9mIG9iaiAhPT0gXCJvYmplY3RcIikgcmV0dXJuIG9iajtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHJldHVybiBvYmoubWFwKChvKSA9PiBwcmVTZXJpYWxpemUuY2FsbChzZWxmLCBvKSk7XG4gICAgICByZXR1cm4gdGhpcy5wcmVTZXJpYWxpemUuY2FsbCh0aGlzLCBvYmopO1xuICAgIH0uYmluZCh0aGlzKTtcblxuICAgIE1vZGVsLnJlbGF0aW9ucyhtb2RlbCkuZm9yRWFjaCgocikgPT4ge1xuICAgICAgdG9TZXJpYWxpemVbcl0gPSBwcmVTZXJpYWxpemUodG9TZXJpYWxpemVbcl0pO1xuICAgIH0pO1xuICAgIHJldHVybiB0b1NlcmlhbGl6ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSBSZWJ1aWxkcyBhIG1vZGVsIGZyb20gYSBzZXJpYWxpemF0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzdHJcbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIGl0IGZhaWxzIHRvIHBhcnNlIHRoZSBzdHJpbmcsIG9yIHRvIGJ1aWxkIHRoZSBtb2RlbFxuICAgKi9cbiAgb3ZlcnJpZGUgZGVzZXJpYWxpemUoc3RyOiBzdHJpbmcpOiBNIHtcbiAgICBjb25zdCBkZXNlcmlhbGl6YXRpb24gPSBKU09OLnBhcnNlKHN0cik7XG4gICAgY29uc3QgY2xhc3NOYW1lID0gZGVzZXJpYWxpemF0aW9uW01vZGVsS2V5cy5BTkNIT1JdO1xuICAgIGlmICghY2xhc3NOYW1lKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGQgbm90IGZpbmQgY2xhc3MgcmVmZXJlbmNlIGluIHNlcmlhbGl6ZWQgbW9kZWxcIik7XG4gICAgY29uc3QgbW9kZWw6IE0gPSBNb2RlbC5idWlsZChkZXNlcmlhbGl6YXRpb24sIGNsYXNzTmFtZSkgYXMgdW5rbm93biBhcyBNO1xuICAgIHJldHVybiBtb2RlbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2VyaWFsaXplIGEgbW9kZWwgaW50byBhIGRldGVybWluaXN0aWMgSlNPTiBzdHJpbmdcbiAgICogQHN1bW1hcnkgUHJlcGFyZXMgdGhlIG1vZGVsIHdpdGggcHJlU2VyaWFsaXplLCBzb3J0cyBrZXlzIHJlY3Vyc2l2ZWx5LCBhbmQgc3RyaW5naWZpZXMgZGV0ZXJtaW5pc3RpY2FsbHkgZm9yIHN0YWJsZSBvcmRlcmluZ1xuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHRvIHNlcmlhbGl6ZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IERldGVybWluaXN0aWMgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgbW9kZWxcbiAgICovXG4gIG92ZXJyaWRlIHNlcmlhbGl6ZShtb2RlbDogTSk6IHN0cmluZyB7XG4gICAgY29uc3Qgc3RyaW5naWZ5ID0gcmVxdWlyZShcImpzb24tc3RyaW5naWZ5LWRldGVybWluaXN0aWNcIik7XG4gICAgY29uc3Qgc29ydEtleXNSZWN1cnNpdmUgPSByZXF1aXJlKFwic29ydC1rZXlzLXJlY3Vyc2l2ZVwiKTtcbiAgICByZXR1cm4gc3RyaW5naWZ5KHNvcnRLZXlzUmVjdXJzaXZlKHRoaXMucHJlU2VyaWFsaXplKG1vZGVsKSkpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBCdWxrQ3J1ZE9wZXJhdGlvbktleXMsIE9wZXJhdGlvbktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gR2VuZXJhdGVzIGEgRmFicmljIGV2ZW50IG5hbWUgZnJvbSBjb21wb25lbnRzXG4gKiBAc3VtbWFyeSBDcmVhdGVzIGEgc3RhbmRhcmRpemVkIGV2ZW50IG5hbWUgYnkgam9pbmluZyB0YWJsZSwgZXZlbnQsIGFuZCBvcHRpb25hbCBvd25lciB3aXRoIHVuZGVyc2NvcmVzXG4gKiBAcGFyYW0ge3N0cmluZ30gdGFibGUgLSBUaGUgdGFibGUvY29sbGVjdGlvbiBuYW1lXG4gKiBAcGFyYW0ge09wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmd9IGV2ZW50IC0gVGhlIGV2ZW50IHR5cGVcbiAqIEBwYXJhbSB7c3RyaW5nfSBbb3duZXJdIC0gT3B0aW9uYWwgb3duZXIgaWRlbnRpZmllclxuICogQHJldHVybiB7c3RyaW5nfSBUaGUgZ2VuZXJhdGVkIGV2ZW50IG5hbWUgaW4gZm9ybWF0IFwidGFibGVfZXZlbnRcIiBvciBcInRhYmxlX2V2ZW50X293bmVyXCJcbiAqIEBmdW5jdGlvbiBnZW5lcmF0ZUZhYnJpY0V2ZW50TmFtZVxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVGYWJyaWNFdmVudE5hbWUoXG4gIHRhYmxlOiBzdHJpbmcsXG4gIGV2ZW50OiBPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nLFxuICBvd25lcj86IHN0cmluZ1xuKSB7XG4gIGNvbnN0IHBhcmFtcyA9IFt0YWJsZSwgZXZlbnRdO1xuICBpZiAob3duZXIpIHBhcmFtcy5wdXNoKG93bmVyKTtcbiAgcmV0dXJuIHBhcmFtcy5qb2luKFwiX1wiKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUGFyc2VzIGEgRmFicmljIGV2ZW50IG5hbWUgaW50byBpdHMgY29tcG9uZW50c1xuICogQHN1bW1hcnkgU3BsaXRzIGFuIGV2ZW50IG5hbWUgYnkgdW5kZXJzY29yZXMgYW5kIGV4dHJhY3RzIHRhYmxlLCBldmVudCwgYW5kIG9wdGlvbmFsIG93bmVyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBldmVudCBuYW1lIHRvIHBhcnNlXG4gKiBAcmV0dXJuIHt7dGFibGU6IHN0cmluZywgZXZlbnQ6IE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmcsIG93bmVyOiBzdHJpbmd9fSBUaGUgcGFyc2VkIGNvbXBvbmVudHMgYXMgYSBzdHJ1Y3R1cmVkIG9iamVjdFxuICogQHRocm93cyB7SW50ZXJuYWxFcnJvcn0gSWYgdGhlIGV2ZW50IG5hbWUgZm9ybWF0IGlzIGludmFsaWRcbiAqIEBmdW5jdGlvbiBwYXJzZUV2ZW50TmFtZVxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgUGFyc2VyIGFzIHBhcnNlRXZlbnROYW1lXG4gKiAgIENhbGxlci0+PlBhcnNlcjogcGFyc2VFdmVudE5hbWUobmFtZSlcbiAqICAgUGFyc2VyLT4+UGFyc2VyOiBzcGxpdCBuYW1lIGJ5IFwiX1wiXG4gKiAgIGFsdCBwYXJ0cyBsZW5ndGggaW52YWxpZFxuICogICAgIFBhcnNlci0tPj5DYWxsZXI6IHRocm93IEludGVybmFsRXJyb3JcbiAqICAgZWxzZVxuICogICAgIFBhcnNlci0tPj5DYWxsZXI6IHsgdGFibGUsIGV2ZW50LCBvd25lcj8gfVxuICogICBlbmRcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlRXZlbnROYW1lKG5hbWU6IHN0cmluZyk6IHtcbiAgdGFibGU/OiBzdHJpbmc7XG4gIGV2ZW50OiBPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nO1xuICBvd25lcj86IHN0cmluZztcbn0ge1xuICBjb25zdCBwYXJ0cyA9IG5hbWUuc3BsaXQoXCJfXCIpO1xuICBpZiAocGFydHMubGVuZ3RoIDwgMiB8fCBwYXJ0cy5sZW5ndGggPiAzKVxuICAgIHJldHVybiB7IHRhYmxlOiB1bmRlZmluZWQsIGV2ZW50OiBuYW1lLCBvd25lcjogdW5kZWZpbmVkIH07XG4gIHJldHVybiB7XG4gICAgdGFibGU6IHBhcnRzWzBdLFxuICAgIGV2ZW50OiBwYXJ0c1sxXSxcbiAgICBvd25lcjogcGFydHNbMl0sXG4gIH0gYXMge1xuICAgIHRhYmxlOiBzdHJpbmc7XG4gICAgZXZlbnQ6IE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmc7XG4gICAgb3duZXI/OiBzdHJpbmc7XG4gIH07XG59XG4iLCJpbXBvcnQgeyBzdHJpbmdGb3JtYXQgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBPdmVyZmxvd0Vycm9yIH0gZnJvbSBcIi4vZXJyb3JzXCI7XG5pbXBvcnQgeyBWYWxpZGF0aW9uRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gT3ZlcmZsb3ctc2FmZSBhZGRpdGlvbiBvcGVyYXRpb25cbiAqIEBzdW1tYXJ5IEFkZHMgdHdvIG51bWJlcnMgYW5kIHZlcmlmaWVzIG5vIG92ZXJmbG93IGJ5IHJldmVyc2UtY2hlY2tpbmcgdGhlIG9wZXJhbmRzXG4gKiBAcGFyYW0ge251bWJlcn0gYSAtIEZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7bnVtYmVyfSBiIC0gU2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm4ge251bWJlcn0gVGhlIHN1bSBvZiBhIGFuZCBiXG4gKiBAZnVuY3Rpb24gYWRkXG4gKiBAdGhyb3dzIHtPdmVyZmxvd0Vycm9yfSBvbiBhZGRpdGlvbiBvdmVyZmxvd1xuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gYWRkKGE6IG51bWJlciwgYjogbnVtYmVyKTogbnVtYmVyIHtcbiAgY29uc3QgYyA9IGEgKyBiO1xuICBpZiAoYSAhPT0gYyAtIGIgfHwgYiAhPT0gYyAtIGEpIHtcbiAgICB0aHJvdyBuZXcgT3ZlcmZsb3dFcnJvcihgQWRkaXRpb24gb3ZlcmZsb3c6ICR7YX0gKyAke2J9YCk7XG4gIH1cbiAgcmV0dXJuIGM7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE92ZXJmbG93LXNhZmUgc3VidHJhY3Rpb24gb3BlcmF0aW9uXG4gKiBAc3VtbWFyeSBTdWJ0cmFjdHMgYiBmcm9tIGEgYW5kIHZhbGlkYXRlcyBubyBvdmVyZmxvdyBieSByZXZlcnNlLWNoZWNraW5nIHRoZSBvcGVyYW5kc1xuICogQHBhcmFtIHtudW1iZXJ9IGEgLSBNaW51ZW5kXG4gKiBAcGFyYW0ge251bWJlcn0gYiAtIFN1YnRyYWhlbmRcbiAqIEByZXR1cm4ge251bWJlcn0gVGhlIGRpZmZlcmVuY2UgYSAtIGJcbiAqIEBmdW5jdGlvbiBzdWJcbiAqIEB0aHJvd3Mge092ZXJmbG93RXJyb3J9IG9uIHN1YnRhY3Rpb24gb3ZlcmZsb3dcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN1YihhOiBudW1iZXIsIGI6IG51bWJlcik6IG51bWJlciB7XG4gIGNvbnN0IGMgPSBhIC0gYjtcbiAgaWYgKGEgIT09IGMgKyBiIHx8IGIgIT09IGEgLSBjKSB7XG4gICAgdGhyb3cgbmV3IE92ZXJmbG93RXJyb3IoYFN1YnRyYWN0aW9uIG92ZXJmbG93OiAke2F9IC0gJHtifWApO1xuICB9XG4gIHJldHVybiBjO1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFNhZmUgSW50ZWdlciBQYXJzZVxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdcbiAqXG4gKiBAZnVuY3Rpb24gc2FmZVBhcnNlSW50XG4gKlxuICogQHRocm93cyB7VmFsaWRhdGlvbkVycm9yfSBpZiBwYXJzZUludCByZXR1cm5zIE5hTlxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNhZmVQYXJzZUludChzdHJpbmc6IHN0cmluZyk6IG51bWJlciB7XG4gIC8vIFJlZ3VsYXIgZXhwcmVzc2lvbiB0byBjaGVjayBpZiBzdHJpbmcgb25seSBoYXZlIGRpZ2l0c1xuICBjb25zdCBkaWdpdFJlZ2V4ID0gL15cXGQrJC87XG4gIGlmICghZGlnaXRSZWdleC50ZXN0KHN0cmluZykpIHtcbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFxuICAgICAgc3RyaW5nRm9ybWF0KFwiRmFpbGVkIHRvIHBhcnNlOiB7MH1cIiwgXCJzdHJpbmcgY29udGFpbnMgZGlnaXRzXCIpXG4gICAgKTtcbiAgfVxuICBjb25zdCBwYXJzZWRpbnQgPSBwYXJzZUludChzdHJpbmcpO1xuICBpZiAoaXNOYU4ocGFyc2VkaW50KSkge1xuICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXG4gICAgICBzdHJpbmdGb3JtYXQoXCJGYWlsZWQgdG8gcGFyc2U6IHswfVwiLCBcInN0cmluZyBpcyBub3QgYSBwYXJzYWJsZSBpbnRlZ2VyXCIpXG4gICAgKTtcbiAgfVxuICByZXR1cm4gcGFyc2VkaW50O1xufVxuIiwiaW1wb3J0IHtcbiAgSlNPTlNlcmlhbGl6ZXIsXG4gIE1vZGVsLFxuICBNb2RlbEtleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yLCBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuXG5leHBvcnQgY2xhc3MgU2ltcGxlRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbj4gZXh0ZW5kcyBKU09OU2VyaWFsaXplcjxNPiB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIG92ZXJyaWRlIGRlc2VyaWFsaXplKHN0cjogc3RyaW5nLCB0YWJsZU5hbWU/OiBzdHJpbmcpOiBNIHtcbiAgICBjb25zdCBkZXNlcmlhbGl6YXRpb24gPSBKU09OLnBhcnNlKHN0cik7XG4gICAgLy8gY29uc3QgY2xhc3NOYW1lID0gdGFibGVOYW1lO1xuICAgIC8vIGlmICghY2xhc3NOYW1lKVxuICAgIC8vICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGQgbm90IGZpbmQgY2xhc3MgcmVmZXJlbmNlIGluIHNlcmlhbGl6ZWQgbW9kZWxcIik7XG5cbiAgICAvLyAvLyB0aGlzIHdpbGwgcmV0dXJuIHVuZGVmaW5lZCB2YWx1ZXNcbiAgICAvLyBjb25zdCBtb2RlbDogTSA9IE1vZGVsLmJ1aWxkKGRlc2VyaWFsaXphdGlvbiwgY2xhc3NOYW1lKSBhcyB1bmtub3duIGFzIE07XG5cbiAgICAvLyAvLyBQb3B1bGF0ZSBNb2RlbFxuICAgIC8vIGNvbnN0IHByb2Nlc3NlZERlc2VhbGl6YXRpb24gPSBPYmplY3Qua2V5cyhtb2RlbCkucmVkdWNlKFxuICAgIC8vICAgKGFjY3VtOiBNLCBrZXkpID0+IHtcbiAgICAvLyAgICAgKGFjY3VtIGFzIFJlY29yZDxzdHJpbmcsIGFueT4pW2tleV0gPVxuICAgIC8vICAgICAgIGRlc2VyaWFsaXphdGlvbltSZXBvc2l0b3J5LmNvbHVtbihhY2N1bSwga2V5KV07XG4gICAgLy8gICAgIHJldHVybiBhY2N1bTtcbiAgICAvLyAgIH0sXG4gICAgLy8gICBtb2RlbFxuICAgIC8vICk7XG5cbiAgICAvLyBjb25zdCByZXN1bHQgPSBNb2RlbC5idWlsZChcbiAgICAvLyAgIHByb2Nlc3NlZERlc2VhbGl6YXRpb24sXG4gICAgLy8gICBjbGFzc05hbWVcbiAgICAvLyApIGFzIHVua25vd24gYXMgTTtcblxuICAgIC8vIHJldHVybiByZXN1bHQ7XG4gICAgcmV0dXJuIGRlc2VyaWFsaXphdGlvbjtcbiAgfVxuXG4gIG92ZXJyaWRlIHNlcmlhbGl6ZShtb2RlbDogTSwgcHV0QW5jaG9yID0gdHJ1ZSk6IHN0cmluZyB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCBzdHJpbmdpZnkgPSByZXF1aXJlKFwianNvbi1zdHJpbmdpZnktZGV0ZXJtaW5pc3RpY1wiKTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICAgIGNvbnN0IHNvcnRLZXlzUmVjdXJzaXZlID0gcmVxdWlyZShcInNvcnQta2V5cy1yZWN1cnNpdmVcIik7XG4gICAgY29uc3QgcHJlU2VyaWFsaXphdGlvbiA9IHRoaXMucHJlU2VyaWFsaXplKG1vZGVsLCBwdXRBbmNob3IpO1xuICAgIHJldHVybiBzdHJpbmdpZnkoc29ydEtleXNSZWN1cnNpdmUocHJlU2VyaWFsaXphdGlvbikpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHByZVNlcmlhbGl6ZShtb2RlbDogTSwgcHV0QW5jaG9yOiBib29sZWFuID0gdHJ1ZSkge1xuICAgIC8vIFRPRE86IG5lc3RlZCBwcmVzZXJpYWxpemF0aW9uIChzbyBpbmNyZWFzZSBwZXJmb3JtYW5jZSB3aGVuIGRlc2VyaWFsaXppbmcpXG4gICAgLy8gVE9ETzogVmVyaWZ5IHdoeSB0aGVyZSBpcyBubyBtZXRhZGF0YVxuICAgIGNvbnN0IHRvU2VyaWFsaXplOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gT2JqZWN0LmFzc2lnbih7fSwgbW9kZWwpO1xuICAgIGxldCBtZXRhZGF0YTtcbiAgICB0cnkge1xuICAgICAgbWV0YWRhdGEgPSBNZXRhZGF0YS5tb2RlbE5hbWUobW9kZWwuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICBtZXRhZGF0YSA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgaWYgKHB1dEFuY2hvcilcbiAgICAgIHRvU2VyaWFsaXplW01vZGVsS2V5cy5BTkNIT1JdID0gbWV0YWRhdGEgfHwgbW9kZWwuY29uc3RydWN0b3IubmFtZTtcblxuICAgIGZ1bmN0aW9uIHByZVNlcmlhbGl6ZShcbiAgICAgIHRoaXM6IFNpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyPGFueT4sXG4gICAgICBvYmo6IGFueVxuICAgICk6IGFueSB7XG4gICAgICBpZiAodHlwZW9mIG9iaiAhPT0gXCJvYmplY3RcIikgcmV0dXJuIG9iajtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHJldHVybiBvYmoubWFwKHByZVNlcmlhbGl6ZSk7XG4gICAgICByZXR1cm4gdGhpcy5wcmVTZXJpYWxpemUob2JqKTtcbiAgICB9XG4gICAgTW9kZWwucmVsYXRpb25zKG1vZGVsKS5mb3JFYWNoKChyKSA9PiB7XG4gICAgICB0b1NlcmlhbGl6ZVtyXSA9IHByZVNlcmlhbGl6ZS5jYWxsKHRoaXMsIHRvU2VyaWFsaXplW3JdKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdG9TZXJpYWxpemU7XG4gIH1cbn1cbiIsImltcG9ydCB7XG4gIEF1dGhvcml6YXRpb25FcnJvcixcbiAgQ2xpZW50QmFzZWRTZXJ2aWNlLFxuICBDb250ZXh0LFxuICBNYXliZUNvbnRleHR1YWxBcmcsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IEZhYnJpY0NBU2VydmljZXMsIHtcbiAgQWZmaWxpYXRpb25TZXJ2aWNlLFxuICBJZGVudGl0eVNlcnZpY2UsXG4gIElFbnJvbGxSZXNwb25zZSxcbiAgSVJlZ2lzdGVyUmVxdWVzdCxcbiAgSVNlcnZpY2VSZXNwb25zZSxcbiAgVExTT3B0aW9ucyxcbn0gZnJvbSBcImZhYnJpYy1jYS1jbGllbnRcIjtcbmltcG9ydCB7IENBQ29uZmlnLCBDcmVkZW50aWFscyB9IGZyb20gXCIuLi8uLi9zaGFyZWQvdHlwZXNcIjtcbmltcG9ydCB7XG4gIENvbmZsaWN0RXJyb3IsXG4gIEludGVybmFsRXJyb3IsXG4gIE5vdEZvdW5kRXJyb3IsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQ29yZVV0aWxzIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQge1xuICBDZXJ0aWZpY2F0ZVJlc3BvbnNlLFxuICBGYWJyaWNJZGVudGl0eSxcbiAgR2V0Q2VydGlmaWNhdGVzUmVxdWVzdCxcbiAgSWRlbnRpdHlSZXNwb25zZSxcbn0gZnJvbSBcIi4uLy4uL3NoYXJlZC9mYWJyaWMtdHlwZXNcIjtcbmltcG9ydCB7IFVzZXIgfSBmcm9tIFwiZmFicmljLWNvbW1vblwiO1xuaW1wb3J0IHsgUmVnaXN0cmF0aW9uRXJyb3IgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL2Vycm9yc1wiO1xuaW1wb3J0IHsgQ0FfUk9MRSB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgSUtleVZhbHVlQXR0cmlidXRlIH0gZnJvbSBcIi4vRmFicmljRW5yb2xsbWVudFNlcnZpY2VcIjtcbmltcG9ydCB7IElkZW50aXR5IH0gZnJvbSBcIi4uLy4uL3NoYXJlZC9pbmRleFwiO1xuaW1wb3J0IHsgQ3J5cHRvVXRpbHMgfSBmcm9tIFwiLi4vY3J5cHRvXCI7XG5cbmV4cG9ydCBjbGFzcyBGYWJyaWNJZGVudGl0eVNlcnZpY2UgZXh0ZW5kcyBDbGllbnRCYXNlZFNlcnZpY2U8XG4gIEZhYnJpY0NBU2VydmljZXMsXG4gIENBQ29uZmlnXG4+IHtcbiAgcHJvdGVjdGVkIF91c2VyITogVXNlcjtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldCByb290Q2xpZW50KCk6IHsgbmV3Q2VydGlmaWNhdGVTZXJ2aWNlOiBhbnkgfSB7XG4gICAgcmV0dXJuICh0aGlzLmNsaWVudCBhcyBhbnkpW1wiX0ZhYnJpY0NhU2VydmljZXNcIl0gYXMgYW55O1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldCB1c2VyKCk6IFVzZXIge1xuICAgIGlmICghdGhpcy5fdXNlcilcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBcIkZhYnJpYyBpZGVudGl0eSBzZXJ2aWNlIG5vdCBwcm9wZXJseSBzZXR1cDogbWlzc2luZyB1c2VyXCJcbiAgICAgICk7XG4gICAgcmV0dXJuIHRoaXMuX3VzZXI7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IGNlcnRpZmljYXRlcygpIHtcbiAgICByZXR1cm4gdGhpcy5yb290Q2xpZW50Lm5ld0NlcnRpZmljYXRlU2VydmljZSgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldCBhZmZpbGlhdGlvbnMoKTogQWZmaWxpYXRpb25TZXJ2aWNlIHtcbiAgICByZXR1cm4gdGhpcy5jbGllbnQubmV3QWZmaWxpYXRpb25TZXJ2aWNlKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IGlkZW50aXRpZXMoKTogSWRlbnRpdHlTZXJ2aWNlIHtcbiAgICByZXR1cm4gdGhpcy5jbGllbnQubmV3SWRlbnRpdHlTZXJ2aWNlKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0VXNlcihjZmc6IENBQ29uZmlnLCBjdHg6IENvbnRleHQpIHtcbiAgICBjb25zdCBsb2cgPSBjdHgubG9nZ2VyLmZvcih0aGlzLmdldFVzZXIpO1xuICAgIGNvbnN0IHsgY2FOYW1lLCBjYUNlcnQsIGNhS2V5LCB1cmwsIGhzbSB9ID0gY2ZnO1xuXG4gICAgbG9nLmluZm8oYENyZWF0aW5nIENBIHVzZXIgZm9yICR7Y2FOYW1lfSBhdCAke3VybH1gKTtcbiAgICBsb2cudmVyYm9zZShgUmV0cmlldmluZyBDQSBjZXJ0aWZpY2F0ZSBmcm9tICR7Y2FDZXJ0fWApO1xuICAgIGNvbnN0IGNlcnRpZmljYXRlID0gYXdhaXQgQ29yZVV0aWxzLmdldEZpcnN0RGlyRmlsZU5hbWVDb250ZW50KGNhQ2VydCk7XG4gICAgbGV0IGtleTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGlmICghaHNtKSB7XG4gICAgICBpZiAoIWNhS2V5KSB7XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgIGBNaXNzaW5nIGNhS2V5IGNvbmZpZ3VyYXRpb24gZm9yIENBICR7Y2FOYW1lfS4gUHJvdmlkZSBhIGtleSBkaXJlY3Rvcnkgb3IgY29uZmlndXJlIEhTTSBzdXBwb3J0LmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGxvZy5kZWJ1ZyhgUmV0cmlldmluZyBDQSBrZXkgZnJvbSAke2NhS2V5fWApO1xuICAgICAga2V5ID0gYXdhaXQgQ29yZVV0aWxzLmdldEZpcnN0RGlyRmlsZU5hbWVDb250ZW50KGNhS2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgbG9nLmRlYnVnKFxuICAgICAgICBgVXNpbmcgSFNNIGNvbmZpZ3VyYXRpb24gZm9yIENBICR7Y2FOYW1lfSB3aXRoIGxpYnJhcnkgJHtoc20ubGlicmFyeX1gXG4gICAgICApO1xuICAgIH1cbiAgICBsb2cuZGVidWcoYExvYWRpbmcgQWRtaW4gdXNlciBmb3IgY2EgJHtjYU5hbWV9YCk7XG4gICAgdGhpcy5fdXNlciA9IGF3YWl0IENvcmVVdGlscy5nZXRDQVVzZXIoXCJhZG1pblwiLCBrZXksIGNlcnRpZmljYXRlLCBjYU5hbWUsIHtcbiAgICAgIGhzbSxcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcy5fdXNlcjtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGluaXRpYWxpemUoXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPGFueT5cbiAgKTogUHJvbWlzZTx7IGNvbmZpZzogQ0FDb25maWc7IGNsaWVudDogRmFicmljQ0FTZXJ2aWNlcyB9PiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgdGhpcy5pbml0aWFsaXplLCB0cnVlKTtcbiAgICBjb25zdCBbY29uZmlnXSA9IGFyZ3M7XG4gICAgaWYgKCFjb25maWcpIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiTWlzc2luZyBGYWJyaWMgQ0EgY29uZmlndXJhdGlvblwiKTtcblxuICAgIGNvbnN0IHsgdXJsLCB0bHMsIGNhTmFtZSB9ID0gY29uZmlnO1xuICAgIGxvZy5pbmZvKGBJbml0aWFsaXppbmcgQ0EgQ2xpZW50IGZvciBDQSAke2NvbmZpZy5jYU5hbWV9IGF0ICR7Y29uZmlnLnVybH1gKTtcbiAgICBjb25zdCB7IHRydXN0ZWRSb290cywgdmVyaWZ5IH0gPSB0bHMgYXMgVExTT3B0aW9ucztcblxuICAgIGNvbnN0IHJvb3QgPSAodHJ1c3RlZFJvb3RzIGFzIHN0cmluZ1tdKVswXSBhcyBzdHJpbmc7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIENBIGNlcnRpZmljYXRlIGZyb20gJHtyb290fS4gY3dkOiAke3Byb2Nlc3MuY3dkKCl9YCk7XG5cbiAgICBjb25zdCBjZXJ0aWZpY2F0ZSA9IGF3YWl0IENvcmVVdGlscy5nZXRGaWxlQ29udGVudChyb290KTtcblxuICAgIGxvZy5kZWJ1ZyhgQ0EgQ2VydGlmaWNhdGU6ICR7Y2VydGlmaWNhdGUudG9TdHJpbmcoKX1gKTtcblxuICAgIGNvbnN0IGNsaWVudCA9IG5ldyBGYWJyaWNDQVNlcnZpY2VzKFxuICAgICAgdXJsLFxuICAgICAge1xuICAgICAgICB0cnVzdGVkUm9vdHM6IEJ1ZmZlci5mcm9tKGNlcnRpZmljYXRlKSxcbiAgICAgICAgdmVyaWZ5LFxuICAgICAgfSBhcyBUTFNPcHRpb25zLFxuICAgICAgY2FOYW1lXG4gICAgKTtcblxuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmdldFVzZXIoY29uZmlnLCBjdHgpO1xuICAgIGxvZy5kZWJ1ZyhgQ0EgdXNlciBsb2FkZWQ6ICR7dXNlci5nZXROYW1lKCl9YCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbmZpZyxcbiAgICAgIGNsaWVudCxcbiAgICB9O1xuICB9XG5cbiAgYXN5bmMgZ2V0Q2VydGlmaWNhdGVzKC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxhbnk+KTogUHJvbWlzZTxzdHJpbmdbXT47XG4gIGFzeW5jIGdldENlcnRpZmljYXRlcyhcbiAgICByZXF1ZXN0OiBHZXRDZXJ0aWZpY2F0ZXNSZXF1ZXN0LFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxhbnk+XG4gICk6IFByb21pc2U8c3RyaW5nW10+O1xuICBhc3luYyBnZXRDZXJ0aWZpY2F0ZXM8TUFQIGV4dGVuZHMgYm9vbGVhbj4oXG4gICAgZG9NYXA6IE1BUCxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPE1BUCBleHRlbmRzIGZhbHNlID8gQ2VydGlmaWNhdGVSZXNwb25zZSA6IHN0cmluZ1tdPjtcbiAgYXN5bmMgZ2V0Q2VydGlmaWNhdGVzPE1BUCBleHRlbmRzIGJvb2xlYW4+KFxuICAgIHJlcXVlc3Q6IEdldENlcnRpZmljYXRlc1JlcXVlc3QsXG4gICAgZG9NYXA6IE1BUCxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPE1BUCBleHRlbmRzIGZhbHNlID8gQ2VydGlmaWNhdGVSZXNwb25zZSA6IHN0cmluZ1tdPjtcbiAgYXN5bmMgZ2V0Q2VydGlmaWNhdGVzPE1BUCBleHRlbmRzIGJvb2xlYW4+KFxuICAgIHJlcXVlc3Q/OiBHZXRDZXJ0aWZpY2F0ZXNSZXF1ZXN0IHwgTUFQLFxuICAgIGRvTWFwOiBNQVAgPSB0cnVlIGFzIE1BUCxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPE1BUCBleHRlbmRzIGZhbHNlID8gQ2VydGlmaWNhdGVSZXNwb25zZSA6IHN0cmluZ1tdPiB7XG4gICAgaWYgKHJlcXVlc3QgaW5zdGFuY2VvZiBDb250ZXh0KSB7XG4gICAgICBhcmdzID0gW3JlcXVlc3RdO1xuICAgICAgZG9NYXAgPSB0cnVlIGFzIE1BUDtcbiAgICAgIHJlcXVlc3QgPSB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgcmVxdWVzdCA9PT0gXCJib29sZWFuXCIpIHtcbiAgICAgIGRvTWFwID0gcmVxdWVzdDtcbiAgICAgIHJlcXVlc3QgPSB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgZG9NYXAgIT09IFwiYm9vbGVhblwiKSB7XG4gICAgICBhcmdzID0gW2RvTWFwIGFzIE1heWJlQ29udGV4dHVhbEFyZzxhbnk+LCAuLi5hcmdzXTtcbiAgICAgIGRvTWFwID0gdHJ1ZSBhcyBNQVA7XG4gICAgfVxuXG4gICAgY29uc3QgeyBsb2cgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuZ2V0Q2VydGlmaWNhdGVzLCB0cnVlKTtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgUmV0cmlldmluZyBjZXJ0aWZpY2F0ZXMke3JlcXVlc3QgPyBgIGZvciAke3JlcXVlc3QuaWR9YCA6IFwiXCJ9IGZvciBDQSAke3RoaXMuY29uZmlnLmNhTmFtZX1gXG4gICAgKTtcbiAgICBjb25zdCByZXNwb25zZTogQ2VydGlmaWNhdGVSZXNwb25zZSA9IChcbiAgICAgIGF3YWl0IHRoaXMuY2VydGlmaWNhdGVzLmdldENlcnRpZmljYXRlcyhyZXF1ZXN0IHx8IHt9LCB0aGlzLnVzZXIpXG4gICAgKS5yZXN1bHQ7XG4gICAgbG9nLnZlcmJvc2UoYEZvdW5kICR7cmVzcG9uc2UuY2VydHMubGVuZ3RofSBjZXJ0aWZpY2F0ZXNgKTtcbiAgICBsb2cuZGVidWcocmVzcG9uc2UuY2VydHMpO1xuICAgIHJldHVybiAoXG4gICAgICBkb01hcCA/IHJlc3BvbnNlLmNlcnRzLm1hcCgoYykgPT4gYy5QRU0pIDogcmVzcG9uc2VcbiAgICApIGFzIE1BUCBleHRlbmRzIGZhbHNlID8gQ2VydGlmaWNhdGVSZXNwb25zZSA6IHN0cmluZ1tdO1xuICB9XG5cbiAgYXN5bmMgZ2V0SWRlbnRpdGllcyhjdHg6IENvbnRleHQpOiBQcm9taXNlPEZhYnJpY0lkZW50aXR5W10+IHtcbiAgICBjb25zdCBsb2cgPSBjdHgubG9nZ2VyLmZvcih0aGlzLmdldElkZW50aXRpZXMpO1xuICAgIGxvZy52ZXJib3NlKGBSZXRyaWV2aW5nIElkZW50aXRpZXMgdW5kZXIgQ0EgJHt0aGlzLmNvbmZpZy5jYU5hbWV9YCk7XG4gICAgY29uc3QgcmVzcG9uc2U6IElkZW50aXR5UmVzcG9uc2UgPSAoYXdhaXQgdGhpcy5pZGVudGl0aWVzLmdldEFsbCh0aGlzLnVzZXIpKVxuICAgICAgLnJlc3VsdDtcbiAgICBsb2cudmVyYm9zZShgRm91bmQgJHtyZXNwb25zZS5pZGVudGl0aWVzLmxlbmd0aH0gSWRlbnRpdGllc2ApO1xuICAgIGxvZy5kZWJ1ZyhyZXNwb25zZS5pZGVudGl0aWVzKTtcbiAgICByZXR1cm4gcmVzcG9uc2UuaWRlbnRpdGllcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmV0cmlldmUgYWZmaWxpYXRpb25zIGZyb20gdGhlIENBLlxuICAgKiBAc3VtbWFyeSBRdWVyaWVzIHRoZSBDQSBmb3IgdGhlIGxpc3Qgb2YgYWZmaWxpYXRpb25zIGF2YWlsYWJsZSB1bmRlciB0aGUgY29uZmlndXJlZCBDQS5cbiAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgYWZmaWxpYXRpb25zIHJlc3VsdCBwYXlsb2FkLlxuICAgKi9cbiAgYXN5bmMgZ2V0QWZmaWxpYXRpb25zKGN0eDogQ29udGV4dCkge1xuICAgIGNvbnN0IGxvZyA9IGN0eC5sb2dnZXIuZm9yKHRoaXMuZ2V0QWZmaWxpYXRpb25zKTtcbiAgICBsb2cudmVyYm9zZShgUmV0cmlldmluZyBBZmZpbGlhdGlvbnMgdW5kZXIgQ0EgJHt0aGlzLmNvbmZpZy5jYU5hbWV9YCk7XG4gICAgY29uc3QgcmVzcG9uc2UgPSAoYXdhaXQgdGhpcy5hZmZpbGlhdGlvbnMuZ2V0QWxsKHRoaXMudXNlcikpLnJlc3VsdDtcbiAgICBsb2cudmVyYm9zZShgRm91bmQgJHtyZXNwb25zZS5hLmxlbmd0aH0gQWZmaWxpYXRpb25zYCk7XG4gICAgbG9nLmRlYnVnKEpTT04uc3RyaW5naWZ5KHJlc3BvbnNlKSk7XG4gICAgcmV0dXJuIHJlc3BvbnNlO1xuICB9XG5cbiAgcHJvdGVjdGVkIHBhcnNlRXJyb3IoZTogRXJyb3IpIHtcbiAgICBjb25zdCByZWdleHAgPSAvLipjb2RlOlxccyhcXGQrKS4qP21lc3NhZ2U6XFxzW1wiJ10oLispW1wiJ10vZ3M7XG4gICAgY29uc3QgbWF0Y2ggPSByZWdleHAuZXhlYyhlLm1lc3NhZ2UpO1xuICAgIGlmICghbWF0Y2gpIHJldHVybiBuZXcgUmVnaXN0cmF0aW9uRXJyb3IoZSk7XG4gICAgY29uc3QgWywgY29kZSwgbWVzc2FnZV0gPSBtYXRjaDtcbiAgICBzd2l0Y2ggKGNvZGUpIHtcbiAgICAgIGNhc2UgXCI3NFwiOlxuICAgICAgY2FzZSBcIjcxXCI6XG4gICAgICAgIHJldHVybiBuZXcgQ29uZmxpY3RFcnJvcihtZXNzYWdlKTtcbiAgICAgIGNhc2UgXCIyMFwiOlxuICAgICAgICByZXR1cm4gbmV3IEF1dGhvcml6YXRpb25FcnJvcihtZXNzYWdlKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBuZXcgUmVnaXN0cmF0aW9uRXJyb3IobWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWFkIGlkZW50aXR5IGRldGFpbHMgZnJvbSB0aGUgQ0EgYnkgZW5yb2xsbWVudCBJRC5cbiAgICogQHN1bW1hcnkgUmV0cmlldmVzIGFuZCB2YWxpZGF0ZXMgYSBzaW5nbGUgaWRlbnRpdHksIHRocm93aW5nIE5vdEZvdW5kRXJyb3Igd2hlbiBtaXNzaW5nLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZW5yb2xsbWVudElkIC0gRW5yb2xsbWVudCBJRCB0byBsb29rdXAuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8RmFicmljSWRlbnRpdHk+fSBUaGUgaWRlbnRpdHkgZGV0YWlscyBzdG9yZWQgaW4gdGhlIENBLlxuICAgKi9cbiAgYXN5bmMgcmVhZChcbiAgICBlbnJvbGxtZW50SWQ6IHN0cmluZyxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPEZhYnJpY0lkZW50aXR5PiB7XG4gICAgY29uc3QgeyBsb2cgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmVhZCwgdHJ1ZSk7XG4gICAgbG9nLnZlcmJvc2UoYFJldHJpZXZpbmcgaWRlbnRpdHkgd2l0aCBlbnJvbGxtZW50IElEICR7ZW5yb2xsbWVudElkfWApO1xuICAgIGxldCByZXN1bHQ6IElTZXJ2aWNlUmVzcG9uc2U7XG4gICAgdHJ5IHtcbiAgICAgIHJlc3VsdCA9IGF3YWl0IHRoaXMuaWRlbnRpdGllcy5nZXRPbmUoZW5yb2xsbWVudElkLCB0aGlzLnVzZXIpO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXJyb3IoXG4gICAgICAgIGBDb3VsZG4ndCBmaW5kIGVucm9sbG1lbnQgd2l0aCBpZCAke2Vucm9sbG1lbnRJZH06ICR7ZX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICghcmVzdWx0LnN1Y2Nlc3MpXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihcbiAgICAgICAgYENvdWxkbid0IGZpbmQgZW5yb2xsbWVudCB3aXRoIGlkICR7ZW5yb2xsbWVudElkfTogJHtyZXN1bHQuZXJyb3JzLmpvaW4oXCJcXG5cIil9YFxuICAgICAgKTtcblxuICAgIHJldHVybiByZXN1bHQucmVzdWx0IGFzIEZhYnJpY0lkZW50aXR5O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWdpc3RlciBhIG5ldyBpZGVudGl0eSB3aXRoIHRoZSBDQS5cbiAgICogQHN1bW1hcnkgU3VibWl0cyBhIHJlZ2lzdHJhdGlvbiByZXF1ZXN0IGZvciBhIG5ldyBlbnJvbGxtZW50IElELCByZXR1cm5pbmcgdGhlIGVucm9sbG1lbnQgc2VjcmV0IHVwb24gc3VjY2Vzcy5cbiAgICogQHBhcmFtIHtDcmVkZW50aWFsc30gbW9kZWwgLSBDcmVkZW50aWFscyBjb250YWluaW5nIHVzZXJOYW1lIGFuZCBwYXNzd29yZCBmb3IgdGhlIG5ldyBpZGVudGl0eS5cbiAgICogQHBhcmFtIHtib29sZWFufSBbaXNTdXBlclVzZXI9ZmFsc2VdIC0gV2hldGhlciB0byByZWdpc3RlciB0aGUgaWRlbnRpdHkgYXMgYSBzdXBlciB1c2VyLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FmZmlsaWF0aW9uPVwiXCJdIC0gQWZmaWxpYXRpb24gc3RyaW5nIChlLmcuLCBvcmcxLmRlcGFydG1lbnQxKS5cbiAgICogQHBhcmFtIHtDQV9ST0xFIHwgc3RyaW5nfSBbdXNlclJvbGVdIC0gUm9sZSB0byBhc3NpZ24gdG8gdGhlIGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge0lLZXlWYWx1ZUF0dHJpYnV0ZX0gW2F0dHJzXSAtIE9wdGlvbmFsIGF0dHJpYnV0ZXMgdG8gYXR0YWNoIHRvIHRoZSBpZGVudGl0eS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhFbnJvbGxtZW50c10gLSBNYXhpbXVtIG51bWJlciBvZiBlbnJvbGxtZW50cyBhbGxvd2VkIGZvciB0aGUgaWRlbnRpdHkuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gVGhlIGVucm9sbG1lbnQgc2VjcmV0IGZvciB0aGUgcmVnaXN0ZXJlZCBpZGVudGl0eS5cbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyKFxuICAgIG1vZGVsOiBDcmVkZW50aWFscyxcbiAgICBpc1N1cGVyVXNlcjogYm9vbGVhbiA9IGZhbHNlLFxuICAgIGFmZmlsaWF0aW9uOiBzdHJpbmcgPSBcIlwiLFxuICAgIHVzZXJSb2xlPzogQ0FfUk9MRSB8IHN0cmluZyxcbiAgICBhdHRycz86IElLZXlWYWx1ZUF0dHJpYnV0ZSxcbiAgICBtYXhFbnJvbGxtZW50cz86IG51bWJlcixcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHsgbG9nIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnJlZ2lzdGVyLCB0cnVlKTtcblxuICAgIGxldCByZWdpc3RyYXRpb246IHN0cmluZztcbiAgICB0cnkge1xuICAgICAgY29uc3QgeyB1c2VyTmFtZSwgcGFzc3dvcmQgfSA9IG1vZGVsO1xuICAgICAgY29uc3QgcHJvcHMgPSB7XG4gICAgICAgIGVucm9sbG1lbnRJRDogdXNlck5hbWUgYXMgc3RyaW5nLFxuICAgICAgICBlbnJvbGxtZW50U2VjcmV0OiBwYXNzd29yZCxcbiAgICAgICAgYWZmaWxpYXRpb246IGFmZmlsaWF0aW9uLFxuICAgICAgICB1c2VyUm9sZTogdXNlclJvbGUsXG4gICAgICAgIGF0dHJzOiBhdHRycyxcbiAgICAgICAgbWF4RW5yb2xsbWVudHM6IG1heEVucm9sbG1lbnRzLFxuICAgICAgfSBhcyBJUmVnaXN0ZXJSZXF1ZXN0O1xuICAgICAgcmVnaXN0cmF0aW9uID0gYXdhaXQgdGhpcy5jbGllbnQucmVnaXN0ZXIocHJvcHMsIHRoaXMudXNlcik7XG4gICAgICBsb2cuaW5mbyhcbiAgICAgICAgYFJlZ2lzdHJhdGlvbiBmb3IgJHt1c2VyTmFtZX0gY3JlYXRlZCB3aXRoIHVzZXIgdHlwZSAke3VzZXJSb2xlID8/IFwiVW5kZWZpbmVkIFJvbGVcIn0gJHtpc1N1cGVyVXNlciA/IFwiYXMgc3VwZXIgdXNlclwiIDogXCJcIn1gXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUpO1xuICAgIH1cbiAgICByZXR1cm4gcmVnaXN0cmF0aW9uO1xuICB9XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBpZGVudGl0eUZyb21FbnJvbGxtZW50KFxuICAgIGVucm9sbG1lbnQ6IElFbnJvbGxSZXNwb25zZSxcbiAgICBtc3BJZDogc3RyaW5nLFxuICAgIGN0eDogQ29udGV4dFxuICApOiBJZGVudGl0eSB7XG4gICAgY29uc3QgbG9nID0gY3R4LmxvZ2dlci5mb3IodGhpcy5pZGVudGl0eUZyb21FbnJvbGxtZW50KTtcbiAgICBjb25zdCB7IGNlcnRpZmljYXRlLCBrZXksIHJvb3RDZXJ0aWZpY2F0ZSB9ID0gZW5yb2xsbWVudDtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBHZW5lcmF0aW5nIElkZW50aXR5IGZyb20gY2VydGlmaWNhdGUgJHtjZXJ0aWZpY2F0ZX0gaW4gbXNwICR7bXNwSWR9YFxuICAgICk7XG4gICAgY29uc3QgY2xpZW50SWQgPSBDcnlwdG9VdGlscy5mYWJyaWNJZEZyb21DZXJ0aWZpY2F0ZShjZXJ0aWZpY2F0ZSk7XG4gICAgY29uc3QgaWQgPSBDcnlwdG9VdGlscy5lbmNvZGUoY2xpZW50SWQpO1xuICAgIGxvZy5kZWJ1ZyhgSWRlbnRpdHkgJHtjbGllbnRJZH0gYW5kIGVuY29kZWRJZCAke2lkfWApO1xuICAgIHJldHVybiBuZXcgSWRlbnRpdHkoe1xuICAgICAgaWQ6IGlkLFxuICAgICAgY3JlZGVudGlhbHM6IHtcbiAgICAgICAgaWQ6IGlkLFxuICAgICAgICBjZXJ0aWZpY2F0ZTogY2VydGlmaWNhdGUsXG4gICAgICAgIHByaXZhdGVLZXk6IGtleS50b0J5dGVzKCksXG4gICAgICAgIHJvb3RDZXJ0aWZpY2F0ZTogcm9vdENlcnRpZmljYXRlLFxuICAgICAgfSxcbiAgICAgIG1zcElkOiBtc3BJZCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRW5yb2xsIGFuIGlkZW50aXR5IHdpdGggdGhlIENBIHVzaW5nIGEgcmVnaXN0cmF0aW9uIHNlY3JldC5cbiAgICogQHN1bW1hcnkgRXhjaGFuZ2VzIHRoZSBlbnJvbGxtZW50IElEIGFuZCBzZWNyZXQgZm9yIGNlcnRpZmljYXRlcywgcmV0dXJuaW5nIGEgY29uc3RydWN0ZWQgSWRlbnRpdHkgbW9kZWwuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBlbnJvbGxtZW50SWQgLSBFbnJvbGxtZW50IElEIHRvIGVucm9sbC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZ2lzdHJhdGlvbiAtIEVucm9sbG1lbnQgc2VjcmV0IHJldHVybmVkIGF0IHJlZ2lzdHJhdGlvbiB0aW1lLlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPElkZW50aXR5Pn0gVGhlIGVucm9sbGVkIGlkZW50aXR5IG9iamVjdCB3aXRoIGNyZWRlbnRpYWxzLlxuICAgKi9cbiAgYXN5bmMgZW5yb2xsKFxuICAgIGVucm9sbG1lbnRJZDogc3RyaW5nLFxuICAgIHJlZ2lzdHJhdGlvbjogc3RyaW5nLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxhbnk+XG4gICk6IFByb21pc2U8SWRlbnRpdHk+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLmVucm9sbCwgdHJ1ZSk7XG4gICAgbGV0IGlkZW50aXR5OiBJZGVudGl0eTtcbiAgICB0cnkge1xuICAgICAgbG9nLmRlYnVnKGBFbnJvbGxpbmcgJHtlbnJvbGxtZW50SWR9YCk7XG4gICAgICBjb25zdCBlbnJvbGxtZW50OiBJRW5yb2xsUmVzcG9uc2UgPSBhd2FpdCB0aGlzLmNsaWVudC5lbnJvbGwoe1xuICAgICAgICBlbnJvbGxtZW50SUQ6IGVucm9sbG1lbnRJZCxcbiAgICAgICAgZW5yb2xsbWVudFNlY3JldDogcmVnaXN0cmF0aW9uLFxuICAgICAgfSk7XG4gICAgICBpZGVudGl0eSA9IEZhYnJpY0lkZW50aXR5U2VydmljZS5pZGVudGl0eUZyb21FbnJvbGxtZW50KFxuICAgICAgICBlbnJvbGxtZW50LFxuICAgICAgICB0aGlzLmNvbmZpZy5jYU5hbWUsXG4gICAgICAgIGN0eFxuICAgICAgKTtcbiAgICAgIGxvZy5pbmZvKFxuICAgICAgICBgU3VjY2Vzc2Z1bGx5IGVucm9sbGVkICR7ZW5yb2xsbWVudElkfSB1bmRlciAke3RoaXMuY29uZmlnLmNhTmFtZX0gYXMgJHtpZGVudGl0eS5pZH1gXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUpO1xuICAgIH1cbiAgICByZXR1cm4gaWRlbnRpdHk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlZ2lzdGVyIGFuZCBlbnJvbGwgYSBuZXcgaWRlbnRpdHkgaW4gb25lIHN0ZXAuXG4gICAqIEBzdW1tYXJ5IFJlZ2lzdGVycyBhIG5ldyBlbnJvbGxtZW50IElEIHdpdGggdGhlIENBIGFuZCBpbW1lZGlhdGVseSBleGNoYW5nZXMgdGhlIHNlY3JldCB0byBlbnJvbGwsIHJldHVybmluZyB0aGUgY3JlYXRlZCBJZGVudGl0eS5cbiAgICogQHBhcmFtIHtDcmVkZW50aWFsc30gbW9kZWwgLSBDcmVkZW50aWFscyBmb3IgdGhlIG5ldyBpZGVudGl0eSBjb250YWluaW5nIHVzZXJOYW1lIGFuZCBwYXNzd29yZC5cbiAgICogQHBhcmFtIHtib29sZWFufSBbaXNTdXBlclVzZXI9ZmFsc2VdIC0gV2hldGhlciB0byByZWdpc3RlciB0aGUgaWRlbnRpdHkgYXMgYSBzdXBlciB1c2VyLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FmZmlsaWF0aW9uPVwiXCJdIC0gQWZmaWxpYXRpb24gc3RyaW5nIChlLmcuLCBvcmcxLmRlcGFydG1lbnQxKS5cbiAgICogQHBhcmFtIHtDQV9ST0xFIHwgc3RyaW5nfSBbdXNlclJvbGVdIC0gUm9sZSB0byBhc3NpZ24gdG8gdGhlIGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge0lLZXlWYWx1ZUF0dHJpYnV0ZX0gW2F0dHJzXSAtIE9wdGlvbmFsIGF0dHJpYnV0ZXMgdG8gYXR0YWNoIHRvIHRoZSBpZGVudGl0eS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhFbnJvbGxtZW50c10gLSBNYXhpbXVtIG51bWJlciBvZiBlbnJvbGxtZW50cyBhbGxvd2VkIGZvciB0aGUgaWRlbnRpdHkuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8SWRlbnRpdHk+fSBUaGUgZW5yb2xsZWQgaWRlbnRpdHkuXG4gICAqL1xuICBhc3luYyByZWdpc3RlckFuZEVucm9sbChcbiAgICBtb2RlbDogQ3JlZGVudGlhbHMsXG4gICAgaXNTdXBlclVzZXI6IGJvb2xlYW4gPSBmYWxzZSxcbiAgICBhZmZpbGlhdGlvbjogc3RyaW5nID0gXCJcIixcbiAgICB1c2VyUm9sZT86IENBX1JPTEUgfCBzdHJpbmcsXG4gICAgYXR0cnM/OiBJS2V5VmFsdWVBdHRyaWJ1dGUsXG4gICAgbWF4RW5yb2xsbWVudHM/OiBudW1iZXIsXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPGFueT5cbiAgKTogUHJvbWlzZTxJZGVudGl0eT4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnJlZ2lzdGVyQW5kRW5yb2xsLCB0cnVlKTtcbiAgICBjb25zdCByZWdpc3RyYXRpb24gPSBhd2FpdCB0aGlzLnJlZ2lzdGVyKFxuICAgICAgbW9kZWwsXG4gICAgICBpc1N1cGVyVXNlcixcbiAgICAgIGFmZmlsaWF0aW9uLFxuICAgICAgdXNlclJvbGUsXG4gICAgICBhdHRycyxcbiAgICAgIG1heEVucm9sbG1lbnRzLFxuICAgICAgY3R4XG4gICAgKTtcbiAgICBjb25zdCB7IHVzZXJOYW1lIH0gPSBtb2RlbDtcbiAgICByZXR1cm4gdGhpcy5lbnJvbGwodXNlck5hbWUgYXMgc3RyaW5nLCByZWdpc3RyYXRpb24sIGN0eCk7XG4gIH1cblxuICAvKipcbiAgICogUmV2b2tlcyB0aGUgZW5yb2xsbWVudCBvZiBhbiBpZGVudGl0eSB3aXRoIHRoZSBzcGVjaWZpZWQgZW5yb2xsbWVudCBJRC5cbiAgICpcbiAgICogQHBhcmFtIGVucm9sbG1lbnRJZCAtIFRoZSBlbnJvbGxtZW50IElEIG9mIHRoZSBpZGVudGl0eSB0byBiZSByZXZva2VkLlxuICAgKlxuICAgKiBAcmV0dXJucyBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSByZXZvY2F0aW9uIG9wZXJhdGlvbi5cbiAgICpcbiAgICogQHRocm93cyB7Tm90Rm91bmRFcnJvcn0gSWYgdGhlIGVucm9sbG1lbnQgd2l0aCB0aGUgc3BlY2lmaWVkIElEIGRvZXMgbm90IGV4aXN0LlxuICAgKiBAdGhyb3dzIHtJbnRlcm5hbEVycm9yfSBJZiB0aGVyZSBpcyBhbiBlcnJvciBkdXJpbmcgdGhlIHJldm9jYXRpb24gcHJvY2Vzcy5cbiAgICovXG4gIGFzeW5jIHJldm9rZShcbiAgICBlbnJvbGxtZW50SWQ6IHN0cmluZyxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPElTZXJ2aWNlUmVzcG9uc2U+IHtcbiAgICBjb25zdCB7IGxvZyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgdGhpcy5yZXZva2UsIHRydWUpO1xuICAgIGxvZy52ZXJib3NlKGBSZXZva2luZyBpZGVudGl0eSB3aXRoIGVucm9sbG1lbnQgSUQgJHtlbnJvbGxtZW50SWR9YCk7XG4gICAgY29uc3QgaWRlbnRpdHkgPSBhd2FpdCB0aGlzLnJlYWQoZW5yb2xsbWVudElkKTtcbiAgICBpZiAoIWlkZW50aXR5KVxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXJyb3IoXG4gICAgICAgIGBDb3VsZCBub3QgZmluZCBlbnJvbGxtZW50IHdpdGggaWQgJHtlbnJvbGxtZW50SWR9YFxuICAgICAgKTtcbiAgICBsZXQgcmVzdWx0OiBJU2VydmljZVJlc3BvbnNlO1xuICAgIHRyeSB7XG4gICAgICByZXN1bHQgPSBhd2FpdCB0aGlzLmNsaWVudC5yZXZva2UoXG4gICAgICAgIHsgZW5yb2xsbWVudElEOiBpZGVudGl0eS5pZCwgcmVhc29uOiBcIlVzZXIgRGVsZXRpb25cIiB9LFxuICAgICAgICB0aGlzLnVzZXJcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBDb3VsZCBub3QgcmV2b2tlIGVucm9sbG1lbnQgd2l0aCBpZCAke2Vucm9sbG1lbnRJZH06ICR7ZX1gXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAoIXJlc3VsdC5zdWNjZXNzKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBDb3VsZCBub3QgcmV2b2tlIGVucm9sbG1lbnQgd2l0aCBpZCAke2Vucm9sbG1lbnRJZH06ICR7cmVzdWx0LmVycm9ycy5qb2luKFwiXFxuXCIpfWBcbiAgICAgICk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxufVxuIiwiaW1wb3J0IHsgRmFicmljQ2xpZW50RmxhZ3MgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgRGVmYXVsdEFkYXB0ZXJGbGFncyB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuXG5leHBvcnQgY29uc3QgRGVmYXVsdEZhYnJpY0NsaWVudEZsYWdzOiBGYWJyaWNDbGllbnRGbGFncyA9IE9iamVjdC5hc3NpZ24oXG4gIHtcbiAgICBldmFsdWF0ZVRpbWVvdXQ6IDUsXG4gICAgZW5kb3JzZVRpbWVvdXQ6IDE1LFxuICAgIHN1Ym1pdFRpbWVvdXQ6IDUsXG4gICAgY29tbWl0VGltZW91dDogNjAsXG4gIH0sXG4gIERlZmF1bHRBZGFwdGVyRmxhZ3NcbikgYXMgYW55O1xuIiwiaW1wb3J0IHsgaXNCcm93c2VyLCBNaW5pTG9nZ2VyIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQgeyBVc2VyIH0gZnJvbSBcImZhYnJpYy1jb21tb25cIjtcbmltcG9ydCB7IElkZW50aXR5LCBTaWduZXIsIHNpZ25lcnMgfSBmcm9tIFwiQGh5cGVybGVkZ2VyL2ZhYnJpYy1nYXRld2F5XCI7XG5pbXBvcnQgeyBJbnRlcm5hbEVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBub3JtYWxpemVJbXBvcnQgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcblxuY29uc3QgbG9nID0gbmV3IE1pbmlMb2dnZXIoXCJmYWJyaWMtZnNcIik7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIExvYWRzIGNvbnRlbnQgZnJvbSBhIGZpbGUgb3IgcmV0dXJucyB0aGUgY29udGVudCBpZiBhbHJlYWR5IGxvYWRlZFxuICogQHN1bW1hcnkgRGV0ZXJtaW5lcyBpZiB0aGUgaW5wdXQgaXMgYWxyZWFkeSBjb250ZW50IG9yIGEgcGF0aCB0byBhIGZpbGUsIGFuZCBsb2FkcyB0aGUgZmlsZSBpZiBuZWVkZWRcbiAqIEBwYXJhbSB7c3RyaW5nIHwgVWludDhBcnJheX0gY29udGVudE9yUGF0aCAtIFRoZSBjb250ZW50IG9yIHBhdGggdG8gbG9hZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gZmlsZVJlYWRlciAtIEZ1bmN0aW9uIHRvIHJlYWQgdGhlIGZpbGUgaWYgY29udGVudE9yUGF0aCBpcyBhIHBhdGhcbiAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nIHwgVWludDhBcnJheSB8IEJ1ZmZlcj59IFRoZSBjb250ZW50XG4gKiBAZnVuY3Rpb24gY29udGVudE9mTG9hZEZpbGVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvbnRlbnRPZkxvYWRGaWxlKFxuICBjb250ZW50T3JQYXRoOiBzdHJpbmcgfCBVaW50OEFycmF5LFxuICBmaWxlUmVhZGVyOiAocGF0aDogc3RyaW5nKSA9PiBQcm9taXNlPHN0cmluZyB8IFVpbnQ4QXJyYXkgfCBCdWZmZXI+XG4pIHtcbiAgaWYgKGNvbnRlbnRPclBhdGggaW5zdGFuY2VvZiBVaW50OEFycmF5KSByZXR1cm4gY29udGVudE9yUGF0aDtcbiAgaWYgKFxuICAgIGNvbnRlbnRPclBhdGgubWF0Y2goXG4gICAgICAvLS0tLS1CRUdJTiAoQ0VSVElGSUNBVEV8S0VZfFBSSVZBVEUgS0VZKS0tLS0tLis/LS0tLS1FTkQgXFwxLS0tLS0kL2dtc1xuICAgIClcbiAgKVxuICAgIHJldHVybiBjb250ZW50T3JQYXRoO1xuICByZXR1cm4gYXdhaXQgZmlsZVJlYWRlcihjb250ZW50T3JQYXRoKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmVhZHMgYSBmaWxlIGZyb20gdGhlIGZpbGUgc3lzdGVtXG4gKiBAc3VtbWFyeSBMb2FkcyBhIGZpbGUgdXNpbmcgdGhlIE5vZGUuanMgZmlsZSBzeXN0ZW0gbW9kdWxlXG4gKiBAcGFyYW0ge3N0cmluZyB8IEJ1ZmZlcn0gY29udGVudE9yUGF0aCAtIFRoZSBjb250ZW50IG9yIHBhdGggdG8gbG9hZFxuICogQHJldHVybiB7UHJvbWlzZTxCdWZmZXI+fSBUaGUgZmlsZSBjb250ZW50IGFzIGEgQnVmZmVyXG4gKiBAZnVuY3Rpb24gcmVhZEZpbGVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRGaWxlKGNvbnRlbnRPclBhdGg6IHN0cmluZyB8IEJ1ZmZlcikge1xuICBpZiAodHlwZW9mIGNvbnRlbnRPclBhdGggIT09IFwic3RyaW5nXCIpIHJldHVybiBjb250ZW50T3JQYXRoO1xuXG4gIGNvbnN0IGZpbGVSZWFkZXIgPSBhc3luYyAocGF0aDogc3RyaW5nKSA9PiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICByZXR1cm4gYXdhaXQgcHJvbWlzZXMucmVhZEZpbGUocGF0aCk7XG4gIH07XG5cbiAgcmV0dXJuIGF3YWl0IGZpbGVSZWFkZXIoY29udGVudE9yUGF0aCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgdXNlclxuICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYSB1c2VyIHdpdGggdGhlIGdpdmVuIGNyZWRlbnRpYWxzIGZvciBpbnRlcmFjdGluZyB3aXRoIGEgRmFicmljIENBXG4gKiBAcGFyYW0ge3N0cmluZ30gdXNlck5hbWUgLSBUaGUgdXNlciBuYW1lXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJpdmF0ZUtleSAtIFRoZSBwcml2YXRlIGtleSBhcyBhIHN0cmluZ1xuICogQHBhcmFtIHtzdHJpbmd9IGNlcnRpZmljYXRlIC0gVGhlIGNlcnRpZmljYXRlIGFzIGEgc3RyaW5nXG4gKiBAcGFyYW0ge3N0cmluZ30gbXNwSWQgLSBUaGUgTWVtYmVyc2hpcCBTZXJ2aWNlIFByb3ZpZGVyIElEXG4gKiBAcmV0dXJuIHtQcm9taXNlPFVzZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgY3JlYXRlZCB1c2VyXG4gKiBAZnVuY3Rpb24gZ2V0Q0FVc2VyXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuY2xpZW50XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRDQVVzZXIoXG4gIHVzZXJOYW1lOiBzdHJpbmcsXG4gIHByaXZhdGVLZXk6IHN0cmluZyxcbiAgY2VydGlmaWNhdGU6IHN0cmluZyxcbiAgbXNwSWQ6IHN0cmluZ1xuKTogUHJvbWlzZTxVc2VyPiB7XG4gIGxvZy5kZWJ1ZyhcbiAgICBgQ3JlYXRpbmcgYSBDQSAke21zcElkfSB1c2VyICR7dXNlck5hbWV9IHdpdGggY2VydGlmaWNhdGUgJHtjZXJ0aWZpY2F0ZX1gXG4gICk7XG4gIGNvbnN0IHVzZXIgPSBuZXcgVXNlcih1c2VyTmFtZSk7XG4gIGNvbnN0IGNyeXB0b1N1aXRlID0gVXNlci5uZXdDcnlwdG9TdWl0ZSgpO1xuICB1c2VyLnNldENyeXB0b1N1aXRlKGNyeXB0b1N1aXRlKTtcbiAgY29uc3QgaW1wb3J0ZWRLZXkgPSBjcnlwdG9TdWl0ZS5jcmVhdGVLZXlGcm9tUmF3KHByaXZhdGVLZXkpO1xuICBhd2FpdCB1c2VyLnNldEVucm9sbG1lbnQoaW1wb3J0ZWRLZXksIGNlcnRpZmljYXRlLCBtc3BJZCk7XG4gIHJldHVybiB1c2VyO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBHZXRzIGFuIGlkZW50aXR5IGZyb20gYSBjZXJ0aWZpY2F0ZSBkaXJlY3RvcnlcbiAqIEBzdW1tYXJ5IExvYWRzIGEgY2VydGlmaWNhdGUgZnJvbSBhIGRpcmVjdG9yeSBhbmQgY3JlYXRlcyBhbiBJZGVudGl0eSBvYmplY3RcbiAqIEBwYXJhbSB7c3RyaW5nfSBtc3BJZCAtIFRoZSBNZW1iZXJzaGlwIFNlcnZpY2UgUHJvdmlkZXIgSURcbiAqIEBwYXJhbSB7c3RyaW5nfSBjZXJ0RGlyZWN0b3J5UGF0aCAtIFBhdGggdG8gdGhlIGRpcmVjdG9yeSBjb250YWluaW5nIHRoZSBjZXJ0aWZpY2F0ZVxuICogQHJldHVybiB7UHJvbWlzZTxJZGVudGl0eT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpZGVudGl0eVxuICogQGZ1bmN0aW9uIGdldElkZW50aXR5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuY2xpZW50XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRJZGVudGl0eShcbiAgbXNwSWQ6IHN0cmluZyxcbiAgY2VydERpcmVjdG9yeVBhdGg6IHN0cmluZ1xuKTogUHJvbWlzZTxJZGVudGl0eT4ge1xuICBjb25zdCBpZGVudGl0eUZpbGVSZWFkZXIgPSBhc3luYyAocGF0aDogc3RyaW5nKSA9PiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICBjb25zdCBjZXJ0UGF0aCA9IGF3YWl0IGdldEZpcnN0RGlyRmlsZU5hbWUocGF0aCk7XG4gICAgY29uc3QgY3JlZGVudGlhbHMgPSBhd2FpdCBwcm9taXNlcy5yZWFkRmlsZShjZXJ0UGF0aCk7XG4gICAgcmV0dXJuIGNyZWRlbnRpYWxzO1xuICB9O1xuXG4gIGNvbnN0IGNyZWRlbnRpYWxzOiBVaW50OEFycmF5ID0gKGF3YWl0IGNvbnRlbnRPZkxvYWRGaWxlKFxuICAgIGNlcnREaXJlY3RvcnlQYXRoLFxuICAgIGlkZW50aXR5RmlsZVJlYWRlclxuICApKSBhcyBVaW50OEFycmF5O1xuXG4gIHJldHVybiB7IG1zcElkLCBjcmVkZW50aWFscyB9O1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBHZXRzIHRoZSBmdWxsIHBhdGggb2YgdGhlIGZpcnN0IGZpbGUgaW4gYSBkaXJlY3RvcnlcbiAqIEBzdW1tYXJ5IFJlYWRzIGEgZGlyZWN0b3J5IGFuZCByZXR1cm5zIHRoZSBwYXRoIHRvIHRoZSBmaXJzdCBmaWxlIGZvdW5kXG4gKiBAcGFyYW0ge3N0cmluZ30gZGlyUGF0aCAtIFBhdGggdG8gdGhlIGRpcmVjdG9yeVxuICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZnVsbCBwYXRoIG9mIHRoZSBmaXJzdCBmaWxlXG4gKiBAZnVuY3Rpb24gZ2V0Rmlyc3REaXJGaWxlTmFtZVxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLmNsaWVudFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0Rmlyc3REaXJGaWxlTmFtZShkaXJQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCB7IHByb21pc2VzIH0gPSBhd2FpdCBub3JtYWxpemVJbXBvcnQoaW1wb3J0KFwiZnNcIikpO1xuICBjb25zdCB7IGpvaW4gfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJwYXRoXCIpKTtcbiAgY29uc3QgZmlsZXMgPSBhd2FpdCBwcm9taXNlcy5yZWFkZGlyKGRpclBhdGgpO1xuICByZXR1cm4gam9pbihkaXJQYXRoLCBmaWxlc1swXSk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEdldHMgdGhlIGNvbnRlbnQgb2YgdGhlIGZpcnN0IGZpbGUgaW4gYSBkaXJlY3RvcnlcbiAqIEBzdW1tYXJ5IFJlYWRzIGEgZGlyZWN0b3J5LCBmaW5kcyB0aGUgZmlyc3QgZmlsZSwgYW5kIHJldHVybnMgaXRzIGNvbnRlbnQgYXMgYSBzdHJpbmdcbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXJQYXRoIC0gUGF0aCB0byB0aGUgZGlyZWN0b3J5XG4gKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBjb250ZW50IG9mIHRoZSBmaXJzdCBmaWxlXG4gKiBAZnVuY3Rpb24gZ2V0Rmlyc3REaXJGaWxlTmFtZUNvbnRlbnRcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldEZpcnN0RGlyRmlsZU5hbWVDb250ZW50KFxuICBkaXJQYXRoOiBzdHJpbmdcbik6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHsgcHJvbWlzZXMgfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJmc1wiKSk7XG4gIGNvbnN0IHsgam9pbiB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcInBhdGhcIikpO1xuICBjb25zdCBmaWxlcyA9IGF3YWl0IHByb21pc2VzLnJlYWRkaXIoZGlyUGF0aCk7XG4gIHJldHVybiAoYXdhaXQgcHJvbWlzZXMucmVhZEZpbGUoam9pbihkaXJQYXRoLCBmaWxlc1swXSkpKS50b1N0cmluZygpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBHZXRzIGEgc2lnbmVyIGZyb20gYSBrZXkgZGlyZWN0b3J5XG4gKiBAc3VtbWFyeSBMb2FkcyBhIHByaXZhdGUga2V5IGZyb20gYSBkaXJlY3RvcnkgYW5kIGNyZWF0ZXMgYSBTaWduZXIgZm9yIEZhYnJpYyB0cmFuc2FjdGlvbnNcbiAqIEBwYXJhbSB7c3RyaW5nfSBrZXlEaXJlY3RvcnlQYXRoIC0gUGF0aCB0byB0aGUgZGlyZWN0b3J5IGNvbnRhaW5pbmcgdGhlIHByaXZhdGUga2V5XG4gKiBAcmV0dXJuIHtQcm9taXNlPFNpZ25lcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBzaWduZXJcbiAqIEBmdW5jdGlvbiBnZXRTaWduZXJcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldFNpZ25lcihrZXlEaXJlY3RvcnlQYXRoOiBzdHJpbmcpOiBQcm9taXNlPFNpZ25lcj4ge1xuICBjb25zdCBzaWduZXJGaWxlUmVhZGVyID0gYXN5bmMgKHBhdGg6IHN0cmluZykgPT4ge1xuICAgIGNvbnN0IHsgcHJvbWlzZXMgfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJmc1wiKSk7XG4gICAgY29uc3Qga2V5UGF0aCA9IGF3YWl0IGdldEZpcnN0RGlyRmlsZU5hbWUocGF0aCk7XG4gICAgcmV0dXJuIGF3YWl0IHByb21pc2VzLnJlYWRGaWxlKGtleVBhdGgpO1xuICB9O1xuXG4gIGNvbnN0IHByaXZhdGVLZXlQZW0gPSAoYXdhaXQgY29udGVudE9mTG9hZEZpbGUoXG4gICAga2V5RGlyZWN0b3J5UGF0aCxcbiAgICBzaWduZXJGaWxlUmVhZGVyXG4gICkpIGFzIEJ1ZmZlcjtcbiAgLy8gTm9kZSBiYXNlZCBpbXBsZW1lbnRhdGlvblxuICAvLyBwcml2YXRlS2V5ID0gY3JlYXRlUHJpdmF0ZUtleShwcml2YXRlS2V5UGVtKTtcbiAgLy8gLS1cblxuICAvLyB3ZWIgYmFzZWQgaW1wbGVtZW50YXRpb25cbiAgY29uc3QgcHJpdmF0ZUtleSA9IGF3YWl0IGV4dHJhY3RQcml2YXRlS2V5KHByaXZhdGVLZXlQZW0pO1xuICBjb25zdCBrZXlzID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhwcml2YXRlS2V5KTtcbiAgY29uc3QgayA9IChwcml2YXRlS2V5IGFzIGFueSlba2V5c1swXV07XG4gIC8vIC0tXG5cbiAgcmV0dXJuIHNpZ25lcnMubmV3UHJpdmF0ZUtleVNpZ25lcihrIGFzIGFueSk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEV4dHJhY3RzIGEgcHJpdmF0ZSBrZXkgZnJvbSBhIFBFTSBidWZmZXJcbiAqIEBzdW1tYXJ5IENvbnZlcnRzIGEgUEVNLWVuY29kZWQgcHJpdmF0ZSBrZXkgdG8gYSBDcnlwdG9LZXkgb2JqZWN0XG4gKiBAcGFyYW0ge0J1ZmZlcn0gcGVtIC0gVGhlIFBFTS1lbmNvZGVkIHByaXZhdGUga2V5XG4gKiBAcmV0dXJuIHtQcm9taXNlPENyeXB0b0tleT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBDcnlwdG9LZXlcbiAqIEBmdW5jdGlvbiBleHRyYWN0UHJpdmF0ZUtleVxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLmNsaWVudFxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgRXh0cmFjdFByaXZhdGVLZXlcbiAqICAgcGFydGljaXBhbnQgU3VidGxlQ3J5cHRvXG4gKlxuICogICBDYWxsZXItPj5FeHRyYWN0UHJpdmF0ZUtleTogZXh0cmFjdFByaXZhdGVLZXkocGVtKVxuICogICBFeHRyYWN0UHJpdmF0ZUtleS0+PkV4dHJhY3RQcml2YXRlS2V5OiBHZXQgU3VidGxlQ3J5cHRvIGltcGxlbWVudGF0aW9uXG4gKiAgIEV4dHJhY3RQcml2YXRlS2V5LT4+RXh0cmFjdFByaXZhdGVLZXk6IFBhcnNlIFBFTSBmb3JtYXRcbiAqICAgRXh0cmFjdFByaXZhdGVLZXktPj5FeHRyYWN0UHJpdmF0ZUtleTogQ29udmVydCB0byBiaW5hcnkgREVSXG4gKiAgIEV4dHJhY3RQcml2YXRlS2V5LT4+U3VidGxlQ3J5cHRvOiBpbXBvcnRLZXkocGtjczgsIGJpbmFyeURlciwgb3B0aW9ucylcbiAqICAgU3VidGxlQ3J5cHRvLS0+PkV4dHJhY3RQcml2YXRlS2V5OiBDcnlwdG9LZXlcbiAqICAgRXh0cmFjdFByaXZhdGVLZXktLT4+Q2FsbGVyOiBDcnlwdG9LZXlcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RQcml2YXRlS2V5KHBlbTogQnVmZmVyKSB7XG4gIGNvbnN0IGxpYk5hbWUgPSBcImNyeXB0b1wiO1xuICBsZXQgc3VidGxlO1xuICBpZiAoaXNCcm93c2VyKCkpIHtcbiAgICBzdWJ0bGUgPSAoZ2xvYmFsVGhpcyBhcyBhbnkpLmNyeXB0by5zdWJ0bGU7XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgbGliID0gKGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQobGliTmFtZSkpKSBhcyBhbnk7XG4gICAgc3VidGxlID0gbGliLnN1YnRsZSB8fCBsaWIud2ViY3J5cHRvLnN1YnRsZTtcbiAgfVxuXG4gIGlmICghc3VidGxlKSB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgbG9hZCBTdWJ0bGVDcnlwdG8gbW9kdWxlXCIpO1xuXG4gIGZ1bmN0aW9uIHN0cjJhYihzdHI6IHN0cmluZykge1xuICAgIGNvbnN0IGJ1ZiA9IG5ldyBBcnJheUJ1ZmZlcihzdHIubGVuZ3RoKTtcbiAgICBjb25zdCBidWZWaWV3ID0gbmV3IFVpbnQ4QXJyYXkoYnVmKTtcbiAgICBmb3IgKGxldCBpID0gMCwgc3RyTGVuID0gc3RyLmxlbmd0aDsgaSA8IHN0ckxlbjsgaSsrKSB7XG4gICAgICBidWZWaWV3W2ldID0gc3RyLmNoYXJDb2RlQXQoaSk7XG4gICAgfVxuICAgIHJldHVybiBidWY7XG4gIH1cblxuICBjb25zdCBzdHIgPSBwZW1cbiAgICAudG9TdHJpbmcoXCJ1dGY4XCIpXG4gICAgLnJlcGxhY2UoXCItLS0tLUJFR0lOIFBSSVZBVEUgS0VZLS0tLS1cIiwgXCJcIilcbiAgICAucmVwbGFjZUFsbChcIlxcblwiLCBcIlwiKVxuICAgIC5yZXBsYWNlKFwiLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLVwiLCBcIlwiKTtcbiAgY29uc3QgZGVjb2RlZCA9IEJ1ZmZlci5mcm9tKHN0ciwgXCJiYXNlNjRcIikudG9TdHJpbmcoXCJiaW5hcnlcIik7XG4gIGNvbnN0IGJpbmFyeURlciA9IHN0cjJhYihkZWNvZGVkKTtcblxuICB0cnkge1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IHN1YnRsZS5pbXBvcnRLZXkoXG4gICAgICBcInBrY3M4XCIsXG4gICAgICBiaW5hcnlEZXIsXG4gICAgICB7XG4gICAgICAgIG5hbWU6IFwiRUNEU0FcIixcbiAgICAgICAgbmFtZWRDdXJ2ZTogXCJQLTI1NlwiLFxuICAgICAgfSxcbiAgICAgIHRydWUsXG4gICAgICBbXCJzaWduXCJdXG4gICAgKTtcblxuICAgIHJldHVybiBrZXk7XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGUpO1xuICB9XG59XG4iLCJpbXBvcnQgcGtjczExIGZyb20gXCJwa2NzMTFqc1wiO1xuaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IE1pc3NpbmdQS0NTUzExTGliIH0gZnJvbSBcIi4uL3NoYXJlZC9lcnJvcnNcIjtcbmltcG9ydCBjcnlwdG8gZnJvbSBcImNyeXB0b1wiO1xuaW1wb3J0IHsgcDI1NiB9IGZyb20gXCJAbm9ibGUvY3VydmVzL25pc3RcIjtcblxuZXhwb3J0IGNsYXNzIEhTTVNpZ25lckZhY3RvcnlDdXN0b20ge1xuICBzdGF0aWMgI3BrY3MxMTogcGtjczExLlBLQ1MxMSB8IG51bGwgPSBudWxsO1xuICBzdGF0aWMgI2luaXRpYWxpemVkID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IobGlicmFyeTogc3RyaW5nKSB7XG4gICAgaWYgKCFIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEpIHtcbiAgICAgIEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSA9IG5ldyBwa2NzMTEuUEtDUzExKCk7XG4gICAgICBIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEubG9hZCh0aGlzLmZpbmRIU01QS0NTMTFMaWIobGlicmFyeSkpO1xuICAgIH1cblxuICAgIGlmICghSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jaW5pdGlhbGl6ZWQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMS5DX0luaXRpYWxpemUoKTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgLy8gaWdub3JlIFwiYWxyZWFkeSBpbml0aWFsaXplZFwiIGlmIHRlc3RzIC8gaG90IHJlbG9hZHMgY2F1c2UgcmV1c2VcbiAgICAgICAgaWYgKChlIGFzIGFueSkuY29kZSAhPT0gcGtjczExLkNLUl9DUllQVE9LSV9BTFJFQURZX0lOSVRJQUxJWkVEKSB7XG4gICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jaW5pdGlhbGl6ZWQgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmluZEhTTVBLQ1MxMUxpYihsaWI/OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvbW1vblNvZnRIU01QYXRoTmFtZXMgPSBbXG4gICAgICBcIi91c3IvbGliL3NvZnRoc20vbGlic29mdGhzbTIuc29cIixcbiAgICAgIFwiL3Vzci9saWIveDg2XzY0LWxpbnV4LWdudS9zb2Z0aHNtL2xpYnNvZnRoc20yLnNvXCIsXG4gICAgICBcIi91c3IvbG9jYWwvbGliL3NvZnRoc20vbGlic29mdGhzbTIuc29cIixcbiAgICAgIFwiL3Vzci9saWIvbGliYWNzcC1wa2NzMTEuc29cIixcbiAgICAgIFwiL29wdC9ob21lYnJldy9saWIvc29mdGhzbS9saWJzb2Z0aHNtMi5zb1wiLFxuICAgIF07XG5cbiAgICBpZiAobGliKSBjb21tb25Tb2Z0SFNNUGF0aE5hbWVzLnB1c2gobGliKTtcblxuICAgIGZvciAoY29uc3QgcGF0aG5hbWVUb1RyeSBvZiBjb21tb25Tb2Z0SFNNUGF0aE5hbWVzKSB7XG4gICAgICBpZiAoZnMuZXhpc3RzU3luYyhwYXRobmFtZVRvVHJ5KSkge1xuICAgICAgICByZXR1cm4gcGF0aG5hbWVUb1RyeTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgTWlzc2luZ1BLQ1NTMTFMaWIoXCJVbmFibGUgdG8gZmluZCBQS0NTMTEgbGlicmFyeVwiKTtcbiAgfVxuXG4gIGRpc3Bvc2UoKSB7XG4gICAgSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jcGtjczExIS5DX0ZpbmFsaXplKCk7XG4gIH1cblxuICBwcml2YXRlIHNhbml0aXplT3B0aW9ucyhoc21TaWduZXJPcHRpb25zOiBIU01Db25maWcpIHtcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcbiAgICAgIHtcbiAgICAgICAgdXNlclR5cGU6IHBrY3MxMS5DS1VfVVNFUixcbiAgICAgIH0sXG4gICAgICBoc21TaWduZXJPcHRpb25zXG4gICAgKTtcbiAgICB0aGlzLmFzc2VydE5vdEVtcHR5KG9wdGlvbnMubGFiZWwsIFwibGFiZWxcIik7XG4gICAgdGhpcy5hc3NlcnROb3RFbXB0eShvcHRpb25zLnBpbiwgXCJwaW5cIik7XG4gICAgdGhpcy5hc3NlcnROb3RFbXB0eShvcHRpb25zLmlkZW50aWZpZXIgYXMgdW5rbm93biBhcyBzdHJpbmcsIFwiaWRlbnRpZmllclwiKTtcbiAgICByZXR1cm4gb3B0aW9ucztcbiAgfVxuXG4gIHByaXZhdGUgYXNzZXJ0Tm90RW1wdHkocHJvcGVydHk6IHN0cmluZywgbmFtZTogc3RyaW5nKSB7XG4gICAgaWYgKCFwcm9wZXJ0eSB8fCBwcm9wZXJ0eS50b1N0cmluZygpLnRyaW0oKS5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtuYW1lfSBwcm9wZXJ0eSBtdXN0IGJlIHByb3ZpZGVkYCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBmaW5kU2xvdEZvckxhYmVsKHBrY3MxMUxhYmVsOiBzdHJpbmcpIHtcbiAgICBjb25zdCBzbG90cyA9IChcbiAgICAgIEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExXG4gICAgKS5DX0dldFNsb3RMaXN0KHRydWUpO1xuICAgIGlmIChzbG90cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIHBrY3MxMSBzbG90cyBjYW4gYmUgZm91bmRcIik7XG4gICAgfVxuICAgIGNvbnN0IHNsb3QgPSBzbG90cy5maW5kKChzbG90VG9DaGVjaykgPT4ge1xuICAgICAgY29uc3QgdG9rZW5JbmZvID0gKFxuICAgICAgICBIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEgYXMgcGtjczExLlBLQ1MxMVxuICAgICAgKS5DX0dldFRva2VuSW5mbyhzbG90VG9DaGVjayk7XG4gICAgICByZXR1cm4gdG9rZW5JbmZvLmxhYmVsLnRyaW0oKSA9PT0gcGtjczExTGFiZWw7XG4gICAgfSk7XG4gICAgaWYgKCFzbG90KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBsYWJlbCAke3BrY3MxMUxhYmVsfSBjYW5ub3QgYmUgZm91bmQgaW4gdGhlIHBrY3MxMSBzbG90IGxpc3RgXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gc2xvdDtcbiAgfVxuXG4gIHByaXZhdGUgbG9naW4oc2Vzc2lvbjogcGtjczExLkhhbmRsZSwgdXNlclR5cGU6IG51bWJlciwgcGluOiBzdHJpbmcpIHtcbiAgICB0cnkge1xuICAgICAgKEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExKS5DX0xvZ2luKFxuICAgICAgICBzZXNzaW9uLFxuICAgICAgICB1c2VyVHlwZSxcbiAgICAgICAgcGluXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycjogdW5rbm93bikge1xuICAgICAgY29uc3QgcGtjczExZXJyID0gZXJyIGFzIHsgY29kZTogbnVtYmVyIH07XG4gICAgICBpZiAocGtjczExZXJyLmNvZGUgIT09IHBrY3MxMS5DS1JfVVNFUl9BTFJFQURZX0xPR0dFRF9JTikge1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBmaW5kT2JqZWN0SW5IU00oXG4gICAgc2Vzc2lvbjogcGtjczExLkhhbmRsZSxcbiAgICBrZXl0eXBlOiBudW1iZXIsXG4gICAgaWRlbnRpZmllcjogYW55XG4gICkge1xuICAgIGNvbnN0IHBrY3MxMVRlbXBsYXRlID0gW1xuICAgICAgeyB0eXBlOiBwa2NzMTEuQ0tBX0lELCB2YWx1ZTogaWRlbnRpZmllciB9LFxuICAgICAgeyB0eXBlOiBwa2NzMTEuQ0tBX0NMQVNTLCB2YWx1ZToga2V5dHlwZSB9LFxuICAgICAgeyB0eXBlOiBwa2NzMTEuQ0tBX0tFWV9UWVBFLCB2YWx1ZTogcGtjczExLkNLS19FQyB9LFxuICAgIF07XG5cbiAgICAoSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jcGtjczExIGFzIHBrY3MxMS5QS0NTMTEpLkNfRmluZE9iamVjdHNJbml0KFxuICAgICAgc2Vzc2lvbixcbiAgICAgIHBrY3MxMVRlbXBsYXRlXG4gICAgKTtcbiAgICBjb25zdCBoc21PYmplY3QgPSAoXG4gICAgICBIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEgYXMgcGtjczExLlBLQ1MxMVxuICAgICkuQ19GaW5kT2JqZWN0cyhzZXNzaW9uLCAxKVswXTtcbiAgICBpZiAoIWhzbU9iamVjdCkge1xuICAgICAgKEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExKS5DX0ZpbmRPYmplY3RzRmluYWwoXG4gICAgICAgIHNlc3Npb25cbiAgICAgICk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBVbmFibGUgdG8gZmluZCBvYmplY3QgaW4gSFNNIHdpdGggSUQgJHtpZGVudGlmaWVyLnRvU3RyaW5nKCl9YFxuICAgICAgKTtcbiAgICB9XG4gICAgKEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExKS5DX0ZpbmRPYmplY3RzRmluYWwoXG4gICAgICBzZXNzaW9uXG4gICAgKTtcbiAgICByZXR1cm4gaHNtT2JqZWN0O1xuICB9XG5cbiAgbmV3U2lnbmVyKGhzbVNpZ25lck9wdGlvbnM6IEhTTUNvbmZpZykge1xuICAgIGNvbnN0IG9wdGlvbnMgPSB0aGlzLnNhbml0aXplT3B0aW9ucyhoc21TaWduZXJPcHRpb25zKTtcbiAgICBjb25zdCBwa2NzID0gSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jcGtjczExIGFzIHBrY3MxMS5QS0NTMTE7XG4gICAgY29uc3Qgc2xvdCA9IHRoaXMuZmluZFNsb3RGb3JMYWJlbChvcHRpb25zLmxhYmVsKTtcbiAgICBjb25zdCBzZXNzaW9uID0gcGtjcy5DX09wZW5TZXNzaW9uKHNsb3QsIHBrY3MxMS5DS0ZfU0VSSUFMX1NFU1NJT04pO1xuICAgIGxldCBwcml2YXRlS2V5SGFuZGxlO1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmxvZ2luKHNlc3Npb24sIG9wdGlvbnMudXNlclR5cGUsIG9wdGlvbnMucGluKTtcbiAgICAgIHByaXZhdGVLZXlIYW5kbGUgPSB0aGlzLmZpbmRPYmplY3RJbkhTTShcbiAgICAgICAgc2Vzc2lvbixcbiAgICAgICAgcGtjczExLkNLT19QUklWQVRFX0tFWSxcbiAgICAgICAgb3B0aW9ucy5pZGVudGlmaWVyXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgKEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExKS5DX0Nsb3NlU2Vzc2lvbihzZXNzaW9uKTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIHNpZ25lcjogYXN5bmMgKGRpZ2VzdDogYW55KSA9PiB7XG4gICAgICAgIChIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEgYXMgcGtjczExLlBLQ1MxMSkuQ19TaWduSW5pdChcbiAgICAgICAgICBzZXNzaW9uLFxuICAgICAgICAgIHsgbWVjaGFuaXNtOiBwa2NzMTEuQ0tNX0VDRFNBIH0sXG4gICAgICAgICAgcHJpdmF0ZUtleUhhbmRsZVxuICAgICAgICApO1xuICAgICAgICBjb25zdCBjb21wYWN0U2lnbmF0dXJlID0gYXdhaXQgKFxuICAgICAgICAgIEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExXG4gICAgICAgICkuQ19TaWduQXN5bmMoXG4gICAgICAgICAgc2Vzc2lvbixcbiAgICAgICAgICBCdWZmZXIuZnJvbShkaWdlc3QpLFxuICAgICAgICAgIC8vIEVDIHNpZ25hdHVyZXMgaGF2ZSBsZW5ndGggb2YgMm4gYWNjb3JkaW5nIHRvIHRoZSBQS0NTMTEgc3BlYzpcbiAgICAgICAgICAvLyBodHRwczovL2RvY3Mub2FzaXMtb3Blbi5vcmcvcGtjczExL3BrY3MxMS1zcGVjL3YzLjEvcGtjczExLXNwZWMtdjMuMS5odG1sXG4gICAgICAgICAgQnVmZmVyLmFsbG9jKHAyNTYuUG9pbnQuRm4uQllURVMgKiAyKVxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gcDI1Ni5TaWduYXR1cmUuZnJvbUJ5dGVzKGNvbXBhY3RTaWduYXR1cmUsIFwiY29tcGFjdFwiKVxuICAgICAgICAgIC5ub3JtYWxpemVTKClcbiAgICAgICAgICAudG9CeXRlcyhcImRlclwiKTtcbiAgICAgIH0sXG4gICAgICBjbG9zZTogKCkgPT4ge1xuICAgICAgICAoSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jcGtjczExIGFzIHBrY3MxMS5QS0NTMTEpLkNfQ2xvc2VTZXNzaW9uKFxuICAgICAgICAgIHNlc3Npb25cbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXNzZXJ0RGVmaW5lZDxUPih2YWx1ZTogVCB8IHVuZGVmaW5lZCk6IFQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJyZXF1aXJlZCB2YWx1ZSB3YXMgdW5kZWZpbmVkXCIpO1xuICAgIH1cblxuICAgIHJldHVybiB2YWx1ZTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0VW5jb21wcmVzc2VkUG9pbnRPbkN1cnZlKGtleTogY3J5cHRvLktleU9iamVjdCk6IEJ1ZmZlciB7XG4gICAgY29uc3QgandrID0ga2V5LmV4cG9ydCh7IGZvcm1hdDogXCJqd2tcIiB9KTtcbiAgICBjb25zdCB4ID0gQnVmZmVyLmZyb20odGhpcy5hc3NlcnREZWZpbmVkKGp3ay54KSwgXCJiYXNlNjR1cmxcIik7XG4gICAgY29uc3QgeSA9IEJ1ZmZlci5mcm9tKHRoaXMuYXNzZXJ0RGVmaW5lZChqd2sueSksIFwiYmFzZTY0dXJsXCIpO1xuICAgIGNvbnN0IHByZWZpeCA9IEJ1ZmZlci5mcm9tKFwiMDRcIiwgXCJoZXhcIik7XG4gICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoW3ByZWZpeCwgeCwgeV0pO1xuICB9XG5cbiAgZ2V0U0tJRnJvbUNlcnRpZmljYXRlUGF0aChjZXJ0UGF0aDogc3RyaW5nKSB7XG4gICAgY29uc3QgcCA9IGNlcnRQYXRoLmVuZHNXaXRoKFwiLnBlbVwiKVxuICAgICAgPyBjZXJ0UGF0aFxuICAgICAgOiBwYXRoLmpvaW4oY2VydFBhdGgsIFwiY2VydC5wZW1cIik7XG4gICAgY29uc3QgY3JlZGVudGlhbHMgPSBmcy5yZWFkRmlsZVN5bmMocCk7XG5cbiAgICByZXR1cm4gdGhpcy5nZXRTS0lGcm9tQ2VydGlmaWNhdGUoY3JlZGVudGlhbHMpO1xuICB9XG5cbiAgZ2V0U0tJRnJvbUNlcnRpZmljYXRlKGNlcnQ6IHN0cmluZyB8IE5vblNoYXJlZEJ1ZmZlcik6IEJ1ZmZlciB7XG4gICAgY29uc3QgY2VydGlmaWNhdGUgPSBuZXcgY3J5cHRvLlg1MDlDZXJ0aWZpY2F0ZShjZXJ0KTtcbiAgICBjb25zdCB1bmNvbXByZXNzZWRQb2ludCA9IHRoaXMuZ2V0VW5jb21wcmVzc2VkUG9pbnRPbkN1cnZlKFxuICAgICAgY2VydGlmaWNhdGUucHVibGljS2V5XG4gICAgKTtcblxuICAgIHJldHVybiBjcnlwdG8uY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUodW5jb21wcmVzc2VkUG9pbnQpLmRpZ2VzdCgpO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSFNNQ29uZmlnIHtcbiAgbGFiZWw6IHN0cmluZztcbiAgaWRlbnRpZmllcjogQnVmZmVyPEFycmF5QnVmZmVyTGlrZT47XG4gIHBpbjogc3RyaW5nO1xufVxuIiwiaW1wb3J0IHtcbiAgQWRhcHRlckZsYWdzLFxuICBDb25kaXRpb24sXG4gIENvbnRleHQsXG4gIE1heWJlQ29udGV4dHVhbEFyZyxcbiAgUGVyc2lzdGVuY2VLZXlzLFxuICBQcmVwYXJlZFN0YXRlbWVudCxcbiAgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLFxuICBRdWVyeUNsYXVzZSxcbiAgUmVwb3NpdG9yeSxcbiAgU3RhdGVtZW50LFxuICBTdGF0ZW1lbnRFeGVjdXRvcixcbiAgVW5zdXBwb3J0ZWRFcnJvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBNb2RlbCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudEFkYXB0ZXIgfSBmcm9tIFwiLi9GYWJyaWNDbGllbnRBZGFwdGVyXCI7XG5pbXBvcnQgeyBNYW5nb1F1ZXJ5IH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuaW1wb3J0IHsgRmFicmljQ2xpZW50RmxhZ3MgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgdG9DYW1lbENhc2UgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7IEludGVybmFsRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuZXhwb3J0IGNsYXNzIEZhYnJpY0NsaWVudFN0YXRlbWVudDxNIGV4dGVuZHMgTW9kZWwsIFI+IGV4dGVuZHMgU3RhdGVtZW50PFxuICBNLFxuICBGYWJyaWNDbGllbnRBZGFwdGVyLFxuICBSLFxuICBNYW5nb1F1ZXJ5XG4+IHtcbiAgY29uc3RydWN0b3IoYWRhcHRlcjogRmFicmljQ2xpZW50QWRhcHRlciwgb3ZlcnJpZGVzPzogUGFydGlhbDxBZGFwdGVyRmxhZ3M+KSB7XG4gICAgc3VwZXIoYWRhcHRlciwgb3ZlcnJpZGVzKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvdmVycmlkZSBzcXVhc2goXG4gICAgY3R4OiBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPlxuICApOiBQcmVwYXJlZFN0YXRlbWVudDxhbnk+IHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBzcXVhc2hlZDogUHJlcGFyZWRTdGF0ZW1lbnQ8TT4gfCB1bmRlZmluZWQgPSBzdXBlci5zcXVhc2goXG4gICAgICBjdHggYXMgbmV2ZXJcbiAgICApO1xuICAgIGlmICghc3F1YXNoZWQpIHJldHVybiBzcXVhc2hlZDtcblxuICAgIGNvbnN0IHsgbWV0aG9kLCBwYXJhbXMsIGFyZ3MgfSA9IHNxdWFzaGVkO1xuICAgIGNvbnN0IHsgZGlyZWN0aW9uLCBsaW1pdCB9ID0gcGFyYW1zO1xuICAgIHN3aXRjaCAobWV0aG9kKSB7XG4gICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZOlxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkxJU1RfQlk6XG4gICAgICAgIGFyZ3MucHVzaChkaXJlY3Rpb24pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlBBR0VfQlk6XG4gICAgICAgIGFyZ3MucHVzaChkaXJlY3Rpb24sIGxpbWl0KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX09ORV9CWTpcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihgVW5zdXBwb3J0ZWQgbWV0aG9kICR7bWV0aG9kfWApO1xuICAgIH1cblxuICAgIHJldHVybiBzcXVhc2hlZDtcbiAgfVxuXG4gIHByb3RlY3RlZCBvdmVycmlkZSBhc3luYyBleGVjdXRlUHJlcGFyZWQoXG4gICAgLi4uYXJnejogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBQcm9taXNlPFI+IHtcbiAgICBjb25zdCByZXBvID0gUmVwb3NpdG9yeS5mb3JNb2RlbCh0aGlzLmZyb21TZWxlY3RvciwgdGhpcy5hZGFwdGVyLmFsaWFzKTtcbiAgICBjb25zdCB7IG1ldGhvZCwgYXJncyB9ID0gdGhpcy5wcmVwYXJlZCBhcyBQcmVwYXJlZFN0YXRlbWVudDxhbnk+O1xuICAgIHJldHVybiByZXBvLnN0YXRlbWVudChtZXRob2QsIC4uLmFyZ3MsIC4uLmFyZ3opO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgcHJlcGFyZShcbiAgICBjdHg/OiBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPlxuICApOiBQcm9taXNlPFN0YXRlbWVudEV4ZWN1dG9yPE0sIFI+PiB7XG4gICAgY3R4ID1cbiAgICAgIGN0eCB8fFxuICAgICAgKGF3YWl0IHRoaXMuYWRhcHRlci5jb250ZXh0KFxuICAgICAgICBQZXJzaXN0ZW5jZUtleXMuUVVFUlksXG4gICAgICAgIHRoaXMub3ZlcnJpZGVzIHx8IHt9LFxuICAgICAgICB0aGlzLmZyb21TZWxlY3RvclxuICAgICAgKSk7XG5cbiAgICBpZiAoXG4gICAgICB0aGlzLmlzU2ltcGxlUXVlcnkoKSAmJlxuICAgICAgKGN0eCBhcyBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPikuZ2V0KFwiZm9yY2VQcmVwYXJlU2ltcGxlUXVlcmllc1wiKVxuICAgICkge1xuICAgICAgY29uc3Qgc3F1YXNoZWQgPSB0aGlzLnNxdWFzaChjdHggYXMgQ29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4pO1xuICAgICAgaWYgKHNxdWFzaGVkKSB7XG4gICAgICAgIHRoaXMucHJlcGFyZWQgPSBzcXVhc2hlZDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGFyZ3M6IChzdHJpbmcgfCBudW1iZXIpW10gPSBbXTtcbiAgICBjb25zdCBwYXJhbXM6IGFueSA9IHt9IGFzIGFueTtcblxuICAgIGNvbnN0IHByZXBhcmVkOiBQcmVwYXJlZFN0YXRlbWVudDxhbnk+ID0ge1xuICAgICAgY2xhc3M6IHRoaXMuZnJvbVNlbGVjdG9yLFxuICAgICAgYXJncyxcbiAgICAgIHBhcmFtcyxcbiAgICB9IGFzIGFueTtcblxuICAgIGNvbnN0IG1ldGhvZDogc3RyaW5nW10gPSBbUXVlcnlDbGF1c2UuRklORF9CWV07XG5cbiAgICBpZiAodGhpcy53aGVyZUNvbmRpdGlvbikge1xuICAgICAgY29uc3QgcGFyc2VkID0gdGhpcy5wcmVwYXJlQ29uZGl0aW9uKHRoaXMud2hlcmVDb25kaXRpb24sIGN0eCBhcyBuZXZlcik7XG4gICAgICBtZXRob2QucHVzaChwYXJzZWQubWV0aG9kKTtcbiAgICAgIGlmIChwYXJzZWQuYXJncyAmJiBwYXJzZWQuYXJncy5sZW5ndGgpXG4gICAgICAgIGFyZ3MucHVzaCguLi4ocGFyc2VkLmFyZ3MgYXMgKHN0cmluZyB8IG51bWJlcilbXSkpO1xuICAgIH1cbiAgICBpZiAodGhpcy5zZWxlY3RTZWxlY3RvcilcbiAgICAgIG1ldGhvZC5wdXNoKFxuICAgICAgICBRdWVyeUNsYXVzZS5TRUxFQ1QsXG4gICAgICAgIHRoaXMuc2VsZWN0U2VsZWN0b3Iuam9pbihgICR7UXVlcnlDbGF1c2UuQU5ELnRvTG93ZXJDYXNlKCl9IGApXG4gICAgICApO1xuICAgIGlmICh0aGlzLm9yZGVyQnlTZWxlY3Rvcikge1xuICAgICAgbWV0aG9kLnB1c2goUXVlcnlDbGF1c2UuT1JERVJfQlksIHRoaXMub3JkZXJCeVNlbGVjdG9yWzBdIGFzIHN0cmluZyk7XG4gICAgICBhcmdzLnB1c2godGhpcy5vcmRlckJ5U2VsZWN0b3JbMV0pO1xuICAgIH1cbiAgICAvLyBpZiAodGhpcy5ncm91cEJ5U2VsZWN0b3IpXG4gICAgLy8gICBtZXRob2QucHVzaChRdWVyeUNsYXVzZS5HUk9VUF9CWSwgdGhpcy5ncm91cEJ5U2VsZWN0b3IgYXMgc3RyaW5nKTtcbiAgICAvLyBpZiAodGhpcy5saW1pdFNlbGVjdG9yKSBwYXJhbXMubGltaXQgPSB0aGlzLmxpbWl0U2VsZWN0b3I7XG4gICAgLy8gaWYgKHRoaXMub2Zmc2V0U2VsZWN0b3IpIHtcbiAgICAvLyAgIHBhcmFtcy5za2lwID0gdGhpcy5vZmZzZXRTZWxlY3RvcjtcbiAgICAvLyB9XG4gICAgcHJlcGFyZWQubWV0aG9kID0gdG9DYW1lbENhc2UobWV0aG9kLmpvaW4oXCIgXCIpKTtcbiAgICBwcmVwYXJlZC5wYXJhbXMgPSBwYXJhbXM7XG4gICAgdGhpcy5wcmVwYXJlZCA9IHByZXBhcmVkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGJ1aWxkKCk6IE1hbmdvUXVlcnkge1xuICAgIHRocm93IG5ldyBVbnN1cHBvcnRlZEVycm9yKFxuICAgICAgYFRoaXMgbWV0aG9kIGlzIG9ubHkgY2FsbGVkIGlzIHByZXBhcmVkIHN0YXRlbWVudHMgYXJlIG5vdCB1c2VkLiBJZiBzbywgYSBkZWRpY2F0ZWQgaW1wbGVtZW50YXRpb24gZm9yIHRoZSBuYXRpdmUgcXVlcmllcyB1c2VkIGlzIHJlcXVpcmVkYFxuICAgICk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgcGFyc2VDb25kaXRpb24oXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIGNvbmRpdGlvbjogQ29uZGl0aW9uPE0+LFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBNYW5nb1F1ZXJ5IHtcbiAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgIGBUaGlzIG1ldGhvZCBpcyBvbmx5IGNhbGxlZCBpcyBwcmVwYXJlZCBzdGF0ZW1lbnRzIGFyZSBub3QgdXNlZC4gSXMgc28sIGEgZGVkaWNhdGVkIGltcGxlbWVudGF0aW9uIGZvciB0aGUgbmF0aXZlIHF1ZXJpZXMgdXNlZCBpcyByZXF1aXJlZGBcbiAgICApO1xuICB9XG59XG4iLCJpbXBvcnQge1xuICBNYXliZUNvbnRleHR1YWxBcmcsXG4gIFBhZ2luYXRvcixcbiAgUHJlcGFyZWRTdGF0ZW1lbnQsXG4gIFVuc3VwcG9ydGVkRXJyb3IsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljQ2xpZW50QWRhcHRlciB9IGZyb20gXCIuL0ZhYnJpY0NsaWVudEFkYXB0ZXJcIjtcbmltcG9ydCB7IE1hbmdvUXVlcnkgfSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1jb3VjaGRiXCI7XG5cbmV4cG9ydCBjbGFzcyBGYWJyaWNDbGllbnRQYWdpbmF0b3I8TSBleHRlbmRzIE1vZGVsPiBleHRlbmRzIFBhZ2luYXRvcjxcbiAgTSxcbiAgTVtdLFxuICBNYW5nb1F1ZXJ5XG4+IHtcbiAgYm9va21hcms/OiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgYWRhcHRlcjogRmFicmljQ2xpZW50QWRhcHRlcixcbiAgICBxdWVyeTogTWFuZ29RdWVyeSB8IFByZXBhcmVkU3RhdGVtZW50PGFueT4sXG4gICAgc2l6ZTogbnVtYmVyLFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPlxuICApIHtcbiAgICBzdXBlcihhZGFwdGVyLCBxdWVyeSwgc2l6ZSwgY2xhenopO1xuICB9XG5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICBwcm90ZWN0ZWQgcHJlcGFyZShyYXdTdGF0ZW1lbnQ6IE1hbmdvUXVlcnkpOiBNYW5nb1F1ZXJ5IHtcbiAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgIGBSYXcgcXVlcnkgYWNjZXNzIG11c3QgYmUgaW1wbGVtZW50ZWQgYnkgYSBzdWJjbGFzcy4gb25seSBwcmVwYXJlZCBzdGF0ZW1lbnRzIGFyZSBuYXRpdmVseSBhdmFpbGFibGVgXG4gICAgKTtcbiAgfVxuXG4gIG92ZXJyaWRlIHBhZ2UoXG4gICAgcGFnZTogbnVtYmVyID0gMSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPE1bXT4ge1xuICAgIHJldHVybiBzdXBlci5wYWdlKHBhZ2UsIC4uLmFyZ3MpOyAvLyB0aGlzIHdpbGwgZmFpbCBmb3Igbm9uLXByZXBhcmVkIHN0YXRlbWVudHNcbiAgfVxufVxuIiwiaW1wb3J0IFwiLi4vc2hhcmVkL292ZXJyaWRlc1wiO1xuaW1wb3J0IHsgQ291Y2hEQktleXMsIHR5cGUgTWFuZ29RdWVyeSB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLWNvdWNoZGJcIjtcbmltcG9ydCB7IENsaWVudCB9IGZyb20gXCJAZ3JwYy9ncnBjLWpzXCI7XG5pbXBvcnQgKiBhcyBncnBjIGZyb20gXCJAZ3JwYy9ncnBjLWpzXCI7XG5pbXBvcnQge1xuICBNb2RlbCxcbiAgdHlwZSBNb2RlbENvbnN0cnVjdG9yLFxuICB0eXBlIFNlcmlhbGl6ZXIsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IGRlYnVnLCBmaW5hbCwgTG9nZ2luZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgdHlwZSBQZWVyQ29uZmlnLCB0eXBlIFNlZ3JlZ2F0ZWRNb2RlbCB9IGZyb20gXCIuLi9zaGFyZWQvdHlwZXNcIjtcbmltcG9ydCB7XG4gIGNvbm5lY3QsXG4gIHR5cGUgQ29ubmVjdE9wdGlvbnMsXG4gIEdhdGV3YXksXG4gIE5ldHdvcmssXG4gIFByb3Bvc2FsT3B0aW9ucyxcbiAgQ29udHJhY3QgYXMgQ29udHJha3QsXG4gIHR5cGUgU2lnbmVyLFxufSBmcm9tIFwiQGh5cGVybGVkZ2VyL2ZhYnJpYy1nYXRld2F5XCI7XG5pbXBvcnQgeyBnZXRJZGVudGl0eSwgZ2V0U2lnbmVyIH0gZnJvbSBcIi4vZmFicmljLWZzXCI7XG5pbXBvcnQge1xuICBCYXNlRXJyb3IsXG4gIEludGVybmFsRXJyb3IsXG4gIE9wZXJhdGlvbktleXMsXG4gIFNlcmlhbGl6YXRpb25FcnJvcixcbiAgQnVsa0NydWRPcGVyYXRpb25LZXlzLFxuICBOb3RGb3VuZEVycm9yLFxuICBDb25mbGljdEVycm9yLFxuICBCYWRSZXF1ZXN0RXJyb3IsXG4gIHR5cGUgUHJpbWFyeUtleVR5cGUsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHtcbiAgQ29udGV4dCxcbiAgQWRhcHRlcixcbiAgdHlwZSBBZGFwdGVyRmxhZ3MsXG4gIEF1dGhvcml6YXRpb25FcnJvcixcbiAgQ29ubmVjdGlvbkVycm9yLFxuICBGb3JiaWRkZW5FcnJvcixcbiAgTWlncmF0aW9uRXJyb3IsXG4gIE9ic2VydmVyRXJyb3IsXG4gIFBhZ2luZ0Vycm9yLFxuICBQZXJzaXN0ZW5jZUtleXMsXG4gIFF1ZXJ5RXJyb3IsXG4gIFJlcG9zaXRvcnksXG4gIFVuc3VwcG9ydGVkRXJyb3IsXG4gIFN0YXRlbWVudCxcbiAgdHlwZSBQcmVwYXJlZFN0YXRlbWVudCxcbiAgUGFnaW5hdG9yLFxuICBNYXliZUNvbnRleHR1YWxBcmcsXG4gIENvbnRleHR1YWxBcmdzLFxuICB0eXBlIFByZXBhcmVkTW9kZWwsXG4gIEFsbE9wZXJhdGlvbktleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgRmFicmljRmxhdm91ciB9IGZyb20gXCIuLi9zaGFyZWQvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBDbGllbnRTZXJpYWxpemVyIH0gZnJvbSBcIi4uL3NoYXJlZC9DbGllbnRTZXJpYWxpemVyXCI7XG5pbXBvcnQgeyBGYWJyaWNDbGllbnREaXNwYXRjaCB9IGZyb20gXCIuL0ZhYnJpY0NsaWVudERpc3BhdGNoXCI7XG5pbXBvcnQgeyBIU01TaWduZXJGYWN0b3J5Q3VzdG9tIH0gZnJvbSBcIi4vZmFicmljLWhzbVwiO1xuaW1wb3J0IHsgdHlwZSBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljQ2xpZW50U3RhdGVtZW50IH0gZnJvbSBcIi4vRmFicmljQ2xpZW50U3RhdGVtZW50XCI7XG5pbXBvcnQgeyBGYWJyaWNDbGllbnRQYWdpbmF0b3IgfSBmcm9tIFwiLi9GYWJyaWNDbGllbnRQYWdpbmF0b3JcIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudFJlcG9zaXRvcnkgfSBmcm9tIFwiLi9GYWJyaWNDbGllbnRSZXBvc2l0b3J5XCI7XG5pbXBvcnQge1xuICBFbmRvcnNlbWVudEVycm9yLFxuICBFbmRvcnNlbWVudFBvbGljeUVycm9yLFxuICBNdmNjUmVhZENvbmZsaWN0RXJyb3IsXG4gIFBoYW50b21SZWFkQ29uZmxpY3RFcnJvcixcbn0gZnJvbSBcIi4uL3NoYXJlZC9lcnJvcnNcIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudEZsYWdzIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IERlZmF1bHRGYWJyaWNDbGllbnRGbGFncyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBBZGFwdGVyIGZvciBpbnRlcmFjdGluZyB3aXRoIEh5cGVybGVkZ2VyIEZhYnJpYyBuZXR3b3Jrc1xuICogQHN1bW1hcnkgVGhlIEZhYnJpY0FkYXB0ZXIgZXh0ZW5kcyBDb3VjaERCQWRhcHRlciB0byBwcm92aWRlIGEgc2VhbWxlc3MgaW50ZXJmYWNlIGZvciBpbnRlcmFjdGluZyB3aXRoIEh5cGVybGVkZ2VyIEZhYnJpYyBuZXR3b3Jrcy5cbiAqIEl0IGhhbmRsZXMgY29ubmVjdGlvbiBtYW5hZ2VtZW50LCB0cmFuc2FjdGlvbiBzdWJtaXNzaW9uLCBhbmQgQ1JVRCBvcGVyYXRpb25zIGFnYWluc3QgRmFicmljIGNoYWluY29kZS5cbiAqIEB0ZW1wbGF0ZSBQZWVyQ29uZmlnIC0gQ29uZmlndXJhdGlvbiB0eXBlIGZvciBjb25uZWN0aW5nIHRvIGEgRmFicmljIHBlZXJcbiAqIEB0ZW1wbGF0ZSBGYWJyaWNGbGFncyAtIEZsYWdzIHNwZWNpZmljIHRvIEZhYnJpYyBvcGVyYXRpb25zXG4gKiBAdGVtcGxhdGUgQ29udGV4dDxGYWJyaWNGbGFncz4gLSBDb250ZXh0IHR5cGUgY29udGFpbmluZyBGYWJyaWMtc3BlY2lmaWMgZmxhZ3NcbiAqIEBwYXJhbSBjb25maWcgLSBDb25maWd1cmF0aW9uIGZvciBjb25uZWN0aW5nIHRvIGEgRmFicmljIHBlZXJcbiAqIEBwYXJhbSBhbGlhcyAtIE9wdGlvbmFsIGFsaWFzIGZvciB0aGUgYWRhcHRlciBpbnN0YW5jZVxuICogQGNsYXNzIEZhYnJpY0NsaWVudEFkYXB0ZXJcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBDcmVhdGUgYSBuZXcgRmFicmljQWRhcHRlciBpbnN0YW5jZVxuICogY29uc3QgY29uZmlnOiBQZWVyQ29uZmlnID0ge1xuICogICBtc3BJZDogJ09yZzFNU1AnLFxuICogICBwZWVyRW5kcG9pbnQ6ICdsb2NhbGhvc3Q6NzA1MScsXG4gKiAgIGNoYW5uZWxOYW1lOiAnbXljaGFubmVsJyxcbiAqICAgY2hhaW5jb2RlTmFtZTogJ215Y2MnLFxuICogICBjb250cmFjdE5hbWU6ICdteWNvbnRyYWN0JyxcbiAqICAgdGxzQ2VydFBhdGg6ICcvcGF0aC90by90bHMvY2VydCcsXG4gKiAgIGNlcnREaXJlY3RvcnlQYXRoOiAnL3BhdGgvdG8vY2VydC9kaXInLFxuICogICBrZXlEaXJlY3RvcnlQYXRoOiAnL3BhdGgvdG8va2V5L2RpcidcbiAqIH07XG4gKlxuICogY29uc3QgYWRhcHRlciA9IG5ldyBGYWJyaWNBZGFwdGVyKGNvbmZpZywgJ29yZzEtYWRhcHRlcicpO1xuICpcbiAqIC8vIFVzZSB0aGUgYWRhcHRlciB0byBpbnRlcmFjdCB3aXRoIHRoZSBGYWJyaWMgbmV0d29ya1xuICogY29uc3QgcmVzdWx0ID0gYXdhaXQgYWRhcHRlci5yZWFkKCd1c2VycycsICd1c2VyMScsIG15U2VyaWFsaXplcik7XG4gKiBgYGBcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2xpZW50XG4gKiAgIHBhcnRpY2lwYW50IEZhYnJpY0FkYXB0ZXJcbiAqICAgcGFydGljaXBhbnQgR2F0ZXdheVxuICogICBwYXJ0aWNpcGFudCBOZXR3b3JrXG4gKiAgIHBhcnRpY2lwYW50IENvbnRyYWN0XG4gKiAgIHBhcnRpY2lwYW50IENoYWluY29kZVxuICpcbiAqICAgQ2xpZW50LT4+RmFicmljQWRhcHRlcjogY3JlYXRlKHRhYmxlTmFtZSwgaWQsIG1vZGVsLCB0cmFuc2llbnQsIHNlcmlhbGl6ZXIpXG4gKiAgIEZhYnJpY0FkYXB0ZXItPj5GYWJyaWNBZGFwdGVyOiBzdWJtaXRUcmFuc2FjdGlvbihPcGVyYXRpb25LZXlzLkNSRUFURSwgW3NlcmlhbGl6ZWRNb2RlbF0sIHRyYW5zaWVudClcbiAqICAgRmFicmljQWRhcHRlci0+PkdhdGV3YXk6IGNvbm5lY3QoKVxuICogICBHYXRld2F5LT4+TmV0d29yazogZ2V0TmV0d29yayhjaGFubmVsTmFtZSlcbiAqICAgTmV0d29yay0+PkNvbnRyYWN0OiBnZXRDb250cmFjdChjaGFpbmNvZGVOYW1lLCBjb250cmFjdE5hbWUpXG4gKiAgIEZhYnJpY0FkYXB0ZXItPj5Db250cmFjdDogc3VibWl0KGFwaSwgcHJvcG9zYWxPcHRpb25zKVxuICogICBDb250cmFjdC0+PkNoYWluY29kZTogaW52b2tlXG4gKiAgIENoYWluY29kZS0tPj5Db250cmFjdDogcmVzcG9uc2VcbiAqICAgQ29udHJhY3QtLT4+RmFicmljQWRhcHRlcjogcmVzdWx0XG4gKiAgIEZhYnJpY0FkYXB0ZXItPj5GYWJyaWNBZGFwdGVyOiBkZWNvZGUocmVzdWx0KVxuICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogc2VyaWFsaXplci5kZXNlcmlhbGl6ZShkZWNvZGVkUmVzdWx0KVxuICogICBGYWJyaWNBZGFwdGVyLS0+PkNsaWVudDogZGVzZXJpYWxpemVkUmVzdWx0XG4gKi9cbmV4cG9ydCBjbGFzcyBGYWJyaWNDbGllbnRBZGFwdGVyIGV4dGVuZHMgQWRhcHRlcjxcbiAgUGVlckNvbmZpZyxcbiAgQ2xpZW50LFxuICBNYW5nb1F1ZXJ5LFxuICBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPlxuPiB7XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU3RhdGljIHRleHQgZGVjb2RlciBmb3IgY29udmVydGluZyBVaW50OEFycmF5IHRvIHN0cmluZ1xuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlcihcInV0ZjhcIik7XG5cbiAgcHJpdmF0ZSBzdGF0aWMgc2VyaWFsaXplciA9IG5ldyBDbGllbnRTZXJpYWxpemVyKCk7XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBsb2cgPSBMb2dnaW5nLmZvcihGYWJyaWNDbGllbnRBZGFwdGVyKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2VyaWFsaXplcjogU2VyaWFsaXplcjxhbnk+ID1cbiAgICBGYWJyaWNDbGllbnRBZGFwdGVyLnNlcmlhbGl6ZXI7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbmV3IEZhYnJpY0FkYXB0ZXIgaW5zdGFuY2VcbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYSBuZXcgYWRhcHRlciBmb3IgaW50ZXJhY3Rpbmcgd2l0aCBhIEh5cGVybGVkZ2VyIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBwYXJhbSB7UGVlckNvbmZpZ30gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBmb3IgY29ubmVjdGluZyB0byBhIEZhYnJpYyBwZWVyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYWxpYXNdIC0gT3B0aW9uYWwgYWxpYXMgZm9yIHRoZSBhZGFwdGVyIGluc3RhbmNlXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihjb25maWc6IFBlZXJDb25maWcsIGFsaWFzPzogc3RyaW5nKSB7XG4gICAgc3VwZXIoY29uZmlnLCBGYWJyaWNGbGF2b3VyLCBhbGlhcyk7XG4gIH1cblxuICBvdmVycmlkZSBTdGF0ZW1lbnQ8TSBleHRlbmRzIE1vZGVsPihcbiAgICBvdmVycmlkZXM/OiBQYXJ0aWFsPEFkYXB0ZXJGbGFncz5cbiAgKTogU3RhdGVtZW50PE0sIEZhYnJpY0NsaWVudEFkYXB0ZXIsIGFueSwgTWFuZ29RdWVyeT4ge1xuICAgIHJldHVybiBuZXcgRmFicmljQ2xpZW50U3RhdGVtZW50KHRoaXMsIG92ZXJyaWRlcyk7XG4gIH1cblxuICBQYWdpbmF0b3I8TSBleHRlbmRzIE1vZGVsPihcbiAgICBxdWVyeTogUHJlcGFyZWRTdGF0ZW1lbnQ8YW55PiB8IE1hbmdvUXVlcnksXG4gICAgc2l6ZTogbnVtYmVyLFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPlxuICApOiBQYWdpbmF0b3I8TSwgYW55LCBNYW5nb1F1ZXJ5PiB7XG4gICAgcmV0dXJuIG5ldyBGYWJyaWNDbGllbnRQYWdpbmF0b3IodGhpcywgcXVlcnksIHNpemUsIGNsYXp6KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvdmVycmlkZSBmbGFnczxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIG9wZXJhdGlvbjogT3BlcmF0aW9uS2V5cyB8IHN0cmluZyxcbiAgICBtb2RlbDogQ29uc3RydWN0b3I8TT4gfCBDb25zdHJ1Y3RvcjxNPltdIHwgdW5kZWZpbmVkLFxuICAgIGZsYWdzOiBQYXJ0aWFsPEZhYnJpY0NsaWVudEZsYWdzPixcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPEZhYnJpY0NsaWVudEZsYWdzPiB7XG4gICAgcmV0dXJuIHN1cGVyLmZsYWdzKG9wZXJhdGlvbiwgbW9kZWwsIGZsYWdzLCAuLi5hcmdzKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGNvbnRleHQ8TSBleHRlbmRzIE1vZGVsPihcbiAgICBvcGVyYXRpb246ICgoLi4uYXJnczogYW55W10pID0+IGFueSkgfCBBbGxPcGVyYXRpb25LZXlzLFxuICAgIG92ZXJyaWRlczogUGFydGlhbDxGYWJyaWNDbGllbnRGbGFncz4sXG4gICAgbW9kZWw6IENvbnN0cnVjdG9yPE0+IHwgQ29uc3RydWN0b3I8TT5bXSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dDxhbnk+PlxuICApOiBQcm9taXNlPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PiB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuY29udGV4dCk7XG4gICAgbG9nLnNpbGx5KFxuICAgICAgYGNyZWF0aW5nIG5ldyBjb250ZXh0IGZvciAke29wZXJhdGlvbn0gb3BlcmF0aW9uIG9uICR7bW9kZWwgPyAoQXJyYXkuaXNBcnJheShtb2RlbCkgPyBtb2RlbC5tYXAoKG0pID0+IE1vZGVsLnRhYmxlTmFtZShtKSkgOiBNb2RlbC50YWJsZU5hbWUobW9kZWwpKSA6IFwibm9cIn0gdGFibGUgJHtvdmVycmlkZXMgJiYgT2JqZWN0LmtleXMob3ZlcnJpZGVzKSA/IE9iamVjdC5rZXlzKG92ZXJyaWRlcykubGVuZ3RoIDogXCJub1wifSB3aXRoIGZsYWcgb3ZlcnJpZGVzYFxuICAgICk7XG4gICAgbGV0IGN0eCA9IGFyZ3MucG9wKCk7XG4gICAgaWYgKHR5cGVvZiBjdHggIT09IFwidW5kZWZpbmVkXCIgJiYgIShjdHggaW5zdGFuY2VvZiBDb250ZXh0KSkge1xuICAgICAgYXJncy5wdXNoKGN0eCk7XG4gICAgICBjdHggPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgb3ZlcnJpZGVzID0gY3R4XG4gICAgICA/IE9iamVjdC5hc3NpZ24oe30sIG92ZXJyaWRlcywgY3R4LnRvT3ZlcnJpZGVzKCkpXG4gICAgICA6IG92ZXJyaWRlcztcbiAgICBjb25zdCBmbGFncyA9IGF3YWl0IHRoaXMuZmxhZ3MoXG4gICAgICB0eXBlb2Ygb3BlcmF0aW9uID09PSBcInN0cmluZ1wiID8gb3BlcmF0aW9uIDogb3BlcmF0aW9uLm5hbWUsXG4gICAgICBtb2RlbCxcbiAgICAgIG92ZXJyaWRlcyBhcyBQYXJ0aWFsPEZhYnJpY0NsaWVudEZsYWdzPixcbiAgICAgIC4uLmFyZ3MsXG4gICAgICBjdHhcbiAgICApO1xuXG4gICAgaWYgKGN0eCkge1xuICAgICAgaWYgKCEoY3R4IGluc3RhbmNlb2YgdGhpcy5Db250ZXh0KSkge1xuICAgICAgICByZXR1cm4gbmV3IHRoaXMuQ29udGV4dCgpLmFjY3VtdWxhdGUoe1xuICAgICAgICAgIC4uLmN0eFtcImNhY2hlXCJdLFxuICAgICAgICAgIC4uLmZsYWdzLFxuICAgICAgICAgIHBhcmVudENvbnRleHQ6IGN0eCxcbiAgICAgICAgfSkgYXMgYW55O1xuICAgICAgfVxuICAgICAgY29uc3QgY3VycmVudE9wID0gY3R4LmdldChcIm9wZXJhdGlvblwiKTtcbiAgICAgIGNvbnN0IGN1cnJlbnRNb2RlbCA9IGN0eC5nZXQoXCJhZmZlY3RlZFRhYmxlc1wiKTtcbiAgICAgIGlmIChjdXJyZW50T3AgIT09IG9wZXJhdGlvbiB8fCBtb2RlbCAhPT0gY3VycmVudE1vZGVsKVxuICAgICAgICByZXR1cm4gbmV3IHRoaXMuQ29udGV4dCgpLmFjY3VtdWxhdGUoe1xuICAgICAgICAgIC4uLmN0eFtcImNhY2hlXCJdLFxuICAgICAgICAgIC4uLmZsYWdzLFxuICAgICAgICAgIHBhcmVudENvbnRleHQ6IGN0eCxcbiAgICAgICAgfSkgYXMgYW55O1xuICAgICAgcmV0dXJuIGN0eC5hY2N1bXVsYXRlKGZsYWdzKSBhcyBhbnk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyB0aGlzLkNvbnRleHQoKS5hY2N1bXVsYXRlKHtcbiAgICAgIC4uLkRlZmF1bHRGYWJyaWNDbGllbnRGbGFncyxcbiAgICAgIC4uLmZsYWdzLFxuICAgIH0pIGFzIGFueTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVjb2RlcyBhIFVpbnQ4QXJyYXkgdG8gYSBzdHJpbmdcbiAgICogQHN1bW1hcnkgQ29udmVydHMgYmluYXJ5IGRhdGEgcmVjZWl2ZWQgZnJvbSBGYWJyaWMgdG8gYSBzdHJpbmcgdXNpbmcgVVRGLTggZW5jb2RpbmdcbiAgICogQHBhcmFtIHtVaW50OEFycmF5fSBkYXRhIC0gVGhlIGJpbmFyeSBkYXRhIHRvIGRlY29kZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBkZWNvZGVkIHN0cmluZ1xuICAgKi9cbiAgZGVjb2RlKGRhdGE6IFVpbnQ4QXJyYXkpOiBzdHJpbmcge1xuICAgIHJldHVybiBGYWJyaWNDbGllbnRBZGFwdGVyLmRlY29kZXIuZGVjb2RlKGRhdGEpO1xuICB9XG5cbiAgb3ZlcnJpZGUgcmVwb3NpdG9yeTxcbiAgICBSIGV4dGVuZHMgUmVwb3NpdG9yeTxcbiAgICAgIGFueSxcbiAgICAgIEFkYXB0ZXI8UGVlckNvbmZpZywgQ2xpZW50LCBNYW5nb1F1ZXJ5LCBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj5cbiAgICA+LFxuICA+KCk6IENvbnN0cnVjdG9yPFI+IHtcbiAgICByZXR1cm4gRmFicmljQ2xpZW50UmVwb3NpdG9yeSBhcyB1bmtub3duIGFzIENvbnN0cnVjdG9yPFI+O1xuICB9XG5cbiAgcHJvdGVjdGVkIGNyZWF0ZVByZWZpeDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBbQ29uc3RydWN0b3I8TT4sIFByaW1hcnlLZXlUeXBlLCBSZWNvcmQ8c3RyaW5nLCBhbnk+LCAuLi5hbnlbXSwgQ29udGV4dF0ge1xuICAgIGNvbnN0IHsgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5jcmVhdGVQcmVmaXgpO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IHRhYmxlTmFtZTtcbiAgICBPYmplY3QuYXNzaWduKHJlY29yZCwgbW9kZWwpO1xuICAgIHJldHVybiBbY2xhenosIGlkLCByZWNvcmQsIC4uLmN0eEFyZ3NdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcmVwYXJlcyBtdWx0aXBsZSByZWNvcmRzIGZvciBjcmVhdGlvblxuICAgKiBAc3VtbWFyeSBBZGRzIG5lY2Vzc2FyeSBDb3VjaERCIGZpZWxkcyB0byBtdWx0aXBsZSByZWNvcmRzIGJlZm9yZSBjcmVhdGlvblxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlXG4gICAqIEBwYXJhbSB7c3RyaW5nW118bnVtYmVyW119IGlkcyAtIFRoZSBJRHMgb2YgdGhlIHJlY29yZHNcbiAgICogQHBhcmFtIG1vZGVscyAtIFRoZSBtb2RlbHMgdG8gcHJlcGFyZVxuICAgKiBAcmV0dXJuIEEgdHVwbGUgY29udGFpbmluZyB0aGUgdGFibGVOYW1lLCBpZHMsIGFuZCBwcmVwYXJlZCByZWNvcmRzXG4gICAqIEB0aHJvd3Mge0ludGVybmFsRXJyb3J9IElmIGlkcyBhbmQgbW9kZWxzIGFycmF5cyBoYXZlIGRpZmZlcmVudCBsZW5ndGhzXG4gICAqL1xuICBwcm90ZWN0ZWQgY3JlYXRlQWxsUHJlZml4PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkczogc3RyaW5nW10gfCBudW1iZXJbXSxcbiAgICBtb2RlbHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICkge1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgaWYgKGlkcy5sZW5ndGggIT09IG1vZGVscy5sZW5ndGgpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIklkcyBhbmQgbW9kZWxzIG11c3QgaGF2ZSB0aGUgc2FtZSBsZW5ndGhcIik7XG4gICAgY29uc3QgeyBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLmNyZWF0ZUFsbFByZWZpeCk7XG4gICAgY29uc3QgcmVjb3JkcyA9IGlkcy5tYXAoKGlkLCBjb3VudCkgPT4ge1xuICAgICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgICByZWNvcmRbQ291Y2hEQktleXMuVEFCTEVdID0gdGFibGVOYW1lO1xuICAgICAgT2JqZWN0LmFzc2lnbihyZWNvcmQsIG1vZGVsc1tjb3VudF0pO1xuICAgICAgcmV0dXJuIHJlY29yZDtcbiAgICB9KTtcbiAgICByZXR1cm4gW2NsYXp6LCBpZHMsIHJlY29yZHMsIC4uLmN0eEFyZ3NdO1xuICB9XG5cbiAgcHJvdGVjdGVkIHVwZGF0ZUFsbFByZWZpeDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZHM6IFByaW1hcnlLZXlUeXBlW10sXG4gICAgbW9kZWxzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+W10sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApIHtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIGlmIChpZHMubGVuZ3RoICE9PSBtb2RlbHMubGVuZ3RoKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJJZHMgYW5kIG1vZGVscyBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoXCIpO1xuICAgIGNvbnN0IHsgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy51cGRhdGVBbGxQcmVmaXgpO1xuICAgIGNvbnN0IHJlY29yZHMgPSBpZHMubWFwKCgpID0+IHtcbiAgICAgIGNvbnN0IHJlY29yZDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IHRhYmxlTmFtZTtcbiAgICAgIHJldHVybiByZWNvcmQ7XG4gICAgfSk7XG4gICAgcmV0dXJuIFtjbGF6eiwgaWRzLCByZWNvcmRzLCAuLi5jdHhBcmdzXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBtdWx0aXBsZSByZWNvcmRzIGluIGEgc2luZ2xlIHRyYW5zYWN0aW9uXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgYSB0cmFuc2FjdGlvbiB0byBjcmVhdGUgbXVsdGlwbGUgcmVjb3JkcyBpbiB0aGUgRmFicmljIGxlZGdlclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlL2NvbGxlY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmdbXSB8IG51bWJlcltdfSBpZHMgLSBBcnJheSBvZiByZWNvcmQgaWRlbnRpZmllcnNcbiAgICogQHBhcmFtIHtBcnJheTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pn0gbW9kZWxzIC0gQXJyYXkgb2YgcmVjb3JkIGRhdGFcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSB0cmFuc2llbnQgLSBUcmFuc2llbnQgZGF0YSBmb3IgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8QXJyYXk8UmVjb3JkPHN0cmluZywgYW55Pj4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgY3JlYXRlZCByZWNvcmRzXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyBjcmVhdGVBbGw8TSBleHRlbmRzIE1vZGVsPihcbiAgICBjbGF6ejogQ29uc3RydWN0b3I8TT4sXG4gICAgaWRzOiBQcmltYXJ5S2V5VHlwZVtdLFxuICAgIG1vZGVsczogUmVjb3JkPHN0cmluZywgYW55PltdLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT5bXT4ge1xuICAgIGlmIChpZHMubGVuZ3RoICE9PSBtb2RlbHMubGVuZ3RoKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJJZHMgYW5kIG1vZGVscyBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoXCIpO1xuICAgIC8vSEVSRSFcbiAgICBjb25zdCBjdHhBcmdzID0gWy4uLihhcmdzIGFzIHVua25vd24gYXMgYW55W10pXTtcbiAgICBjb25zdCB0cmFuc2llbnQgPSBjdHhBcmdzLnNoaWZ0KCkgYXMgUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSB0aGlzLmxvZ0N0eChcbiAgICAgIGN0eEFyZ3MgYXMgQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+LFxuICAgICAgdGhpcy5jcmVhdGVBbGxcbiAgICApO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG5cbiAgICBsb2cuaW5mbyhgYWRkaW5nICR7aWRzLmxlbmd0aH0gZW50cmllcyB0byAke3RhYmxlTmFtZX0gdGFibGVgKTtcbiAgICBsb2cudmVyYm9zZShgcGtzOiAke2lkc31gKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnN1Ym1pdFRyYW5zYWN0aW9uKFxuICAgICAgY3R4LFxuICAgICAgQnVsa0NydWRPcGVyYXRpb25LZXlzLkNSRUFURV9BTEwsXG4gICAgICBbXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KFxuICAgICAgICAgIG1vZGVscy5tYXAoKG0pID0+IHRoaXMuc2VyaWFsaXplci5zZXJpYWxpemUobSwgY2xhenoubmFtZSkpXG4gICAgICAgICksXG4gICAgICBdLFxuICAgICAgdHJhbnNpZW50LFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgY2xhenoubmFtZVxuICAgICk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBKU09OLnBhcnNlKHRoaXMuZGVjb2RlKHJlc3VsdCkpLm1hcCgocjogYW55KSA9PiBKU09OLnBhcnNlKHIpKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgU2VyaWFsaXphdGlvbkVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVhZHMgbXVsdGlwbGUgcmVjb3JkcyBpbiBhIHNpbmdsZSB0cmFuc2FjdGlvblxuICAgKiBAc3VtbWFyeSBTdWJtaXRzIGEgdHJhbnNhY3Rpb24gdG8gcmVhZCBtdWx0aXBsZSByZWNvcmRzIGZyb20gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nW10gfCBudW1iZXJbXX0gaWRzIC0gQXJyYXkgb2YgcmVjb3JkIGlkZW50aWZpZXJzIHRvIHJlYWRcbiAgICogQHJldHVybiB7UHJvbWlzZTxBcnJheTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSByZXRyaWV2ZWQgcmVjb3Jkc1xuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgcmVhZEFsbDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZHM6IFByaW1hcnlLZXlUeXBlW10sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55PltdPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5yZWFkQWxsKTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIGxvZy5pbmZvKGByZWFkaW5nICR7aWRzLmxlbmd0aH0gZW50cmllcyB0byAke3RhYmxlTmFtZX0gdGFibGVgKTtcbiAgICBsb2cudmVyYm9zZShgcGtzOiAke2lkc31gKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmV2YWx1YXRlVHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuUkVBRF9BTEwsXG4gICAgICBbSlNPTi5zdHJpbmdpZnkoaWRzKV0sXG4gICAgICB1bmRlZmluZWQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBjbGF6ei5uYW1lXG4gICAgKTtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEpTT04ucGFyc2UodGhpcy5kZWNvZGUocmVzdWx0KSkubWFwKChyOiBhbnkpID0+IEpTT04ucGFyc2UocikpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIG11bHRpcGxlIHJlY29yZHMgaW4gYSBzaW5nbGUgdHJhbnNhY3Rpb25cbiAgICogQHN1bW1hcnkgU3VibWl0cyBhIHRyYW5zYWN0aW9uIHRvIHVwZGF0ZSBtdWx0aXBsZSByZWNvcmRzIGluIHRoZSBGYWJyaWMgbGVkZ2VyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGFibGUvY29sbGVjdGlvblxuICAgKiBAcGFyYW0ge3N0cmluZ1tdIHwgbnVtYmVyW119IGlkcyAtIEFycmF5IG9mIHJlY29yZCBpZGVudGlmaWVyc1xuICAgKiBAcGFyYW0ge0FycmF5PFJlY29yZDxzdHJpbmcsIGFueT4+fSBtb2RlbHMgLSBBcnJheSBvZiB1cGRhdGVkIHJlY29yZCBkYXRhXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gdHJhbnNpZW50IC0gVHJhbnNpZW50IGRhdGEgZm9yIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPEFycmF5PFJlY29yZDxzdHJpbmcsIGFueT4+Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWQgcmVjb3Jkc1xuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgdXBkYXRlQWxsPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkczogUHJpbWFyeUtleVR5cGVbXSxcbiAgICBtb2RlbHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXSxcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj5cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+W10+IHtcbiAgICBpZiAoaWRzLmxlbmd0aCAhPT0gbW9kZWxzLmxlbmd0aClcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiSWRzIGFuZCBtb2RlbHMgbXVzdCBoYXZlIHRoZSBzYW1lIGxlbmd0aFwiKTtcbiAgICBjb25zdCBjdHhBcmdzID0gWy4uLihhcmdzIGFzIHVua25vd24gYXMgYW55W10pXTtcbiAgICBjb25zdCB0cmFuc2llbnQgPSBjdHhBcmdzLnNoaWZ0KCkgYXMgUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSB0aGlzLmxvZ0N0eChcbiAgICAgIGN0eEFyZ3MgYXMgQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+LFxuICAgICAgdGhpcy51cGRhdGVBbGxcbiAgICApO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgbG9nLmluZm8oYHVwZGF0aW5nICR7aWRzLmxlbmd0aH0gZW50cmllcyB0byAke3RhYmxlTmFtZX0gdGFibGVgKTtcbiAgICBsb2cudmVyYm9zZShgcGtzOiAke2lkc31gKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuc3VibWl0VHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuVVBEQVRFX0FMTCxcbiAgICAgIFtcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgbW9kZWxzLm1hcCgobSkgPT4gdGhpcy5zZXJpYWxpemVyLnNlcmlhbGl6ZShtLCBjbGF6ei5uYW1lKSlcbiAgICAgICAgKSxcbiAgICAgIF0sXG4gICAgICB0cmFuc2llbnQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBjbGF6ei5uYW1lXG4gICAgKTtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEpTT04ucGFyc2UodGhpcy5kZWNvZGUocmVzdWx0KSkubWFwKChyOiBhbnkpID0+IEpTT04ucGFyc2UocikpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBEZWxldGVzIG11bHRpcGxlIHJlY29yZHMgaW4gYSBzaW5nbGUgdHJhbnNhY3Rpb25cbiAgICogQHN1bW1hcnkgU3VibWl0cyBhIHRyYW5zYWN0aW9uIHRvIGRlbGV0ZSBtdWx0aXBsZSByZWNvcmRzIGZyb20gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50Pn0gaWRzIC0gQXJyYXkgb2YgcmVjb3JkIGlkZW50aWZpZXJzIHRvIGRlbGV0ZVxuICAgKiBAcGFyYW0ge1NlcmlhbGl6ZXI8YW55Pn0gc2VyaWFsaXplciAtIFNlcmlhbGl6ZXIgZm9yIHRoZSBtb2RlbCBkYXRhXG4gICAqIEByZXR1cm4ge1Byb21pc2U8QXJyYXk8UmVjb3JkPHN0cmluZywgYW55Pj4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZGVsZXRlZCByZWNvcmRzXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyBkZWxldGVBbGw8TSBleHRlbmRzIE1vZGVsPihcbiAgICBjbGF6ejogQ29uc3RydWN0b3I8TT4sXG4gICAgaWRzOiBQcmltYXJ5S2V5VHlwZVtdLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT5bXT4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuZGVsZXRlQWxsKTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIGxvZy5pbmZvKGBkZWxldGluZyAke2lkcy5sZW5ndGh9IGVudHJpZXMgdG8gJHt0YWJsZU5hbWV9IHRhYmxlYCk7XG4gICAgbG9nLnZlcmJvc2UoYHBrczogJHtpZHN9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cy5ERUxFVEVfQUxMLFxuICAgICAgW0pTT04uc3RyaW5naWZ5KGlkcyldLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgY2xhenoubmFtZVxuICAgICk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBKU09OLnBhcnNlKHRoaXMuZGVjb2RlKHJlc3VsdCkpLm1hcCgocjogYW55KSA9PiBKU09OLnBhcnNlKHIpKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgU2VyaWFsaXphdGlvbkVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJlcGFyZXMgYSBtb2RlbCBmb3IgcGVyc2lzdGVuY2VcbiAgICogQHN1bW1hcnkgQ29udmVydHMgYSBtb2RlbCBpbnN0YW5jZSBpbnRvIGEgZm9ybWF0IHN1aXRhYmxlIGZvciBkYXRhYmFzZSBzdG9yYWdlLFxuICAgKiBoYW5kbGluZyBjb2x1bW4gbWFwcGluZyBhbmQgc2VwYXJhdGluZyB0cmFuc2llbnQgcHJvcGVydGllc1xuICAgKiBAdGVtcGxhdGUgTSAtIFRoZSBtb2RlbCB0eXBlXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgdG8gcHJlcGFyZVxuICAgKiBAcGFyYW0gcGsgLSBUaGUgcHJpbWFyeSBrZXkgcHJvcGVydHkgbmFtZVxuICAgKiBAcmV0dXJuIFRoZSBwcmVwYXJlZCBkYXRhXG4gICAqL1xuICBvdmVycmlkZSBwcmVwYXJlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgbW9kZWw6IE0sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFNlZ3JlZ2F0ZWRNb2RlbDxNPiAmIFByZXBhcmVkTW9kZWwge1xuICAgIGNvbnN0IHsgbG9nIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnByZXBhcmUpO1xuICAgIGNvbnN0IHNwbGl0ID0gTW9kZWwuc2VncmVnYXRlKG1vZGVsKTtcbiAgICBpZiAoKG1vZGVsIGFzIGFueSlbUGVyc2lzdGVuY2VLZXlzLk1FVEFEQVRBXSkge1xuICAgICAgbG9nLnNpbGx5KFxuICAgICAgICBgUGFzc2luZyBhbG9uZyBwZXJzaXN0ZW5jZSBtZXRhZGF0YSBmb3IgJHsobW9kZWwgYXMgYW55KVtQZXJzaXN0ZW5jZUtleXMuTUVUQURBVEFdfWBcbiAgICAgICk7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoc3BsaXQubW9kZWwsIFBlcnNpc3RlbmNlS2V5cy5NRVRBREFUQSwge1xuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgIHZhbHVlOiAobW9kZWwgYXMgYW55KVtQZXJzaXN0ZW5jZUtleXMuTUVUQURBVEFdLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHJlY29yZDogc3BsaXQubW9kZWwsXG4gICAgICBtb2RlbDogc3BsaXQubW9kZWwsXG4gICAgICBpZDogbW9kZWxbTW9kZWwucGsobW9kZWwuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3I8TT4pXSBhcyBzdHJpbmcsXG4gICAgICB0cmFuc2llbnQ6IHNwbGl0LnRyYW5zaWVudCxcbiAgICAgIHByaXZhdGU6IHNwbGl0LnByaXZhdGUsXG4gICAgICBzaGFyZWQ6IHNwbGl0LnNoYXJlZCxcbiAgICB9O1xuICB9XG5cbiAgb3ZlcnJpZGUgcmV2ZXJ0PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgb2JqOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgdHJhbnNpZW50PzogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj5cbiAgKTogTSB7XG4gICAgY29uc3QgeyBsb2cgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmV2ZXJ0KTtcbiAgICBpZiAodHJhbnNpZW50KSB7XG4gICAgICBsb2cudmVyYm9zZShcbiAgICAgICAgYHJlLWFkZGluZyB0cmFuc2llbnQgcHJvcGVydGllczogJHtPYmplY3Qua2V5cyh0cmFuc2llbnQpLmpvaW4oXCIsIFwiKX1gXG4gICAgICApO1xuICAgICAgT2JqZWN0LmVudHJpZXModHJhbnNpZW50IGFzIFJlY29yZDxzdHJpbmcsIGFueT4pLmZvckVhY2goKFtrZXksIHZhbF0pID0+IHtcbiAgICAgICAgaWYgKGtleSBpbiBvYmopXG4gICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgICAgICBgVHJhbnNpZW50IHByb3BlcnR5ICR7a2V5fSBhbHJlYWR5IGV4aXN0cyBvbiBtb2RlbCAke3R5cGVvZiBjbGF6eiA9PT0gXCJzdHJpbmdcIiA/IGNsYXp6IDogY2xhenoubmFtZX0uIHNob3VsZCBiZSBpbXBvc3NpYmxlYFxuICAgICAgICAgICk7XG4gICAgICAgIChvYmogYXMgTSlba2V5IGFzIGtleW9mIE1dID0gdmFsO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyAoY2xhenogYXMgQ29uc3RydWN0b3I8TT4pKG9iaik7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBzaW5nbGUgcmVjb3JkXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgYSB0cmFuc2FjdGlvbiB0byBjcmVhdGUgYSByZWNvcmQgaW4gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIFRoZSByZWNvcmQgaWRlbnRpZmllclxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IG1vZGVsIC0gVGhlIHJlY29yZCBkYXRhXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gdHJhbnNpZW50IC0gVHJhbnNpZW50IGRhdGEgZm9yIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgY3JlYXRlZCByZWNvcmRcbiAgICovXG4gIEBkZWJ1ZygpXG4gIEBmaW5hbCgpXG4gIG92ZXJyaWRlIGFzeW5jIGNyZWF0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgdHJhbnNpZW50OiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge30sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IGN0eEFyZ3MgPSBbLi4uKGFyZ3MgYXMgdW5rbm93biBhcyBhbnlbXSldO1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KFxuICAgICAgY3R4QXJncyBhcyBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj4sXG4gICAgICB0aGlzLmNyZWF0ZVxuICAgICk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKGNsYXp6KTtcbiAgICBsb2cudmVyYm9zZShgYWRkaW5nIGVudHJ5IHRvICR7dGFibGVOYW1lfSB0YWJsZWApO1xuICAgIGxvZy5kZWJ1ZyhgcGs6ICR7aWR9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICAgICAgW3RoaXMuc2VyaWFsaXplci5zZXJpYWxpemUobW9kZWwsIGNsYXp6Lm5hbWUpXSxcbiAgICAgIHRyYW5zaWVudCxcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIGNsYXp6Lm5hbWVcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZXIuZGVzZXJpYWxpemUodGhpcy5kZWNvZGUocmVzdWx0KSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlYWRzIGEgc2luZ2xlIHJlY29yZFxuICAgKiBAc3VtbWFyeSBFdmFsdWF0ZXMgYSB0cmFuc2FjdGlvbiB0byByZWFkIGEgcmVjb3JkIGZyb20gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIFRoZSByZWNvcmQgaWRlbnRpZmllclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgcmV0cmlldmVkIHJlY29yZFxuICAgKi9cbiAgQGRlYnVnKClcbiAgQGZpbmFsKClcbiAgYXN5bmMgcmVhZDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmVhZEFsbCk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKGNsYXp6KTtcblxuICAgIGxvZy52ZXJib3NlKGByZWFkaW5nIGVudHJ5IGZyb20gJHt0YWJsZU5hbWV9IHRhYmxlYCk7XG4gICAgbG9nLmRlYnVnKGBwazogJHtpZH1gKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmV2YWx1YXRlVHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBPcGVyYXRpb25LZXlzLlJFQUQsXG4gICAgICBbaWQudG9TdHJpbmcoKV0sXG4gICAgICB1bmRlZmluZWQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBjbGF6ei5uYW1lXG4gICAgKTtcbiAgICByZXR1cm4gdGhpcy5zZXJpYWxpemVyLmRlc2VyaWFsaXplKHRoaXMuZGVjb2RlKHJlc3VsdCkpO1xuICB9XG5cbiAgdXBkYXRlUHJlZml4PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkOiBQcmltYXJ5S2V5VHlwZSxcbiAgICBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICkge1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgY29uc3QgeyBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnVwZGF0ZVByZWZpeCk7XG4gICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IHRhYmxlTmFtZTtcbiAgICAvLyByZWNvcmRbQ291Y2hEQktleXMuSURdID0gdGhpcy5nZW5lcmF0ZUlkKHRhYmxlTmFtZSwgaWQpO1xuICAgIE9iamVjdC5hc3NpZ24ocmVjb3JkLCBtb2RlbCk7XG4gICAgcmV0dXJuIFtjbGF6eiwgaWQsIHJlY29yZCwgLi4uY3R4QXJnc107XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVwZGF0ZXMgYSBzaW5nbGUgcmVjb3JkXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgYSB0cmFuc2FjdGlvbiB0byB1cGRhdGUgYSByZWNvcmQgaW4gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIFRoZSByZWNvcmQgaWRlbnRpZmllclxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IG1vZGVsIC0gVGhlIHVwZGF0ZWQgcmVjb3JkIGRhdGFcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSB0cmFuc2llbnQgLSBUcmFuc2llbnQgZGF0YSBmb3IgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIHJlY29yZFxuICAgKi9cbiAgQGRlYnVnKClcbiAgQGZpbmFsKClcbiAgYXN5bmMgdXBkYXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkOiBQcmltYXJ5S2V5VHlwZSxcbiAgICBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICB0cmFuc2llbnQ6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fSxcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj5cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+PiB7XG4gICAgY29uc3QgY3R4QXJncyA9IFsuLi4oYXJncyBhcyB1bmtub3duIGFzIGFueVtdKV07XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gdGhpcy5sb2dDdHgoXG4gICAgICBjdHhBcmdzIGFzIENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PixcbiAgICAgIHRoaXMudXBkYXRlQWxsXG4gICAgKTtcbiAgICBsb2cuaW5mbyhgQ0xJRU5UIFVQREFURSBjbGFzcyA6ICR7dHlwZW9mIGNsYXp6fWApO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgbG9nLnZlcmJvc2UoYHVwZGF0aW5nIGVudHJ5IHRvICR7dGFibGVOYW1lfSB0YWJsZWApO1xuICAgIGxvZy5kZWJ1ZyhgcGs6ICR7aWR9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIE9wZXJhdGlvbktleXMuVVBEQVRFLFxuICAgICAgW3RoaXMuc2VyaWFsaXplci5zZXJpYWxpemUobW9kZWwsIGNsYXp6Lm5hbWUgfHwgY2xhenopXSwgLy8gVE9ETyBzaG91bGQgYmUgcmVjZXZpbmcgY2xhc3MgYnV0IGlzIHJlY2VpdmluZyBzdHJpbmdcbiAgICAgIHRyYW5zaWVudCxcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIGNsYXp6Lm5hbWVcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZXIuZGVzZXJpYWxpemUodGhpcy5kZWNvZGUocmVzdWx0KSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIERlbGV0ZXMgYSBzaW5nbGUgcmVjb3JkXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgYSB0cmFuc2FjdGlvbiB0byBkZWxldGUgYSByZWNvcmQgZnJvbSB0aGUgRmFicmljIGxlZGdlclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlL2NvbGxlY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXJ9IGlkIC0gVGhlIHJlY29yZCBpZGVudGlmaWVyIHRvIGRlbGV0ZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZGVsZXRlZCByZWNvcmRcbiAgICovXG4gIEBkZWJ1ZygpXG4gIEBmaW5hbCgpXG4gIG92ZXJyaWRlIGFzeW5jIGRlbGV0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuZGVsZXRlKTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIGxvZy52ZXJib3NlKGBkZWxldGluZyBlbnRyeSBmcm9tICR7dGFibGVOYW1lfSB0YWJsZWApO1xuICAgIGxvZy5kZWJ1ZyhgcGs6ICR7aWR9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIE9wZXJhdGlvbktleXMuREVMRVRFLFxuICAgICAgW2lkLnRvU3RyaW5nKCldLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgY2xhenoubmFtZVxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuc2VyaWFsaXplci5kZXNlcmlhbGl6ZSh0aGlzLmRlY29kZShyZXN1bHQpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRXhlY3V0ZXMgYSByYXcgcXVlcnkgYWdhaW5zdCB0aGUgRmFicmljIGxlZGdlclxuICAgKiBAc3VtbWFyeSBFdmFsdWF0ZXMgYSB0cmFuc2FjdGlvbiB0byBwZXJmb3JtIGEgcXVlcnkgdXNpbmcgTWFuZ28gUXVlcnkgc3ludGF4XG4gICAqIEB0ZW1wbGF0ZSBWIC0gVGhlIHJldHVybiB0eXBlXG4gICAqIEBwYXJhbSB7TWFuZ29RdWVyeX0gcmF3SW5wdXQgLSBUaGUgTWFuZ28gUXVlcnkgdG8gZXhlY3V0ZVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHByb2Nlc3MgLSBXaGV0aGVyIHRvIHByb2Nlc3MgdGhlIHJlc3VsdFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFY+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgcXVlcnkgcmVzdWx0XG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IENsaWVudFxuICAgKiAgIHBhcnRpY2lwYW50IEZhYnJpY0FkYXB0ZXJcbiAgICogICBwYXJ0aWNpcGFudCBDb250cmFjdFxuICAgKiAgIHBhcnRpY2lwYW50IENoYWluY29kZVxuICAgKlxuICAgKiAgIENsaWVudC0+PkZhYnJpY0FkYXB0ZXI6IHJhdyhyYXdJbnB1dCwgcHJvY2VzcylcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogSlNPTi5zdHJpbmdpZnkocmF3SW5wdXQpXG4gICAqICAgRmFicmljQWRhcHRlci0+PkZhYnJpY0FkYXB0ZXI6IGV2YWx1YXRlVHJhbnNhY3Rpb24oXCJxdWVyeVwiLCBbaW5wdXRdKVxuICAgKiAgIEZhYnJpY0FkYXB0ZXItPj5Db250cmFjdDogZXZhbHVhdGUoXCJxdWVyeVwiLCBwcm9wb3NhbE9wdGlvbnMpXG4gICAqICAgQ29udHJhY3QtPj5DaGFpbmNvZGU6IGludm9rZVxuICAgKiAgIENoYWluY29kZS0tPj5Db250cmFjdDogcmVzcG9uc2VcbiAgICogICBDb250cmFjdC0tPj5GYWJyaWNBZGFwdGVyOiByZXN1bHRcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogSlNPTi5wYXJzZShkZWNvZGUocmVzdWx0KSlcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogUHJvY2VzcyByZXN1bHQgYmFzZWQgb24gdHlwZVxuICAgKiAgIEZhYnJpY0FkYXB0ZXItLT4+Q2xpZW50OiBwcm9jZXNzZWQgcmVzdWx0XG4gICAqL1xuICBAZGVidWcoKVxuICBhc3luYyByYXc8ViwgRCBleHRlbmRzIGJvb2xlYW4+KFxuICAgIHJhd0lucHV0OiBNYW5nb1F1ZXJ5LFxuICAgIGRvY3NPbmx5OiBEID0gdHJ1ZSBhcyBELFxuICAgIGNsYXp6OiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8Vj4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmF3KTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBjbGF6ei5uYW1lO1xuICAgIGxvZy5pbmZvKGBQZXJmb3JtaW5nIHJhdyBzdGF0ZW1lbnQgb24gdGFibGUgJHtNb2RlbC50YWJsZU5hbWUoY2xhenopfWApO1xuICAgIGxldCB0cmFuc2FjdGlvblJlc3VsdDogYW55O1xuICAgIHRyeSB7XG4gICAgICB0cmFuc2FjdGlvblJlc3VsdCA9IGF3YWl0IHRoaXMuZXZhbHVhdGVUcmFuc2FjdGlvbihcbiAgICAgICAgY3R4LFxuICAgICAgICBcInJhd1wiLFxuICAgICAgICBbSlNPTi5zdHJpbmdpZnkocmF3SW5wdXQpLCBkb2NzT25seV0sXG4gICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICB0YWJsZU5hbWVcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgICBsZXQgcmVzdWx0OiBhbnk7XG4gICAgdHJ5IHtcbiAgICAgIHJlc3VsdCA9IEpTT04ucGFyc2UodGhpcy5kZWNvZGUodHJhbnNhY3Rpb25SZXN1bHQpKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoYEZhaWxlZCB0byBwcm9jZXNzIHJlc3VsdDogJHtlfWApO1xuICAgIH1cblxuICAgIGNvbnN0IHBhcnNlUmVjb3JkID0gKHJlY29yZDogUmVjb3JkPGFueSwgYW55PikgPT4ge1xuICAgICAgaWYgKE1vZGVsLmlzTW9kZWwocmVjb3JkKSkgcmV0dXJuIE1vZGVsLmJ1aWxkKHJlY29yZCk7XG4gICAgICByZXR1cm4gcmVjb3JkO1xuICAgIH07XG5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShyZXN1bHQpKSB7XG4gICAgICBpZiAoIXJlc3VsdC5sZW5ndGgpIHJldHVybiByZXN1bHQgYXMgVjtcbiAgICAgIGNvbnN0IGVsID0gcmVzdWx0WzBdO1xuICAgICAgaWYgKE1vZGVsLmlzTW9kZWwoZWwpKVxuICAgICAgICAvLyBpZiB0aGUgZmlyc3Qgb25lIGlzIGEgbW9kZWwsIGFsbCBhcmUgbW9kZWxzXG4gICAgICAgIHJldHVybiByZXN1bHQubWFwKChlbCkgPT4gTW9kZWwuYnVpbGQoZWwpKSBhcyBWO1xuICAgICAgcmV0dXJuIHJlc3VsdCBhcyBWO1xuICAgIH1cblxuICAgIHJldHVybiBwYXJzZVJlY29yZChyZXN1bHQgYXMgYW55KSBhcyBWO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIG9yIGNyZWF0ZXMgYSBnUlBDIGNsaWVudCBmb3IgdGhlIEZhYnJpYyBwZWVyXG4gICAqIEBzdW1tYXJ5IFJldHVybnMgYSBjYWNoZWQgY2xpZW50IG9yIGNyZWF0ZXMgYSBuZXcgb25lIGlmIG5vbmUgZXhpc3RzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Q2xpZW50Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGdSUEMgY2xpZW50XG4gICAqL1xuICBvdmVycmlkZSBnZXRDbGllbnQoKTogQ2xpZW50IHtcbiAgICBpZiAoIXRoaXMuX2NsaWVudClcbiAgICAgIHRoaXMuX2NsaWVudCA9IEZhYnJpY0NsaWVudEFkYXB0ZXIuZ2V0Q2xpZW50KHRoaXMuY29uZmlnKTtcbiAgICByZXR1cm4gdGhpcy5fY2xpZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIGEgR2F0ZXdheSBpbnN0YW5jZSBmb3IgdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBuZXcgR2F0ZXdheSBpbnN0YW5jZSB1c2luZyB0aGUgY3VycmVudCBjbGllbnRcbiAgICogQHJldHVybiB7UHJvbWlzZTxHYXRld2F5Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEdhdGV3YXkgaW5zdGFuY2VcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBHYXRld2F5KGN0eDogQ29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4pOiBQcm9taXNlPEdhdGV3YXk+IHtcbiAgICByZXR1cm4gRmFicmljQ2xpZW50QWRhcHRlci5nZXRHYXRld2F5KGN0eCwgdGhpcy5jb25maWcsIHRoaXMuY2xpZW50KTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0Q29udHJhY3ROYW1lKGNsYXNzTmFtZT86IHN0cmluZykge1xuICAgIGlmICghY2xhc3NOYW1lKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIHJldHVybiBgJHtjbGFzc05hbWV9Q29udHJhY3RgO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIGEgQ29udHJhY3QgaW5zdGFuY2UgZm9yIHRoZSBGYWJyaWMgY2hhaW5jb2RlXG4gICAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBuZXcgQ29udHJhY3QgaW5zdGFuY2UgdXNpbmcgdGhlIGN1cnJlbnQgR2F0ZXdheVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPENvbnRyYWt0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIENvbnRyYWN0IGluc3RhbmNlXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgQ29udHJhY3QoXG4gICAgY3R4OiBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPixcbiAgICBjb250cmFjdE5hbWU/OiBzdHJpbmdcbiAgKTogUHJvbWlzZTxDb250cmFrdD4ge1xuICAgIHJldHVybiBGYWJyaWNDbGllbnRBZGFwdGVyLmdldENvbnRyYWN0KFxuICAgICAgYXdhaXQgdGhpcy5HYXRld2F5KGN0eCksXG4gICAgICB0aGlzLmNvbmZpZyxcbiAgICAgIGNvbnRyYWN0TmFtZVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgdHJhbnNhY3Rpb24gb24gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgb3IgZXZhbHVhdGVzIGEgdHJhbnNhY3Rpb24gb24gdGhlIEZhYnJpYyBjaGFpbmNvZGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFwaSAtIFRoZSBjaGFpbmNvZGUgZnVuY3Rpb24gdG8gY2FsbFxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN1Ym1pdCAtIFdoZXRoZXIgdG8gc3VibWl0ICh0cnVlKSBvciBldmFsdWF0ZSAoZmFsc2UpIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge2FueVtdfSBbYXJnc10gLSBBcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgY2hhaW5jb2RlIGZ1bmN0aW9uXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgc3RyaW5nPn0gW3RyYW5zaWVudERhdGFdIC0gVHJhbnNpZW50IGRhdGEgZm9yIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IFtlbmRvcnNpbmdPcmdhbml6YXRpb25zXSAtIE9yZ2FuaXphdGlvbnMgdGhhdCBtdXN0IGVuZG9yc2UgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8VWludDhBcnJheT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB0cmFuc2FjdGlvbiByZXN1bHRcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgRmFicmljQWRhcHRlclxuICAgKiAgIHBhcnRpY2lwYW50IEdhdGV3YXlcbiAgICogICBwYXJ0aWNpcGFudCBDb250cmFjdFxuICAgKiAgIHBhcnRpY2lwYW50IENoYWluY29kZVxuICAgKlxuICAgKiAgIEZhYnJpY0FkYXB0ZXItPj5HYXRld2F5OiBjb25uZWN0KClcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+Q29udHJhY3Q6IGdldENvbnRyYWN0KClcbiAgICogICBhbHQgc3VibWl0IHRyYW5zYWN0aW9uXG4gICAqICAgICBGYWJyaWNBZGFwdGVyLT4+Q29udHJhY3Q6IHN1Ym1pdChhcGksIHByb3Bvc2FsT3B0aW9ucylcbiAgICogICBlbHNlIGV2YWx1YXRlIHRyYW5zYWN0aW9uXG4gICAqICAgICBGYWJyaWNBZGFwdGVyLT4+Q29udHJhY3Q6IGV2YWx1YXRlKGFwaSwgcHJvcG9zYWxPcHRpb25zKVxuICAgKiAgIGVuZFxuICAgKiAgIENvbnRyYWN0LT4+Q2hhaW5jb2RlOiBpbnZva2VcbiAgICogICBDaGFpbmNvZGUtLT4+Q29udHJhY3Q6IHJlc3BvbnNlXG4gICAqICAgQ29udHJhY3QtLT4+RmFicmljQWRhcHRlcjogcmVzdWx0XG4gICAqICAgRmFicmljQWRhcHRlci0+PkdhdGV3YXk6IGNsb3NlKClcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyB0cmFuc2FjdGlvbihcbiAgICBjdHg6IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+LFxuICAgIGFwaTogc3RyaW5nLFxuICAgIHN1Ym1pdCA9IHRydWUsXG4gICAgYXJncz86IGFueVtdLFxuICAgIHRyYW5zaWVudERhdGE/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICAgIGVuZG9yc2luZ09yZ2FuaXphdGlvbnM/OiBBcnJheTxzdHJpbmc+LFxuICAgIGNsYXNzTmFtZT86IHN0cmluZ1xuICApOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy50cmFuc2FjdGlvbik7XG4gICAgY29uc3QgZ2F0ZXdheSA9IGF3YWl0IHRoaXMuR2F0ZXdheShjdHgpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb250cmFjdCA9IGF3YWl0IHRoaXMuQ29udHJhY3QoXG4gICAgICAgIGN0eCxcbiAgICAgICAgdGhpcy5nZXRDb250cmFjdE5hbWUoY2xhc3NOYW1lKVxuICAgICAgKTtcbiAgICAgIGxvZy52ZXJib3NlKFxuICAgICAgICBgJHtzdWJtaXQgPyBcIlN1Ym1pdFwiIDogXCJFdmFsdWF0ZVwifXRpbmcgdHJhbnNhY3Rpb24gJHt0aGlzLmdldENvbnRyYWN0TmFtZShjbGFzc05hbWUpIHx8IHRoaXMuY29uZmlnLmNvbnRyYWN0TmFtZX0uJHthcGl9YFxuICAgICAgKTtcbiAgICAgIGxvZy5kZWJ1ZyhgYXJnczogJHthcmdzPy5tYXAoKGEpID0+IGEudG9TdHJpbmcoKSkuam9pbihcIlxcblwiKSB8fCBcIm5vbmVcIn1gKTtcbiAgICAgIGNvbnN0IG1ldGhvZCA9IHN1Ym1pdCA/IGNvbnRyYWN0LnN1Ym1pdCA6IGNvbnRyYWN0LmV2YWx1YXRlO1xuXG4gICAgICBlbmRvcnNpbmdPcmdhbml6YXRpb25zID0gZW5kb3JzaW5nT3JnYW5pemF0aW9ucz8ubGVuZ3RoXG4gICAgICAgID8gZW5kb3JzaW5nT3JnYW5pemF0aW9uc1xuICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IHByb3Bvc2FsT3B0aW9uczogUHJvcG9zYWxPcHRpb25zID0ge1xuICAgICAgICBhcmd1bWVudHM6IGFyZ3MgfHwgW10sXG4gICAgICAgIHRyYW5zaWVudERhdGE6IHRyYW5zaWVudERhdGEsXG4gICAgICAgIC8vIC4uLihlbmRvcnNpbmdPcmdhbml6YXRpb25zICYmIHsgZW5kb3JzaW5nT3JnYW5pemF0aW9ucyB9KSAvLyBtc3BJZCBsaXN0XG4gICAgICB9O1xuXG4gICAgICByZXR1cm4gYXdhaXQgbWV0aG9kLmNhbGwoY29udHJhY3QsIGFwaSwgcHJvcG9zYWxPcHRpb25zKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGlmIChlLmNvZGUgPT09IDEwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtlLmRldGFpbHNbMF0ubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5sb2cuZGVidWcoYENsb3NpbmcgJHt0aGlzLmNvbmZpZy5tc3BJZH0gZ2F0ZXdheSBjb25uZWN0aW9uYCk7XG4gICAgICBnYXRld2F5LmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQYXJzZXMgYW4gZXJyb3IgaW50byBhIEJhc2VFcnJvclxuICAgKiBAc3VtbWFyeSBDb252ZXJ0cyBhbnkgZXJyb3IgaW50byBhIHN0YW5kYXJkaXplZCBCYXNlRXJyb3JcbiAgICogQHBhcmFtIHtFcnJvciB8IHN0cmluZ30gZXJyIC0gVGhlIGVycm9yIHRvIHBhcnNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcmVhc29uXSAtIE9wdGlvbmFsIHJlYXNvbiBmb3IgdGhlIGVycm9yXG4gICAqIEByZXR1cm4ge0Jhc2VFcnJvcn0gVGhlIHBhcnNlZCBlcnJvclxuICAgKi9cbiAgb3ZlcnJpZGUgcGFyc2VFcnJvcjxFIGV4dGVuZHMgQmFzZUVycm9yPihlcnI6IEVycm9yIHwgc3RyaW5nKTogRSB7XG4gICAgcmV0dXJuIEZhYnJpY0NsaWVudEFkYXB0ZXIucGFyc2VFcnJvcjxFPihlcnIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTdWJtaXRzIGEgdHJhbnNhY3Rpb24gdG8gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IEV4ZWN1dGVzIGEgdHJhbnNhY3Rpb24gdGhhdCBtb2RpZmllcyB0aGUgbGVkZ2VyIHN0YXRlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcGkgLSBUaGUgY2hhaW5jb2RlIGZ1bmN0aW9uIHRvIGNhbGxcbiAgICogQHBhcmFtIHthbnlbXX0gW2FyZ3NdIC0gQXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIGNoYWluY29kZSBmdW5jdGlvblxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHN0cmluZz59IFt0cmFuc2llbnREYXRhXSAtIFRyYW5zaWVudCBkYXRhIGZvciB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBbZW5kb3JzaW5nT3JnYW5pemF0aW9uc10gLSBPcmdhbml6YXRpb25zIHRoYXQgbXVzdCBlbmRvcnNlIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFVpbnQ4QXJyYXk+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdHJhbnNhY3Rpb24gcmVzdWx0XG4gICAqL1xuICBhc3luYyBzdWJtaXRUcmFuc2FjdGlvbihcbiAgICBjdHg6IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+LFxuICAgIGFwaTogc3RyaW5nLFxuICAgIGFyZ3M/OiBhbnlbXSxcbiAgICB0cmFuc2llbnREYXRhPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcbiAgICBlbmRvcnNpbmdPcmdhbml6YXRpb25zPzogQXJyYXk8c3RyaW5nPixcbiAgICBjbGFzc05hbWU/OiBzdHJpbmdcbiAgKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBhcGksXG4gICAgICB0cnVlLFxuICAgICAgYXJncyxcbiAgICAgIHRyYW5zaWVudERhdGEsXG4gICAgICBlbmRvcnNpbmdPcmdhbml6YXRpb25zLFxuICAgICAgY2xhc3NOYW1lXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRXZhbHVhdGVzIGEgdHJhbnNhY3Rpb24gb24gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IEV4ZWN1dGVzIGEgdHJhbnNhY3Rpb24gdGhhdCBkb2VzIG5vdCBtb2RpZnkgdGhlIGxlZGdlciBzdGF0ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXBpIC0gVGhlIGNoYWluY29kZSBmdW5jdGlvbiB0byBjYWxsXG4gICAqIEBwYXJhbSB7YW55W119IFthcmdzXSAtIEFyZ3VtZW50cyB0byBwYXNzIHRvIHRoZSBjaGFpbmNvZGUgZnVuY3Rpb25cbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+fSBbdHJhbnNpZW50RGF0YV0gLSBUcmFuc2llbnQgZGF0YSBmb3IgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nPn0gW2VuZG9yc2luZ09yZ2FuaXphdGlvbnNdIC0gT3JnYW5pemF0aW9ucyB0aGF0IG11c3QgZW5kb3JzZSB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxVaW50OEFycmF5Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRyYW5zYWN0aW9uIHJlc3VsdFxuICAgKi9cbiAgYXN5bmMgZXZhbHVhdGVUcmFuc2FjdGlvbihcbiAgICBjdHg6IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+LFxuICAgIGFwaTogc3RyaW5nLFxuICAgIGFyZ3M/OiBhbnlbXSxcbiAgICB0cmFuc2llbnREYXRhPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcbiAgICBlbmRvcnNpbmdPcmdhbml6YXRpb25zPzogQXJyYXk8c3RyaW5nPixcbiAgICBjbGFzc05hbWU/OiBzdHJpbmdcbiAgKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBhcGksXG4gICAgICBmYWxzZSxcbiAgICAgIGFyZ3MsXG4gICAgICB0cmFuc2llbnREYXRhLFxuICAgICAgZW5kb3JzaW5nT3JnYW5pemF0aW9ucyxcbiAgICAgIGNsYXNzTmFtZVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENsb3NlcyB0aGUgY29ubmVjdGlvbiB0byB0aGUgRmFicmljIG5ldHdvcmtcbiAgICogQHN1bW1hcnkgQ2xvc2VzIHRoZSBnUlBDIGNsaWVudCBpZiBpdCBleGlzdHNcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGNsaWVudCBpcyBjbG9zZWRcbiAgICovXG4gIGFzeW5jIGNsb3NlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNsaWVudCkge1xuICAgICAgdGhpcy5sb2cudmVyYm9zZShgQ2xvc2luZyAke3RoaXMuY29uZmlnLm1zcElkfSBnYXRld2F5IGNsaWVudGApO1xuICAgICAgdGhpcy5jbGllbnQuY2xvc2UoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEdldHMgYSBDb250cmFjdCBpbnN0YW5jZSBmcm9tIGEgR2F0ZXdheVxuICAgKiBAc3VtbWFyeSBSZXRyaWV2ZXMgYSBjaGFpbmNvZGUgY29udHJhY3QgZnJvbSB0aGUgc3BlY2lmaWVkIG5ldHdvcmtcbiAgICogQHBhcmFtIHtHYXRld2F5fSBnYXRld2F5IC0gVGhlIEdhdGV3YXkgaW5zdGFuY2VcbiAgICogQHBhcmFtIHtQZWVyQ29uZmlnfSBjb25maWcgLSBUaGUgcGVlciBjb25maWd1cmF0aW9uXG4gICAqIEByZXR1cm4ge0NvbnRyYWt0fSBUaGUgQ29udHJhY3QgaW5zdGFuY2VcbiAgICovXG4gIHN0YXRpYyBnZXRDb250cmFjdChcbiAgICBnYXRld2F5OiBHYXRld2F5LFxuICAgIGNvbmZpZzogUGVlckNvbmZpZyxcbiAgICBjb250cmFjdE5hbWU/OiBzdHJpbmdcbiAgKTogQ29udHJha3Qge1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmdldENvbnRyYWN0KTtcbiAgICBjb25zdCBuZXR3b3JrID0gdGhpcy5nZXROZXR3b3JrKGdhdGV3YXksIGNvbmZpZy5jaGFubmVsKTtcbiAgICBsZXQgY29udHJhY3Q6IENvbnRyYWt0O1xuICAgIHRyeSB7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBSZXRyaWV2aW5nIGNoYWluY29kZSAke2NvbmZpZy5jaGFpbmNvZGVOYW1lfSBjb250cmFjdCAke2NvbnRyYWN0TmFtZSB8fCBjb25maWcuY29udHJhY3ROYW1lfSBmcm9tIG5ldHdvcmsgJHtjb25maWcuY2hhbm5lbH1gXG4gICAgICApO1xuICAgICAgY29udHJhY3ROYW1lID0gY29udHJhY3ROYW1lID8gY29udHJhY3ROYW1lIDogY29uZmlnLmNvbnRyYWN0TmFtZTtcbiAgICAgIGNvbnRyYWN0ID0gbmV0d29yay5nZXRDb250cmFjdChjb25maWcuY2hhaW5jb2RlTmFtZSwgY29udHJhY3ROYW1lKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlKTtcbiAgICB9XG4gICAgcmV0dXJuIGNvbnRyYWN0O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIGEgTmV0d29yayBpbnN0YW5jZSBmcm9tIGEgR2F0ZXdheVxuICAgKiBAc3VtbWFyeSBDb25uZWN0cyB0byBhIHNwZWNpZmljIGNoYW5uZWwgb24gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBwYXJhbSB7R2F0ZXdheX0gZ2F0ZXdheSAtIFRoZSBHYXRld2F5IGluc3RhbmNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjaGFubmVsTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjaGFubmVsIHRvIGNvbm5lY3QgdG9cbiAgICogQHJldHVybiB7TmV0d29ya30gVGhlIE5ldHdvcmsgaW5zdGFuY2VcbiAgICovXG4gIHN0YXRpYyBnZXROZXR3b3JrKGdhdGV3YXk6IEdhdGV3YXksIGNoYW5uZWxOYW1lOiBzdHJpbmcpOiBOZXR3b3JrIHtcbiAgICBjb25zdCBsb2cgPSBMb2dnaW5nLmZvcih0aGlzLmdldE5ldHdvcmspO1xuICAgIGxldCBuZXR3b3JrOiBOZXR3b3JrO1xuICAgIHRyeSB7XG4gICAgICBsb2cuZGVidWcoYENvbm5lY3RpbmcgdG8gY2hhbm5lbCAke2NoYW5uZWxOYW1lfWApO1xuICAgICAgbmV0d29yayA9IGdhdGV3YXkuZ2V0TmV0d29yayhjaGFubmVsTmFtZSk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldHdvcms7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEdldHMgYSBHYXRld2F5IGluc3RhbmNlIGZvciBjb25uZWN0aW5nIHRvIHRoZSBGYWJyaWMgbmV0d29ya1xuICAgKiBAc3VtbWFyeSBDcmVhdGVzIGEgR2F0ZXdheSB1c2luZyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgY2xpZW50XG4gICAqIEBwYXJhbSB7UGVlckNvbmZpZ30gY29uZmlnIC0gVGhlIHBlZXIgY29uZmlndXJhdGlvblxuICAgKiBAcGFyYW0ge0NsaWVudH0gW2NsaWVudF0gLSBPcHRpb25hbCBnUlBDIGNsaWVudCwgd2lsbCBiZSBjcmVhdGVkIGlmIG5vdCBwcm92aWRlZFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPEdhdGV3YXk+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgR2F0ZXdheSBpbnN0YW5jZVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGdldEdhdGV3YXkoXG4gICAgY3R4OiBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPixcbiAgICBjb25maWc6IFBlZXJDb25maWcsXG4gICAgY2xpZW50PzogQ2xpZW50XG4gICkge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5nZXRDb25uZWN0aW9uKFxuICAgICAgY2xpZW50IHx8IChhd2FpdCB0aGlzLmdldENsaWVudChjb25maWcpKSxcbiAgICAgIGNvbmZpZyxcbiAgICAgIGN0eFxuICAgICkpIGFzIEdhdGV3YXk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBnUlBDIGNsaWVudCBmb3IgY29ubmVjdGluZyB0byBhIEZhYnJpYyBwZWVyXG4gICAqIEBzdW1tYXJ5IEluaXRpYWxpemVzIGEgY2xpZW50IHdpdGggVExTIGNyZWRlbnRpYWxzIGZvciBzZWN1cmUgY29tbXVuaWNhdGlvblxuICAgKiBAcGFyYW0ge1BlZXJDb25maWd9IGNvbmZpZyAtIFRoZSBwZWVyIGNvbmZpZ3VyYXRpb25cbiAgICogQHJldHVybiB7Q2xpZW50fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZ1JQQyBjbGllbnRcbiAgICovXG4gIHN0YXRpYyBnZXRDbGllbnQoY29uZmlnOiBQZWVyQ29uZmlnKTogQ2xpZW50IHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5nZXRDbGllbnQpO1xuICAgIGxvZy5kZWJ1ZyhgZ2VuZXJhdGluZyBUTFMgY3JlZGVudGlhbHMgZm9yIG1zcCAke2NvbmZpZy5tc3BJZH1gKTtcbiAgICBsZXQgcGF0aE9yQ2VydDogc3RyaW5nIHwgQnVmZmVyID0gY29uZmlnLnRsc0NlcnQgYXMgc3RyaW5nIHwgQnVmZmVyO1xuXG4gICAgaWYgKHR5cGVvZiBwYXRoT3JDZXJ0ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBpZiAoXG4gICAgICAgIHBhdGhPckNlcnQubWF0Y2goXG4gICAgICAgICAgLy0tLS0tQkVHSU4gKENFUlRJRklDQVRFfEtFWXxQUklWQVRFIEtFWSktLS0tLS4rPy0tLS0tRU5EIFxcMS0tLS0tJC9nbXNcbiAgICAgICAgKVxuICAgICAgKSB7XG4gICAgICAgIHBhdGhPckNlcnQgPSBCdWZmZXIuZnJvbShwYXRoT3JDZXJ0LCBcInV0ZjhcIik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHBhdGhPckNlcnQgPSBCdWZmZXIuZnJvbShmcy5yZWFkRmlsZVN5bmMocGF0aE9yQ2VydCwgXCJ1dGY4XCIpKTtcbiAgICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgYEZhaWxlZCB0byByZWFkIHRoZSB0bHMgY2VydGlmaWNhdGUgZnJvbSAke3BhdGhPckNlcnR9OiAke2V9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCB0bHNDcmVkZW50aWFscyA9IGdycGMuY3JlZGVudGlhbHMuY3JlYXRlU3NsKHBhdGhPckNlcnQpO1xuICAgIGxvZy5kZWJ1ZyhgZ2VuZXJhdGluZyBHYXRld2F5IENsaWVudCBmb3IgdXJsICR7Y29uZmlnLnBlZXJFbmRwb2ludH1gKTtcbiAgICByZXR1cm4gbmV3IENsaWVudChjb25maWcucGVlckVuZHBvaW50LCB0bHNDcmVkZW50aWFscywge1xuICAgICAgXCJncnBjLm1heF9yZWNlaXZlX21lc3NhZ2VfbGVuZ3RoXCI6IChjb25maWcuc2l6ZUxpbWl0IHx8IDE1KSAqIDEwMjQgKiAxMDI0LFxuICAgICAgXCJncnBjLm1heF9zZW5kX21lc3NhZ2VfbGVuZ3RoXCI6IChjb25maWcuc2l6ZUxpbWl0IHx8IDE1KSAqIDEwMjQgKiAxMDI0LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFc3RhYmxpc2hlcyBhIGNvbm5lY3Rpb24gdG8gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBHYXRld2F5IGNvbm5lY3Rpb24gd2l0aCBpZGVudGl0eSBhbmQgc2lnbmVyXG4gICAqIEBwYXJhbSB7Q2xpZW50fSBjbGllbnQgLSBUaGUgZ1JQQyBjbGllbnRcbiAgICogQHBhcmFtIHtQZWVyQ29uZmlnfSBjb25maWcgLSBUaGUgcGVlciBjb25maWd1cmF0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8R2F0ZXdheT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBjb25uZWN0ZWQgR2F0ZXdheVxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAgICogICBwYXJ0aWNpcGFudCBGYWJyaWNBZGFwdGVyXG4gICAqICAgcGFydGljaXBhbnQgSWRlbnRpdHlcbiAgICogICBwYXJ0aWNpcGFudCBTaWduZXJcbiAgICogICBwYXJ0aWNpcGFudCBHYXRld2F5XG4gICAqXG4gICAqICAgQ2FsbGVyLT4+RmFicmljQWRhcHRlcjogZ2V0Q29ubmVjdGlvbihjbGllbnQsIGNvbmZpZylcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+SWRlbnRpdHk6IGdldElkZW50aXR5KG1zcElkLCBjZXJ0RGlyZWN0b3J5UGF0aClcbiAgICogICBJZGVudGl0eS0tPj5GYWJyaWNBZGFwdGVyOiBpZGVudGl0eVxuICAgKiAgIEZhYnJpY0FkYXB0ZXItPj5TaWduZXI6IGdldFNpZ25lcihrZXlEaXJlY3RvcnlQYXRoKVxuICAgKiAgIFNpZ25lci0tPj5GYWJyaWNBZGFwdGVyOiBzaWduZXJcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogQ3JlYXRlIENvbm5lY3RPcHRpb25zXG4gICAqICAgRmFicmljQWRhcHRlci0+PkdhdGV3YXk6IGNvbm5lY3Qob3B0aW9ucylcbiAgICogICBHYXRld2F5LS0+PkZhYnJpY0FkYXB0ZXI6IGdhdGV3YXlcbiAgICogICBGYWJyaWNBZGFwdGVyLS0+PkNhbGxlcjogZ2F0ZXdheVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGdldENvbm5lY3Rpb24oXG4gICAgY2xpZW50OiBDbGllbnQsXG4gICAgY29uZmlnOiBQZWVyQ29uZmlnLFxuICAgIGN0eDogQ29udGV4dDxGYWJyaWNDbGllbnRGbGFncz5cbiAgKSB7XG4gICAgY29uc3QgbG9nID0gTG9nZ2luZy5mb3IodGhpcy5nZXRDb25uZWN0aW9uKTtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgUmV0cmlldmluZyBQZWVyIElkZW50aXR5IGZvciAke2NvbmZpZy5tc3BJZH0gdW5kZXIgJHtjb25maWcuY2VydENlcnRPckRpcmVjdG9yeVBhdGh9YFxuICAgICk7XG4gICAgY29uc3QgaWRlbnRpdHkgPSBhd2FpdCBnZXRJZGVudGl0eShcbiAgICAgIGNvbmZpZy5tc3BJZCxcbiAgICAgIGNvbmZpZy5jZXJ0Q2VydE9yRGlyZWN0b3J5UGF0aCBhcyBhbnlcbiAgICApO1xuICAgIGxvZy5kZWJ1ZyhgUmV0cmlldmluZyBzaWduZXIga2V5IGZyb20gJHtjb25maWcua2V5Q2VydE9yRGlyZWN0b3J5UGF0aH1gKTtcblxuICAgIGxldCBzaWduZXI6IFNpZ25lcixcbiAgICAgIGNsb3NlID0gKCkgPT4ge307XG4gICAgaWYgKCFjb25maWcuaHNtKSB7XG4gICAgICBzaWduZXIgPSBhd2FpdCBnZXRTaWduZXIoY29uZmlnLmtleUNlcnRPckRpcmVjdG9yeVBhdGggYXMgYW55KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgaHNtID0gbmV3IEhTTVNpZ25lckZhY3RvcnlDdXN0b20oY29uZmlnLmhzbS5saWJyYXJ5KTtcbiAgICAgIGNvbnN0IGlkZW50aWZpZXIgPSBoc20uZ2V0U0tJRnJvbUNlcnRpZmljYXRlUGF0aChcbiAgICAgICAgY29uZmlnLmNlcnRDZXJ0T3JEaXJlY3RvcnlQYXRoIGFzIGFueVxuICAgICAgKTtcbiAgICAgIGNvbnN0IHBrY3MxMVNpZ25lciA9IGhzbS5uZXdTaWduZXIoe1xuICAgICAgICBsYWJlbDogY29uZmlnLmhzbS50b2tlbkxhYmVsIGFzIHN0cmluZyxcbiAgICAgICAgcGluOiBTdHJpbmcoY29uZmlnLmhzbS5waW4pIGFzIHN0cmluZyxcbiAgICAgICAgaWRlbnRpZmllcjogaWRlbnRpZmllcixcbiAgICAgICAgLy8gdXNlclR5cGU6IDEgLypDS1VfVVNFUiAqLyxcbiAgICAgIH0pO1xuICAgICAgc2lnbmVyID0gcGtjczExU2lnbmVyLnNpZ25lcjtcblxuICAgICAgY2xvc2UgPSBwa2NzMTFTaWduZXIuY2xvc2U7XG4gICAgfVxuXG4gICAgY29uc3Qgb3B0aW9ucyA9IHtcbiAgICAgIGNsaWVudCxcbiAgICAgIGlkZW50aXR5OiBpZGVudGl0eSxcbiAgICAgIHNpZ25lcjogc2lnbmVyLFxuICAgICAgLy8gRGVmYXVsdCB0aW1lb3V0cyBmb3IgZGlmZmVyZW50IGdSUEMgY2FsbHNcbiAgICAgIGV2YWx1YXRlT3B0aW9uczogKCkgPT4ge1xuICAgICAgICByZXR1cm4geyBkZWFkbGluZTogRGF0ZS5ub3coKSArIDEwMDAgKiBjdHguZ2V0KFwiZXZhbHVhdGVUaW1lb3V0XCIpIH07IC8vIGRlZmF1bHRzIHRvIDUgc2Vjb25kc1xuICAgICAgfSxcbiAgICAgIGVuZG9yc2VPcHRpb25zOiAoKSA9PiB7XG4gICAgICAgIHJldHVybiB7IGRlYWRsaW5lOiBEYXRlLm5vdygpICsgMTAwMCAqIGN0eC5nZXQoXCJlbmRvcnNlVGltZW91dFwiKSB9OyAvLyBkZWZhdWx0cyB0byAxNSBzZWNvbmRzXG4gICAgICB9LFxuICAgICAgc3VibWl0T3B0aW9uczogKCkgPT4ge1xuICAgICAgICByZXR1cm4geyBkZWFkbGluZTogRGF0ZS5ub3coKSArIDEwMDAgKiBjdHguZ2V0KFwic3VibWl0VGltZW91dFwiKSB9OyAvLyBkZWZhdWx0cyB0byA1IHNlY29uZHNcbiAgICAgIH0sXG4gICAgICBjb21taXRTdGF0dXNPcHRpb25zOiAoKSA9PiB7XG4gICAgICAgIHJldHVybiB7IGRlYWRsaW5lOiBEYXRlLm5vdygpICsgMTAwMCAqIGN0eC5nZXQoXCJjb21taXRUaW1lb3V0XCIpIH07IC8vIGRlZmF1bHRzIHRvIDEgbWludXRlXG4gICAgICB9LFxuICAgIH0gYXMgQ29ubmVjdE9wdGlvbnM7XG5cbiAgICBsb2cuZGVidWcoYENvbm5lY3RpbmcgdG8gJHtjb25maWcubXNwSWR9YCk7XG4gICAgY29uc3QgZ2F0ZXdheSA9IGNvbm5lY3Qob3B0aW9ucyk7XG5cbiAgICAvLyBUT0RPOiByZXBsYWNlP1xuICAgIGlmIChjb25maWcuaHNtKSB7XG4gICAgICBnYXRld2F5LmNsb3NlID0gbmV3IFByb3h5KGdhdGV3YXkuY2xvc2UsIHtcbiAgICAgICAgYXBwbHkodGFyZ2V0OiAoKSA9PiB2b2lkLCB0aGlzQXJnOiBhbnksIGFyZ0FycmF5OiBhbnlbXSk6IGFueSB7XG4gICAgICAgICAgUmVmbGVjdC5hcHBseSh0YXJnZXQsIHRoaXNBcmcsIGFyZ0FycmF5KTtcbiAgICAgICAgICBjbG9zZSgpO1xuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGdhdGV3YXk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgRGlzcGF0Y2ggaW5zdGFuY2UgZm9yIHRoZSBGYWJyaWMgY2xpZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIGZ1bmN0aW9uIGlzIHJlc3BvbnNpYmxlIGZvciBjcmVhdGluZyBhIG5ldyBGYWJyaWNDbGllbnREaXNwYXRjaCBpbnN0YW5jZSB0aGF0IGNhbiBiZSB1c2VkIHRvIGludGVyYWN0IHdpdGggdGhlIEZhYnJpYyBuZXR3b3JrLlxuICAgKiBAcmV0dXJucyB7RGlzcGF0Y2h9IEEgbmV3IERpc3BhdGNoIGluc3RhbmNlIGNvbmZpZ3VyZWQgZm9yIHRoZSBGYWJyaWMgY2xpZW50LlxuICAgKiBAcmVtYXJrcyBUaGUgRGlzcGF0Y2ggaW5zdGFuY2UgaXMgdXNlZCB0byBlbmNhcHN1bGF0ZSB0aGUgbG9naWMgZm9yIGludGVyYWN0aW5nIHdpdGggdGhlIEZhYnJpYyBuZXR3b3JrLCBzdWNoIGFzIHN1Ym1pdHRpbmcgdHJhbnNhY3Rpb25zIG9yIHF1ZXJ5aW5nIGRhdGEuXG4gICAqIEBleGFtcGxlXG4gICAqIGNvbnN0IGZhYnJpY0Rpc3BhdGNoID0gZmFicmljQ2xpZW50QWRhcHRlci5EaXNwYXRjaCgpO1xuICAgKiBmYWJyaWNEaXNwYXRjaC5zdWJtaXRUcmFuc2FjdGlvbignY3JlYXRlUHJvZHVjdCcsIHsgbmFtZTogJ1Byb2R1Y3QgQScsIHByaWNlOiAxMDAgfSk7XG4gICAqL1xuICBvdmVycmlkZSBEaXNwYXRjaCgpOiBGYWJyaWNDbGllbnREaXNwYXRjaCB7XG4gICAgcmV0dXJuIG5ldyBGYWJyaWNDbGllbnRBZGFwdGVyW1wiX2Jhc2VEaXNwYXRjaFwiXSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQYXJzZXMgYW4gZXJyb3IgaW50byBhIEJhc2VFcnJvclxuICAgKiBAc3VtbWFyeSBDb252ZXJ0cyBhbnkgZXJyb3IgaW50byBhIHN0YW5kYXJkaXplZCBCYXNlRXJyb3IgdXNpbmcgdGhlIHBhcmVudCBjbGFzcyBpbXBsZW1lbnRhdGlvblxuICAgKiBAcGFyYW0ge0Vycm9yIHwgc3RyaW5nfSBlcnIgLSBUaGUgZXJyb3IgdG8gcGFyc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtyZWFzb25dIC0gT3B0aW9uYWwgcmVhc29uIGZvciB0aGUgZXJyb3JcbiAgICogQHJldHVybiB7QmFzZUVycm9yfSBUaGUgcGFyc2VkIGVycm9yXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIHBhcnNlRXJyb3I8RSBleHRlbmRzIEJhc2VFcnJvcj4oZXJyOiBFcnJvciB8IHN0cmluZyk6IEUge1xuICAgIC8vIGlmIChcbiAgICAvLyAgIE1JU1NJTkdfUFJJVkFURV9EQVRBX1JFR0VYLnRlc3QoXG4gICAgLy8gICAgIHR5cGVvZiBlcnIgPT09IFwic3RyaW5nXCIgPyBlcnIgOiBlcnIubWVzc2FnZVxuICAgIC8vICAgKVxuICAgIC8vIClcbiAgICAvLyAgIHJldHVybiBuZXcgVW5hdXRob3JpemVkUHJpdmF0ZURhdGFBY2Nlc3MoZXJyKSBhcyBFO1xuICAgIGNvbnN0IG1zZyA9IHR5cGVvZiBlcnIgPT09IFwic3RyaW5nXCIgPyBlcnIgOiBlcnIubWVzc2FnZTtcblxuICAgIGlmIChtc2cuaW5jbHVkZXMoXCJNVkNDX1JFQURfQ09ORkxJQ1RcIikpXG4gICAgICByZXR1cm4gbmV3IE12Y2NSZWFkQ29uZmxpY3RFcnJvcihlcnIpIGFzIEU7XG5cbiAgICBpZiAobXNnLmluY2x1ZGVzKFwiRU5ET1JTRU1FTlRfUE9MSUNZX0ZBSUxVUkVcIikpXG4gICAgICByZXR1cm4gbmV3IEVuZG9yc2VtZW50UG9saWN5RXJyb3IoZXJyKSBhcyBFO1xuXG4gICAgaWYgKG1zZy5pbmNsdWRlcyhcIlBIQU5UT01fUkVBRF9DT05GTElDVFwiKSlcbiAgICAgIHJldHVybiBuZXcgUGhhbnRvbVJlYWRDb25mbGljdEVycm9yKGVycikgYXMgRTtcblxuICAgIGlmIChlcnIgaW5zdGFuY2VvZiBFcnJvciAmJiAoZXJyIGFzIGFueSkuY29kZSkge1xuICAgICAgc3dpdGNoICgoZXJyIGFzIGFueSkuY29kZSkge1xuICAgICAgICBjYXNlIDk6XG4gICAgICAgICAgcmV0dXJuIG5ldyBFbmRvcnNlbWVudEVycm9yKGVycikgYXMgRTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAobXNnLmluY2x1ZGVzKE5vdEZvdW5kRXJyb3IubmFtZSkpIHJldHVybiBuZXcgTm90Rm91bmRFcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhDb25mbGljdEVycm9yLm5hbWUpKSByZXR1cm4gbmV3IENvbmZsaWN0RXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoQmFkUmVxdWVzdEVycm9yLm5hbWUpKVxuICAgICAgcmV0dXJuIG5ldyBCYWRSZXF1ZXN0RXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoUXVlcnlFcnJvci5uYW1lKSkgcmV0dXJuIG5ldyBRdWVyeUVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKFBhZ2luZ0Vycm9yLm5hbWUpKSByZXR1cm4gbmV3IFBhZ2luZ0Vycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKFVuc3VwcG9ydGVkRXJyb3IubmFtZSkpXG4gICAgICByZXR1cm4gbmV3IFVuc3VwcG9ydGVkRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoTWlncmF0aW9uRXJyb3IubmFtZSkpIHJldHVybiBuZXcgTWlncmF0aW9uRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoT2JzZXJ2ZXJFcnJvci5uYW1lKSkgcmV0dXJuIG5ldyBPYnNlcnZlckVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKEF1dGhvcml6YXRpb25FcnJvci5uYW1lKSlcbiAgICAgIHJldHVybiBuZXcgQXV0aG9yaXphdGlvbkVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKEZvcmJpZGRlbkVycm9yLm5hbWUpKSByZXR1cm4gbmV3IEZvcmJpZGRlbkVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKENvbm5lY3Rpb25FcnJvci5uYW1lKSlcbiAgICAgIHJldHVybiBuZXcgQ29ubmVjdGlvbkVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKFNlcmlhbGl6YXRpb25FcnJvci5uYW1lKSlcbiAgICAgIHJldHVybiBuZXcgU2VyaWFsaXphdGlvbkVycm9yKGVycikgYXMgRTtcbiAgICByZXR1cm4gbmV3IEludGVybmFsRXJyb3IoZXJyKSBhcyBFO1xuICB9XG59XG5cbkZhYnJpY0NsaWVudEFkYXB0ZXIuZGVjb3JhdGlvbigpO1xuQWRhcHRlci5zZXRDdXJyZW50KEZhYnJpY0ZsYXZvdXIpO1xuIiwiaW1wb3J0IHtcbiAgQWRhcHRlcixcbiAgQ29udGV4dHVhbEFyZ3MsXG4gIERpc3BhdGNoLFxuICBFdmVudElkcyxcbiAgVW5zdXBwb3J0ZWRFcnJvcixcbiAgQ29udGV4dCxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBQZWVyQ29uZmlnIH0gZnJvbSBcIi4uL3NoYXJlZC90eXBlc1wiO1xuaW1wb3J0IHsgQ2xpZW50IH0gZnJvbSBcIkBncnBjL2dycGMtanNcIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudEFkYXB0ZXIgfSBmcm9tIFwiLi9GYWJyaWNDbGllbnRBZGFwdGVyXCI7XG5pbXBvcnQge1xuICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMsXG4gIEludGVybmFsRXJyb3IsXG4gIE9wZXJhdGlvbktleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHtcbiAgQ2hhaW5jb2RlRXZlbnQsXG4gIENsb3NlYWJsZUFzeW5jSXRlcmFibGUsXG59IGZyb20gXCJAaHlwZXJsZWRnZXIvZmFicmljLWdhdGV3YXlcIjtcbmltcG9ydCB7IHBhcnNlRXZlbnROYW1lIH0gZnJvbSBcIi4uL3NoYXJlZC9ldmVudHNcIjtcbmltcG9ydCB7IE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudEZsYWdzIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRXZlbnQgZGlzcGF0Y2hlciBmb3IgSHlwZXJsZWRnZXIgRmFicmljIGNoYWluY29kZSBldmVudHNcbiAqIEBzdW1tYXJ5IExpc3RlbnMgZm9yIGFuZCBwcm9jZXNzZXMgZXZlbnRzIGVtaXR0ZWQgYnkgRmFicmljIGNoYWluY29kZSwgZGlzcGF0Y2hpbmcgdGhlbSB0byByZWdpc3RlcmVkIG9ic2VydmVyc1xuICogQHRlbXBsYXRlIFBlZXJDb25maWcgLSBDb25maWd1cmF0aW9uIHR5cGUgZm9yIGNvbm5lY3RpbmcgdG8gYSBGYWJyaWMgcGVlclxuICogQHBhcmFtIGNsaWVudCAtIGdSUEMgY2xpZW50IGZvciBjb25uZWN0aW5nIHRvIHRoZSBGYWJyaWMgbmV0d29ya1xuICogQGNsYXNzIEZhYnJpY0NsaWVudERpc3BhdGNoXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gQ3JlYXRlIGEgbmV3IEZhYnJpY0Rpc3BhdGNoIGluc3RhbmNlXG4gKiBjb25zdCBjbGllbnQgPSBhd2FpdCBGYWJyaWNBZGFwdGVyLmdldENsaWVudChwZWVyQ29uZmlnKTtcbiAqIGNvbnN0IGRpc3BhdGNoID0gbmV3IEZhYnJpY0Rpc3BhdGNoKGNsaWVudCk7XG4gKlxuICogLy8gQ29uZmlndXJlIHRoZSBkaXNwYXRjaCB3aXRoIHBlZXIgY29uZmlndXJhdGlvblxuICogZGlzcGF0Y2guY29uZmlndXJlKHBlZXJDb25maWcpO1xuICpcbiAqIC8vIFJlZ2lzdGVyIGFuIG9ic2VydmVyIGZvciBhIHNwZWNpZmljIHRhYmxlIGFuZCBldmVudFxuICogZGlzcGF0Y2gub2JzZXJ2ZSgndXNlcnMnLCAnY3JlYXRlJywgKGlkKSA9PiB7XG4gKiAgIGNvbnNvbGUubG9nKGBVc2VyIGNyZWF0ZWQ6ICR7aWR9YCk7XG4gKiB9KTtcbiAqXG4gKiAvLyBTdGFydCBsaXN0ZW5pbmcgZm9yIGV2ZW50c1xuICogYXdhaXQgZGlzcGF0Y2guc3RhcnQoKTtcbiAqIGBgYFxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgRmFicmljRGlzcGF0Y2hcbiAqICAgcGFydGljaXBhbnQgR2F0ZXdheVxuICogICBwYXJ0aWNpcGFudCBOZXR3b3JrXG4gKiAgIHBhcnRpY2lwYW50IENoYWluY29kZVxuICpcbiAqICAgQ2xpZW50LT4+RmFicmljRGlzcGF0Y2g6IG5ldyBGYWJyaWNEaXNwYXRjaChjbGllbnQpXG4gKiAgIENsaWVudC0+PkZhYnJpY0Rpc3BhdGNoOiBjb25maWd1cmUocGVlckNvbmZpZylcbiAqICAgQ2xpZW50LT4+RmFicmljRGlzcGF0Y2g6IG9ic2VydmUodGFibGUsIGV2ZW50LCBjYWxsYmFjaylcbiAqICAgQ2xpZW50LT4+RmFicmljRGlzcGF0Y2g6IHN0YXJ0KClcbiAqICAgRmFicmljRGlzcGF0Y2gtPj5GYWJyaWNEaXNwYXRjaDogaW5pdGlhbGl6ZSgpXG4gKiAgIEZhYnJpY0Rpc3BhdGNoLT4+R2F0ZXdheTogZ2V0R2F0ZXdheShjb25maWcsIGNsaWVudClcbiAqICAgR2F0ZXdheS0+Pk5ldHdvcms6IGdldE5ldHdvcmsoY2hhbm5lbClcbiAqICAgTmV0d29yay0+Pk5ldHdvcms6IGdldENoYWluY29kZUV2ZW50cyhjaGFpbmNvZGVOYW1lKVxuICogICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiBoYW5kbGVFdmVudHMoKVxuICogICBsb29wIEZvciBlYWNoIGV2ZW50XG4gKiAgICAgQ2hhaW5jb2RlLS0+PkZhYnJpY0Rpc3BhdGNoOiBDaGFpbmNvZGVFdmVudFxuICogICAgIEZhYnJpY0Rpc3BhdGNoLT4+RmFicmljRGlzcGF0Y2g6IHBhcnNlRXZlbnROYW1lKGV2ZW50TmFtZSlcbiAqICAgICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiBwYXJzZVBheWxvYWQocGF5bG9hZClcbiAqICAgICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiB1cGRhdGVPYnNlcnZlcnModGFibGUsIGV2ZW50LCBpZClcbiAqICAgICBGYWJyaWNEaXNwYXRjaC0tPj5DbGllbnQ6IGNhbGxiYWNrKGlkKVxuICogICBlbmRcbiAqL1xuZXhwb3J0IGNsYXNzIEZhYnJpY0NsaWVudERpc3BhdGNoIGV4dGVuZHMgRGlzcGF0Y2g8RmFicmljQ2xpZW50QWRhcHRlcj4ge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV2ZW50IGxpc3RlbmluZyBzdGFjayBmb3IgY2hhaW5jb2RlIGV2ZW50c1xuICAgKi9cbiAgcHJpdmF0ZSBsaXN0ZW5pbmdTdGFjaz86IENsb3NlYWJsZUFzeW5jSXRlcmFibGU8Q2hhaW5jb2RlRXZlbnQ+O1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGV4dCBkZWNvZGVyIGZvciBjb252ZXJ0aW5nIGV2ZW50IHBheWxvYWRzIGZyb20gYnl0ZXMgdG8gc3RyaW5nc1xuICAgKi9cbiAgcHJpdmF0ZSBkZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKFwidXRmOFwiKTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgRmFicmljRGlzcGF0Y2ggaW5zdGFuY2VcbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYSBkaXNwYXRjaGVyIGZvciBGYWJyaWMgY2hhaW5jb2RlIGV2ZW50c1xuICAgKiBAcGFyYW0ge0NsaWVudH0gY2xpZW50IC0gZ1JQQyBjbGllbnQgZm9yIGNvbm5lY3RpbmcgdG8gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgY2xpZW50OiBDbGllbnQpIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDbG9zZXMgdGhlIGV2ZW50IGxpc3RlbmluZyBjb25uZWN0aW9uXG4gICAqIEBzdW1tYXJ5IFN0b3BzIGxpc3RlbmluZyBmb3IgY2hhaW5jb2RlIGV2ZW50cyBhbmQgcmVsZWFzZXMgcmVzb3VyY2VzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZFxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgY2xvc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMubGlzdGVuaW5nU3RhY2spIHRoaXMubGlzdGVuaW5nU3RhY2suY2xvc2UoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUGFyc2VzIGV2ZW50IHBheWxvYWQgZnJvbSBiaW5hcnkgZm9ybWF0XG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIGEgVWludDhBcnJheSBjb250YWluaW5nIEpTT04gdG8gYW4gb2JqZWN0IHdpdGggYW4gaWQgcHJvcGVydHlcbiAgICogQHBhcmFtIHtVaW50OEFycmF5fSBqc29uQnl0ZXMgLSBUaGUgYmluYXJ5IHBheWxvYWQgZnJvbSB0aGUgY2hhaW5jb2RlIGV2ZW50XG4gICAqIEByZXR1cm4ge3sgaWQ6IHN0cmluZyB9fSBUaGUgcGFyc2VkIHBheWxvYWQgY29udGFpbmluZyB0aGUgcmVjb3JkIElEXG4gICAqL1xuICBwcml2YXRlIHBhcnNlUGF5bG9hZChqc29uQnl0ZXM6IFVpbnQ4QXJyYXkpOiB7IGlkOiBzdHJpbmcgfSB7XG4gICAgY29uc3QganNvbiA9IHRoaXMuZGVjb2Rlci5kZWNvZGUoanNvbkJ5dGVzKTtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShqc29uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU3RhcnRzIG9ic2VydmluZyBhbiBhZGFwdGVyXG4gICAqIEBzdW1tYXJ5IENvbm5lY3RzIHRoaXMgZGlzcGF0Y2ggdG8gYW4gYWRhcHRlciB0byBtb25pdG9yIGl0cyBvcGVyYXRpb25zXG4gICAqIEBwYXJhbSB7QWRhcHRlcjxhbnksIGFueSwgYW55LCBhbnk+fSBvYnNlcnZlciAtIFRoZSBhZGFwdGVyIHRvIG9ic2VydmVcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICovXG4gIG92ZXJyaWRlIG9ic2VydmUob2JzZXJ2ZXI6IEFkYXB0ZXI8YW55LCBhbnksIGFueSwgYW55Pik6ICgpID0+IHZvaWQge1xuICAgIGlmICghKG9ic2VydmVyIGluc3RhbmNlb2YgRmFicmljQ2xpZW50QWRhcHRlcikpXG4gICAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgICAgXCJPbmx5IEZhYnJpY0NsaWVudEFkYXB0ZXIgY2FuIGJlIG9ic2VydmVkIGJ5IGRpc3BhdGNoXCJcbiAgICAgICk7XG4gICAgc3VwZXIub2JzZXJ2ZShvYnNlcnZlciBhcyBGYWJyaWNDbGllbnRBZGFwdGVyKTtcbiAgICByZXR1cm4gKCkgPT4gdGhpcy51bk9ic2VydmUob2JzZXJ2ZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIG9ic2VydmVycyBhYm91dCBhIGRhdGFiYXNlIGV2ZW50XG4gICAqIEBzdW1tYXJ5IE5vdGlmaWVzIG9ic2VydmVycyBhYm91dCBhIGNoYW5nZSBpbiB0aGUgZGF0YWJhc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlIHdoZXJlIHRoZSBjaGFuZ2Ugb2NjdXJyZWRcbiAgICogQHBhcmFtIHtPcGVyYXRpb25LZXlzfEJ1bGtDcnVkT3BlcmF0aW9uS2V5c3xzdHJpbmd9IGV2ZW50IC0gVGhlIHR5cGUgb2Ygb3BlcmF0aW9uIHRoYXQgb2NjdXJyZWRcbiAgICogQHBhcmFtIHthbnl9IHBheWxvYWQgLSBUaGUgZXZlbnQgcGF5bG9hZFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBvYnNlcnZlcnMgaGF2ZSBiZWVuIG5vdGlmaWVkXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyB1cGRhdGVPYnNlcnZlcnMoXG4gICAgbW9kZWw6IENvbnN0cnVjdG9yPGFueT4gfCBzdHJpbmcsXG4gICAgZXZlbnQ6IE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmcsXG4gICAgaWQ6IEV2ZW50SWRzLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gQWRhcHRlci5sb2dDdHg8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+KFxuICAgICAgdGhpcy51cGRhdGVPYnNlcnZlcnMsXG4gICAgICBldmVudCxcbiAgICAgIGZhbHNlLFxuICAgICAgLi4uYXJnc1xuICAgICk7XG4gICAgaWYgKCF0aGlzLmFkYXB0ZXIpIHtcbiAgICAgIGxvZy52ZXJib3NlKFxuICAgICAgICBgTm8gYWRhcHRlciBvYnNlcnZlZCBmb3IgZGlzcGF0Y2g7IHNraXBwaW5nIG9ic2VydmVyIHVwZGF0ZSBmb3IgJHt0eXBlb2YgbW9kZWwgPT09IFwic3RyaW5nXCIgPyBtb2RlbCA6IE1vZGVsLnRhYmxlTmFtZShtb2RlbCl9OiR7ZXZlbnR9YFxuICAgICAgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuYWRhcHRlci5yZWZyZXNoKG1vZGVsLCBldmVudCwgaWQsIC4uLmN0eEFyZ3MpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBGYWlsZWQgdG8gcmVmcmVzaCBkaXNwYXRjaDogJHtlfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJvY2Vzc2VzIGluY29taW5nIGNoYWluY29kZSBldmVudHNcbiAgICogQHN1bW1hcnkgTGlzdGVucyBmb3IgZXZlbnRzIGZyb20gdGhlIGNoYWluY29kZSBhbmQgZGlzcGF0Y2hlcyB0aGVtIHRvIHJlZ2lzdGVyZWQgb2JzZXJ2ZXJzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGV2ZW50IGhhbmRsaW5nIHN0b3BzXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEZhYnJpY0Rpc3BhdGNoXG4gICAqICAgcGFydGljaXBhbnQgRXZlbnRTdGFja1xuICAgKiAgIHBhcnRpY2lwYW50IEV2ZW50UGFyc2VyXG4gICAqICAgcGFydGljaXBhbnQgT2JzZXJ2ZXJzXG4gICAqXG4gICAqICAgRmFicmljRGlzcGF0Y2gtPj5GYWJyaWNEaXNwYXRjaDogaGFuZGxlRXZlbnRzKClcbiAgICogICBGYWJyaWNEaXNwYXRjaC0+PkV2ZW50U3RhY2s6IGZvciBhd2FpdCAoY29uc3QgZXZ0IG9mIGxpc3RlbmluZ1N0YWNrKVxuICAgKiAgIEV2ZW50U3RhY2stLT4+RmFicmljRGlzcGF0Y2g6IENoYWluY29kZUV2ZW50XG4gICAqICAgRmFicmljRGlzcGF0Y2gtPj5FdmVudFBhcnNlcjogcGFyc2VFdmVudE5hbWUoZXZ0LmV2ZW50TmFtZSlcbiAgICogICBFdmVudFBhcnNlci0tPj5GYWJyaWNEaXNwYXRjaDogeyB0YWJsZSwgZXZlbnQsIG93bmVyIH1cbiAgICogICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiBDaGVjayBpZiBldmVudCBpcyBmb3IgdGhpcyBNU1BcbiAgICogICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiBwYXJzZVBheWxvYWQoZXZ0LnBheWxvYWQpXG4gICAqICAgRmFicmljRGlzcGF0Y2gtPj5PYnNlcnZlcnM6IHVwZGF0ZU9ic2VydmVycyh0YWJsZSwgZXZlbnQsIHBheWxvYWQuaWQpXG4gICAqICAgT2JzZXJ2ZXJzLS0+PkZhYnJpY0Rpc3BhdGNoOiBDYWxsYmFja3MgZXhlY3V0ZWRcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBoYW5kbGVFdmVudHMoXG4gICAgY3R4QXJnPzogQ29udGV4dDxGYWJyaWNDbGllbnRGbGFncz5cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmxpc3RlbmluZ1N0YWNrKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBFdmVudCBzdGFjayBub3QgaW5pdGlhbGl6ZWQuIEVuc3VyZSB0aGF0IFwic3RhcnRMaXN0ZW5pbmdcIiBpcyBjYWxsZWQgYmVmb3JlIGF0dGVtcHRpbmcgdGhpcyBvcGVyYXRpb24uYFxuICAgICAgKTtcblxuICAgIGlmICghdGhpcy5hZGFwdGVyIHx8ICF0aGlzLmFkYXB0ZXIuY29uZmlnKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYE5vIGFkYXB0ZXIgZm91bmQuIHNob3VsZCBiZSBpbXBvc3NpYmxlYCk7XG5cbiAgICBjb25zdCBjdHggPVxuICAgICAgY3R4QXJnIHx8XG4gICAgICAoYXdhaXQgdGhpcy5hZGFwdGVyLmNvbnRleHQoXG4gICAgICAgIE9wZXJhdGlvbktleXMuUkVBRCxcbiAgICAgICAge1xuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHRoaXMuYWRhcHRlci5jb25maWcuY2hhaW5jb2RlTmFtZSxcbiAgICAgICAgfSxcbiAgICAgICAgKHRoaXMubW9kZWxzICYmIHRoaXMubW9kZWxzWzBdKSB8fCAoTW9kZWwgYXMgdW5rbm93biBhcyBDb25zdHJ1Y3RvcilcbiAgICAgICkpO1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmhhbmRsZUV2ZW50cyk7XG5cbiAgICBsb2cuaW5mbyhcbiAgICAgIGBMaXN0ZW5pbmcgZm9yIGluY29taW5nIGV2ZW50cyBvbiBjaGFpbmNvZGUgXCIke3RoaXMuYWRhcHRlci5jb25maWcuY2hhaW5jb2RlTmFtZX1cIiBvbiBjaGFubmVsIFwiJHt0aGlzLmFkYXB0ZXIuY29uZmlnLmNoYW5uZWx9XCIuLi5gXG4gICAgKTtcblxuICAgIHRyeSB7XG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IGV2dCBvZiB0aGlzLmxpc3RlbmluZ1N0YWNrKSB7XG4gICAgICAgIGNvbnN0IHsgdGFibGUsIGV2ZW50LCBvd25lciB9ID0gcGFyc2VFdmVudE5hbWUoZXZ0LmV2ZW50TmFtZSk7XG4gICAgICAgIGlmIChvd25lciAmJiBvd25lciAhPT0gdGhpcy5hZGFwdGVyLmNvbmZpZz8ubXNwSWQpIGNvbnRpbnVlO1xuICAgICAgICBjb25zdCBwYXlsb2FkOiB7IGlkOiBzdHJpbmcgfSA9IHRoaXMucGFyc2VQYXlsb2FkKGV2dC5wYXlsb2FkKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCB0YXJnZXRNb2RlbCA9IHRhYmxlXG4gICAgICAgICAgICA/IE1vZGVsLmdldCh0YWJsZSlcbiAgICAgICAgICAgIDogTW9kZWwuZ2V0KHRoaXMubW9kZWxzWzBdLm5hbWUpO1xuICAgICAgICAgIGNvbnN0IG1vZGVsUmVmID0gdGFyZ2V0TW9kZWwgPz8gKHRhYmxlIHx8IHRoaXMubW9kZWxzWzBdPy5uYW1lKTtcbiAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZU9ic2VydmVycyhcbiAgICAgICAgICAgIG1vZGVsUmVmIGFzIENvbnN0cnVjdG9yIHwgc3RyaW5nLFxuICAgICAgICAgICAgZXZlbnQsXG4gICAgICAgICAgICBwYXlsb2FkLmlkIGFzIHN0cmluZyxcbiAgICAgICAgICAgIGN0eFxuICAgICAgICAgICk7XG4gICAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgICBsb2cuZXJyb3IoXG4gICAgICAgICAgICBgRmFpbGVkIHVwZGF0ZSBvYnNlcnZhYmxlcyBmb3IgdGFibGUgJHt0YWJsZX0gZXZlbnQgJHtldmVudH0gaWQ6ICR7cGF5bG9hZC5pZH06ICR7ZX1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgbG9nLmVycm9yKFxuICAgICAgICBgRmFpbGVkIHRvIHJlYWQgZXZlbnQgZm9yIGNoYWluY29kZSBcIiR7dGhpcy5hZGFwdGVyLmNvbmZpZy5jaGFpbmNvZGVOYW1lfVwiIG9uIGNoYW5uZWwgXCIke3RoaXMuYWRhcHRlci5jb25maWcuY2hhbm5lbH1cIjogJHtlfWBcbiAgICAgICk7XG4gICAgICBhd2FpdCB0aGlzLmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBJbml0aWFsaXplcyB0aGUgZXZlbnQgbGlzdGVuZXJcbiAgICogQHN1bW1hcnkgU2V0cyB1cCB0aGUgY29ubmVjdGlvbiB0byB0aGUgRmFicmljIG5ldHdvcmsgYW5kIHN0YXJ0cyBsaXN0ZW5pbmcgZm9yIGNoYWluY29kZSBldmVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gaW5pdGlhbGl6YXRpb24gaXMgY29tcGxldGVcbiAgICovXG4gIHByb3RlY3RlZCBvdmVycmlkZSBhc3luYyBpbml0aWFsaXplKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5hZGFwdGVyKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYE5vIGFkYXB0ZXIgb3IgY29uZmlnIG9ic2VydmVkIGZvciBkaXNwYXRjaGApO1xuICAgIGNvbnN0IGNvbnRleHQgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuY29udGV4dChcbiAgICAgIFwiZGlzcGF0Y2hcIixcbiAgICAgIHtcbiAgICAgICAgY29ycmVsYXRpb25JZDogdGhpcy5hZGFwdGVyLmNvbmZpZy5jaGFpbmNvZGVOYW1lLFxuICAgICAgfSxcbiAgICAgIE1vZGVsIGFzIGFueVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5pbml0aWFsaXplKTtcbiAgICBjb25zdCBnYXRld2F5ID0gYXdhaXQgRmFicmljQ2xpZW50QWRhcHRlci5nZXRHYXRld2F5KFxuICAgICAgY3R4LFxuICAgICAgdGhpcy5hZGFwdGVyLmNvbmZpZyBhcyBQZWVyQ29uZmlnLFxuICAgICAgdGhpcy5jbGllbnRcbiAgICApO1xuICAgIGNvbnN0IG5ldHdvcmsgPSBnYXRld2F5LmdldE5ldHdvcmsodGhpcy5hZGFwdGVyLmNvbmZpZy5jaGFubmVsKTtcbiAgICBpZiAoIXRoaXMuYWRhcHRlcilcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBObyBhZGFwdGVyIG9ic2VydmVkIGZvciBkaXNwYXRjaGApO1xuICAgIHRoaXMubGlzdGVuaW5nU3RhY2sgPSBhd2FpdCBuZXR3b3JrLmdldENoYWluY29kZUV2ZW50cyhcbiAgICAgIHRoaXMuYWRhcHRlci5jb25maWcuY2hhaW5jb2RlTmFtZVxuICAgICk7XG4gICAgdGhpcy5oYW5kbGVFdmVudHMoY3R4KTtcbiAgfVxufVxuXG5pZiAoRmFicmljQ2xpZW50QWRhcHRlcilcbiAgRmFicmljQ2xpZW50QWRhcHRlcltcIl9iYXNlRGlzcGF0Y2hcIl0gPSBGYWJyaWNDbGllbnREaXNwYXRjaDtcbiIsImltcG9ydCB7IE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gXCIjI1ZFUlNJT04jI1wiO1xuZXhwb3J0IGNvbnN0IFBBQ0tBR0VfTkFNRSA9IFwiIyNQQUNLQUdFIyNcIjtcblxuTWV0YWRhdGEucmVnaXN0ZXJMaWJyYXJ5KFBBQ0tBR0VfTkFNRSwgVkVSU0lPTik7XG4iXSwibmFtZXMiOlsiRmFicmljQ2xpZW50UmVwb3NpdG9yeSIsIlJlcG9zaXRvcnkiLCJjb25zdHJ1Y3RvciIsImFkYXB0ZXIiLCJjbGF6eiIsInN1cGVyIiwidGhpcyIsIl9vdmVycmlkZXMiLCJPYmplY3QiLCJhc3NpZ24iLCJpZ25vcmVWYWxpZGF0aW9uIiwiaWdub3JlSGFuZGxlcnMiLCJhbGxvd1Jhd1N0YXRlbWVudHMiLCJmb3JjZVByZXBhcmVTaW1wbGVRdWVyaWVzIiwiZm9yY2VQcmVwYXJlQ29tcGxleFF1ZXJpZXMiLCJhbGxvd0dlbmVyYXRpb25PdmVycmlkZSIsInBhZ2luYXRlQnkiLCJrZXkiLCJvcmRlciIsInJlZiIsIm9mZnNldCIsImxpbWl0IiwiYXJncyIsImxvZyIsImN0eEFyZ3MiLCJsb2dDdHgiLCJQcmVwYXJlZFN0YXRlbWVudEtleXMiLCJQQUdFX0JZIiwiZm9yIiwidmVyYm9zZSIsIk1vZGVsIiwidGFibGVOYW1lIiwiY2xhc3MiLCJzdGF0ZW1lbnQiLCJuYW1lIiwiYm9va21hcmsiLCJsaXN0QnkiLCJMSVNUX0JZIiwiZmluZEJ5IiwidmFsdWUiLCJGSU5EX0JZIiwiZmluZE9uZUJ5IiwiRklORF9PTkVfQlkiLCJjdHgiLCJQZXJzaXN0ZW5jZUtleXMiLCJTVEFURU1FTlQiLCJjYWxsQXJncyIsInNsaWNlIiwicmVzdWx0IiwiSlNPTiIsInBhcnNlIiwiZGVjb2RlIiwiZXZhbHVhdGVUcmFuc2FjdGlvbiIsInN0cmluZ2lmeSIsInVuZGVmaW5lZCIsIkFycmF5IiwiaXNBcnJheSIsIm1hcCIsInIiLCJDb3VjaERCS2V5cyIsIlRBQkxFIiwiUGFnaW5hdG9yIiwiaXNTZXJpYWxpemVkUGFnZSIsImRhdGEiLCJkIiwiY3JlYXRlIiwibW9kZWwiLCJkZWJ1ZyIsInJlY29yZCIsImlkIiwidHJhbnNpZW50IiwicHJlcGFyZSIsInJldmVydCIsInVwZGF0ZSIsImNyZWF0ZUFsbFByZWZpeCIsIm1vZGVscyIsIk9wZXJhdGlvbktleXMiLCJDUkVBVEUiLCJnZXQiLCJpZ25vcmVWYWxpZGF0ZSIsImxlbmd0aCIsIlByb21pc2UiLCJhbGwiLCJhc3luYyIsIm0iLCJlbmZvcmNlREJEZWNvcmF0b3JzIiwiT04iLCJpZ25vcmVkUHJvcHMiLCJlcnJvcnMiLCJyZXNvbHZlIiwiaGFzRXJyb3JzIiwiZXJyb3JNZXNzYWdlcyIsInJlZHVjZUVycm9yc1RvUHJpbnQiLCJWYWxpZGF0aW9uRXJyb3IiLCJjcmVhdGVBbGwiLCJwcmVwYXJlZCIsImlkcyIsInAiLCJyZWNvcmRzIiwiaSIsInVwZGF0ZUFsbCIsInVwZGF0ZWQiLCJ1IiwiRVJDMjBUb2tlbiIsIkJhc2VNb2RlbCIsIl9fZGVjb3JhdGUiLCJwayIsInR5cGUiLCJTdHJpbmciLCJwcm90b3R5cGUiLCJjb2x1bW4iLCJyZXF1aXJlZCIsInRhYmxlIiwiRVJDMjBXYWxsZXQiLCJBbGxvd2FuY2UiLCJDbGllbnRTZXJpYWxpemVyIiwiSlNPTlNlcmlhbGl6ZXIiLCJwcmVTZXJpYWxpemUiLCJtb2RlbE5hbWUiLCJ0b1NlcmlhbGl6ZSIsIm1ldGFkYXRhIiwiTWV0YWRhdGEiLCJTZXJpYWxpemF0aW9uRXJyb3IiLCJNb2RlbEtleXMiLCJBTkNIT1IiLCJkZXNlcmlhbGl6ZSIsInN0ciIsImRlc2VyaWFsaXphdGlvbiIsImNsYXNzTmFtZSIsIkVycm9yIiwiYnVpbGQiLCJzZXJpYWxpemUiLCJGYWJyaWNFUkMyMENsaWVudFJlcG9zaXRvcnkiLCJzZXJpYWxpemVyIiwiZGVjb2RlciIsIlRleHREZWNvZGVyIiwidXBkYXRlT2JzZXJ2ZXJzIiwiZXZlbnQiLCJvYnNlcnZlckhhbmRsZXIiLCJJbnRlcm5hbEVycm9yIiwiY291bnQiLCJwYXJzZWRJZCIsIlNlcXVlbmNlIiwicGFyc2VWYWx1ZSIsInNlcXVlbmNlRm9yIiwidG9rZW5OYW1lIiwic3ltYm9sIiwiZGVjaW1hbHMiLCJOdW1iZXIiLCJ0b3RhbFN1cHBseSIsInRvdGFsIiwiYmFsYW5jZU9mIiwib3duZXIiLCJiYWxhbmNlIiwidHJhbnNmZXIiLCJ0byIsInRyYW5zZmVycmVkIiwic3VibWl0VHJhbnNhY3Rpb24iLCJ0b1N0cmluZyIsInRyYW5zZmVyRnJvbSIsImZyb20iLCJjb250ZXh0QXJncyIsIkNvbnRleHQiLCJhcHByb3ZlIiwic3BlbmRlciIsImFwcHJvdmVkIiwiYWxsb3dhbmNlIiwiaW5pdGlhbGl6ZSIsInRva2VuIiwiaW5pdGlsaWF6ZWQiLCJjaGVja0luaXRpYWxpemVkIiwibWludCIsImFtb3VudCIsImJ1cm4iLCJidXJuRnJvbSIsImFjY291bnQiLCJjbGllbnRBY2NvdW50QmFsYW5jZSIsInNlcmlhbGl6ZWRBY2NvdW50QmFsYW5jZSIsImNsaWVudEFjY291bnRJRCIsImdldEluZGV4UmVmZXJlbmNlIiwiZGlyZWN0aW9uIiwiY29tcG9zaXRpb25zIiwibiIsImpvaW4iLCJzcGxpdHRlciIsImFkZEluZGV4IiwiYWNjdW0iLCJmaWVsZHMiLCJ0YWJsZUZpZWxkIiwicG9wIiwicHVzaCIsInVuc2hpZnQiLCJmIiwicmVkdWNlIiwiZWwiLCJlbnRyeSIsImluZGV4IiwiZGRvYyIsImdlbmVyYXRlTW9kZWxJbmRleGVzIiwiaW5kZXhlcyIsIm1vZGVsSW5kZXhlcyIsInByb3AiLCJrZXlzIiwiZGVjIiwiZW50cmllcyIsImRpcmVjdGlvbnMiLCJmb3JFYWNoIiwidmFsdWVzIiwicmVhZE1vZGVsRmlsZSIsImZpbGUiLCJwYXRoIiwicmVxdWlyZSIsImV4cG9ydHMiLCJwcm9jZXNzIiwiY3dkIiwicGFyZW50UGF0aCIsImZpbHRlciIsImUiLCJyZWFkTW9kZWxGb2xkZXJzIiwiZm9sZGVycyIsImZzIiwiZm9sZGVyIiwiZmlsZXMiLCJyZWFkZGlyU3luYyIsIndpdGhGaWxlVHlwZXMiLCJyZWN1cnNpdmUiLCJpc0ZpbGUiLCJlbmRzV2l0aCIsIndyaXRlSW5kZXhlcyIsImNvbGxlY3Rpb24iLCJlbnN1cmVEaXJlY3RvcnlFeGlzdGVuY2UiLCJmaWxlUGF0aCIsImRpcm5hbWUiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwid3JpdGVGaWxlU3luYyIsIklkZW50aXR5Q3JlZGVudGlhbHMiLCJhcmciLCJkZXNjcmlwdGlvbiIsIkZhYnJpY01vZGVsS2V5cyIsIklkZW50aXR5VHlwZSIsIkZhYnJpY0ZsYXZvdXIiLCJJZGVudGl0eSIsIlg1MDkiLCJvbmVUb09uZSIsIkNhc2NhZGUiLCJDQVNDQURFIiwiZGVsZXRlIiwiQ29yZVV0aWxzIiwibG9nZ2VyIiwiTWluaUxvZ2dlciIsImNvbnRlbnRPZkxvYWRGaWxlIiwiY29udGVudE9yUGF0aCIsImZpbGVSZWFkZXIiLCJVaW50OEFycmF5IiwibWF0Y2giLCJyZWFkRmlsZSIsInByb21pc2VzIiwibm9ybWFsaXplSW1wb3J0IiwiaW1wb3J0IiwiZ2V0Q0FVc2VyIiwidXNlck5hbWUiLCJwcml2YXRlS2V5IiwiY2VydGlmaWNhdGUiLCJtc3BJZCIsIm9wdGlvbnMiLCJzdHJpbmdGb3JtYXQiLCJ1c2VyIiwiVXNlciIsImNvbmZpZyIsImhzbSIsInNvZnR3YXJlIiwibGliIiwibGlicmFyeSIsInNsb3QiLCJsYWJlbCIsInRva2VuTGFiZWwiLCJwaW4iLCJjcnlwdG9TdWl0ZSIsImdldENyeXB0b1N1aXRlIiwic2V0Q3J5cHRvU3VpdGUiLCJlbnJvbGxtZW50S2V5IiwiZ2V0SFNNRW5yb2xsbWVudEtleSIsImdldFNvZnR3YXJlRW5yb2xsbWVudEtleSIsInNldEVucm9sbG1lbnQiLCJuZXdDcnlwdG9TdWl0ZSIsImNyZWF0ZUtleUZyb21SYXciLCJza2kiLCJrZXlJZEhleCIsInRyaW0iLCJCdWZmZXIiLCJnZXRDZXJ0aWZpY2F0ZVNLSSIsImdldEtleSIsImlzUHJpdmF0ZSIsIng1MDkiLCJYNTA5Q2VydGlmaWNhdGUiLCJqd2siLCJwdWJsaWNLZXkiLCJleHBvcnQiLCJmb3JtYXQiLCJwcmVmaXgiLCJ4IiwieSIsImNyeXB0byIsImNyZWF0ZUhhc2giLCJjb25jYXQiLCJkaWdlc3QiLCJnZXRJZGVudGl0eSIsImNlcnREaXJlY3RvcnlQYXRoIiwiaWRlbnRpdHlGaWxlUmVhZGVyIiwiY2VydFBhdGgiLCJnZXRGaXJzdERpckZpbGVOYW1lIiwiY3JlZGVudGlhbHMiLCJkaXJQYXRoIiwicmVhZGRpciIsImdldEZpcnN0RGlyRmlsZU5hbWVDb250ZW50IiwiZ2V0RmlsZUNvbnRlbnQiLCJnZXRTaWduZXIiLCJrZXlEaXJlY3RvcnlQYXRoIiwic2lnbmVyRmlsZVJlYWRlciIsImtleVBhdGgiLCJwcml2YXRlS2V5UGVtIiwiZXh0cmFjdFByaXZhdGVLZXkiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJrIiwic2lnbmVycyIsIm5ld1ByaXZhdGVLZXlTaWduZXIiLCJwZW0iLCJsaWJOYW1lIiwic3VidGxlIiwiZ2xvYmFsVGhpcyIsIndpbmRvdyIsIkNyeXB0byIsIndlYmNyeXB0byIsInN0cjJhYiIsImJ1ZiIsIkFycmF5QnVmZmVyIiwiYnVmVmlldyIsInN0ckxlbiIsImNoYXJDb2RlQXQiLCJyZXBsYWNlIiwicmVwbGFjZUFsbCIsImRlY29kZWQiLCJiaW5hcnlEZXIiLCJpbXBvcnRLZXkiLCJuYW1lZEN1cnZlIiwiY3J5cHRvUHJvdmlkZXIiLCJzZXQiLCJCQVNFX0FMUEhBQkVUIiwiQ1JZUFRPIiwiQmFzZUVuY29kZXIiLCJhbHBoYWJldCIsImJhc2VNYXAiLCJqIiwiY2hhckF0IiwieGMiLCJiYXNlIiwibGVhZGVyIiwiZmFjdG9yIiwiTWF0aCIsImlGYWN0b3IiLCJlbmNvZGUiLCJzb3VyY2UiLCJpc1ZpZXciLCJidWZmZXIiLCJieXRlT2Zmc2V0IiwiYnl0ZUxlbmd0aCIsInplcm9lcyIsInBiZWdpbiIsInBlbmQiLCJzaXplIiwiYjU4IiwiY2FycnkiLCJpdDEiLCJpdDIiLCJyZXBlYXQiLCJkZWNvZGVVbnNhZmUiLCJwc3oiLCJiMjU2IiwiaXQzIiwiaXQ0IiwidmNoIiwiQ3J5cHRvVXRpbHMiLCJiNThlbmNvZGVyIiwiQkFTRTU4IiwiZmFicmljSWRGcm9tQ2VydGlmaWNhdGUiLCJjZXJ0Iiwic3ViamVjdCIsImlzc3VlciIsInN0cmluZ1RvQXJyYXlCdWZmZXIiLCJleHRyYWN0S2V5IiwidXNhZ2VzIiwiUmVnRXhwIiwidG9VcHBlckNhc2UiLCJleHRyYWN0UHVibGljS2V5Iiwic2lnbiIsImJ1ZmYiLCJoYXNoIiwiYiIsInBhZFN0YXJ0IiwidmVyaWZ5Iiwic2lnbmF0dXJlIiwiZW5jcnlwdCIsImdldFN1YnRsZUNyeXB0byIsImlzQnJvd3NlciIsImRlY3J5cHQiLCJnZXRNYXN0ZXIiLCJ0ZXh0RW5jb2RlciIsIlRleHRFbmNvZGVyIiwiZ2VuR2VuZXNpcyIsInJhbmRvbVVVSUQiLCJpbXBvcnRlZEtleSIsIktFWV9BTEdPUllUSE0iLCJpdiIsImdldERlcml2YXRpb25LZXkiLCJzYWx0Iiwic2FsdEJ1ZmZlciIsInNhbHRIYXNoZWQiLCJwYXJhbXMiLCJIQVNIIiwiaXRlcmF0aW9ucyIsIklURVJBVElPTlMiLCJkZXJpdmF0aW9uIiwiZGVyaXZlQml0cyIsIktFWUxFTkdUSCIsIml2bGVuIiwia2V5bGVuIiwiZGVyaXZlZEtleSIsImltcG9ydGVkRW5jcnlwdGlvbktleSIsIkFMR09SWVRITSIsImVuY3J5cHRQaW4iLCJ0ZXh0Iiwia2V5T2JqZWN0IiwidGV4dEJ1ZmZlciIsImVuY3J5cHRlZFRleHQiLCJkZWNyeXB0UGluIiwidGV4dERlY29kZXIiLCJkZWNyeXB0ZWRUZXh0IiwiT3ZlcmZsb3dFcnJvciIsIm1zZyIsIkJhbGFuY2VFcnJvciIsIkFsbG93YW5jZUVycm9yIiwiUmVnaXN0cmF0aW9uRXJyb3IiLCJBdXRob3JpemF0aW9uRXJyb3IiLCJNaXNzaW5nQ29udGV4dEVycm9yIiwiVW5hdXRob3JpemVkUHJpdmF0ZURhdGFBY2Nlc3MiLCJCYXNlRXJyb3IiLCJOb3RJbml0aWFsaXplZEVycm9yIiwiTWlzc2luZ1BLQ1NTMTFMaWIiLCJFbmRvcnNlbWVudEVycm9yIiwibWVzc2FnZSIsIk12Y2NSZWFkQ29uZmxpY3RFcnJvciIsIlBoYW50b21SZWFkQ29uZmxpY3RFcnJvciIsIkVuZG9yc2VtZW50UG9saWN5RXJyb3IiLCJIRkNBSWRlbnRpdHlUeXBlIiwiSEZDQUlkZW50aXR5QXR0cmlidXRlcyIsIkZhYnJpY0Vucm9sbG1lbnRTZXJ2aWNlIiwiTG9nZ2VkQ2xhc3MiLCJjYUNvbmZpZyIsImNhTmFtZSIsImNhQ2VydCIsImNhS2V5IiwidXJsIiwiQ0EiLCJjYSIsInRscyIsInRydXN0ZWRSb290cyIsInJvb3QiLCJGYWJyaWNDQVNlcnZpY2VzIiwiQ2xpZW50IiwiY2xpZW50IiwiQ2VydGlmaWNhdGUiLCJjZXJ0aWZpY2F0ZVNlcnZpY2UiLCJuZXdDZXJ0aWZpY2F0ZVNlcnZpY2UiLCJBZmZpbGlhdGlvbnMiLCJhZmZpbGlhdGlvblNlcnZpY2UiLCJuZXdBZmZpbGlhdGlvblNlcnZpY2UiLCJJZGVudGl0aWVzIiwiaWRlbnRpdHlTZXJ2aWNlIiwibmV3SWRlbnRpdHlTZXJ2aWNlIiwiZ2V0Q2VydGlmaWNhdGVzIiwicmVxdWVzdCIsImRvTWFwIiwicmVzcG9uc2UiLCJjZXJ0cyIsImMiLCJQRU0iLCJnZXRJZGVudGl0aWVzIiwiaWRlbnRpdGllc1NlcnZpY2UiLCJnZXRBbGwiLCJpZGVudGl0aWVzIiwicGFyc2VFcnJvciIsInJlZ2V4cCIsImV4ZWMiLCJjb2RlIiwiQ29uZmxpY3RFcnJvciIsImdldEFmZmlsaWF0aW9ucyIsImEiLCJyZWFkIiwiZW5yb2xsbWVudElkIiwiZ2V0T25lIiwiTm90Rm91bmRFcnJvciIsInN1Y2Nlc3MiLCJyZWdpc3RlciIsImlzU3VwZXJVc2VyIiwiYWZmaWxpYXRpb24iLCJ1c2VyUm9sZSIsImF0dHJzIiwibWF4RW5yb2xsbWVudHMiLCJyZWdpc3RyYXRpb24iLCJwYXNzd29yZCIsInByb3BzIiwiZW5yb2xsbWVudElEIiwiZW5yb2xsbWVudFNlY3JldCIsImluZm8iLCJpZGVudGl0eUZyb21FbnJvbGxtZW50IiwiZW5yb2xsbWVudCIsInJvb3RDZXJ0aWZpY2F0ZSIsIkxvZ2dpbmciLCJjbGllbnRJZCIsIm5vdyIsIkRhdGUiLCJ0b0J5dGVzIiwiY3JlYXRlZE9uIiwidXBkYXRlZE9uIiwiZW5yb2xsIiwiaWRlbnRpdHkiLCJyZWdpc3RlckFuZEVucm9sbCIsInJldm9rZSIsInJlYXNvbiIsIlJlZ2lzdHJhdGlvblJlcXVlc3RCdWlsZGVyIiwiZXJycyIsInJvbGUiLCJzZXRBZmZpbGlhdGlvbiIsImFkZEF0dHIiLCJhdHRyIiwic2V0QXR0cnMiLCJzZXRFbnJvbGxtZW50SUQiLCJzZXRFbnJvbGxtZW50U2VjcmV0Iiwic2V0TWF4RW5yb2xsbWVudHMiLCJzZXRSb2xlIiwibWlubGVuZ3RoIiwibWluIiwiRVJDMjBFdmVudHMiLCJGYWJyaWNCYXNlTW9kZWwiLCJjcmVhdGVkQXQiLCJ1cGRhdGVkQXQiLCJ2ZXJzaW9uIiwidXNlcyIsIkZhYnJpY0lkZW50aWZpZWRCYXNlTW9kZWwiLCJjcmVhdGVkQnkiLCJ1cGRhdGVkQnkiLCJpc1NoYXJlZCIsInNlZ3JlZ2F0ZSIsImlzVHJhbnNpZW50IiwiZGVjb3JhdGVkUHJvcGVydGllcyIsInZhbGlkYXRhYmxlUHJvcGVydGllcyIsInRyYW5zaWVudFByb3BzIiwiREJLZXlzIiwiVFJBTlNJRU5UIiwicHJpdmF0ZVByb3BlcnRpZXMiLCJQUklWQVRFIiwic2hhcmVkUHJvcGVydGllcyIsInByaXZhdGUiLCJzaGFyZWQiLCJ0cmFuc2llbnRLZXlzIiwicHJpdmF0ZUtleXMiLCJzaGFyZWRLZXlzIiwiaW5jbHVkZXMiLCJiaW5kIiwiU0hBUkVEIiwibWlycm9yZWQiLCJGQUJSSUMiLCJNSVJST1IiLCJvd25lck9mIiwibWV0YSIsIk9XTkVEX0JZIiwibWlycm9yZWRBdCIsImNvbGxlY3Rpb25zRm9yIiwic2hhcmVkS2V5IiwiY29uc3RyIiwicHJpdmF0ZU1ldGEiLCJzaGFyZWRNZXRhIiwicHJpdmF0ZUNvbHMiLCJjb2xsZWN0aW9ucyIsInNoYXJlZENvbHMiLCJPd25lciIsInRhcmdldCIsInByb3BlcnR5S2V5IiwiZGVzY3JpcHRvciIsIm9yaWdpbmFsTWV0aG9kIiwiYWNvdW50SWQiLCJjbGllbnRJZGVudGl0eSIsImdldElEIiwic2VsZWN0IiwidG9rZW5zIiwiZXhlY3V0ZSIsImFwcGx5Iiwib3duZWRCeU9uQ3JlYXRlIiwiY29udGV4dCIsInN0dWIiLCJjcmVhdG9yIiwiZ2V0Q3JlYXRvciIsIm1zcGlkIiwic2V0T3duZWRCeUtleVZhbHVlIiwiZGVmaW5lUHJvcGVydHkiLCJlbnVtZXJhYmxlIiwid3JpdGFibGUiLCJjb25maWd1cmFibGUiLCJvd25lZEJ5Iiwib2JqIiwiYXR0cmlidXRlIiwicmVhZG9ubHkiLCJvbkNyZWF0ZSIsInByb3BNZXRhZGF0YSIsIkRlY29yYXRpb24iLCJkZWZpbmUiLCJkZWNvcmF0b3IiLCJ0cmFuc2FjdGlvbklkT25DcmVhdGUiLCJnZXRUeElEIiwidHJhbnNhY3Rpb25JZCIsIm9uVXBkYXRlIiwiVFJBTlNBQ1RJT05fSUQiLCJldmFsTWlycm9yTWV0YWRhdGEiLCJyZXNvbHZlciIsImNyZWF0ZU1pcnJvckhhbmRsZXIiLCJyZXBvIiwib3ZlcnJpZGUiLCJtaXJyb3IiLCJ1cGRhdGVNaXJyb3JIYW5kbGVyIiwiZGVsZXRlTWlycm9ySGFuZGxlciIsImNvbmRpdGlvbiIsInByaXZhdGVEYXRhIiwiYWZ0ZXJDcmVhdGUiLCJwcmlvcml0eSIsImFmdGVyVXBkYXRlIiwiYWZ0ZXJEZWxldGUiLCJNb2RlbENvbGxlY3Rpb24iLCJvcmdOYW1lIiwidG9QYXNjYWxDYXNlIiwiSW1wbGljaXRQcml2YXRlQ29sbGVjdGlvbiIsInNlZ3JlZ2F0ZWREYXRhT25DcmVhdGUiLCJtc3AiLCJjb2xsZWN0aW9uUmVzb2x2ZXIiLCJyZWJ1aWx0IiwiYWNjIiwiVW5zdXBwb3J0ZWRFcnJvciIsInRvQ3JlYXRlIiwiY3JlYXRlZCIsInNlZ3JlZ2F0ZWQiLCJtZXJnZU1vZGVsIiwic2VncmVnYXRlZERhdGFPblJlYWQiLCJzZWdyZWdhdGVkRGF0YU9uVXBkYXRlIiwib2xkTW9kZWwiLCJzZWdyZWdhdGVkRGF0YU9uRGVsZXRlIiwiaW5uZXJTZWdyZWdhdGVkIiwic2VncmVnYXRlZERlYyIsIlNldCIsImFkZCIsImNvbnN0ck1ldGEiLCJjb25zdHJDb2xsZWN0aW9ucyIsImRlY3MiLCJwcm9wZXJ0aWVzIiwiZ3JvdXAiLCJvblJlYWQiLCJvbkRlbGV0ZSIsInNoYXJlZERhdGEiLCJEZXRlcm1pbmlzdGljU2VyaWFsaXplciIsImVycm9yIiwic2VsZiIsIm8iLCJjYWxsIiwicmVsYXRpb25zIiwic29ydEtleXNSZWN1cnNpdmUiLCJnZW5lcmF0ZUZhYnJpY0V2ZW50TmFtZSIsInBhcnNlRXZlbnROYW1lIiwicGFydHMiLCJzcGxpdCIsInN1YiIsInNhZmVQYXJzZUludCIsInN0cmluZyIsImRpZ2l0UmVnZXgiLCJ0ZXN0IiwicGFyc2VkaW50IiwicGFyc2VJbnQiLCJpc05hTiIsIlNpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyIiwicHV0QW5jaG9yIiwicHJlU2VyaWFsaXphdGlvbiIsIkZhYnJpY0lkZW50aXR5U2VydmljZSIsIkNsaWVudEJhc2VkU2VydmljZSIsInJvb3RDbGllbnQiLCJfdXNlciIsImNlcnRpZmljYXRlcyIsImFmZmlsaWF0aW9ucyIsImdldFVzZXIiLCJjZmciLCJnZXROYW1lIiwiRGVmYXVsdEZhYnJpY0NsaWVudEZsYWdzIiwiZXZhbHVhdGVUaW1lb3V0IiwiZW5kb3JzZVRpbWVvdXQiLCJzdWJtaXRUaW1lb3V0IiwiY29tbWl0VGltZW91dCIsIkRlZmF1bHRBZGFwdGVyRmxhZ3MiLCJIU01TaWduZXJGYWN0b3J5Q3VzdG9tIiwic3RhdGljIiwicGtjczExIiwiUEtDUzExIiwibG9hZCIsImZpbmRIU01QS0NTMTFMaWIiLCJpbml0aWFsaXplZCIsIkNfSW5pdGlhbGl6ZSIsIkNLUl9DUllQVE9LSV9BTFJFQURZX0lOSVRJQUxJWkVEIiwiY29tbW9uU29mdEhTTVBhdGhOYW1lcyIsInBhdGhuYW1lVG9UcnkiLCJkaXNwb3NlIiwiQ19GaW5hbGl6ZSIsInNhbml0aXplT3B0aW9ucyIsImhzbVNpZ25lck9wdGlvbnMiLCJ1c2VyVHlwZSIsIkNLVV9VU0VSIiwiYXNzZXJ0Tm90RW1wdHkiLCJpZGVudGlmaWVyIiwicHJvcGVydHkiLCJmaW5kU2xvdEZvckxhYmVsIiwicGtjczExTGFiZWwiLCJzbG90cyIsIkNfR2V0U2xvdExpc3QiLCJmaW5kIiwic2xvdFRvQ2hlY2siLCJ0b2tlbkluZm8iLCJDX0dldFRva2VuSW5mbyIsImxvZ2luIiwic2Vzc2lvbiIsIkNfTG9naW4iLCJlcnIiLCJwa2NzMTFlcnIiLCJDS1JfVVNFUl9BTFJFQURZX0xPR0dFRF9JTiIsImZpbmRPYmplY3RJbkhTTSIsImtleXR5cGUiLCJwa2NzMTFUZW1wbGF0ZSIsIkNLQV9JRCIsIkNLQV9DTEFTUyIsIkNLQV9LRVlfVFlQRSIsIkNLS19FQyIsIkNfRmluZE9iamVjdHNJbml0IiwiaHNtT2JqZWN0IiwiQ19GaW5kT2JqZWN0cyIsIkNfRmluZE9iamVjdHNGaW5hbCIsIm5ld1NpZ25lciIsInBrY3MiLCJDX09wZW5TZXNzaW9uIiwiQ0tGX1NFUklBTF9TRVNTSU9OIiwicHJpdmF0ZUtleUhhbmRsZSIsIkNLT19QUklWQVRFX0tFWSIsIkNfQ2xvc2VTZXNzaW9uIiwic2lnbmVyIiwiQ19TaWduSW5pdCIsIm1lY2hhbmlzbSIsIkNLTV9FQ0RTQSIsImNvbXBhY3RTaWduYXR1cmUiLCJDX1NpZ25Bc3luYyIsImFsbG9jIiwicDI1NiIsIlBvaW50IiwiRm4iLCJCWVRFUyIsIlNpZ25hdHVyZSIsImZyb21CeXRlcyIsIm5vcm1hbGl6ZVMiLCJjbG9zZSIsImFzc2VydERlZmluZWQiLCJnZXRVbmNvbXByZXNzZWRQb2ludE9uQ3VydmUiLCJnZXRTS0lGcm9tQ2VydGlmaWNhdGVQYXRoIiwicmVhZEZpbGVTeW5jIiwiZ2V0U0tJRnJvbUNlcnRpZmljYXRlIiwidW5jb21wcmVzc2VkUG9pbnQiLCJGYWJyaWNDbGllbnRTdGF0ZW1lbnQiLCJTdGF0ZW1lbnQiLCJvdmVycmlkZXMiLCJzcXVhc2giLCJzcXVhc2hlZCIsIm1ldGhvZCIsImV4ZWN1dGVQcmVwYXJlZCIsImFyZ3oiLCJmb3JNb2RlbCIsImZyb21TZWxlY3RvciIsImFsaWFzIiwiUVVFUlkiLCJpc1NpbXBsZVF1ZXJ5IiwiUXVlcnlDbGF1c2UiLCJ3aGVyZUNvbmRpdGlvbiIsInBhcnNlZCIsInByZXBhcmVDb25kaXRpb24iLCJzZWxlY3RTZWxlY3RvciIsIlNFTEVDVCIsIkFORCIsInRvTG93ZXJDYXNlIiwib3JkZXJCeVNlbGVjdG9yIiwiT1JERVJfQlkiLCJ0b0NhbWVsQ2FzZSIsInBhcnNlQ29uZGl0aW9uIiwiRmFicmljQ2xpZW50UGFnaW5hdG9yIiwicXVlcnkiLCJyYXdTdGF0ZW1lbnQiLCJwYWdlIiwiRmFicmljQ2xpZW50QWRhcHRlciIsIkFkYXB0ZXIiLCJmbGFncyIsIm9wZXJhdGlvbiIsInNpbGx5IiwidG9PdmVycmlkZXMiLCJhY2N1bXVsYXRlIiwicGFyZW50Q29udGV4dCIsImN1cnJlbnRPcCIsImN1cnJlbnRNb2RlbCIsInJlcG9zaXRvcnkiLCJjcmVhdGVQcmVmaXgiLCJ1cGRhdGVBbGxQcmVmaXgiLCJzaGlmdCIsIkJ1bGtDcnVkT3BlcmF0aW9uS2V5cyIsIkNSRUFURV9BTEwiLCJyZWFkQWxsIiwiUkVBRF9BTEwiLCJVUERBVEVfQUxMIiwiZGVsZXRlQWxsIiwiREVMRVRFX0FMTCIsIk1FVEFEQVRBIiwidmFsIiwiUkVBRCIsInVwZGF0ZVByZWZpeCIsIlVQREFURSIsIkRFTEVURSIsInJhdyIsInJhd0lucHV0IiwiZG9jc09ubHkiLCJ0cmFuc2FjdGlvblJlc3VsdCIsInBhcnNlUmVjb3JkIiwiaXNNb2RlbCIsImdldENsaWVudCIsIl9jbGllbnQiLCJHYXRld2F5IiwiZ2V0R2F0ZXdheSIsImdldENvbnRyYWN0TmFtZSIsIkNvbnRyYWN0IiwiY29udHJhY3ROYW1lIiwiZ2V0Q29udHJhY3QiLCJ0cmFuc2FjdGlvbiIsImFwaSIsInN1Ym1pdCIsInRyYW5zaWVudERhdGEiLCJlbmRvcnNpbmdPcmdhbml6YXRpb25zIiwiZ2F0ZXdheSIsImNvbnRyYWN0IiwiZXZhbHVhdGUiLCJwcm9wb3NhbE9wdGlvbnMiLCJhcmd1bWVudHMiLCJkZXRhaWxzIiwibmV0d29yayIsImdldE5ldHdvcmsiLCJjaGFubmVsIiwiY2hhaW5jb2RlTmFtZSIsImNoYW5uZWxOYW1lIiwiZ2V0Q29ubmVjdGlvbiIsInBhdGhPckNlcnQiLCJ0bHNDZXJ0IiwidGxzQ3JlZGVudGlhbHMiLCJncnBjIiwiY3JlYXRlU3NsIiwicGVlckVuZHBvaW50Iiwic2l6ZUxpbWl0IiwiY2VydENlcnRPckRpcmVjdG9yeVBhdGgiLCJrZXlDZXJ0T3JEaXJlY3RvcnlQYXRoIiwicGtjczExU2lnbmVyIiwiZXZhbHVhdGVPcHRpb25zIiwiZGVhZGxpbmUiLCJlbmRvcnNlT3B0aW9ucyIsInN1Ym1pdE9wdGlvbnMiLCJjb21taXRTdGF0dXNPcHRpb25zIiwiY29ubmVjdCIsIlByb3h5IiwidGhpc0FyZyIsImFyZ0FycmF5IiwiUmVmbGVjdCIsIkRpc3BhdGNoIiwiQmFkUmVxdWVzdEVycm9yIiwiUXVlcnlFcnJvciIsIlBhZ2luZ0Vycm9yIiwiTWlncmF0aW9uRXJyb3IiLCJPYnNlcnZlckVycm9yIiwiRm9yYmlkZGVuRXJyb3IiLCJDb25uZWN0aW9uRXJyb3IiLCJmaW5hbCIsIkQiLCJfYSIsImRlY29yYXRpb24iLCJzZXRDdXJyZW50IiwiRmFicmljQ2xpZW50RGlzcGF0Y2giLCJsaXN0ZW5pbmdTdGFjayIsInBhcnNlUGF5bG9hZCIsImpzb25CeXRlcyIsImpzb24iLCJvYnNlcnZlIiwib2JzZXJ2ZXIiLCJ1bk9ic2VydmUiLCJyZWZyZXNoIiwiaGFuZGxlRXZlbnRzIiwiY3R4QXJnIiwiY29ycmVsYXRpb25JZCIsImV2dCIsImV2ZW50TmFtZSIsInBheWxvYWQiLCJ0YXJnZXRNb2RlbCIsIm1vZGVsUmVmIiwiZ2V0Q2hhaW5jb2RlRXZlbnRzIiwiVkVSU0lPTiIsIlBBQ0tBR0VfTkFNRSIsInJlZ2lzdGVyTGlicmFyeSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0lBbURNLE1BQU9BLCtCQUdIQyxLQUFBQTtRQVVSLFdBQUFDLENBQVlDLFNBQWFDO1lBQ3ZCQyxNQUFNRixTQUFTQztZQVZFRSxLQUFVQyxhQUFHQyxPQUFPQyxPQUFPLENBQUEsR0FBSUosTUFBTSxlQUFlO2dCQUNyRUssa0JBQWtCO2dCQUNsQkMsZ0JBQWdCO2dCQUNoQkMsb0JBQW9CO2dC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
|