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