@decaf-ts/for-fabric 0.1.78 → 0.1.79
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 +3048 -2
- package/dist/for-fabric.js +3138 -2
- package/lib/bin/cli.cjs +2 -1
- package/lib/cli-module.cjs +77 -68
- package/lib/cli-utils.cjs +1 -1
- package/lib/client/FabricClientAdapter.cjs +1 -1
- package/lib/client/FabricClientDispatch.cjs +1 -1
- package/lib/client/FabricClientPaginator.cjs +1 -1
- package/lib/client/FabricClientRepository.cjs +1 -1
- package/lib/client/FabricClientStatement.cjs +1 -1
- package/lib/client/collections/generation.cjs +1 -1
- package/lib/client/collections/index.cjs +1 -1
- package/lib/client/constants.cjs +1 -1
- package/lib/client/crypto.cjs +1 -1
- package/lib/client/erc20/FabricERC20ClientRepository.cjs +1 -1
- package/lib/client/erc20/index.cjs +1 -1
- package/lib/client/fabric-fs.cjs +1 -1
- package/lib/client/fabric-fs.d.ts +1 -1
- package/lib/client/fabric-hsm.cjs +1 -1
- package/lib/client/index.cjs +1 -1
- package/lib/client/indexes/generation.cjs +1 -1
- package/lib/client/indexes/index.cjs +1 -1
- package/lib/client/logging.cjs +1 -1
- package/lib/client/services/FabricEnrollmentService.cjs +1 -1
- package/lib/client/services/FabricIdentityService.cjs +1 -1
- package/lib/client/services/RegistrationRequestBuilder.cjs +1 -1
- package/lib/client/services/constants.cjs +1 -1
- package/lib/client/services/index.cjs +1 -1
- package/lib/client/types.cjs +1 -1
- package/lib/client/utils.cjs +1 -1
- package/lib/client/utils.d.ts +1 -1
- package/lib/contract/Address.cjs +1 -1
- package/lib/contract/AddressContract.cjs +1 -1
- package/lib/contract/BatchContract.cjs +1 -1
- package/lib/contract/OtherProductContract.cjs +1 -1
- package/lib/contract/OtherProductSharedContract.cjs +1 -1
- package/lib/contract/Product.cjs +1 -1
- package/lib/contract/ProductContract.cjs +1 -1
- package/lib/contract/SegregatedPrivateDocumentContract.cjs +1 -1
- package/lib/contract/SegregatedSharedDocumentContract.cjs +1 -1
- package/lib/contract/User.cjs +1 -1
- package/lib/contract/UserContract.cjs +1 -1
- package/lib/contract/index.cjs +1 -1
- package/lib/contract/models/Audit.cjs +1 -1
- package/lib/contract/models/BaseIdentifiedModel.cjs +1 -1
- package/lib/contract/models/BaseModel.cjs +1 -1
- package/lib/contract/models/Batch.cjs +1 -1
- package/lib/contract/models/Leaflet.cjs +1 -1
- package/lib/contract/models/LeafletFile.cjs +1 -1
- package/lib/contract/models/Market.cjs +1 -1
- package/lib/contract/models/OtherProduct.cjs +1 -1
- package/lib/contract/models/OtherProductShared.cjs +1 -1
- package/lib/contract/models/Product.cjs +1 -1
- package/lib/contract/models/ProductStrength.cjs +1 -1
- package/lib/contract/models/SegregatedDocument.cjs +1 -1
- package/lib/contract/models/constants.cjs +1 -1
- package/lib/contract/models/decorators.cjs +1 -1
- package/lib/contract/models/gtin.cjs +1 -1
- package/lib/contracts/ContractAdapter.cjs +1 -1
- package/lib/contracts/ContractContext.cjs +1 -1
- package/lib/contracts/ContractPrivateDataAdapter.cjs +1 -1
- package/lib/contracts/FabricConstruction.cjs +1 -1
- package/lib/contracts/FabricContractPaginator.cjs +1 -1
- package/lib/contracts/FabricContractRepository.cjs +1 -1
- package/lib/contracts/FabricContractRepositoryObservableHandler.cjs +1 -1
- package/lib/contracts/FabricContractSequence.cjs +1 -1
- package/lib/contracts/FabricContractStatement.cjs +1 -1
- package/lib/contracts/PrivateSequence.cjs +1 -1
- package/lib/contracts/crud/crud-contract.cjs +1 -1
- package/lib/contracts/crud/index.cjs +1 -1
- package/lib/contracts/crud/serialized-crud-contract.cjs +1 -1
- package/lib/contracts/erc20/erc20contract.cjs +1 -1
- package/lib/contracts/erc20/index.cjs +1 -1
- package/lib/contracts/erc20/models.cjs +1 -1
- package/lib/contracts/index.cjs +1 -1
- package/lib/contracts/logging.cjs +1 -1
- package/lib/contracts/overrides.cjs +1 -1
- package/lib/contracts/private-data.cjs +1 -1
- package/lib/contracts/types.cjs +1 -1
- package/lib/contracts/uuid.cjs +1 -1
- package/lib/esm/bin/cli.js +1 -1
- package/lib/esm/cli-module.js +77 -68
- package/lib/esm/cli-utils.js +1 -1
- package/lib/esm/client/FabricClientAdapter.js +1 -1
- package/lib/esm/client/FabricClientDispatch.js +1 -1
- package/lib/esm/client/FabricClientPaginator.js +1 -1
- package/lib/esm/client/FabricClientRepository.js +1 -1
- package/lib/esm/client/FabricClientStatement.js +1 -1
- package/lib/esm/client/collections/generation.js +1 -1
- package/lib/esm/client/collections/index.js +1 -1
- package/lib/esm/client/constants.js +1 -1
- package/lib/esm/client/crypto.js +1 -1
- package/lib/esm/client/erc20/FabricERC20ClientRepository.js +1 -1
- package/lib/esm/client/erc20/index.js +1 -1
- package/lib/esm/client/fabric-fs.d.ts +1 -1
- package/lib/esm/client/fabric-fs.js +1 -1
- package/lib/esm/client/fabric-hsm.js +1 -1
- package/lib/esm/client/index.js +1 -1
- package/lib/esm/client/indexes/generation.js +1 -1
- package/lib/esm/client/indexes/index.js +1 -1
- package/lib/esm/client/logging.js +1 -1
- package/lib/esm/client/services/FabricEnrollmentService.js +1 -1
- package/lib/esm/client/services/FabricIdentityService.js +1 -1
- package/lib/esm/client/services/RegistrationRequestBuilder.js +1 -1
- package/lib/esm/client/services/constants.js +1 -1
- package/lib/esm/client/services/index.js +1 -1
- package/lib/esm/client/types.js +1 -1
- package/lib/esm/client/utils.d.ts +1 -1
- package/lib/esm/client/utils.js +1 -1
- package/lib/esm/contract/Address.js +1 -1
- package/lib/esm/contract/AddressContract.js +1 -1
- package/lib/esm/contract/BatchContract.js +1 -1
- package/lib/esm/contract/OtherProductContract.js +1 -1
- package/lib/esm/contract/OtherProductSharedContract.js +1 -1
- package/lib/esm/contract/Product.js +1 -1
- package/lib/esm/contract/ProductContract.js +1 -1
- package/lib/esm/contract/SegregatedPrivateDocumentContract.js +1 -1
- package/lib/esm/contract/SegregatedSharedDocumentContract.js +1 -1
- package/lib/esm/contract/User.js +1 -1
- package/lib/esm/contract/UserContract.js +1 -1
- package/lib/esm/contract/index.js +1 -1
- package/lib/esm/contract/models/Audit.js +1 -1
- package/lib/esm/contract/models/BaseIdentifiedModel.js +1 -1
- package/lib/esm/contract/models/BaseModel.js +1 -1
- package/lib/esm/contract/models/Batch.js +1 -1
- package/lib/esm/contract/models/Leaflet.js +1 -1
- package/lib/esm/contract/models/LeafletFile.js +1 -1
- package/lib/esm/contract/models/Market.js +1 -1
- package/lib/esm/contract/models/OtherProduct.js +1 -1
- package/lib/esm/contract/models/OtherProductShared.js +1 -1
- package/lib/esm/contract/models/Product.js +1 -1
- package/lib/esm/contract/models/ProductStrength.js +1 -1
- package/lib/esm/contract/models/SegregatedDocument.js +1 -1
- package/lib/esm/contract/models/constants.js +1 -1
- package/lib/esm/contract/models/decorators.js +1 -1
- package/lib/esm/contract/models/gtin.js +1 -1
- package/lib/esm/contracts/ContractAdapter.js +1 -1
- package/lib/esm/contracts/ContractContext.js +1 -1
- package/lib/esm/contracts/ContractPrivateDataAdapter.js +1 -1
- package/lib/esm/contracts/FabricConstruction.js +1 -1
- package/lib/esm/contracts/FabricContractPaginator.js +1 -1
- package/lib/esm/contracts/FabricContractRepository.js +1 -1
- package/lib/esm/contracts/FabricContractRepositoryObservableHandler.js +1 -1
- package/lib/esm/contracts/FabricContractSequence.js +1 -1
- package/lib/esm/contracts/FabricContractStatement.js +1 -1
- package/lib/esm/contracts/PrivateSequence.js +1 -1
- package/lib/esm/contracts/crud/crud-contract.js +1 -1
- package/lib/esm/contracts/crud/index.js +1 -1
- package/lib/esm/contracts/crud/serialized-crud-contract.js +1 -1
- package/lib/esm/contracts/erc20/erc20contract.js +1 -1
- package/lib/esm/contracts/erc20/index.js +1 -1
- package/lib/esm/contracts/erc20/models.js +1 -1
- package/lib/esm/contracts/index.js +1 -1
- package/lib/esm/contracts/logging.js +1 -1
- package/lib/esm/contracts/overrides.js +1 -1
- package/lib/esm/contracts/private-data.js +1 -1
- package/lib/esm/contracts/types.js +1 -1
- package/lib/esm/contracts/uuid.js +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/shared/ClientSerializer.js +1 -1
- package/lib/esm/shared/DeterministicSerializer.js +1 -1
- package/lib/esm/shared/SimpleDeterministicSerializer.js +1 -1
- package/lib/esm/shared/constants.js +1 -1
- package/lib/esm/shared/decorators.js +1 -1
- package/lib/esm/shared/erc20/erc20-constants.js +1 -1
- package/lib/esm/shared/erc20/index.js +1 -1
- package/lib/esm/shared/errors.js +1 -1
- package/lib/esm/shared/events.js +1 -1
- package/lib/esm/shared/fabric-types.js +1 -1
- package/lib/esm/shared/index.js +1 -1
- package/lib/esm/shared/interfaces/Checkable.js +1 -1
- package/lib/esm/shared/interfaces/index.js +1 -1
- package/lib/esm/shared/math.js +1 -1
- package/lib/esm/shared/model/FabricBaseModel.js +1 -1
- package/lib/esm/shared/model/FabricIdentifiedBaseModel.js +1 -1
- package/lib/esm/shared/model/Identity.js +1 -1
- package/lib/esm/shared/model/IdentityCredentials.js +1 -1
- package/lib/esm/shared/model/index.js +1 -1
- package/lib/esm/shared/overrides/Model.js +1 -1
- package/lib/esm/shared/overrides/index.js +1 -1
- package/lib/esm/shared/overrides/overrides.js +1 -1
- package/lib/esm/shared/types.js +1 -1
- package/lib/esm/version.d.ts +1 -1
- package/lib/esm/version.js +2 -2
- package/lib/index.cjs +1 -1
- package/lib/shared/ClientSerializer.cjs +1 -1
- package/lib/shared/DeterministicSerializer.cjs +1 -1
- package/lib/shared/SimpleDeterministicSerializer.cjs +1 -1
- package/lib/shared/constants.cjs +1 -1
- package/lib/shared/decorators.cjs +1 -1
- package/lib/shared/erc20/erc20-constants.cjs +1 -1
- package/lib/shared/erc20/index.cjs +1 -1
- package/lib/shared/errors.cjs +1 -1
- package/lib/shared/events.cjs +1 -1
- package/lib/shared/fabric-types.cjs +1 -1
- package/lib/shared/index.cjs +1 -1
- package/lib/shared/interfaces/Checkable.cjs +1 -1
- package/lib/shared/interfaces/index.cjs +1 -1
- package/lib/shared/math.cjs +1 -1
- package/lib/shared/model/FabricBaseModel.cjs +1 -1
- package/lib/shared/model/FabricIdentifiedBaseModel.cjs +1 -1
- package/lib/shared/model/Identity.cjs +1 -1
- package/lib/shared/model/IdentityCredentials.cjs +1 -1
- package/lib/shared/model/index.cjs +1 -1
- package/lib/shared/overrides/Model.cjs +1 -1
- package/lib/shared/overrides/index.cjs +1 -1
- package/lib/shared/overrides/overrides.cjs +1 -1
- package/lib/shared/types.cjs +1 -1
- package/lib/version.cjs +2 -2
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/for-fabric.cjs.map +0 -1
- package/dist/for-fabric.js.map +0 -1
- package/lib/bin/cli.js.map +0 -1
- package/lib/cli-module.js.map +0 -1
- package/lib/cli-utils.js.map +0 -1
- package/lib/client/FabricClientAdapter.js.map +0 -1
- package/lib/client/FabricClientDispatch.js.map +0 -1
- package/lib/client/FabricClientPaginator.js.map +0 -1
- package/lib/client/FabricClientRepository.js.map +0 -1
- package/lib/client/FabricClientStatement.js.map +0 -1
- package/lib/client/collections/generation.js.map +0 -1
- package/lib/client/collections/index.js.map +0 -1
- package/lib/client/constants.js.map +0 -1
- package/lib/client/crypto.js.map +0 -1
- package/lib/client/erc20/FabricERC20ClientRepository.js.map +0 -1
- package/lib/client/erc20/index.js.map +0 -1
- package/lib/client/fabric-fs.js.map +0 -1
- package/lib/client/fabric-hsm.js.map +0 -1
- package/lib/client/index.js.map +0 -1
- package/lib/client/indexes/generation.js.map +0 -1
- package/lib/client/indexes/index.js.map +0 -1
- package/lib/client/logging.js.map +0 -1
- package/lib/client/services/FabricEnrollmentService.js.map +0 -1
- package/lib/client/services/FabricIdentityService.js.map +0 -1
- package/lib/client/services/RegistrationRequestBuilder.js.map +0 -1
- package/lib/client/services/constants.js.map +0 -1
- package/lib/client/services/index.js.map +0 -1
- package/lib/client/types.js.map +0 -1
- package/lib/client/utils.js.map +0 -1
- package/lib/contract/Address.js.map +0 -1
- package/lib/contract/AddressContract.js.map +0 -1
- package/lib/contract/BatchContract.js.map +0 -1
- package/lib/contract/OtherProductContract.js.map +0 -1
- package/lib/contract/OtherProductSharedContract.js.map +0 -1
- package/lib/contract/Product.js.map +0 -1
- package/lib/contract/ProductContract.js.map +0 -1
- package/lib/contract/SegregatedPrivateDocumentContract.js.map +0 -1
- package/lib/contract/SegregatedSharedDocumentContract.js.map +0 -1
- package/lib/contract/User.js.map +0 -1
- package/lib/contract/UserContract.js.map +0 -1
- package/lib/contract/index.js.map +0 -1
- package/lib/contract/models/Audit.js.map +0 -1
- package/lib/contract/models/BaseIdentifiedModel.js.map +0 -1
- package/lib/contract/models/BaseModel.js.map +0 -1
- package/lib/contract/models/Batch.js.map +0 -1
- package/lib/contract/models/Leaflet.js.map +0 -1
- package/lib/contract/models/LeafletFile.js.map +0 -1
- package/lib/contract/models/Market.js.map +0 -1
- package/lib/contract/models/OtherProduct.js.map +0 -1
- package/lib/contract/models/OtherProductShared.js.map +0 -1
- package/lib/contract/models/Product.js.map +0 -1
- package/lib/contract/models/ProductStrength.js.map +0 -1
- package/lib/contract/models/SegregatedDocument.js.map +0 -1
- package/lib/contract/models/constants.js.map +0 -1
- package/lib/contract/models/decorators.js.map +0 -1
- package/lib/contract/models/gtin.js.map +0 -1
- package/lib/contracts/ContractAdapter.js.map +0 -1
- package/lib/contracts/ContractContext.js.map +0 -1
- package/lib/contracts/ContractPrivateDataAdapter.js.map +0 -1
- package/lib/contracts/FabricConstruction.js.map +0 -1
- package/lib/contracts/FabricContractPaginator.js.map +0 -1
- package/lib/contracts/FabricContractRepository.js.map +0 -1
- package/lib/contracts/FabricContractRepositoryObservableHandler.js.map +0 -1
- package/lib/contracts/FabricContractSequence.js.map +0 -1
- package/lib/contracts/FabricContractStatement.js.map +0 -1
- package/lib/contracts/PrivateSequence.js.map +0 -1
- package/lib/contracts/crud/crud-contract.js.map +0 -1
- package/lib/contracts/crud/index.js.map +0 -1
- package/lib/contracts/crud/serialized-crud-contract.js.map +0 -1
- package/lib/contracts/erc20/erc20contract.js.map +0 -1
- package/lib/contracts/erc20/index.js.map +0 -1
- package/lib/contracts/erc20/models.js.map +0 -1
- package/lib/contracts/index.js.map +0 -1
- package/lib/contracts/logging.js.map +0 -1
- package/lib/contracts/overrides.js.map +0 -1
- package/lib/contracts/private-data.js.map +0 -1
- package/lib/contracts/types.js.map +0 -1
- package/lib/contracts/uuid.js.map +0 -1
- package/lib/esm/bin/cli.js.map +0 -1
- package/lib/esm/cli-module.js.map +0 -1
- package/lib/esm/cli-utils.js.map +0 -1
- package/lib/esm/client/FabricClientAdapter.js.map +0 -1
- package/lib/esm/client/FabricClientDispatch.js.map +0 -1
- package/lib/esm/client/FabricClientPaginator.js.map +0 -1
- package/lib/esm/client/FabricClientRepository.js.map +0 -1
- package/lib/esm/client/FabricClientStatement.js.map +0 -1
- package/lib/esm/client/collections/generation.js.map +0 -1
- package/lib/esm/client/collections/index.js.map +0 -1
- package/lib/esm/client/constants.js.map +0 -1
- package/lib/esm/client/crypto.js.map +0 -1
- package/lib/esm/client/erc20/FabricERC20ClientRepository.js.map +0 -1
- package/lib/esm/client/erc20/index.js.map +0 -1
- package/lib/esm/client/fabric-fs.js.map +0 -1
- package/lib/esm/client/fabric-hsm.js.map +0 -1
- package/lib/esm/client/index.js.map +0 -1
- package/lib/esm/client/indexes/generation.js.map +0 -1
- package/lib/esm/client/indexes/index.js.map +0 -1
- package/lib/esm/client/logging.js.map +0 -1
- package/lib/esm/client/services/FabricEnrollmentService.js.map +0 -1
- package/lib/esm/client/services/FabricIdentityService.js.map +0 -1
- package/lib/esm/client/services/RegistrationRequestBuilder.js.map +0 -1
- package/lib/esm/client/services/constants.js.map +0 -1
- package/lib/esm/client/services/index.js.map +0 -1
- package/lib/esm/client/types.js.map +0 -1
- package/lib/esm/client/utils.js.map +0 -1
- package/lib/esm/contract/Address.js.map +0 -1
- package/lib/esm/contract/AddressContract.js.map +0 -1
- package/lib/esm/contract/BatchContract.js.map +0 -1
- package/lib/esm/contract/OtherProductContract.js.map +0 -1
- package/lib/esm/contract/OtherProductSharedContract.js.map +0 -1
- package/lib/esm/contract/Product.js.map +0 -1
- package/lib/esm/contract/ProductContract.js.map +0 -1
- package/lib/esm/contract/SegregatedPrivateDocumentContract.js.map +0 -1
- package/lib/esm/contract/SegregatedSharedDocumentContract.js.map +0 -1
- package/lib/esm/contract/User.js.map +0 -1
- package/lib/esm/contract/UserContract.js.map +0 -1
- package/lib/esm/contract/index.js.map +0 -1
- package/lib/esm/contract/models/Audit.js.map +0 -1
- package/lib/esm/contract/models/BaseIdentifiedModel.js.map +0 -1
- package/lib/esm/contract/models/BaseModel.js.map +0 -1
- package/lib/esm/contract/models/Batch.js.map +0 -1
- package/lib/esm/contract/models/Leaflet.js.map +0 -1
- package/lib/esm/contract/models/LeafletFile.js.map +0 -1
- package/lib/esm/contract/models/Market.js.map +0 -1
- package/lib/esm/contract/models/OtherProduct.js.map +0 -1
- package/lib/esm/contract/models/OtherProductShared.js.map +0 -1
- package/lib/esm/contract/models/Product.js.map +0 -1
- package/lib/esm/contract/models/ProductStrength.js.map +0 -1
- package/lib/esm/contract/models/SegregatedDocument.js.map +0 -1
- package/lib/esm/contract/models/constants.js.map +0 -1
- package/lib/esm/contract/models/decorators.js.map +0 -1
- package/lib/esm/contract/models/gtin.js.map +0 -1
- package/lib/esm/contracts/ContractAdapter.js.map +0 -1
- package/lib/esm/contracts/ContractContext.js.map +0 -1
- package/lib/esm/contracts/ContractPrivateDataAdapter.js.map +0 -1
- package/lib/esm/contracts/FabricConstruction.js.map +0 -1
- package/lib/esm/contracts/FabricContractPaginator.js.map +0 -1
- package/lib/esm/contracts/FabricContractRepository.js.map +0 -1
- package/lib/esm/contracts/FabricContractRepositoryObservableHandler.js.map +0 -1
- package/lib/esm/contracts/FabricContractSequence.js.map +0 -1
- package/lib/esm/contracts/FabricContractStatement.js.map +0 -1
- package/lib/esm/contracts/PrivateSequence.js.map +0 -1
- package/lib/esm/contracts/crud/crud-contract.js.map +0 -1
- package/lib/esm/contracts/crud/index.js.map +0 -1
- package/lib/esm/contracts/crud/serialized-crud-contract.js.map +0 -1
- package/lib/esm/contracts/erc20/erc20contract.js.map +0 -1
- package/lib/esm/contracts/erc20/index.js.map +0 -1
- package/lib/esm/contracts/erc20/models.js.map +0 -1
- package/lib/esm/contracts/index.js.map +0 -1
- package/lib/esm/contracts/logging.js.map +0 -1
- package/lib/esm/contracts/overrides.js.map +0 -1
- package/lib/esm/contracts/private-data.js.map +0 -1
- package/lib/esm/contracts/types.js.map +0 -1
- package/lib/esm/contracts/uuid.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/shared/ClientSerializer.js.map +0 -1
- package/lib/esm/shared/DeterministicSerializer.js.map +0 -1
- package/lib/esm/shared/SimpleDeterministicSerializer.js.map +0 -1
- package/lib/esm/shared/constants.js.map +0 -1
- package/lib/esm/shared/decorators.js.map +0 -1
- package/lib/esm/shared/erc20/erc20-constants.js.map +0 -1
- package/lib/esm/shared/erc20/index.js.map +0 -1
- package/lib/esm/shared/errors.js.map +0 -1
- package/lib/esm/shared/events.js.map +0 -1
- package/lib/esm/shared/fabric-types.js.map +0 -1
- package/lib/esm/shared/index.js.map +0 -1
- package/lib/esm/shared/interfaces/Checkable.js.map +0 -1
- package/lib/esm/shared/interfaces/index.js.map +0 -1
- package/lib/esm/shared/math.js.map +0 -1
- package/lib/esm/shared/model/FabricBaseModel.js.map +0 -1
- package/lib/esm/shared/model/FabricIdentifiedBaseModel.js.map +0 -1
- package/lib/esm/shared/model/Identity.js.map +0 -1
- package/lib/esm/shared/model/IdentityCredentials.js.map +0 -1
- package/lib/esm/shared/model/index.js.map +0 -1
- package/lib/esm/shared/overrides/Model.js.map +0 -1
- package/lib/esm/shared/overrides/index.js.map +0 -1
- package/lib/esm/shared/overrides/overrides.js.map +0 -1
- package/lib/esm/shared/types.js.map +0 -1
- package/lib/esm/version.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/shared/ClientSerializer.js.map +0 -1
- package/lib/shared/DeterministicSerializer.js.map +0 -1
- package/lib/shared/SimpleDeterministicSerializer.js.map +0 -1
- package/lib/shared/constants.js.map +0 -1
- package/lib/shared/decorators.js.map +0 -1
- package/lib/shared/erc20/erc20-constants.js.map +0 -1
- package/lib/shared/erc20/index.js.map +0 -1
- package/lib/shared/errors.js.map +0 -1
- package/lib/shared/events.js.map +0 -1
- package/lib/shared/fabric-types.js.map +0 -1
- package/lib/shared/index.js.map +0 -1
- package/lib/shared/interfaces/Checkable.js.map +0 -1
- package/lib/shared/interfaces/index.js.map +0 -1
- package/lib/shared/math.js.map +0 -1
- package/lib/shared/model/FabricBaseModel.js.map +0 -1
- package/lib/shared/model/FabricIdentifiedBaseModel.js.map +0 -1
- package/lib/shared/model/Identity.js.map +0 -1
- package/lib/shared/model/IdentityCredentials.js.map +0 -1
- package/lib/shared/model/index.js.map +0 -1
- package/lib/shared/overrides/Model.js.map +0 -1
- package/lib/shared/overrides/index.js.map +0 -1
- package/lib/shared/overrides/overrides.js.map +0 -1
- package/lib/shared/types.js.map +0 -1
- package/lib/version.js.map +0 -1
package/dist/for-fabric.js
CHANGED
|
@@ -1,2 +1,3138 @@
|
|
|
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 g,AuthorizationError as p,createdAt as f,updatedAt as m,createdBy as y,updatedBy as w,UnsupportedError as b,ClientBasedService as A,Statement as v,QueryClause as C,Condition as S,Operator as E,QueryError as N,GroupOperator as x,Adapter as O,PagingError as T,MigrationError as I,ObserverError as $,ForbiddenError as R,ConnectionError as F,Dispatch as k}from"@decaf-ts/core";import{Model as _,required as B,model as P,JSONSerializer as j,ModelKeys as K,stringFormat as L,minlength as M,min as z}from"@decaf-ts/decorator-validation";import{OperationKeys as H,enforceDBDecorators as U,reduceErrorsToPrint as G,ValidationError as Y,SerializationError as V,InternalError as J,BaseError as q,ConflictError as Q,NotFoundError as W,version as X,DBKeys as Z,generated as tt,readonly as et,onCreate as rt,onUpdate as it,afterCreate as st,afterUpdate as nt,afterDelete as at,transient as ot,on as ct,DBOperations as lt,onRead as dt,onDelete as ht,BulkCrudOperationKeys as ut,BadRequestError as gt}from"@decaf-ts/db-decorators";import{CouchDBKeys as pt,generateIndexes as ft,generateViews as mt,CouchDBGroupOperator as yt,CouchDBOperator as wt,CouchDBQueryLimit as bt,translateOperators as At,findViewMetadata as vt,generateViewName as Ct,generateDesignDocName as St}from"@decaf-ts/for-couchdb";import{__decorate as Et,__metadata as Nt}from"tslib";import{Metadata as xt,description as Ot,uses as Tt,Decoration as It,apply as $t,propMetadata as Rt,metadata as Dt,prop as Ft}from"@decaf-ts/decoration";import kt from"fabric-ca-client";import{MiniLogger as _t,isBrowser as Bt,LoggedClass as Pt,Logging as jt,toPascalCase as Kt,toCamelCase as Lt,debug as Mt,final as zt}from"@decaf-ts/logging";import{signers as Ht,connect as Ut}from"@hyperledger/fabric-gateway";import{User as Gt}from"fabric-common";import Yt,{X509Certificate as Vt}from"crypto";import*as Jt from"@peculiar/x509";import{Crypto as qt}from"@peculiar/webcrypto";import*as Qt from"@grpc/grpc-js";import{Client as Wt}from"@grpc/grpc-js";import Xt from"pkcs11js";import Zt from"fs";import te from"path";import{p256 as ee}from"@noble/curves/nist";class re 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})}override(t){return super.override(t).for(t)}ObserverHandler(){return super.ObserverHandler()}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[pt.TABLE]&&t[pt.TABLE]===_.tableName(this.class)?new this.class(t):t)):c[pt.TABLE]&&c[pt.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 countOf(t,...r){const{log:i,ctxArgs:s}=(await this.logCtx(r,e.COUNT_OF,!0)).for(this.countOf);i.verbose(`counting ${_.tableName(this.class)}${t?" by "+t:""}`);const n=t?[t,...s]:s;return this.statement(e.COUNT_OF,...n)}async maxOf(t,...r){const{log:i,ctxArgs:s}=(await this.logCtx(r,e.MAX_OF,!0)).for(this.maxOf);return i.verbose(`finding max of ${t} in ${_.tableName(this.class)}`),this.statement(e.MAX_OF,t,...s)}async minOf(t,...r){const{log:i,ctxArgs:s}=(await this.logCtx(r,e.MIN_OF,!0)).for(this.minOf);return i.verbose(`finding min of ${t} in ${_.tableName(this.class)}`),this.statement(e.MIN_OF,t,...s)}async avgOf(t,...r){const{log:i,ctxArgs:s}=(await this.logCtx(r,e.AVG_OF,!0)).for(this.avgOf);return i.verbose(`calculating avg of ${t} in ${_.tableName(this.class)}`),this.statement(e.AVG_OF,t,...s)}async sumOf(t,...r){const{log:i,ctxArgs:s}=(await this.logCtx(r,e.SUM_OF,!0)).for(this.sumOf);return i.verbose(`calculating sum of ${t} in ${_.tableName(this.class)}`),this.statement(e.SUM_OF,t,...s)}async distinctOf(t,...r){const{log:i,ctxArgs:s}=(await this.logCtx(r,e.DISTINCT_OF,!0)).for(this.distinctOf);return i.verbose(`finding distinct values of ${t} in ${_.tableName(this.class)}`),this.statement(e.DISTINCT_OF,t,...s)}async groupOf(t,...r){const{log:i,ctxArgs:s}=(await this.logCtx(r,e.GROUP_OF,!0)).for(this.groupOf);return i.verbose(`grouping ${_.tableName(this.class)} by ${t}`),this.statement(e.GROUP_OF,t,...s)}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,H.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 U(this,r,t,H.CREATE,H.ON),t)))),!n){const e=r.get("ignoredValidationProperties")||[],i=await Promise.all(t.map((t=>Promise.resolve(t.hasErrors(...e))))),s=G(i);if(s)throw new Y(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 ie=class extends o{constructor(t){super(t)}};Et([s({type:String}),Nt("design:type",String)],ie.prototype,"name",void 0),Et([n(),B(),Nt("design:type",String)],ie.prototype,"owner",void 0),Et([n(),B(),Nt("design:type",String)],ie.prototype,"symbol",void 0),Et([n(),B(),Nt("design:type",Number)],ie.prototype,"decimals",void 0),ie=Et([a("erc20_tokens"),P(),Nt("design:paramtypes",[Object])],ie);let se=class extends o{constructor(t){super(t)}};Et([s({type:String}),Nt("design:type",String)],se.prototype,"id",void 0),Et([n(),B(),Nt("design:type",String)],se.prototype,"token",void 0),Et([n(),B(),Nt("design:type",Number)],se.prototype,"balance",void 0),Et([n(),Nt("design:type",String)],se.prototype,"captive",void 0),se=Et([a("erc20_wallets"),P(),Nt("design:paramtypes",[Object])],se);let ne=class extends o{constructor(t){super(t)}};Et([s({type:String}),n(),B(),Nt("design:type",String)],ne.prototype,"owner",void 0),Et([n(),B(),Nt("design:type",String)],ne.prototype,"spender",void 0),Et([n(),B(),Nt("design:type",Number)],ne.prototype,"value",void 0),ne=Et([a("erc20_allowances"),P(),Nt("design:paramtypes",[Object])],ne);class ae extends j{constructor(){super()}preSerialize(t,e){const r=Object.assign({},t);let i=xt.modelName(t.constructor);if(!i||"Object"===i){if(!e)throw new V("Could not find metadata for "+t.constructor.name);i=e}return r[K.ANCHOR]=i,r}deserialize(t){const e=JSON.parse(t),r=e[K.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 oe extends re{static{this.serializer=new ae}static{this.decoder=new TextDecoder("utf8")}async updateObservers(t,e,r,...i){if(!this.observerHandler)throw new J("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 oe.decoder.decode(t)}constructor(t){super(t,se),this.serializer=oe.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",[oe.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 ce(t){const e=require("fs"),r=require("path").dirname(t);if(e.existsSync(r))return!0;ce(r),e.mkdirSync(r)}function le(t){return ft([t])}function de(t,e){const r=mt([t]),i=e||{};return r.forEach((t=>{i[t._id]=t})),r}function he(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 ue(...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(...he(e))}return r}function ge(t,e=process.cwd(),r){const i=require("fs"),s=require("path");t.forEach((t=>{const n=s.resolve(s.join(e,`./META-INF/statedb/couchdb/${r?`collections/${r}/`:""}indexes/${t.name}.json`));ce(n),i.writeFileSync(n,JSON.stringify(t,void 0,2))}))}function pe(t,e=process.cwd(),r){if(!t.length)return;const i=require("fs"),s=require("path");t.forEach((t=>{const n=t._id.replace(/^_design\//,""),a=s.resolve(s.join(e,`./META-INF/statedb/couchdb/${r?`collections/${r}/`:""}design_docs/${n}.json`));ce(a);const o={...t};delete o._rev,i.writeFileSync(a,JSON.stringify(o,void 0,2))}))}let fe=class extends o{constructor(t){super(t)}};var me,ye;Et([Ot("Unique identifier of the credentials record"),n(),s(),Nt("design:type",String)],fe.prototype,"id",void 0),Et([Ot("PEM-encoded X.509 certificate for the identity"),n(),B(),Nt("design:type",String)],fe.prototype,"certificate",void 0),Et([Ot("PEM-encoded root or intermediate certificate"),n(),B(),Nt("design:type",String)],fe.prototype,"rootCertificate",void 0),Et([Ot("PEM-encoded private key"),n(),B(),Nt("design:type",String)],fe.prototype,"privateKey",void 0),fe=Et([P(),Nt("design:paramtypes",[Object])],fe),(t=>{t.PRIVATE="private",t.SHARED="shared",t.FABRIC="fabric",t.OWNED_BY="owned-by",t.TRANSACTION_ID="transaction-id",t.MIRROR="mirror"})(me||(me={})),(t=>{t.X509="X.509"})(ye||(ye={}));const we="hlf-fabric";let be=class extends o{constructor(t){super(t),this.type=ye.X509}};Et([Ot("Unique identifier of the identity"),s(),Nt("design:type",String)],be.prototype,"id",void 0),Et([d(fe,{update:h.CASCADE,delete:h.CASCADE}),Nt("design:type",fe)],be.prototype,"credentials",void 0),Et([n(),B(),u(),Nt("design:type",String)],be.prototype,"mspId",void 0),Et([n(),B(),Nt("design:type",String)],be.prototype,"type",void 0),be=Et([P(),Nt("design:paramtypes",[Object])],be);class Ae{static{this.logger=new _t(Ae.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 g(import("fs"));return await e.readFile(t)})(t)}static async getCAUser(t,e,r,i,s){this.logger.debug(L("Creating CA {0} user {1} with certificate {2}",i,t,r));const n=new Gt(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?(Ae.cryptoSuite||(Ae.cryptoSuite=Gt.newCryptoSuite(t)),Ae.cryptoSuite):Gt.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 Vt(t).publicKey.export({format:"jwk"}),r=Buffer.from([4]),i=Buffer.from(e.x||"","base64url"),s=Buffer.from(e.y||"","base64url");return Yt.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 g(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 g(import("fs")),{join:r}=await g(import("path"));return r(t,(await e.readdir(t))[0])}static async getFirstDirFileNameContent(t){const{promises:e}=await g(import("fs")),{join:r}=await g(import("path")),i=await e.readdir(t);return(await e.readFile(r(t,i[0]))).toString()}static async getFileContent(t){const{promises:e}=await g(import("fs"));return(await e.readFile(t)).toString()}static async getSigner(t){const e=await this.contentOfLoadFile(t,(async t=>{const{promises:e}=await g(import("fs")),r=await this.getFirstDirFileName(t);return await e.readFile(r)})),r=await this.extractPrivateKey(e),i=r[Object.getOwnPropertySymbols(r)[0]];return Ht.newPrivateKeySigner(i)}static async extractPrivateKey(t){let e;if(globalThis.window&&globalThis.window.Crypto)e=globalThis.Crypto.subtle;else{const t=await g(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 ve=new qt;var Ce,Se,Ee,Ne,xe;Jt.cryptoProvider.set(ve),(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-_.!~"})(Ce||(Ce={})),(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"})(Se||(Se={}));class Oe{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 Te{static{this.b58encoder=new Oe(Ce.BASE58)}static{this.logger=new _t(Te.name)}constructor(){}static fabricIdFromCertificate(t){this.logger.debug(L("Parsing certificate: {0}",t));const e=new Jt.X509Certificate(t),{subject:r,issuer:i}=e;return this.logger.debug(L("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=ve.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 ve.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 Jt.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,ve.subtle.verify({name:"ECDSA",hash:"SHA-256"},s,e,r)}static async encrypt(t,e){const r=new Jt.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 Bt()?globalThis.window.crypto.subtle:ve.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=ve.randomUUID();t=e.encode(r).buffer}return{key:await this.getSubtleCrypto().importKey("raw",t,Se.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:Se.KEY_ALGORYTHM,hash:Se.HASH,salt:i,iterations:Se.ITERATIONS},n=await this.getSubtleCrypto().deriveBits(s,e,8*Se.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:Se.ALGORYTHM},!1,["encrypt","decrypt"]),iv:r}}static async encryptPin(t,e){const r=(new TextEncoder).encode(t);return await this.getSubtleCrypto().encrypt({name:Se.ALGORYTHM,iv:e.iv},e.key,r)}static async decryptPin(t,e){const r=new TextDecoder,i=await this.getSubtleCrypto().decrypt({name:Se.ALGORYTHM,iv:e.iv},e.key,t);return r.decode(i)}}class Ie extends J{constructor(t){super(t,Ie.name)}}class $e extends J{constructor(t){super(t,$e.name)}}class Re extends J{constructor(t){super(t,Re.name)}}class De extends p{constructor(t){super(t,De.name)}}class Fe extends J{constructor(t){super(t,Fe.name,500)}}class ke extends q{constructor(t="MISSING_PRIVATE_DATA_ERROR_MESSAGE"){super(ke.name,t,403)}}class _e extends q{constructor(t){super(_e.name,t,409)}}class Be extends J{constructor(t){super(t,Be.name,500)}}class Pe extends J{constructor(t){super(t,Pe.name,500)}}class je extends J{constructor(t){super(t,je.name,500)}}class Ke extends J{constructor(t){super(t,Ke.name,500)}}class Le extends J{constructor(t){super(t,Le.name,500)}}(t=>{t.PEER="peer",t.ORDERER="orderer",t.CLIENT="client",t.USER="user",t.ADMIN="admin"})(Ee||(Ee={})),(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"})(Ne||(Ne={}));class Me extends Pt{constructor(t){Ae.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 Ae.getFirstDirFileNameContent(e);let o;if(s)n.debug(`Using HSM configuration for CA ${t} with library ${s.library}`);else{if(!r)throw new J(`Missing caKey configuration for CA ${t}. Provide a key directory or configure HSM support.`);n.debug("Retrieving CA key from "+r),o=await Ae.getFirstDirFileNameContent(r)}return n.debug("Loading Admin user for ca "+t),this.user=await Ae.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 Ae.getFileContent(a);return t.debug(`Creating CA Client for CA ${i} under ${e}`),this.ca=new kt(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 De(t);const[,r,i]=e;switch(r){case"74":case"71":return new Q(i);case"20":return new p(i);default:return new De(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 W(`Couldn't find enrollment with id ${t}: ${e}`)}if(!i.success)throw new W(`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=jt.for(Me,{}).for(this.identityFromEnrollment);n.debug(`Generating Identity from certificate ${r} in msp ${e}`);const a=Te.fabricIdFromCertificate(r),o=Te.encode(a);n.debug(`Identity ${a} and encodedId ${o}`);const c=new Date;return new be({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=Me.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 W("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 J(`Could not revoke enrollment with id ${t}: ${e}`)}if(!s.success)throw new J(`Could not revoke enrollment with id ${t}: ${s.errors.join("\n")}`);return s}}class ze extends _{constructor(){super(...arguments),this.affiliation=""}build(){const t=this.hasErrors();if(t)throw new Y(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}}Et([B(),Nt("design:type",String)],ze.prototype,"affiliation",void 0),Et([M(1),Nt("design:type",Array)],ze.prototype,"attrs",void 0),Et([B(),Nt("design:type",String)],ze.prototype,"enrollmentID",void 0),Et([B(),Nt("design:type",String)],ze.prototype,"enrollmentSecret",void 0),Et([z(0),Nt("design:type",Number)],ze.prototype,"maxEnrollments",void 0),Et([B(),Nt("design:type",String)],ze.prototype,"role",void 0),(t=>{t.TRANSFER="Transfer",t.APPROVAL="Approval"})(xe||(xe={}));let He=class extends _{constructor(t){super(t)}};Et([Ot("Stores the original timestamp of creation"),n(),f(),Nt("design:type",Date)],He.prototype,"createdAt",void 0),Et([Ot("Stores the timestamp of the last update"),n(),m(),Nt("design:type",Date)],He.prototype,"updatedAt",void 0),Et([Ot("Stores the version of the model"),n(),X(),Nt("design:type",Number)],He.prototype,"version",void 0),He=Et([Tt(we),Nt("design:paramtypes",[Object])],He);let Ue=class extends He{constructor(t){super(t)}};function Ge(t){if(t)return"string"==typeof t?t:t.getMSPID()}function Ye(){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 W("No tokens avaialble");if(a.length>1)throw new W("To many token available : "+a.length);if(a[0].owner!=s)throw new p(`User not authorized to run ${e} on the token`);return await i.apply(this,t)},r}}async function Ve(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 Je(){return It.for(me.OWNED_BY).define({decorator:()=>(t,e)=>$t(B(),tt(),et(),rt(Ve),Rt(xt.key(me.FABRIC,me.OWNED_BY),e))(t,e),args:[]}).apply()}async function qe(t,e,r,i){const{stub:s}=t;i[r]=s.getTxID()}function Qe(){return It.for(me.TRANSACTION_ID).define({decorator:()=>(t,e)=>$t(B(),et(),rt(qe),it(qe),Rt(xt.key(me.FABRIC,e,me.TRANSACTION_ID),e))(t,e),args:[]}).apply()}async function We(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 J("Failed to resolve collection mirror name: "+t)}if(!i||"string"!=typeof i)throw new J("No collection found model "+t.constructor.name);return i}async function Xe(t,e,r,i){const s=await We(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 Ze(t,e,r,i){const s=await We(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 tr(t,e,r,i){const s=await We(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 er(t,e){return It.for(me.MIRROR).define({decorator:(e,r)=>{const i={condition:r,resolver:e};return $t(Dt(xt.key(me.FABRIC,me.MIRROR),i),ur(t),st(Xe,i,{priority:95}),nt(Ze,i,{priority:95}),at(tr,i,{priority:95}))},args:[t,e]}).apply()}Et([Ot("Stores the creator"),n(),y(),Nt("design:type",String)],Ue.prototype,"createdBy",void 0),Et([Ot("Stores the user that last updated the model"),n(),w(),Nt("design:type",String)],Ue.prototype,"updatedBy",void 0),Ue=Et([Tt(we),Nt("design:paramtypes",[Object])],Ue),_.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=xt.validatableProperties(t.constructor),r=xt.get(t.constructor,Z.TRANSIENT),i=xt.get(t.constructor,me.PRIVATE),s=xt.get(t.constructor,me.SHARED),n={model:{},transient:{},privates:{},shared:{}},a=Object.keys(r||{}),o=Object.keys(i||{}),c=Object.keys(s||{}),l=_.pk(t.constructor);for(const r of e){const e=t[r],i=a.includes(r),s=o.includes(r),d=c.includes(r),h=r!==l||"string"!=typeof e||e.endsWith(",")?e:e+",";(i||s||d)&&(n.transient=n.transient||{},n.transient[r]=h),s&&(n.privates=n.privates||{},n.privates[r]=h),d&&(n.shared=n.shared||{},n.shared[r]=h),!i&&!s&&!d&&(n.model=n.model||{},n.model[r]=e)}return n.model=_.build(n.model,t.constructor.name),n}).bind(_),_.isPrivate=(t=>!!xt.get("function"!=typeof t?t.constructor:t,me.PRIVATE)).bind(_),_.isShared=(t=>!!xt.get("function"!=typeof t?t.constructor:t,me.SHARED)).bind(_),_.mirrored=(t=>xt.get("function"!=typeof t?t.constructor:t,xt.key(me.FABRIC,me.MIRROR))).bind(_),_.ownerOf=(t=>{const e=xt.get(t.constructor,xt.key(me.FABRIC,me.OWNED_BY));if(e)return t[e]}).bind(_),_.mirroredAt=(t=>(t="function"!=typeof t?t.constructor:t,xt.get(t,xt.key(me.FABRIC,me.MIRROR)))).bind(_),_.collectionsFor=(t=>{const e=[me.PRIVATE],r=[me.SHARED],i=xt.key(...e),s=xt.key(...r),n="function"==typeof t?t:t.constructor,a=xt.get(n,i),o=xt.get(n,s);return{privateCols:a?.collections||[],sharedCols:o?.collections||[]}}).bind(_);const rr=(t,e)=>{const r=e||("function"!=typeof t?_.ownerOf(t):void 0),i="function"==typeof t?t:t.constructor;if(!r)throw new J(`Model ${i.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);return`${Kt(i.name)}${r?Kt(r):""}`};function ir(t){return(e,r)=>{const i=r||("function"!=typeof e?_.ownerOf(e):void 0),s="function"==typeof e?e:e.constructor;if(!i)throw new J(`Model ${s.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);return`${t}${i?Kt(i):""}`}}const sr=(t,e)=>{const r=e||("function"!=typeof t?_.ownerOf(t):void 0);if(!r)throw new J(`Model ${t.constructor.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);return`__${Kt(r)}PrivateCollection`},nr=35;async function ar(t,e,r,i){const s=Array.isArray(e)?e:[e],n=_.ownerOf(i)||Ge(t.get("identity"));if(!n)return;const a=[];for(const e of s){const r=e.collections,s="string"==typeof r?r:r(i,n,t);s&&!a.includes(s)&&a.push(s)}a.length>0&&t.readFrom(a)}async function or(t,e,r,i){const s=Array.isArray(e)?e:[e],n=Array.isArray(r)?r:[r];if(n.length!==s.length)throw new J("Segregated data keys and metadata length mismatch");const a=_.ownerOf(i)||Ge(t.get("identity"));if(!a)throw new Y("There's no assigned organization for model "+i.constructor.name);const o=s[0].collections,c="string"==typeof o?o:o(i,a,t),l=n.reduce(((e,r,n)=>{const o="string"==typeof s[n].collections?s[n].collections:s[n].collections(i,a,t);if(o!==c)throw new b(`Segregated data collection mismatch: ${o} vs ${c}`);return e[r]=i[r],e}),{});new this.class(l);const d=_.segregate(i);t.writeTo(c,d)}async function cr(t,e,r,i){const s=Array.isArray(e)?e:[e];if((Array.isArray(r)?r:[r]).length!==s.length)throw new J("Segregated data keys and metadata length mismatch");const n=_.ownerOf(i)||Ge(t.get("identity"));if(!n)throw new Y("There's no assigned organization for model "+i.constructor.name);const a=s[0].collections,o="string"==typeof a?a:await a(i,n,t);t.readFrom(o)}async function lr(t,e,r,i,s){const n=Array.isArray(e)?e:[e],a=Array.isArray(r)?r:[r];if(a.length!==n.length)throw new J("Segregated data keys and metadata length mismatch");const o=_.ownerOf(i)||Ge(t.get("identity"));if(!o)throw new Y("There's no assigned organization for model "+i.constructor.name);const c=n[0].collections,l="string"==typeof c?c:c(i,o,t);a.forEach(((e,r)=>{const s="string"==typeof n[r].collections?n[r].collections:n[r].collections(i,o,t);if(s!==l)throw new b(`Segregated data collection mismatch: ${s} vs ${l}`)}));const d=_.segregate(i);t.writeTo(l,d)}async function dr(t,e,r,i){const s=Array.isArray(e)?e:[e];if((Array.isArray(r)?r:[r]).length!==s.length)throw new J("Segregated data keys and metadata length mismatch");const n=_.ownerOf(i)||Ge(t.get("identity"));if(!n)throw new Y("There's no assigned organization for model "+i.constructor.name);const a=s[0].collections,o="string"==typeof a?a:a(i,n,t);t.readFrom(o)}function hr(t,e,r){return(i,s)=>{const n=[];if(s){const r="string"==typeof t?t:t.toString(),i={collections:t},s={priority:nr,group:r};n.push(Ft(),ot(),((r,i)=>{const s=xt.key(e,i),n=r.constructor,a=xt.get(n,s)||{},o=new Set(a.collections||[]);o.add(t),a.collections=[...o],xt.set(n,s,a);const c=xt.get(n,e)||{},l=new Set(c.collections||[]);l.add(t),c.collections=[...l],xt.set(n,e,c);const d={...xt.get(n,Z.TRANSIENT)||{},[i]:{}};xt.set(n,Z.TRANSIENT,d)}),ct(lt.ALL,ar,i,s),rt(or,{collections:t},{priority:95,group:r}),dt(cr,{collections:t},{priority:95,group:r}),it(lr,{collections:t},{priority:95,group:r}),ht(dr,{collections:t},{priority:95,group:r}))}else{const s=xt.validatableProperties(i);s?.forEach((s=>{r&&!r(s)||hr(t,e)(i.prototype,s)}))}return $t(...n)(i,s)}}function ur(t=sr){return It.for(me.PRIVATE).define({decorator:t=>hr(t,me.PRIVATE),args:[t]}).apply()}function gr(t){return It.for(me.SHARED).define({decorator:t=>hr(t,me.SHARED),args:[t]}).apply()}class pr extends j{constructor(){super()}preSerialize(t){const e=Object.assign({},t);let r;try{r=xt.modelName(t.constructor)}catch(t){r=void 0}e[K.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[K.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 fr(t,e,r){const i=[t,e];return r&&i.push(r),i.join("_")}function mr(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 yr(t,e){const r=t+e;if(t!==r-e||e!==r-t)throw new Ie(`Addition overflow: ${t} + ${e}`);return r}function wr(t,e){const r=t-e;if(t!==r+e||e!==t-r)throw new Ie(`Subtraction overflow: ${t} - ${e}`);return r}function br(t){if(!/^\d+$/.test(t))throw new Y(L("Failed to parse: {0}","string contains digits"));const e=parseInt(t);if(isNaN(e))throw new Y(L("Failed to parse: {0}","string is not a parsable integer"));return e}class Ar extends j{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=xt.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[K.ANCHOR]=i||t.constructor.name),_.relations(t).forEach((t=>{r[t]=s.call(this,r[t])})),r}}class vr extends A{constructor(){super()}get rootClient(){return this.client._FabricCaServices}get user(){if(!this._user)throw new J("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 Ae.getFirstDirFileNameContent(s);let l;if(o)r.debug(`Using HSM configuration for CA ${i} with library ${o.library}`);else{if(!n)throw new J(`Missing caKey configuration for CA ${i}. Provide a key directory or configure HSM support.`);r.debug("Retrieving CA key from "+n),l=await Ae.getFirstDirFileNameContent(n)}return r.debug("Loading Admin user for ca "+i),this._user=await Ae.getCAUser("admin",l,c,i,{hsm:o}),this._user}async initialize(...t){const{log:e,ctx:i}=(await this.logCtx(t,r.INITIALIZATION,!0)).for(this.initialize),[s]=t;if(!s)throw new J("Missing Fabric CA configuration");const{url:n,tls:a,caName:o}=s;e.info(`Initializing CA Client for CA ${s.caName} at ${s.url}`);const{trustedRoots:c,verify:l}=a,d=c[0];e.debug(`Retrieving CA certificate from ${d}. cwd: ${process.cwd()}`);const h=await Ae.getFileContent(d);e.debug("CA Certificate: "+h.toString());const u=new kt(n,{trustedRoots:Buffer.from(h),verify:l},o),g=await this.getUser(s,i);return e.debug("CA user loaded: "+g.getName()),{config:s,client:u}}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,H.READ,!0)).for(this.getCertificates);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 De(t);const[,r,i]=e;switch(r){case"74":case"71":return new Q(i);case"20":return new p(i);default:return new De(i)}}async read(t,...e){const{log:r}=(await this.logCtx(e,H.READ,!0)).for(this.read);let i;r.verbose("Retrieving identity with enrollment ID "+t);try{i=await this.identities.getOne(t,this.user)}catch(e){throw new W(`Couldn't find enrollment with id ${t}: ${e}`)}if(!i.success)throw new W(`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,"register",!0)).for(this.register);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=Te.fabricIdFromCertificate(s),c=Te.encode(o);return i.debug(`Identity ${o} and encodedId ${c}`),new be({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,"enroll",!0)).for(this.enroll);let n;try{i.debug("Enrolling "+t);const r=await this.client.enroll({enrollmentID:t,enrollmentSecret:e});n=vr.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,"register-enroll",!0)).for(this.registerAndEnroll),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,"revoke",!0)).for(this.revoke);r.verbose("Revoking identity with enrollment ID "+t);const i=await this.read(t);if(!i)throw new W("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 J(`Could not revoke enrollment with id ${t}: ${e}`)}if(!s.success)throw new J(`Could not revoke enrollment with id ${t}: ${s.errors.join("\n")}`);return s}}const Cr=Object.assign({evaluateTimeout:5,endorseTimeout:15,submitTimeout:5,commitTimeout:60}),Sr=new _t("fabric-fs");async function Er(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 g(import("fs"));return await e.readFile(t)})(t)}async function xr(t,e,r,i){Sr.debug(`Creating a CA ${i} user ${t} with certificate ${r}`);const s=new Gt(t),n=Gt.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 Er(e,(async t=>{const{promises:e}=await g(import("fs")),r=await Tr(t);return await e.readFile(r)}));return{mspId:t,credentials:r}}async function Tr(t){const{promises:e}=await g(import("fs")),{join:r}=await g(import("path"));return r(t,(await e.readdir(t))[0])}async function Ir(t){const{promises:e}=await g(import("fs")),{join:r}=await g(import("path")),i=await e.readdir(t);return(await e.readFile(r(t,i[0]))).toString()}async function $r(t){const e=await Er(t,(async t=>{const{promises:e}=await g(import("fs")),r=await Tr(t);return await e.readFile(r)})),r=await Rr(e),i=r[Object.getOwnPropertySymbols(r)[0]];return Ht.newPrivateKeySigner(i)}async function Rr(t){let e;if(Bt())e=globalThis.crypto.subtle;else{const t=await g(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 J(t)}}class Dr{static#t=null;static#e=!1;constructor(t){if(Dr.#t||(Dr.#t=new Xt.PKCS11,Dr.#t.load(this.findHSMPKCS11Lib(t))),!Dr.#e){try{Dr.#t.C_Initialize()}catch(t){if(t.code!==Xt.CKR_CRYPTOKI_ALREADY_INITIALIZED)throw t}Dr.#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(Zt.existsSync(t))return t;throw new Be("Unable to find PKCS11 library")}dispose(){Dr.#t.C_Finalize()}sanitizeOptions(t){const e=Object.assign({userType:Xt.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=Dr.#t.C_GetSlotList(!0);if(0===e.length)throw Error("No pkcs11 slots can be found");const r=e.find((e=>Dr.#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{Dr.#t.C_Login(t,e,r)}catch(t){if(t.code!==Xt.CKR_USER_ALREADY_LOGGED_IN)throw t}}findObjectInHSM(t,e,r){const i=[{type:Xt.CKA_ID,value:r},{type:Xt.CKA_CLASS,value:e},{type:Xt.CKA_KEY_TYPE,value:Xt.CKK_EC}];Dr.#t.C_FindObjectsInit(t,i);const s=Dr.#t.C_FindObjects(t,1)[0];if(!s)throw Dr.#t.C_FindObjectsFinal(t),Error("Unable to find object in HSM with ID "+r.toString());return Dr.#t.C_FindObjectsFinal(t),s}newSigner(t){const e=this.sanitizeOptions(t),r=Dr.#t,i=this.findSlotForLabel(e.label),s=r.C_OpenSession(i,Xt.CKF_SERIAL_SESSION);let n;try{this.login(s,e.userType,e.pin),n=this.findObjectInHSM(s,Xt.CKO_PRIVATE_KEY,e.identifier)}catch(t){throw Dr.#t.C_CloseSession(s),t}return{signer:async t=>{Dr.#t.C_SignInit(s,{mechanism:Xt.CKM_ECDSA},n);const e=await Dr.#t.C_SignAsync(s,Buffer.from(t),Buffer.alloc(2*ee.Point.Fn.BYTES));return ee.Signature.fromBytes(e,"compact").normalizeS().toBytes("der")},close:()=>{Dr.#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:te.join(t,"cert.pem"),r=Zt.readFileSync(e);return this.getSKIFromCertificate(r)}getSKIFromCertificate(t){const e=new Yt.X509Certificate(t),r=this.getUncompressedPointOnCurve(e.publicKey);return Yt.createHash("sha256").update(r).digest()}}class Fr extends v{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 J("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=[C.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(C.SELECT,this.selectSelector.join(` ${C.AND.toLowerCase()} `)),this.orderBySelectors?.length&&(n.push(C.ORDER_BY,this.orderBySelectors[0][0]),e.push(this.orderBySelectors[0][1])),s.method=Lt(n.join(" ")),s.params=i,this.prepared=s,this}processRecord(t,e,r,i){if(t[pt.ID]){const[,...e]=t[pt.ID].split(pt.SEPARATOR),s=e.join("_");return this.adapter.revert(t,this.fromSelector,c.parseValue(r,s),void 0,i)}return t}async raw(t,...e){const{ctx:r}=this.logCtx(e,this.raw),i=t?.aggregateInfo;if(t?.aggregate&&i)return this.executeAggregate(i,r);const s=await this.adapter.raw(t,!0,this.fromSelector,r),n=_.pk(this.fromSelector),a=xt.get(this.fromSelector,xt.key(Z.ID,n))?.type;return this.selectSelector?s:s.map((t=>this.processRecord(t,n,a,r)))}build(){const t=this.log.for(this.build),e=this.buildAggregateQuery();if(e)return e;const r={};r[pt.TABLE]={},r[pt.TABLE]=_.tableName(this.fromSelector);const i={selector:r};if(this.selectSelector&&(i.fields=this.selectSelector),this.whereCondition){const e=this.parseCondition(S.and(this.whereCondition,S.attribute(pt.TABLE).eq(i.selector[pt.TABLE]))).selector,r=Object.keys(e);if(1===r.length&&-1!==Object.values(yt).indexOf(r[0]))switch(r[0]){case yt.AND:e[yt.AND]=[...Object.values(e[yt.AND]).reduce(((t,e)=>{const r=Object.keys(e);if(1!==r.length)throw Error("Too many keys in query selector. should be one");const i=r[0];return i===yt.AND?t.push(...e[i]):t.push(e),t}),[])],i.selector=e;break;case yt.OR:{const t={};t[yt.AND]=[e,...Object.entries(i.selector).map((([t,e])=>{const r={};return r[t]=e,r}))],i.selector=t;break}default:throw Error("This should be impossible")}else Object.entries(e).forEach((([e,r])=>{i.selector[e]&&t.warn(`A ${e} query param is about to be overridden: ${i.selector[e]} by ${r}`),i.selector[e]=r}))}if(this.orderBySelectors?.length){i.sort=i.sort||[],i.selector=i.selector||{};for(const[t,e]of this.orderBySelectors){const r=t,s={};s[r]=e,i.sort.push(s),i.selector[r]||(i.selector[r]={},i.selector[r][wt.BIGGER]=null)}}return this.limitSelector?i.limit=this.limitSelector:(t.warn("No limit selector defined. Using default couchdb limit of "+bt),i.limit=bt),this.offsetSelector&&(i.skip=this.offsetSelector),i}parseCondition(t){const{attr1:e,operator:r,comparison:i}=t;if(r===E.BETWEEN){const t=e;if(!Array.isArray(i)||2!==i.length)throw new N("BETWEEN operator requires [min, max] comparison");const[r,s]=i,n={};return n[t]={},n[t][At(E.BIGGER_EQ)]=r,n[t][At(E.SMALLER_EQ)]=s,{selector:n}}let s={};if(-1===[x.AND,x.OR,E.NOT].indexOf(r))s[e]={},s[e][At(r)]=i;else if(r===E.NOT)s=this.parseCondition(e).selector,s[At(E.NOT)]={},s[At(E.NOT)][e.attr1]=i;else{const t=this.parseCondition(e).selector,n=this.parseCondition(i).selector;s=((t,e,r)=>{const i={selector:{}};return i.selector[t]=[e,r],i})(At(r),t,n).selector}return{selector:s}}buildAggregateQuery(){if(!this.fromSelector)return;if(this.avgSelector){const t=this.avgSelector+"",e=this.createAggregateDescriptor("sum",t),r=this.createAggregateDescriptor("count",t);if(!e||!r)throw new N("Avg operation requires sum and count views for attribute "+t);return this.createAggregateQuery({kind:"avg",attribute:t,sumDescriptor:e.descriptor,countDescriptor:r.descriptor})}if(void 0!==this.countDistinctSelector){const t=null==this.countDistinctSelector?void 0:this.countDistinctSelector+"",e=this.createAggregateDescriptor("distinct",t);if(e)return e.countDistinct=!0,this.createAggregateQuery(e)}const t=!!(void 0!==this.countSelector||void 0!==this.countDistinctSelector||this.minSelector||this.maxSelector||this.sumSelector||this.distinctSelector),e=[["count",this.countSelector??void 0],["max",this.maxSelector],["min",this.minSelector],["sum",this.sumSelector],["distinct",this.distinctSelector]];for(const[t,r]of e){const e=r?r+"":void 0,i=this.createAggregateDescriptor(t,e);if(i)return this.createAggregateQuery(i)}if(t)throw new N(`No CouchDB view metadata found for table ${_.tableName(this.fromSelector)} aggregator`)}createAggregateDescriptor(t,e){if(!this.fromSelector)return;const r=vt(this.fromSelector,t,e);if(!r.length)return;const i=r[0],s=_.tableName(this.fromSelector),n=Ct(s,i.attribute,t,i),a=i.ddoc||St(s,n),o={reduce:void 0!==i.reduce||!i.returnDocs};return"distinct"!==t&&"groupBy"!==t||(o.group=!0),{kind:t,meta:i,descriptor:{ddoc:a,view:n,options:o}}}createAggregateQuery(t){return{selector:{},aggregate:!0,aggregateInfo:t}}getFabricAdapter(){return this.adapter}async executeAggregate(t,e){if(!this.isViewAggregate(t))return this.handleAverage(t,e);const r=this.getFabricAdapter(),i=t,s=await r.view(i.descriptor.ddoc,i.descriptor.view,i.descriptor.options,e);return this.processViewResponse(t,s)}async handleAverage(t,e){if("avg"!==t.kind)throw new N("Average descriptor is not valid");const r=this.getFabricAdapter(),[i,s]=[t.sumDescriptor,t.countDescriptor],[n,a]=await Promise.all([r.view(i.ddoc,i.view,i.options,e),r.view(s.ddoc,s.view,s.options,e)]),o=n.rows?.[0]?.value??0,c=a.rows?.[0]?.value??0;return c?o/c:0}processViewResponse(t,e){if("avg"===t.kind)throw new N("Average results should be handled before processing rows");const r=e.rows||[],i=t,s=i.meta;return i.countDistinct?r.length||0:"distinct"===i.kind||"groupBy"===i.kind?r.map((t=>t.key??t.value)):s.returnDocs?r.map((t=>t.value??t.doc??t)):r.length?r[0].value??r[0].key??null:"count"===i.kind?0:null}isViewAggregate(t){return"avg"!==t.kind}}class kr 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 _r;class Br extends O{static{this.decoder=new TextDecoder("utf8")}static{this.serializer=new ae}static{this.log=jt.for(Br)}constructor(t,e){super(Object.assign({},t,{evaluateTimeout:5,endorseTimeout:15,submitTimeout:5,commitTimeout:60}),we,e),this.serializer=Br.serializer}Statement(t){return new Fr(this,t)}Paginator(t,e,r){return new kr(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 Br.decoder.decode(t)}repository(){return re}createPrefix(t,e,r,...i){const{ctxArgs:s}=this.logCtx(i,this.createPrefix),n=_.tableName(t),a={};return a[pt.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 J("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[pt.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 J("Ids and models must have the same length");const{ctxArgs:n}=this.logCtx(i,this.updateAllPrefix),a=e.map((()=>{const t={};return t[pt.TABLE]=s,t}));return[t,e,a,...n]}async createAll(t,e,r,...i){if(e.length!==r.length)throw new J("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,ut.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 V(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,ut.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 V(t)}}async updateAll(t,e,r,...i){if(e.length!==r.length)throw new J("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,ut.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 V(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,ut.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 V(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,privates:s.privates,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&&void 0!==t[r])throw new J(`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,H.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,H.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[pt.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,H.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,H.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 V("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}async view(t,e,r,...i){const{log:s,ctx:n}=this.logCtx(i,this.view);let a,o;s.info(`Querying view ${t}/${e}`);try{a=await this.evaluateTransaction(n,"view",[t,e,JSON.stringify(r)],void 0,void 0,void 0)}catch(t){throw this.parseError(t)}try{o=JSON.parse(this.decode(a))}catch(t){throw new V("Failed to process view result: "+t)}return o}getClient(){return this._client||(this._client=Br.getClient(this.config)),this._client}async Gateway(t){return Br.getGateway(t,this.config,this.client)}getContractName(t){if(t)return t+"Contract"}async Contract(t,e){return Br.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 Br.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=jt.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(Zt.readFileSync(r,"utf8"))}catch(t){throw new J(`Failed to read the tls certificate from ${r}: ${t}`)}const i=Qt.credentials.createSsl(r);return e.debug("generating Gateway Client for url "+t.peerEndpoint),new Wt(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=jt.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 Dr(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 $r(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=Ut(o);return e.hsm&&(c.close=new Proxy(c.close,{apply(t,e,r){Reflect.apply(t,e,r),a()}})),c}Dispatch(){return new Br._baseDispatch}static parseError(t){const e="string"==typeof t?t:t.message;return e.includes("MVCC_READ_CONFLICT")?new je(t):e.includes("ENDORSEMENT_POLICY_FAILURE")?new Le(t):e.includes("PHANTOM_READ_CONFLICT")?new Ke(t):t instanceof Error&&t.code&&9===t.code?new Pe(t):e.includes(W.name)?new W(t):e.includes(Q.name)?new Q(t):e.includes(gt.name)?new gt(t):e.includes(N.name)?new N(t):e.includes(T.name)?new T(t):e.includes(b.name)?new b(t):e.includes(I.name)?new I(t):e.includes($.name)?new $(t):e.includes(p.name)?new p(t):e.includes(R.name)?new R(t):e.includes(F.name)?new F(t):e.includes(V.name)?new V(t):new J(t)}}Et([Mt(),zt(),Nt("design:type",Function),Nt("design:paramtypes",[Object,Object,Object,Object,l]),Nt("design:returntype",Promise)],Br.prototype,"create",null),Et([Mt(),zt(),Nt("design:type",Function),Nt("design:paramtypes",[Object,Object,l]),Nt("design:returntype",Promise)],Br.prototype,"read",null),Et([Mt(),zt(),Nt("design:type",Function),Nt("design:paramtypes",[Object,Object,Object,Object,l]),Nt("design:returntype",Promise)],Br.prototype,"update",null),Et([Mt(),zt(),Nt("design:type",Function),Nt("design:paramtypes",[Object,Object,l]),Nt("design:returntype",Promise)],Br.prototype,"delete",null),Et([Mt(),Nt("design:type",Function),Nt("design:paramtypes",[Object,"function"==typeof(_r="undefined"!=typeof D&&D)?_r:Object,Object,l]),Nt("design:returntype",Promise)],Br.prototype,"raw",null),Et([Mt(),Nt("design:type",Function),Nt("design:paramtypes",[String,String,Object,l]),Nt("design:returntype",Promise)],Br.prototype,"view",null),Br.decoration(),O.setCurrent(we);class Pr extends k{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 Br))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}=O.logCtx(this.updateObservers,e,!1,...i);if(this.adapter)try{await this.adapter.refresh(t,e,r,...n)}catch(t){throw new J("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 J('Event stack not initialized. Ensure that "startListening" is called before attempting this operation.');if(!this.adapter||!this.adapter.config)throw new J("No adapter found. should be impossible");const e=t||await this.adapter.context(H.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}=mr(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 J("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 Br.getGateway(e,this.adapter.config,this.client)).getNetwork(this.adapter.config.channel);if(!this.adapter)throw new J("No adapter observed for dispatch");this.listeningStack=await r.getChaincodeEvents(this.adapter.config.chaincodeName),this.handleEvents(e)}}Br&&(Br._baseDispatch=Pr);const jr="##VERSION##",Kr="##PACKAGE##";xt.registerLibrary(Kr,jr);export{Re as AllowanceError,Ce as BASE_ALPHABET,$e as BalanceError,Oe as BaseEncoder,Se as CRYPTO,ae as ClientSerializer,Ae as CoreUtils,Te as CryptoUtils,Cr as DefaultFabricClientFlags,pr as DeterministicSerializer,xe as ERC20Events,Pe as EndorsementError,Le as EndorsementPolicyError,He as FabricBaseModel,Br as FabricClientAdapter,Pr as FabricClientDispatch,re as FabricClientRepository,oe as FabricERC20ClientRepository,Me as FabricEnrollmentService,we as FabricFlavour,Ue as FabricIdentifiedBaseModel,vr as FabricIdentityService,me as FabricModelKeys,Ne as HFCAIdentityAttributes,Ee as HFCAIdentityType,be as Identity,fe as IdentityCredentials,ye as IdentityType,sr as ImplicitPrivateCollection,Fe as MissingContextError,Be as MissingPKCSS11Lib,rr as ModelCollection,je as MvccReadConflictError,ir as NamespaceCollection,_e as NotInitializedError,Ie as OverflowError,Ye as Owner,Kr as PACKAGE_NAME,Ke as PhantomReadConflictError,De as RegistrationError,ze as RegistrationRequestBuilder,nr as SEGREGATED_COLLECTION_EXTRACTION_PRIORITY,Ar as SimpleDeterministicSerializer,ke as UnauthorizedPrivateDataAccess,jr as VERSION,yr as add,Er as contentOfLoadFile,Xe as createMirrorHandler,tr as deleteMirrorHandler,We as evalMirrorMetadata,Rr as extractPrivateKey,ar as extractSegregatedCollections,fr as generateFabricEventName,de as generateModelDesignDocs,le as generateModelIndexes,xr as getCAUser,Tr as getFirstDirFileName,Ir as getFirstDirFileNameContent,Or as getIdentity,$r as getSigner,er as mirror,Je as ownedBy,Ve as ownedByOnCreate,mr as parseEventName,ur as privateData,Nr as readFile,he as readModelFile,ue as readModelFolders,br as safeParseInt,or as segregatedDataOnCreate,dr as segregatedDataOnDelete,cr as segregatedDataOnRead,lr as segregatedDataOnUpdate,gr as sharedData,wr as sub,Qe as transactionId,qe as transactionIdOnCreate,Ze as updateMirrorHandler,pe as writeDesignDocs,ge as writeIndexes};
|
|
2
|
-
|
|
1
|
+
import { Repository, PreparedStatementKeys, PersistenceKeys, Paginator, BaseModel, pk, column, table, Sequence, Context, oneToOne, Cascade, index, normalizeImport, AuthorizationError, createdAt, updatedAt, createdBy, updatedBy, UnsupportedError, ClientBasedService, Statement, QueryClause, Condition, Operator, QueryError, GroupOperator, Adapter, 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, generated, readonly, onCreate, onUpdate, afterCreate, afterUpdate, afterDelete, transient, on, DBOperations, onRead, onDelete, BulkCrudOperationKeys, BadRequestError } from "@decaf-ts/db-decorators";
|
|
6
|
+
|
|
7
|
+
import { CouchDBKeys, generateIndexes, generateViews, CouchDBGroupOperator, CouchDBOperator, CouchDBQueryLimit, translateOperators, findViewMetadata, generateViewName, generateDesignDocName } 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
|
+
override(flags) {
|
|
52
|
+
return super.override(flags).for(flags);
|
|
53
|
+
}
|
|
54
|
+
ObserverHandler() {
|
|
55
|
+
return super.ObserverHandler();
|
|
56
|
+
}
|
|
57
|
+
async paginateBy(key, order, ref = {
|
|
58
|
+
offset: 1,
|
|
59
|
+
limit: 10
|
|
60
|
+
}, ...args) {
|
|
61
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.PAGE_BY, true)).for(this.paginateBy);
|
|
62
|
+
log.verbose(`paginating ${Model.tableName(this.class)} with page size ${ref.limit}`);
|
|
63
|
+
return this.statement(this.paginateBy.name, key, order, {
|
|
64
|
+
limit: ref.limit,
|
|
65
|
+
offset: ref.offset,
|
|
66
|
+
bookmark: ref.bookmark
|
|
67
|
+
}, ...ctxArgs);
|
|
68
|
+
}
|
|
69
|
+
async listBy(key, order, ...args) {
|
|
70
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.LIST_BY, true)).for(this.listBy);
|
|
71
|
+
log.verbose(`listing ${Model.tableName(this.class)} by ${key} ${order}`);
|
|
72
|
+
return await this.statement(this.listBy.name, key, order, ...ctxArgs);
|
|
73
|
+
}
|
|
74
|
+
async findBy(key, value, ...args) {
|
|
75
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.FIND_BY, true)).for(this.findBy);
|
|
76
|
+
log.verbose(`finding all ${Model.tableName(this.class)} with ${key} ${value}`);
|
|
77
|
+
return await this.statement(this.findBy.name, key, value, ...ctxArgs);
|
|
78
|
+
}
|
|
79
|
+
async findOneBy(key, value, ...args) {
|
|
80
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.FIND_ONE_BY, true)).for(this.findOneBy);
|
|
81
|
+
log.verbose(`finding One ${Model.tableName(this.class)} with ${key} ${value}`);
|
|
82
|
+
return await this.statement(this.findOneBy.name, key, value, ...ctxArgs);
|
|
83
|
+
}
|
|
84
|
+
async statement(name, ...args) {
|
|
85
|
+
const {log: log, ctx: ctx, ctxArgs: ctxArgs} = (await this.logCtx(args, PersistenceKeys.STATEMENT, true)).for(this.statement);
|
|
86
|
+
log.verbose(`Executing prepared statement ${name}`);
|
|
87
|
+
const callArgs = ctxArgs.slice(0, -1);
|
|
88
|
+
const result = JSON.parse(this.adapter.decode(await this.adapter.evaluateTransaction(ctx, PersistenceKeys.STATEMENT, [ name, JSON.stringify(callArgs) ], undefined, undefined, this.class.name)));
|
|
89
|
+
if (Array.isArray(result)) {
|
|
90
|
+
return result.map(r => r[CouchDBKeys.TABLE] && r[CouchDBKeys.TABLE] === Model.tableName(this.class) ? new this.class(r) : r);
|
|
91
|
+
}
|
|
92
|
+
return result[CouchDBKeys.TABLE] && result[CouchDBKeys.TABLE] === Model.tableName(this.class) ? new this.class(result) : Paginator.isSerializedPage(result) ? Object.assign(result, {
|
|
93
|
+
data: result.data.map(d => new this.class(d))
|
|
94
|
+
}) : result;
|
|
95
|
+
}
|
|
96
|
+
async countOf(key, ...args) {
|
|
97
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.COUNT_OF, true)).for(this.countOf);
|
|
98
|
+
log.verbose(`counting ${Model.tableName(this.class)}${key ? ` by ${key}` : ""}`);
|
|
99
|
+
const stmtArgs = key ? [ key, ...ctxArgs ] : ctxArgs;
|
|
100
|
+
return this.statement(PreparedStatementKeys.COUNT_OF, ...stmtArgs);
|
|
101
|
+
}
|
|
102
|
+
async maxOf(key, ...args) {
|
|
103
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.MAX_OF, true)).for(this.maxOf);
|
|
104
|
+
log.verbose(`finding max of ${key} in ${Model.tableName(this.class)}`);
|
|
105
|
+
return this.statement(PreparedStatementKeys.MAX_OF, key, ...ctxArgs);
|
|
106
|
+
}
|
|
107
|
+
async minOf(key, ...args) {
|
|
108
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.MIN_OF, true)).for(this.minOf);
|
|
109
|
+
log.verbose(`finding min of ${key} in ${Model.tableName(this.class)}`);
|
|
110
|
+
return this.statement(PreparedStatementKeys.MIN_OF, key, ...ctxArgs);
|
|
111
|
+
}
|
|
112
|
+
async avgOf(key, ...args) {
|
|
113
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.AVG_OF, true)).for(this.avgOf);
|
|
114
|
+
log.verbose(`calculating avg of ${key} in ${Model.tableName(this.class)}`);
|
|
115
|
+
return this.statement(PreparedStatementKeys.AVG_OF, key, ...ctxArgs);
|
|
116
|
+
}
|
|
117
|
+
async sumOf(key, ...args) {
|
|
118
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.SUM_OF, true)).for(this.sumOf);
|
|
119
|
+
log.verbose(`calculating sum of ${key} in ${Model.tableName(this.class)}`);
|
|
120
|
+
return this.statement(PreparedStatementKeys.SUM_OF, key, ...ctxArgs);
|
|
121
|
+
}
|
|
122
|
+
async distinctOf(key, ...args) {
|
|
123
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.DISTINCT_OF, true)).for(this.distinctOf);
|
|
124
|
+
log.verbose(`finding distinct values of ${key} in ${Model.tableName(this.class)}`);
|
|
125
|
+
return this.statement(PreparedStatementKeys.DISTINCT_OF, key, ...ctxArgs);
|
|
126
|
+
}
|
|
127
|
+
async groupOf(key, ...args) {
|
|
128
|
+
const {log: log, ctxArgs: ctxArgs} = (await this.logCtx(args, PreparedStatementKeys.GROUP_OF, true)).for(this.groupOf);
|
|
129
|
+
log.verbose(`grouping ${Model.tableName(this.class)} by ${key}`);
|
|
130
|
+
return this.statement(PreparedStatementKeys.GROUP_OF, key, ...ctxArgs);
|
|
131
|
+
}
|
|
132
|
+
async create(model, ...args) {
|
|
133
|
+
const {ctx: ctx, log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.create);
|
|
134
|
+
log.debug(`Creating new ${this.class.name} in table ${Model.tableName(this.class)}`);
|
|
135
|
+
let {record: record, id: id, transient: transient} = this.adapter.prepare(model, ctx);
|
|
136
|
+
record = await this.adapter.create(this.class, id, record, transient, ...ctxArgs);
|
|
137
|
+
return this.adapter.revert(record, this.class, id, transient, ctx);
|
|
138
|
+
}
|
|
139
|
+
async update(model, ...args) {
|
|
140
|
+
const {ctxArgs: ctxArgs, log: log, ctx: ctx} = this.logCtx(args, this.update);
|
|
141
|
+
let {record: record, id: id, transient: transient} = this.adapter.prepare(model, ctx);
|
|
142
|
+
log.debug(`updating ${this.class.name} in table ${Model.tableName(this.class)} with id ${id}`);
|
|
143
|
+
record = await this.adapter.update(this.class, id, record, transient, ...ctxArgs);
|
|
144
|
+
return this.adapter.revert(record, this.class, id, transient, ctx);
|
|
145
|
+
}
|
|
146
|
+
async createAllPrefix(models, ...args) {
|
|
147
|
+
const {ctx: ctx, ctxArgs: ctxArgs} = (await this.logCtx(args, OperationKeys.CREATE, true)).for(this.createAllPrefix);
|
|
148
|
+
const ignoreHandlers = ctx.get("ignoreHandlers");
|
|
149
|
+
const ignoreValidate = ctx.get("ignoreValidation");
|
|
150
|
+
if (!models.length) return [ models, ...ctxArgs ];
|
|
151
|
+
models = await Promise.all(models.map(async m => {
|
|
152
|
+
m = new this.class(m);
|
|
153
|
+
if (!ignoreHandlers) await enforceDBDecorators(this, ctx, m, OperationKeys.CREATE, OperationKeys.ON);
|
|
154
|
+
return m;
|
|
155
|
+
}));
|
|
156
|
+
if (!ignoreValidate) {
|
|
157
|
+
const ignoredProps = ctx.get("ignoredValidationProperties") || [];
|
|
158
|
+
const errors = await Promise.all(models.map(m => Promise.resolve(m.hasErrors(...ignoredProps))));
|
|
159
|
+
const errorMessages = reduceErrorsToPrint(errors);
|
|
160
|
+
if (errorMessages) throw new ValidationError(errorMessages);
|
|
161
|
+
}
|
|
162
|
+
return [ models, ...ctxArgs ];
|
|
163
|
+
}
|
|
164
|
+
async createAll(models, ...args) {
|
|
165
|
+
if (!models.length) return models;
|
|
166
|
+
const {ctx: ctx, log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.createAll);
|
|
167
|
+
log.debug(`Creating ${models.length} new ${this.class.name} in table ${Model.tableName(this.class)}`);
|
|
168
|
+
const prepared = models.map(m => this.adapter.prepare(m, ctx));
|
|
169
|
+
const ids = prepared.map(p => p.id);
|
|
170
|
+
let records = prepared.map(p => p.record);
|
|
171
|
+
const transient = prepared.map(p => p.transient);
|
|
172
|
+
records = await this.adapter.createAll(this.class, ids, records, transient, ...ctxArgs);
|
|
173
|
+
return records.map((r, i) => this.adapter.revert(r, this.class, ids[i], ctx.get("rebuildWithTransient") ? prepared[i].transient : undefined, ctx));
|
|
174
|
+
}
|
|
175
|
+
async updateAll(models, ...args) {
|
|
176
|
+
const {ctx: ctx, log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.updateAll);
|
|
177
|
+
log.debug(`Updating ${models.length} new ${this.class.name} in table ${Model.tableName(this.class)}`);
|
|
178
|
+
const records = models.map(m => this.adapter.prepare(m, ctx));
|
|
179
|
+
const updated = await this.adapter.updateAll(this.class, records.map(r => r.id), records.map(r => r.record), records.map(r => r.transient), ...ctxArgs);
|
|
180
|
+
return updated.map((u, i) => this.adapter.revert(u, this.class, records[i].id, ctx.get("rebuildWithTransient") ? records[i].transient : undefined, ctx));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
let ERC20Token = class ERC20Token extends BaseModel {
|
|
185
|
+
constructor(m) {
|
|
186
|
+
super(m);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
__decorate([ pk({
|
|
191
|
+
type: String
|
|
192
|
+
}), __metadata("design:type", String) ], ERC20Token.prototype, "name", void 0);
|
|
193
|
+
|
|
194
|
+
__decorate([ column(), required(), __metadata("design:type", String) ], ERC20Token.prototype, "owner", void 0);
|
|
195
|
+
|
|
196
|
+
__decorate([ column(), required(), __metadata("design:type", String) ], ERC20Token.prototype, "symbol", void 0);
|
|
197
|
+
|
|
198
|
+
__decorate([ column(), required(), __metadata("design:type", Number) ], ERC20Token.prototype, "decimals", void 0);
|
|
199
|
+
|
|
200
|
+
ERC20Token = __decorate([ table("erc20_tokens"), model(), __metadata("design:paramtypes", [ Object ]) ], ERC20Token);
|
|
201
|
+
|
|
202
|
+
let ERC20Wallet = class ERC20Wallet extends BaseModel {
|
|
203
|
+
constructor(m) {
|
|
204
|
+
super(m);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
__decorate([ pk({
|
|
209
|
+
type: String
|
|
210
|
+
}), __metadata("design:type", String) ], ERC20Wallet.prototype, "id", void 0);
|
|
211
|
+
|
|
212
|
+
__decorate([ column(), required(), __metadata("design:type", String) ], ERC20Wallet.prototype, "token", void 0);
|
|
213
|
+
|
|
214
|
+
__decorate([ column(), required(), __metadata("design:type", Number) ], ERC20Wallet.prototype, "balance", void 0);
|
|
215
|
+
|
|
216
|
+
__decorate([ column(), __metadata("design:type", String) ], ERC20Wallet.prototype, "captive", void 0);
|
|
217
|
+
|
|
218
|
+
ERC20Wallet = __decorate([ table("erc20_wallets"), model(), __metadata("design:paramtypes", [ Object ]) ], ERC20Wallet);
|
|
219
|
+
|
|
220
|
+
let Allowance = class Allowance extends BaseModel {
|
|
221
|
+
constructor(m) {
|
|
222
|
+
super(m);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
__decorate([ pk({
|
|
227
|
+
type: String
|
|
228
|
+
}), column(), required(), __metadata("design:type", String) ], Allowance.prototype, "owner", void 0);
|
|
229
|
+
|
|
230
|
+
__decorate([ column(), required(), __metadata("design:type", String) ], Allowance.prototype, "spender", void 0);
|
|
231
|
+
|
|
232
|
+
__decorate([ column(), required(), __metadata("design:type", Number) ], Allowance.prototype, "value", void 0);
|
|
233
|
+
|
|
234
|
+
Allowance = __decorate([ table("erc20_allowances"), model(), __metadata("design:paramtypes", [ Object ]) ], Allowance);
|
|
235
|
+
|
|
236
|
+
class ClientSerializer extends JSONSerializer {
|
|
237
|
+
constructor() {
|
|
238
|
+
super();
|
|
239
|
+
}
|
|
240
|
+
preSerialize(model, modelName) {
|
|
241
|
+
const toSerialize = Object.assign({}, model);
|
|
242
|
+
let metadata = Metadata.modelName(model.constructor);
|
|
243
|
+
if (!metadata || metadata === "Object") if (modelName) metadata = modelName; else throw new SerializationError(`Could not find metadata for ${model.constructor.name}`);
|
|
244
|
+
toSerialize[ModelKeys.ANCHOR] = metadata;
|
|
245
|
+
return toSerialize;
|
|
246
|
+
}
|
|
247
|
+
deserialize(str) {
|
|
248
|
+
const deserialization = JSON.parse(str);
|
|
249
|
+
const className = deserialization[ModelKeys.ANCHOR];
|
|
250
|
+
if (!className) throw new Error("Could not find class reference in serialized model");
|
|
251
|
+
const model = Model.build(deserialization, className);
|
|
252
|
+
return model;
|
|
253
|
+
}
|
|
254
|
+
serialize(model, modelName) {
|
|
255
|
+
return JSON.stringify(this.preSerialize(model, modelName));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
class FabricERC20ClientRepository extends FabricClientRepository {
|
|
260
|
+
static {
|
|
261
|
+
this.serializer = new ClientSerializer;
|
|
262
|
+
}
|
|
263
|
+
static {
|
|
264
|
+
this.decoder = new TextDecoder("utf8");
|
|
265
|
+
}
|
|
266
|
+
async updateObservers(table, event, id, ...args) {
|
|
267
|
+
if (!this.observerHandler) throw new InternalError("ObserverHandler not initialized. Did you register any observables?");
|
|
268
|
+
const {log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.updateObservers);
|
|
269
|
+
log.verbose(`Updating ${this.observerHandler.count()} observers for ${this}`);
|
|
270
|
+
table = typeof table === "string" ? Model.get(table) : table;
|
|
271
|
+
let parsedId;
|
|
272
|
+
if (id === undefined) {
|
|
273
|
+
parsedId = undefined;
|
|
274
|
+
} else if (Array.isArray(id)) {
|
|
275
|
+
parsedId = id.map(i => Sequence.parseValue(Model.sequenceFor(table).type, i));
|
|
276
|
+
} else {
|
|
277
|
+
parsedId = Sequence.parseValue(Model.sequenceFor(table).type, id);
|
|
278
|
+
}
|
|
279
|
+
await this.observerHandler.updateObservers(table, event, parsedId, ...ctxArgs);
|
|
280
|
+
}
|
|
281
|
+
decode(data) {
|
|
282
|
+
return FabricERC20ClientRepository.decoder.decode(data);
|
|
283
|
+
}
|
|
284
|
+
constructor(adapter) {
|
|
285
|
+
super(adapter, ERC20Wallet);
|
|
286
|
+
this.serializer = FabricERC20ClientRepository.serializer;
|
|
287
|
+
}
|
|
288
|
+
async tokenName(...args) {
|
|
289
|
+
const {ctx: ctx} = (await this.logCtx(args, "tokenName", true)).for(this.tokenName);
|
|
290
|
+
const name = await this.adapter.evaluateTransaction(ctx, "TokenName");
|
|
291
|
+
return this.decode(name);
|
|
292
|
+
}
|
|
293
|
+
async symbol(...args) {
|
|
294
|
+
const {ctx: ctx} = (await this.logCtx(args, "symbol", true)).for(this.symbol);
|
|
295
|
+
const symbol = await this.adapter.evaluateTransaction(ctx, "Symbol");
|
|
296
|
+
return this.decode(symbol);
|
|
297
|
+
}
|
|
298
|
+
async decimals(...args) {
|
|
299
|
+
const {ctx: ctx} = (await this.logCtx(args, "decimals", true)).for(this.decimals);
|
|
300
|
+
const decimals = await this.adapter.evaluateTransaction(ctx, "Decimals");
|
|
301
|
+
return Number(this.decode(decimals));
|
|
302
|
+
}
|
|
303
|
+
async totalSupply(...args) {
|
|
304
|
+
const {ctx: ctx} = (await this.logCtx(args, "totalSupply", true)).for(this.totalSupply);
|
|
305
|
+
const total = await this.adapter.evaluateTransaction(ctx, "TotalSupply");
|
|
306
|
+
return Number(this.decode(total));
|
|
307
|
+
}
|
|
308
|
+
async balanceOf(owner, ...args) {
|
|
309
|
+
const {ctx: ctx} = (await this.logCtx(args, "balance", true)).for(this.balanceOf);
|
|
310
|
+
const balance = await this.adapter.evaluateTransaction(ctx, "BalanceOf", [ owner ]);
|
|
311
|
+
return Number(this.decode(balance));
|
|
312
|
+
}
|
|
313
|
+
async transfer(to, value, ...args) {
|
|
314
|
+
const {ctx: ctx} = (await this.logCtx(args, "transfer", true)).for(this.transfer);
|
|
315
|
+
const transferred = await this.adapter.submitTransaction(ctx, "Transfer", [ to, value.toString() ]);
|
|
316
|
+
return this.decode(transferred) === "true" ? true : false;
|
|
317
|
+
}
|
|
318
|
+
async transferFrom(from, to, value) {
|
|
319
|
+
const contextArgs = await Context.args("transferFrom", this.class, [], this.adapter, this._overrides || {});
|
|
320
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.transferFrom);
|
|
321
|
+
const transferred = await this.adapter.submitTransaction(ctx, "TransferFrom", [ from, to, value.toString() ]);
|
|
322
|
+
return this.decode(transferred) === "true" ? true : false;
|
|
323
|
+
}
|
|
324
|
+
async approve(spender, value) {
|
|
325
|
+
const contextArgs = await Context.args("approve", this.class, [], this.adapter, this._overrides || {});
|
|
326
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.approve);
|
|
327
|
+
const approved = await this.adapter.submitTransaction(ctx, "Approve", [ spender, value.toString() ]);
|
|
328
|
+
return this.decode(approved) === "true" ? true : false;
|
|
329
|
+
}
|
|
330
|
+
async allowance(owner, spender) {
|
|
331
|
+
const contextArgs = await Context.args("allowance", this.class, [], this.adapter, this._overrides || {});
|
|
332
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.allowance);
|
|
333
|
+
const allowance = await this.adapter.submitTransaction(ctx, "Allowance", [ owner, spender ]);
|
|
334
|
+
return Number(this.decode(allowance));
|
|
335
|
+
}
|
|
336
|
+
async initialize(token) {
|
|
337
|
+
const contextArgs = await Context.args("initialize", this.class, [], this.adapter, this._overrides || {});
|
|
338
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.initialize);
|
|
339
|
+
const initiliazed = await this.adapter.submitTransaction(ctx, "Initialize", [ FabricERC20ClientRepository.serializer.serialize(token) ]);
|
|
340
|
+
return this.decode(initiliazed) === "true" ? true : false;
|
|
341
|
+
}
|
|
342
|
+
async checkInitialized() {
|
|
343
|
+
const contextArgs = await Context.args("checkInitialized", this.class, [], this.adapter, this._overrides || {});
|
|
344
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.checkInitialized);
|
|
345
|
+
await this.adapter.evaluateTransaction(ctx, "CheckInitialized");
|
|
346
|
+
}
|
|
347
|
+
async mint(amount) {
|
|
348
|
+
const contextArgs = await Context.args("mint", this.class, [], this.adapter, this._overrides || {});
|
|
349
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.mint);
|
|
350
|
+
await this.adapter.submitTransaction(ctx, "Mint", [ amount.toString() ]);
|
|
351
|
+
}
|
|
352
|
+
async burn(amount) {
|
|
353
|
+
const contextArgs = await Context.args("burn", this.class, [], this.adapter, this._overrides || {});
|
|
354
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.burn);
|
|
355
|
+
await this.adapter.submitTransaction(ctx, "Burn", [ amount.toString() ]);
|
|
356
|
+
}
|
|
357
|
+
async burnFrom(account, amount) {
|
|
358
|
+
const contextArgs = await Context.args("burnFrom", this.class, [], this.adapter, this._overrides || {});
|
|
359
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.burnFrom);
|
|
360
|
+
await this.adapter.submitTransaction(ctx, "BurnFrom", [ account, amount.toString() ]);
|
|
361
|
+
}
|
|
362
|
+
async clientAccountBalance() {
|
|
363
|
+
const contextArgs = await Context.args("accountBalance", this.class, [], this.adapter, this._overrides || {});
|
|
364
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.clientAccountBalance);
|
|
365
|
+
const serializedAccountBalance = await this.adapter.evaluateTransaction(ctx, "ClientAccountBalance");
|
|
366
|
+
return Number(this.decode(serializedAccountBalance));
|
|
367
|
+
}
|
|
368
|
+
async clientAccountID() {
|
|
369
|
+
const contextArgs = await Context.args("accountId", this.class, [], this.adapter, this._overrides || {});
|
|
370
|
+
const {ctx: ctx} = this.logCtx(contextArgs.args, this.clientAccountID);
|
|
371
|
+
const clientAccountID = await this.adapter.evaluateTransaction(ctx, "ClientAccountID");
|
|
372
|
+
return this.decode(clientAccountID);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function ensureDirectoryExistence(filePath) {
|
|
377
|
+
const fs = require("fs");
|
|
378
|
+
const path = require("path");
|
|
379
|
+
const dirname = path.dirname(filePath);
|
|
380
|
+
if (fs.existsSync(dirname)) {
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
ensureDirectoryExistence(dirname);
|
|
384
|
+
fs.mkdirSync(dirname);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function generateModelIndexes(m) {
|
|
388
|
+
return generateIndexes([ m ]);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function generateModelDesignDocs(m, accum) {
|
|
392
|
+
const views = generateViews([ m ]);
|
|
393
|
+
const storage = accum || {};
|
|
394
|
+
views.forEach(doc => {
|
|
395
|
+
storage[doc._id] = doc;
|
|
396
|
+
});
|
|
397
|
+
return views;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function readModelFile(file) {
|
|
401
|
+
const path = require("path");
|
|
402
|
+
const exports = require(path.join(process.cwd(), file.parentPath, file.name));
|
|
403
|
+
const values = Object.values(exports).filter(e => {
|
|
404
|
+
try {
|
|
405
|
+
const m = new e;
|
|
406
|
+
return m instanceof Model;
|
|
407
|
+
} catch (e) {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
return values;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async function readModelFolders(...folders) {
|
|
415
|
+
const fs = require("fs");
|
|
416
|
+
const result = [];
|
|
417
|
+
for (const folder of folders) {
|
|
418
|
+
const files = fs.readdirSync(folder, {
|
|
419
|
+
withFileTypes: true,
|
|
420
|
+
recursive: true
|
|
421
|
+
}).filter(f => f.isFile() && f.name.endsWith("js"));
|
|
422
|
+
for (const file of files) {
|
|
423
|
+
result.push(...readModelFile(file));
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return result;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function writeIndexes(indexes, p = process.cwd(), collection) {
|
|
430
|
+
const fs = require("fs");
|
|
431
|
+
const path = require("path");
|
|
432
|
+
indexes.forEach(index => {
|
|
433
|
+
const file = path.resolve(path.join(p, `./META-INF/statedb/couchdb/${collection ? `collections/${collection}/` : ""}indexes/${index.name}.json`));
|
|
434
|
+
ensureDirectoryExistence(file);
|
|
435
|
+
fs.writeFileSync(file, JSON.stringify(index, undefined, 2));
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function writeDesignDocs(designDocs, p = process.cwd(), collection) {
|
|
440
|
+
if (!designDocs.length) return;
|
|
441
|
+
const fs = require("fs");
|
|
442
|
+
const path = require("path");
|
|
443
|
+
designDocs.forEach(doc => {
|
|
444
|
+
const docId = doc._id.replace(/^_design\//, "");
|
|
445
|
+
const file = path.resolve(path.join(p, `./META-INF/statedb/couchdb/${collection ? `collections/${collection}/` : ""}design_docs/${docId}.json`));
|
|
446
|
+
ensureDirectoryExistence(file);
|
|
447
|
+
const payload = {
|
|
448
|
+
...doc
|
|
449
|
+
};
|
|
450
|
+
delete payload._rev;
|
|
451
|
+
fs.writeFileSync(file, JSON.stringify(payload, undefined, 2));
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
let IdentityCredentials = class IdentityCredentials extends BaseModel {
|
|
456
|
+
constructor(arg) {
|
|
457
|
+
super(arg);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
__decorate([ description("Unique identifier of the credentials record"), column(), pk(), __metadata("design:type", String) ], IdentityCredentials.prototype, "id", void 0);
|
|
462
|
+
|
|
463
|
+
__decorate([ description("PEM-encoded X.509 certificate for the identity"), column(), required(), __metadata("design:type", String) ], IdentityCredentials.prototype, "certificate", void 0);
|
|
464
|
+
|
|
465
|
+
__decorate([ description("PEM-encoded root or intermediate certificate"), column(), required(), __metadata("design:type", String) ], IdentityCredentials.prototype, "rootCertificate", void 0);
|
|
466
|
+
|
|
467
|
+
__decorate([ description("PEM-encoded private key"), column(), required(), __metadata("design:type", String) ], IdentityCredentials.prototype, "privateKey", void 0);
|
|
468
|
+
|
|
469
|
+
IdentityCredentials = __decorate([ model(), __metadata("design:paramtypes", [ Object ]) ], IdentityCredentials);
|
|
470
|
+
|
|
471
|
+
var FabricModelKeys;
|
|
472
|
+
|
|
473
|
+
(function(FabricModelKeys) {
|
|
474
|
+
FabricModelKeys["PRIVATE"] = "private";
|
|
475
|
+
FabricModelKeys["SHARED"] = "shared";
|
|
476
|
+
FabricModelKeys["FABRIC"] = "fabric";
|
|
477
|
+
FabricModelKeys["OWNED_BY"] = "owned-by";
|
|
478
|
+
FabricModelKeys["TRANSACTION_ID"] = "transaction-id";
|
|
479
|
+
FabricModelKeys["MIRROR"] = "mirror";
|
|
480
|
+
})(FabricModelKeys || (FabricModelKeys = {}));
|
|
481
|
+
|
|
482
|
+
var IdentityType;
|
|
483
|
+
|
|
484
|
+
(function(IdentityType) {
|
|
485
|
+
IdentityType["X509"] = "X.509";
|
|
486
|
+
})(IdentityType || (IdentityType = {}));
|
|
487
|
+
|
|
488
|
+
const FabricFlavour = "hlf-fabric";
|
|
489
|
+
|
|
490
|
+
let Identity = class Identity extends BaseModel {
|
|
491
|
+
constructor(arg) {
|
|
492
|
+
super(arg);
|
|
493
|
+
this.type = IdentityType.X509;
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
__decorate([ description("Unique identifier of the identity"), pk(), __metadata("design:type", String) ], Identity.prototype, "id", void 0);
|
|
498
|
+
|
|
499
|
+
__decorate([ oneToOne(IdentityCredentials, {
|
|
500
|
+
update: Cascade.CASCADE,
|
|
501
|
+
delete: Cascade.CASCADE
|
|
502
|
+
}), __metadata("design:type", IdentityCredentials) ], Identity.prototype, "credentials", void 0);
|
|
503
|
+
|
|
504
|
+
__decorate([ column(), required(), index(), __metadata("design:type", String) ], Identity.prototype, "mspId", void 0);
|
|
505
|
+
|
|
506
|
+
__decorate([ column(), required(), __metadata("design:type", String) ], Identity.prototype, "type", void 0);
|
|
507
|
+
|
|
508
|
+
Identity = __decorate([ model(), __metadata("design:paramtypes", [ Object ]) ], Identity);
|
|
509
|
+
|
|
510
|
+
class CoreUtils {
|
|
511
|
+
static {
|
|
512
|
+
this.logger = new MiniLogger(CoreUtils.name);
|
|
513
|
+
}
|
|
514
|
+
constructor() {}
|
|
515
|
+
static async contentOfLoadFile(contentOrPath, fileReader) {
|
|
516
|
+
if (contentOrPath instanceof Uint8Array) return contentOrPath;
|
|
517
|
+
if (contentOrPath.match(/-----BEGIN (CERTIFICATE|KEY|PRIVATE KEY)-----.+?-----END \1-----$/gms)) return contentOrPath;
|
|
518
|
+
return await fileReader(contentOrPath);
|
|
519
|
+
}
|
|
520
|
+
static async readFile(contentOrPath) {
|
|
521
|
+
if (typeof contentOrPath !== "string") return contentOrPath;
|
|
522
|
+
const fileReader = async path => {
|
|
523
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
524
|
+
return await promises.readFile(path);
|
|
525
|
+
};
|
|
526
|
+
return await fileReader(contentOrPath);
|
|
527
|
+
}
|
|
528
|
+
static async getCAUser(userName, privateKey, certificate, mspId, options) {
|
|
529
|
+
this.logger.debug(stringFormat("Creating CA {0} user {1} with certificate {2}", mspId, userName, certificate));
|
|
530
|
+
const user = new User(userName);
|
|
531
|
+
const config = options?.hsm ? {
|
|
532
|
+
software: false,
|
|
533
|
+
lib: options.hsm.library,
|
|
534
|
+
slot: options.hsm.slot,
|
|
535
|
+
label: options.hsm.tokenLabel,
|
|
536
|
+
pin: String(options.hsm.pin)
|
|
537
|
+
} : undefined;
|
|
538
|
+
const cryptoSuite = this.getCryptoSuite(config);
|
|
539
|
+
user.setCryptoSuite(cryptoSuite);
|
|
540
|
+
const enrollmentKey = options?.hsm ? await this.getHSMEnrollmentKey(cryptoSuite, certificate, options.hsm) : this.getSoftwareEnrollmentKey(cryptoSuite, privateKey);
|
|
541
|
+
await user.setEnrollment(enrollmentKey, certificate, mspId);
|
|
542
|
+
return user;
|
|
543
|
+
}
|
|
544
|
+
static getCryptoSuite(options) {
|
|
545
|
+
if (!options) return User.newCryptoSuite();
|
|
546
|
+
if (CoreUtils.cryptoSuite) return CoreUtils.cryptoSuite;
|
|
547
|
+
CoreUtils.cryptoSuite = User.newCryptoSuite(options);
|
|
548
|
+
return CoreUtils.cryptoSuite;
|
|
549
|
+
}
|
|
550
|
+
static getSoftwareEnrollmentKey(cryptoSuite, privateKey) {
|
|
551
|
+
if (!privateKey) {
|
|
552
|
+
throw new Error("Private key must be provided when HSM configuration is not supplied");
|
|
553
|
+
}
|
|
554
|
+
return cryptoSuite.createKeyFromRaw(privateKey);
|
|
555
|
+
}
|
|
556
|
+
static async getHSMEnrollmentKey(cryptoSuite, certificate, hsm) {
|
|
557
|
+
const ski = hsm.keyIdHex && hsm.keyIdHex.trim().length > 0 ? Buffer.from(hsm.keyIdHex, "hex") : await this.getCertificateSKI(certificate);
|
|
558
|
+
const key = await cryptoSuite.getKey(ski);
|
|
559
|
+
if (!key || typeof key.isPrivate === "function" && !key.isPrivate()) {
|
|
560
|
+
throw new Error("Unable to resolve private key from HSM");
|
|
561
|
+
}
|
|
562
|
+
return key;
|
|
563
|
+
}
|
|
564
|
+
static async getCertificateSKI(certificate) {
|
|
565
|
+
const x509 = new X509Certificate(certificate);
|
|
566
|
+
const jwk = x509.publicKey.export({
|
|
567
|
+
format: "jwk"
|
|
568
|
+
});
|
|
569
|
+
const prefix = Buffer.from([ 4 ]);
|
|
570
|
+
const x = Buffer.from(jwk.x || "", "base64url");
|
|
571
|
+
const y = Buffer.from(jwk.y || "", "base64url");
|
|
572
|
+
return crypto$1.createHash("sha256").update(Buffer.concat([ prefix, x, y ])).digest();
|
|
573
|
+
}
|
|
574
|
+
static async getIdentity(mspId, certDirectoryPath) {
|
|
575
|
+
const identityFileReader = async path => {
|
|
576
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
577
|
+
const certPath = await this.getFirstDirFileName(path);
|
|
578
|
+
const credentials = await promises.readFile(certPath);
|
|
579
|
+
return credentials;
|
|
580
|
+
};
|
|
581
|
+
const credentials = await this.contentOfLoadFile(certDirectoryPath, identityFileReader);
|
|
582
|
+
return {
|
|
583
|
+
mspId: mspId,
|
|
584
|
+
credentials: credentials
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
static async getFirstDirFileName(dirPath) {
|
|
588
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
589
|
+
const {join: join} = await normalizeImport(import("path"));
|
|
590
|
+
const files = await promises.readdir(dirPath);
|
|
591
|
+
return join(dirPath, files[0]);
|
|
592
|
+
}
|
|
593
|
+
static async getFirstDirFileNameContent(dirPath) {
|
|
594
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
595
|
+
const {join: join} = await normalizeImport(import("path"));
|
|
596
|
+
const files = await promises.readdir(dirPath);
|
|
597
|
+
return (await promises.readFile(join(dirPath, files[0]))).toString();
|
|
598
|
+
}
|
|
599
|
+
static async getFileContent(filePath) {
|
|
600
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
601
|
+
return (await promises.readFile(filePath)).toString();
|
|
602
|
+
}
|
|
603
|
+
static async getSigner(keyDirectoryPath) {
|
|
604
|
+
const signerFileReader = async path => {
|
|
605
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
606
|
+
const keyPath = await this.getFirstDirFileName(path);
|
|
607
|
+
return await promises.readFile(keyPath);
|
|
608
|
+
};
|
|
609
|
+
const privateKeyPem = await this.contentOfLoadFile(keyDirectoryPath, signerFileReader);
|
|
610
|
+
const privateKey = await this.extractPrivateKey(privateKeyPem);
|
|
611
|
+
const keys = Object.getOwnPropertySymbols(privateKey);
|
|
612
|
+
const k = privateKey[keys[0]];
|
|
613
|
+
return signers.newPrivateKeySigner(k);
|
|
614
|
+
}
|
|
615
|
+
static async extractPrivateKey(pem) {
|
|
616
|
+
const libName = "crypto";
|
|
617
|
+
let subtle;
|
|
618
|
+
if (globalThis.window && globalThis.window.Crypto) {
|
|
619
|
+
subtle = globalThis.Crypto.subtle;
|
|
620
|
+
} else {
|
|
621
|
+
const lib = await normalizeImport(import(libName));
|
|
622
|
+
subtle = lib.subtle || lib.webcrypto.subtle;
|
|
623
|
+
}
|
|
624
|
+
if (!subtle) throw new Error("Could not load SubtleCrypto module");
|
|
625
|
+
function str2ab(str) {
|
|
626
|
+
const buf = new ArrayBuffer(str.length);
|
|
627
|
+
const bufView = new Uint8Array(buf);
|
|
628
|
+
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
629
|
+
bufView[i] = str.charCodeAt(i);
|
|
630
|
+
}
|
|
631
|
+
return buf;
|
|
632
|
+
}
|
|
633
|
+
const str = pem.toString("utf8").replace("-----BEGIN PRIVATE KEY-----", "").replaceAll("\n", "").replace("-----END PRIVATE KEY-----", "");
|
|
634
|
+
const decoded = Buffer.from(str, "base64").toString("binary");
|
|
635
|
+
const binaryDer = str2ab(decoded);
|
|
636
|
+
const key = await subtle.importKey("pkcs8", binaryDer, {
|
|
637
|
+
name: "ECDSA",
|
|
638
|
+
namedCurve: "P-256"
|
|
639
|
+
}, true, [ "sign" ]);
|
|
640
|
+
return key;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
const crypto = new Crypto;
|
|
645
|
+
|
|
646
|
+
x509.cryptoProvider.set(crypto);
|
|
647
|
+
|
|
648
|
+
var BASE_ALPHABET;
|
|
649
|
+
|
|
650
|
+
(function(BASE_ALPHABET) {
|
|
651
|
+
BASE_ALPHABET["BASE2"] = "01";
|
|
652
|
+
BASE_ALPHABET["BASE8"] = "01234567";
|
|
653
|
+
BASE_ALPHABET["BASE11"] = "0123456789a";
|
|
654
|
+
BASE_ALPHABET["BASE16"] = "0123456789abcdef";
|
|
655
|
+
BASE_ALPHABET["BASE32"] = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
656
|
+
BASE_ALPHABET["BASE32_Z"] = "ybndrfg8ejkmcpqxot1uwisza345h769";
|
|
657
|
+
BASE_ALPHABET["BASE36"] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
658
|
+
BASE_ALPHABET["BASE58"] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
659
|
+
BASE_ALPHABET["BASE62"] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
660
|
+
BASE_ALPHABET["BASE64"] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
661
|
+
BASE_ALPHABET["BASE67"] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.!~";
|
|
662
|
+
})(BASE_ALPHABET || (BASE_ALPHABET = {}));
|
|
663
|
+
|
|
664
|
+
var CRYPTO;
|
|
665
|
+
|
|
666
|
+
(function(CRYPTO) {
|
|
667
|
+
CRYPTO["HASH"] = "SHA-256";
|
|
668
|
+
CRYPTO[CRYPTO["ITERATIONS"] = 1e3] = "ITERATIONS";
|
|
669
|
+
CRYPTO[CRYPTO["KEYLENGTH"] = 48] = "KEYLENGTH";
|
|
670
|
+
CRYPTO[CRYPTO["DERIVED_IV_LENGTH"] = 16] = "DERIVED_IV_LENGTH";
|
|
671
|
+
CRYPTO[CRYPTO["DERIVED_KEY_LENGTH"] = 32] = "DERIVED_KEY_LENGTH";
|
|
672
|
+
CRYPTO["ALGORYTHM"] = "AES-GCM";
|
|
673
|
+
CRYPTO["KEY_ALGORYTHM"] = "PBKDF2";
|
|
674
|
+
})(CRYPTO || (CRYPTO = {}));
|
|
675
|
+
|
|
676
|
+
class BaseEncoder {
|
|
677
|
+
constructor(alphabet) {
|
|
678
|
+
this.alphabet = alphabet;
|
|
679
|
+
this.baseMap = new Uint8Array(256);
|
|
680
|
+
if (this.alphabet.length >= 255) throw new Error("Alphabet too long");
|
|
681
|
+
for (let j = 0; j < this.baseMap.length; j++) this.baseMap[j] = 255;
|
|
682
|
+
for (let i = 0; i < alphabet.length; i++) {
|
|
683
|
+
const x = alphabet.charAt(i);
|
|
684
|
+
const xc = x.charCodeAt(0);
|
|
685
|
+
if (this.baseMap[xc] !== 255) throw new Error(x + " is ambiguous");
|
|
686
|
+
this.baseMap[xc] = i;
|
|
687
|
+
}
|
|
688
|
+
this.base = this.alphabet.length;
|
|
689
|
+
this.leader = this.alphabet.charAt(0);
|
|
690
|
+
this.factor = Math.log(this.base) / Math.log(256);
|
|
691
|
+
this.iFactor = Math.log(256) / Math.log(this.base);
|
|
692
|
+
}
|
|
693
|
+
encode(source) {
|
|
694
|
+
if (typeof source === "string") {
|
|
695
|
+
source = Buffer.from(source);
|
|
696
|
+
} else if (ArrayBuffer.isView(source)) {
|
|
697
|
+
source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
698
|
+
} else if (Array.isArray(source)) {
|
|
699
|
+
source = Uint8Array.from(source);
|
|
700
|
+
}
|
|
701
|
+
if (source.length === 0) return "";
|
|
702
|
+
let zeroes = 0;
|
|
703
|
+
let length = 0;
|
|
704
|
+
let pbegin = 0;
|
|
705
|
+
const pend = source.length;
|
|
706
|
+
while (pbegin !== pend && source[pbegin] === 0) {
|
|
707
|
+
pbegin++;
|
|
708
|
+
zeroes++;
|
|
709
|
+
}
|
|
710
|
+
const size = (pend - pbegin) * this.iFactor + 1 >>> 0;
|
|
711
|
+
const b58 = new Uint8Array(size);
|
|
712
|
+
while (pbegin !== pend) {
|
|
713
|
+
let carry = source[pbegin];
|
|
714
|
+
let i = 0;
|
|
715
|
+
for (let it1 = size - 1; (carry !== 0 || i < length) && it1 !== -1; it1--, i++) {
|
|
716
|
+
carry += 256 * b58[it1] >>> 0;
|
|
717
|
+
b58[it1] = carry % this.base >>> 0;
|
|
718
|
+
carry = carry / this.base >>> 0;
|
|
719
|
+
}
|
|
720
|
+
if (carry !== 0) throw new Error("Non-zero carry");
|
|
721
|
+
length = i;
|
|
722
|
+
pbegin++;
|
|
723
|
+
}
|
|
724
|
+
let it2 = size - length;
|
|
725
|
+
while (it2 !== size && b58[it2] === 0) it2++;
|
|
726
|
+
let str = this.leader.repeat(zeroes);
|
|
727
|
+
for (;it2 < size; ++it2) {
|
|
728
|
+
str += this.alphabet.charAt(b58[it2]);
|
|
729
|
+
}
|
|
730
|
+
return str;
|
|
731
|
+
}
|
|
732
|
+
decodeUnsafe(source) {
|
|
733
|
+
if (source.length === 0) return new Uint8Array(0);
|
|
734
|
+
let psz = 0;
|
|
735
|
+
let zeroes = 0;
|
|
736
|
+
let length = 0;
|
|
737
|
+
while (source[psz] === this.leader) {
|
|
738
|
+
zeroes++;
|
|
739
|
+
psz++;
|
|
740
|
+
}
|
|
741
|
+
const size = (source.length - psz) * this.factor + 1 >>> 0;
|
|
742
|
+
const b256 = new Uint8Array(size);
|
|
743
|
+
while (source[psz]) {
|
|
744
|
+
let carry = this.baseMap[source.charCodeAt(psz)];
|
|
745
|
+
if (carry === 255) return;
|
|
746
|
+
let i = 0;
|
|
747
|
+
for (let it3 = size - 1; (carry !== 0 || i < length) && it3 !== -1; it3--, i++) {
|
|
748
|
+
carry += this.base * b256[it3] >>> 0;
|
|
749
|
+
b256[it3] = carry % 256 >>> 0;
|
|
750
|
+
carry = carry / 256 >>> 0;
|
|
751
|
+
}
|
|
752
|
+
if (carry !== 0) throw new Error("Non-zero carry");
|
|
753
|
+
length = i;
|
|
754
|
+
psz++;
|
|
755
|
+
}
|
|
756
|
+
let it4 = size - length;
|
|
757
|
+
while (it4 !== size && b256[it4] === 0) it4++;
|
|
758
|
+
const vch = new Uint8Array(zeroes + (size - it4));
|
|
759
|
+
let j = zeroes;
|
|
760
|
+
while (it4 !== size) vch[j++] = b256[it4++];
|
|
761
|
+
return vch;
|
|
762
|
+
}
|
|
763
|
+
decode(source) {
|
|
764
|
+
const buffer = this.decodeUnsafe(source);
|
|
765
|
+
if (buffer) return buffer;
|
|
766
|
+
throw new Error("Non-base" + this.base + " character");
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
class CryptoUtils {
|
|
771
|
+
static {
|
|
772
|
+
this.b58encoder = new BaseEncoder(BASE_ALPHABET.BASE58);
|
|
773
|
+
}
|
|
774
|
+
static {
|
|
775
|
+
this.logger = new MiniLogger(CryptoUtils.name);
|
|
776
|
+
}
|
|
777
|
+
constructor() {}
|
|
778
|
+
static fabricIdFromCertificate(certificate) {
|
|
779
|
+
this.logger.debug(stringFormat("Parsing certificate: {0}", certificate));
|
|
780
|
+
const cert = new x509.X509Certificate(certificate);
|
|
781
|
+
const {subject: subject, issuer: issuer} = cert;
|
|
782
|
+
this.logger.debug(stringFormat("Certificate parsed with subject {0} and issuer {1}", subject, issuer));
|
|
783
|
+
return `x509::/${subject.replaceAll(", ", "/")}::/${issuer.replaceAll(", ", "/")}`;
|
|
784
|
+
}
|
|
785
|
+
static encode(str) {
|
|
786
|
+
return this.b58encoder.encode(str);
|
|
787
|
+
}
|
|
788
|
+
static decode(str) {
|
|
789
|
+
const decoded = this.b58encoder.decode(str);
|
|
790
|
+
const result = (new TextDecoder).decode(decoded);
|
|
791
|
+
return result;
|
|
792
|
+
}
|
|
793
|
+
static stringToArrayBuffer(str) {
|
|
794
|
+
const buf = new ArrayBuffer(str.length);
|
|
795
|
+
const bufView = new Uint8Array(buf);
|
|
796
|
+
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
797
|
+
bufView[i] = str.charCodeAt(i);
|
|
798
|
+
}
|
|
799
|
+
return buf;
|
|
800
|
+
}
|
|
801
|
+
static async extractKey(type, pem, usages) {
|
|
802
|
+
const subtle = crypto.subtle;
|
|
803
|
+
const str = pem.toString("utf8").replace(new RegExp(`-----BEGIN (${type.toUpperCase()} KEY|CERTIFICATE)-----`), "").replaceAll("\n", "").replace(new RegExp(`-----END (${type.toUpperCase()} KEY|CERTIFICATE)-----`), "");
|
|
804
|
+
const decoded = Buffer.from(str, "base64").toString("binary");
|
|
805
|
+
const binaryDer = this.stringToArrayBuffer(decoded);
|
|
806
|
+
const key = await subtle.importKey("pkcs8", binaryDer, {
|
|
807
|
+
name: "ECDSA",
|
|
808
|
+
namedCurve: "P-256"
|
|
809
|
+
}, true, usages ? usages : [ "sign" ]);
|
|
810
|
+
return key;
|
|
811
|
+
}
|
|
812
|
+
static async extractPrivateKey(pem, usages) {
|
|
813
|
+
return this.extractKey("private", pem, usages);
|
|
814
|
+
}
|
|
815
|
+
static async extractPublicKey(pem, usages) {
|
|
816
|
+
return this.extractKey("public", pem, usages);
|
|
817
|
+
}
|
|
818
|
+
static async sign(privateKey, data) {
|
|
819
|
+
const key = await this.extractPrivateKey(privateKey);
|
|
820
|
+
const buff = await crypto.subtle.sign({
|
|
821
|
+
name: "ECDSA",
|
|
822
|
+
hash: "SHA-256"
|
|
823
|
+
}, key, data);
|
|
824
|
+
return Array.from(new Uint8Array(buff)).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
825
|
+
}
|
|
826
|
+
static async verify(certificate, signature, data) {
|
|
827
|
+
const cert = new x509.X509Certificate(certificate);
|
|
828
|
+
const key = await cert.publicKey.export();
|
|
829
|
+
signature = typeof signature === "string" ? Buffer.from(signature, "hex") : signature;
|
|
830
|
+
data = typeof data === "string" ? Buffer.from(data) : data;
|
|
831
|
+
return crypto.subtle.verify({
|
|
832
|
+
name: "ECDSA",
|
|
833
|
+
hash: "SHA-256"
|
|
834
|
+
}, key, signature, data);
|
|
835
|
+
}
|
|
836
|
+
static async encrypt(certificate, data) {
|
|
837
|
+
const cert = new x509.X509Certificate(certificate);
|
|
838
|
+
const key = await cert.publicKey.export();
|
|
839
|
+
data = typeof data === "string" ? Buffer.from(data) : data;
|
|
840
|
+
const buff = await this.getSubtleCrypto().encrypt({
|
|
841
|
+
name: "ECDSA"
|
|
842
|
+
}, key, data);
|
|
843
|
+
return Array.from(new Uint8Array(buff)).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
844
|
+
}
|
|
845
|
+
static getSubtleCrypto() {
|
|
846
|
+
return isBrowser() ? globalThis.window.crypto.subtle : crypto.subtle;
|
|
847
|
+
}
|
|
848
|
+
static async decrypt(privateKey, data) {
|
|
849
|
+
const key = await this.extractPrivateKey(privateKey);
|
|
850
|
+
data = typeof data === "string" ? Buffer.from(data, "hex") : data;
|
|
851
|
+
return this.getSubtleCrypto().decrypt({
|
|
852
|
+
name: "ECDSA"
|
|
853
|
+
}, key, data);
|
|
854
|
+
}
|
|
855
|
+
static async getMaster(data) {
|
|
856
|
+
const textEncoder = new TextEncoder;
|
|
857
|
+
if (data === undefined) {
|
|
858
|
+
const genGenesis = crypto.randomUUID();
|
|
859
|
+
data = textEncoder.encode(genGenesis).buffer;
|
|
860
|
+
}
|
|
861
|
+
const importedKey = await this.getSubtleCrypto().importKey("raw", data, CRYPTO.KEY_ALGORYTHM, false, [ "deriveBits" ]);
|
|
862
|
+
return {
|
|
863
|
+
key: importedKey,
|
|
864
|
+
iv: data
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
static async getDerivationKey(salt, key) {
|
|
868
|
+
const textEncoder = new TextEncoder;
|
|
869
|
+
const saltBuffer = textEncoder.encode(salt);
|
|
870
|
+
const saltHashed = await this.getSubtleCrypto().digest("SHA-256", saltBuffer);
|
|
871
|
+
const params = {
|
|
872
|
+
name: CRYPTO.KEY_ALGORYTHM,
|
|
873
|
+
hash: CRYPTO.HASH,
|
|
874
|
+
salt: saltHashed,
|
|
875
|
+
iterations: CRYPTO.ITERATIONS
|
|
876
|
+
};
|
|
877
|
+
const derivation = await this.getSubtleCrypto().deriveBits(params, key, CRYPTO.KEYLENGTH * 8);
|
|
878
|
+
return this.getKey(derivation);
|
|
879
|
+
}
|
|
880
|
+
static async getKey(derivation) {
|
|
881
|
+
const ivlen = 16;
|
|
882
|
+
const keylen = 32;
|
|
883
|
+
const derivedKey = derivation.slice(0, keylen);
|
|
884
|
+
const iv = derivation.slice(keylen);
|
|
885
|
+
const importedEncryptionKey = await this.getSubtleCrypto().importKey("raw", derivedKey, {
|
|
886
|
+
name: CRYPTO.ALGORYTHM
|
|
887
|
+
}, false, [ "encrypt", "decrypt" ]);
|
|
888
|
+
return {
|
|
889
|
+
key: importedEncryptionKey,
|
|
890
|
+
iv: iv
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
static async encryptPin(text, keyObject) {
|
|
894
|
+
const textEncoder = new TextEncoder;
|
|
895
|
+
const textBuffer = textEncoder.encode(text);
|
|
896
|
+
const encryptedText = await this.getSubtleCrypto().encrypt({
|
|
897
|
+
name: CRYPTO.ALGORYTHM,
|
|
898
|
+
iv: keyObject.iv
|
|
899
|
+
}, keyObject.key, textBuffer);
|
|
900
|
+
return encryptedText;
|
|
901
|
+
}
|
|
902
|
+
static async decryptPin(encryptedText, keyObject) {
|
|
903
|
+
const textDecoder = new TextDecoder;
|
|
904
|
+
const decryptedText = await this.getSubtleCrypto().decrypt({
|
|
905
|
+
name: CRYPTO.ALGORYTHM,
|
|
906
|
+
iv: keyObject.iv
|
|
907
|
+
}, keyObject.key, encryptedText);
|
|
908
|
+
return textDecoder.decode(decryptedText);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
class OverflowError extends InternalError {
|
|
913
|
+
constructor(msg) {
|
|
914
|
+
super(msg, OverflowError.name);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
class BalanceError extends InternalError {
|
|
919
|
+
constructor(msg) {
|
|
920
|
+
super(msg, BalanceError.name);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
class AllowanceError extends InternalError {
|
|
925
|
+
constructor(msg) {
|
|
926
|
+
super(msg, AllowanceError.name);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
class RegistrationError extends AuthorizationError {
|
|
931
|
+
constructor(msg) {
|
|
932
|
+
super(msg, RegistrationError.name);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
class MissingContextError extends InternalError {
|
|
937
|
+
constructor(msg) {
|
|
938
|
+
super(msg, MissingContextError.name, 500);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
class UnauthorizedPrivateDataAccess extends BaseError {
|
|
943
|
+
constructor(msg = "MISSING_PRIVATE_DATA_ERROR_MESSAGE") {
|
|
944
|
+
super(UnauthorizedPrivateDataAccess.name, msg, 403);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
class NotInitializedError extends BaseError {
|
|
949
|
+
constructor(msg) {
|
|
950
|
+
super(NotInitializedError.name, msg, 409);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
class MissingPKCSS11Lib extends InternalError {
|
|
955
|
+
constructor(msg) {
|
|
956
|
+
super(msg, MissingPKCSS11Lib.name, 500);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
class EndorsementError extends InternalError {
|
|
961
|
+
constructor(message) {
|
|
962
|
+
super(message, EndorsementError.name, 500);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
class MvccReadConflictError extends InternalError {
|
|
967
|
+
constructor(message) {
|
|
968
|
+
super(message, MvccReadConflictError.name, 500);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
class PhantomReadConflictError extends InternalError {
|
|
973
|
+
constructor(message) {
|
|
974
|
+
super(message, PhantomReadConflictError.name, 500);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
class EndorsementPolicyError extends InternalError {
|
|
979
|
+
constructor(message) {
|
|
980
|
+
super(message, EndorsementPolicyError.name, 500);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
var HFCAIdentityType;
|
|
985
|
+
|
|
986
|
+
(function(HFCAIdentityType) {
|
|
987
|
+
HFCAIdentityType["PEER"] = "peer";
|
|
988
|
+
HFCAIdentityType["ORDERER"] = "orderer";
|
|
989
|
+
HFCAIdentityType["CLIENT"] = "client";
|
|
990
|
+
HFCAIdentityType["USER"] = "user";
|
|
991
|
+
HFCAIdentityType["ADMIN"] = "admin";
|
|
992
|
+
})(HFCAIdentityType || (HFCAIdentityType = {}));
|
|
993
|
+
|
|
994
|
+
var HFCAIdentityAttributes;
|
|
995
|
+
|
|
996
|
+
(function(HFCAIdentityAttributes) {
|
|
997
|
+
HFCAIdentityAttributes["HFREGISTRARROLES"] = "hf.Registrar.Roles";
|
|
998
|
+
HFCAIdentityAttributes["HFREGISTRARDELEGATEROLES"] = "hf.Registrar.DelegateRoles";
|
|
999
|
+
HFCAIdentityAttributes["HFREGISTRARATTRIBUTES"] = "hf.Registrar.Attributes";
|
|
1000
|
+
HFCAIdentityAttributes["HFINTERMEDIATECA"] = "hf.IntermediateCA";
|
|
1001
|
+
HFCAIdentityAttributes["HFREVOKER"] = "hf.Revoker";
|
|
1002
|
+
HFCAIdentityAttributes["HFAFFILIATIONMGR"] = "hf.AffiliationMgr";
|
|
1003
|
+
HFCAIdentityAttributes["HFGENCRL"] = "hf.GenCRL";
|
|
1004
|
+
})(HFCAIdentityAttributes || (HFCAIdentityAttributes = {}));
|
|
1005
|
+
|
|
1006
|
+
class FabricEnrollmentService extends LoggedClass {
|
|
1007
|
+
constructor(caConfig) {
|
|
1008
|
+
CoreUtils.getCryptoSuite(caConfig.hsm ? {
|
|
1009
|
+
software: false,
|
|
1010
|
+
lib: caConfig.hsm.library,
|
|
1011
|
+
slot: caConfig.hsm.slot,
|
|
1012
|
+
label: caConfig.hsm.tokenLabel,
|
|
1013
|
+
pin: String(caConfig.hsm.pin)
|
|
1014
|
+
} : undefined);
|
|
1015
|
+
super();
|
|
1016
|
+
this.caConfig = caConfig;
|
|
1017
|
+
}
|
|
1018
|
+
async User() {
|
|
1019
|
+
if (this.user) return this.user;
|
|
1020
|
+
const {caName: caName, caCert: caCert, caKey: caKey, url: url, hsm: hsm} = this.caConfig;
|
|
1021
|
+
const log = this.log.for(this.User);
|
|
1022
|
+
log.debug(`Creating CA user for ${caName} at ${url}`);
|
|
1023
|
+
log.debug(`Retrieving CA certificate from ${caCert}`);
|
|
1024
|
+
const certificate = await CoreUtils.getFirstDirFileNameContent(caCert);
|
|
1025
|
+
let key;
|
|
1026
|
+
if (!hsm) {
|
|
1027
|
+
if (!caKey) {
|
|
1028
|
+
throw new InternalError(`Missing caKey configuration for CA ${caName}. Provide a key directory or configure HSM support.`);
|
|
1029
|
+
}
|
|
1030
|
+
log.debug(`Retrieving CA key from ${caKey}`);
|
|
1031
|
+
key = await CoreUtils.getFirstDirFileNameContent(caKey);
|
|
1032
|
+
} else {
|
|
1033
|
+
log.debug(`Using HSM configuration for CA ${caName} with library ${hsm.library}`);
|
|
1034
|
+
}
|
|
1035
|
+
log.debug(`Loading Admin user for ca ${caName}`);
|
|
1036
|
+
this.user = await CoreUtils.getCAUser("admin", key, certificate, caName, {
|
|
1037
|
+
hsm: hsm
|
|
1038
|
+
});
|
|
1039
|
+
return this.user;
|
|
1040
|
+
}
|
|
1041
|
+
async CA() {
|
|
1042
|
+
if (this.ca) return this.ca;
|
|
1043
|
+
const log = this.log.for(this.CA);
|
|
1044
|
+
const {url: url, tls: tls, caName: caName} = this.caConfig;
|
|
1045
|
+
let {trustedRoots: trustedRoots, verify: verify} = tls;
|
|
1046
|
+
const root = trustedRoots[0];
|
|
1047
|
+
log.debug(`Retrieving CA certificate from ${root}. cwd: ${process.cwd()}`);
|
|
1048
|
+
const certificate = await CoreUtils.getFileContent(root);
|
|
1049
|
+
log.debug(`Creating CA Client for CA ${caName} under ${url}`);
|
|
1050
|
+
this.ca = new FabricCAServices(url, {
|
|
1051
|
+
trustedRoots: Buffer.from(certificate),
|
|
1052
|
+
verify: verify
|
|
1053
|
+
}, caName);
|
|
1054
|
+
return this.ca;
|
|
1055
|
+
}
|
|
1056
|
+
async Client() {
|
|
1057
|
+
if (this.client) return this.client;
|
|
1058
|
+
const ca = await this.CA();
|
|
1059
|
+
this.client = ca["_FabricCAServices"];
|
|
1060
|
+
return this.client;
|
|
1061
|
+
}
|
|
1062
|
+
async Certificate() {
|
|
1063
|
+
if (!this.certificateService) this.certificateService = (await this.Client()).newCertificateService();
|
|
1064
|
+
return this.certificateService;
|
|
1065
|
+
}
|
|
1066
|
+
async Affiliations() {
|
|
1067
|
+
if (!this.affiliationService) this.affiliationService = (await this.CA()).newAffiliationService();
|
|
1068
|
+
return this.affiliationService;
|
|
1069
|
+
}
|
|
1070
|
+
async Identities() {
|
|
1071
|
+
if (!this.identityService) this.identityService = (await this.CA()).newIdentityService();
|
|
1072
|
+
return this.identityService;
|
|
1073
|
+
}
|
|
1074
|
+
async getCertificates(request, doMap = true) {
|
|
1075
|
+
const certificateService = await this.Certificate();
|
|
1076
|
+
const user = await this.User();
|
|
1077
|
+
const log = this.log.for(this.getCertificates);
|
|
1078
|
+
log.debug(`Retrieving certificates${request ? ` for ${request.id}` : ""} for CA ${this.caConfig.caName}`);
|
|
1079
|
+
const response = (await certificateService.getCertificates(request || {}, user)).result;
|
|
1080
|
+
log.debug(`Found ${response.certs.length} certificates: ${JSON.stringify(response)}`);
|
|
1081
|
+
return doMap ? response.certs.map(c => c.PEM) : response;
|
|
1082
|
+
}
|
|
1083
|
+
async getIdentities() {
|
|
1084
|
+
const identitiesService = await this.Identities();
|
|
1085
|
+
const log = this.log.for(this.getIdentities);
|
|
1086
|
+
log.debug(`Retrieving Identities under CA ${this.caConfig.caName}`);
|
|
1087
|
+
const response = (await identitiesService.getAll(await this.User())).result;
|
|
1088
|
+
log.debug(`Found ${response.identities.length} Identities: ${JSON.stringify(response)}`);
|
|
1089
|
+
return response.identities;
|
|
1090
|
+
}
|
|
1091
|
+
parseError(e) {
|
|
1092
|
+
const regexp = /.*code:\s(\d+).*?message:\s["'](.+)["']/gs;
|
|
1093
|
+
const match = regexp.exec(e.message);
|
|
1094
|
+
if (!match) return new RegistrationError(e);
|
|
1095
|
+
const [, code, message] = match;
|
|
1096
|
+
switch (code) {
|
|
1097
|
+
case "74":
|
|
1098
|
+
case "71":
|
|
1099
|
+
return new ConflictError(message);
|
|
1100
|
+
|
|
1101
|
+
case "20":
|
|
1102
|
+
return new AuthorizationError(message);
|
|
1103
|
+
|
|
1104
|
+
default:
|
|
1105
|
+
return new RegistrationError(message);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
async getAffiliations() {
|
|
1109
|
+
const affiliationService = await this.Affiliations();
|
|
1110
|
+
const log = this.log.for(this.getAffiliations);
|
|
1111
|
+
log.debug(`Retrieving Affiliations under CA ${this.caConfig.caName}`);
|
|
1112
|
+
const response = (await affiliationService.getAll(await this.User())).result;
|
|
1113
|
+
log.debug(`Found ${response.a.length} Affiliations: ${JSON.stringify(response)}`);
|
|
1114
|
+
return response;
|
|
1115
|
+
}
|
|
1116
|
+
async read(enrollmentId) {
|
|
1117
|
+
const ca = await this.CA();
|
|
1118
|
+
const user = await this.User();
|
|
1119
|
+
let result;
|
|
1120
|
+
try {
|
|
1121
|
+
result = await ca.newIdentityService().getOne(enrollmentId, user);
|
|
1122
|
+
} catch (e) {
|
|
1123
|
+
throw new NotFoundError(`Couldn't find enrollment with id ${enrollmentId}: ${e}`);
|
|
1124
|
+
}
|
|
1125
|
+
if (!result.success) throw new NotFoundError(`Couldn't find enrollment with id ${enrollmentId}: ${result.errors.join("\n")}`);
|
|
1126
|
+
return result.result;
|
|
1127
|
+
}
|
|
1128
|
+
async register(model, isSuperUser = false, affiliation = "", userRole, attrs, maxEnrollments) {
|
|
1129
|
+
let registration;
|
|
1130
|
+
const log = this.log.for(this.register);
|
|
1131
|
+
try {
|
|
1132
|
+
const {userName: userName, password: password} = model;
|
|
1133
|
+
const ca = await this.CA();
|
|
1134
|
+
const user = await this.User();
|
|
1135
|
+
const props = {
|
|
1136
|
+
enrollmentID: userName,
|
|
1137
|
+
enrollmentSecret: password,
|
|
1138
|
+
affiliation: affiliation,
|
|
1139
|
+
userRole: userRole,
|
|
1140
|
+
attrs: attrs,
|
|
1141
|
+
maxEnrollments: maxEnrollments
|
|
1142
|
+
};
|
|
1143
|
+
registration = await ca.register(props, user);
|
|
1144
|
+
log.info(`Registration for ${userName} created with user type ${userRole ?? "Undefined Role"} ${isSuperUser ? "as super user" : ""}`);
|
|
1145
|
+
} catch (e) {
|
|
1146
|
+
throw this.parseError(e);
|
|
1147
|
+
}
|
|
1148
|
+
return registration;
|
|
1149
|
+
}
|
|
1150
|
+
static identityFromEnrollment(enrollment, mspId) {
|
|
1151
|
+
const {certificate: certificate, key: key, rootCertificate: rootCertificate} = enrollment;
|
|
1152
|
+
const log = Logging.for(FabricEnrollmentService, {}).for(this.identityFromEnrollment);
|
|
1153
|
+
log.debug(`Generating Identity from certificate ${certificate} in msp ${mspId}`);
|
|
1154
|
+
const clientId = CryptoUtils.fabricIdFromCertificate(certificate);
|
|
1155
|
+
const id = CryptoUtils.encode(clientId);
|
|
1156
|
+
log.debug(`Identity ${clientId} and encodedId ${id}`);
|
|
1157
|
+
const now = new Date;
|
|
1158
|
+
return new Identity({
|
|
1159
|
+
id: id,
|
|
1160
|
+
credentials: {
|
|
1161
|
+
id: id,
|
|
1162
|
+
certificate: certificate,
|
|
1163
|
+
privateKey: key.toBytes(),
|
|
1164
|
+
rootCertificate: rootCertificate,
|
|
1165
|
+
createdOn: now,
|
|
1166
|
+
updatedOn: now
|
|
1167
|
+
},
|
|
1168
|
+
mspId: mspId,
|
|
1169
|
+
createdOn: now,
|
|
1170
|
+
updatedOn: now
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
async enroll(enrollmentId, registration) {
|
|
1174
|
+
let identity;
|
|
1175
|
+
const log = this.log.for(this.enroll);
|
|
1176
|
+
try {
|
|
1177
|
+
const ca = await this.CA();
|
|
1178
|
+
log.debug(`Enrolling ${enrollmentId}`);
|
|
1179
|
+
const enrollment = await ca.enroll({
|
|
1180
|
+
enrollmentID: enrollmentId,
|
|
1181
|
+
enrollmentSecret: registration
|
|
1182
|
+
});
|
|
1183
|
+
identity = FabricEnrollmentService.identityFromEnrollment(enrollment, this.caConfig.caName);
|
|
1184
|
+
log.info(`Successfully enrolled ${enrollmentId} under ${this.caConfig.caName} as ${identity.id}`);
|
|
1185
|
+
} catch (e) {
|
|
1186
|
+
throw this.parseError(e);
|
|
1187
|
+
}
|
|
1188
|
+
return identity;
|
|
1189
|
+
}
|
|
1190
|
+
async registerAndEnroll(model, isSuperUser = false, affiliation = "", userRole, attrs, maxEnrollments) {
|
|
1191
|
+
const registration = await this.register(model, isSuperUser, affiliation, userRole, attrs, maxEnrollments);
|
|
1192
|
+
const {userName: userName} = model;
|
|
1193
|
+
return this.enroll(userName, registration);
|
|
1194
|
+
}
|
|
1195
|
+
async revoke(enrollmentId) {
|
|
1196
|
+
const ca = await this.CA();
|
|
1197
|
+
const user = await this.User();
|
|
1198
|
+
const identity = await this.read(enrollmentId);
|
|
1199
|
+
if (!identity) throw new NotFoundError(`Could not find enrollment with id ${enrollmentId}`);
|
|
1200
|
+
let result;
|
|
1201
|
+
try {
|
|
1202
|
+
result = await ca.revoke({
|
|
1203
|
+
enrollmentID: identity.id,
|
|
1204
|
+
reason: "User Deletation"
|
|
1205
|
+
}, user);
|
|
1206
|
+
} catch (e) {
|
|
1207
|
+
throw new InternalError(`Could not revoke enrollment with id ${enrollmentId}: ${e}`);
|
|
1208
|
+
}
|
|
1209
|
+
if (!result.success) throw new InternalError(`Could not revoke enrollment with id ${enrollmentId}: ${result.errors.join("\n")}`);
|
|
1210
|
+
return result;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
class RegistrationRequestBuilder extends Model {
|
|
1215
|
+
constructor() {
|
|
1216
|
+
super(...arguments);
|
|
1217
|
+
this.affiliation = "";
|
|
1218
|
+
}
|
|
1219
|
+
build() {
|
|
1220
|
+
const errs = this.hasErrors();
|
|
1221
|
+
if (errs) throw new ValidationError(errs.toString());
|
|
1222
|
+
const response = {
|
|
1223
|
+
enrollmentID: this.enrollmentID,
|
|
1224
|
+
enrollmentSecret: this.enrollmentSecret,
|
|
1225
|
+
role: this.role,
|
|
1226
|
+
affiliation: this.affiliation
|
|
1227
|
+
};
|
|
1228
|
+
if (typeof this.maxEnrollments !== "undefined") response.maxEnrollments = this.maxEnrollments;
|
|
1229
|
+
if (this.attrs) response.attrs = this.attrs;
|
|
1230
|
+
return response;
|
|
1231
|
+
}
|
|
1232
|
+
setAffiliation(value) {
|
|
1233
|
+
this.affiliation = value;
|
|
1234
|
+
return this;
|
|
1235
|
+
}
|
|
1236
|
+
addAttr(attr) {
|
|
1237
|
+
this.attrs = this.attrs || [];
|
|
1238
|
+
this.attrs.push(attr);
|
|
1239
|
+
return this;
|
|
1240
|
+
}
|
|
1241
|
+
setAttrs(value) {
|
|
1242
|
+
this.attrs = value;
|
|
1243
|
+
return this;
|
|
1244
|
+
}
|
|
1245
|
+
setEnrollmentID(value) {
|
|
1246
|
+
this.enrollmentID = value;
|
|
1247
|
+
return this;
|
|
1248
|
+
}
|
|
1249
|
+
setEnrollmentSecret(value) {
|
|
1250
|
+
this.enrollmentSecret = value;
|
|
1251
|
+
return this;
|
|
1252
|
+
}
|
|
1253
|
+
setMaxEnrollments(value) {
|
|
1254
|
+
this.maxEnrollments = value;
|
|
1255
|
+
return this;
|
|
1256
|
+
}
|
|
1257
|
+
setRole(value) {
|
|
1258
|
+
this.role = value;
|
|
1259
|
+
return this;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
__decorate([ required(), __metadata("design:type", String) ], RegistrationRequestBuilder.prototype, "affiliation", void 0);
|
|
1264
|
+
|
|
1265
|
+
__decorate([ minlength(1), __metadata("design:type", Array) ], RegistrationRequestBuilder.prototype, "attrs", void 0);
|
|
1266
|
+
|
|
1267
|
+
__decorate([ required(), __metadata("design:type", String) ], RegistrationRequestBuilder.prototype, "enrollmentID", void 0);
|
|
1268
|
+
|
|
1269
|
+
__decorate([ required(), __metadata("design:type", String) ], RegistrationRequestBuilder.prototype, "enrollmentSecret", void 0);
|
|
1270
|
+
|
|
1271
|
+
__decorate([ min(0), __metadata("design:type", Number) ], RegistrationRequestBuilder.prototype, "maxEnrollments", void 0);
|
|
1272
|
+
|
|
1273
|
+
__decorate([ required(), __metadata("design:type", String) ], RegistrationRequestBuilder.prototype, "role", void 0);
|
|
1274
|
+
|
|
1275
|
+
var ERC20Events;
|
|
1276
|
+
|
|
1277
|
+
(function(ERC20Events) {
|
|
1278
|
+
ERC20Events["TRANSFER"] = "Transfer";
|
|
1279
|
+
ERC20Events["APPROVAL"] = "Approval";
|
|
1280
|
+
})(ERC20Events || (ERC20Events = {}));
|
|
1281
|
+
|
|
1282
|
+
let FabricBaseModel = class FabricBaseModel extends Model {
|
|
1283
|
+
constructor(arg) {
|
|
1284
|
+
super(arg);
|
|
1285
|
+
}
|
|
1286
|
+
};
|
|
1287
|
+
|
|
1288
|
+
__decorate([ description("Stores the original timestamp of creation"), column(), createdAt(), __metadata("design:type", Date) ], FabricBaseModel.prototype, "createdAt", void 0);
|
|
1289
|
+
|
|
1290
|
+
__decorate([ description("Stores the timestamp of the last update"), column(), updatedAt(), __metadata("design:type", Date) ], FabricBaseModel.prototype, "updatedAt", void 0);
|
|
1291
|
+
|
|
1292
|
+
__decorate([ description("Stores the version of the model"), column(), version(), __metadata("design:type", Number) ], FabricBaseModel.prototype, "version", void 0);
|
|
1293
|
+
|
|
1294
|
+
FabricBaseModel = __decorate([ uses(FabricFlavour), __metadata("design:paramtypes", [ Object ]) ], FabricBaseModel);
|
|
1295
|
+
|
|
1296
|
+
let FabricIdentifiedBaseModel = class FabricIdentifiedBaseModel extends FabricBaseModel {
|
|
1297
|
+
constructor(arg) {
|
|
1298
|
+
super(arg);
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
|
|
1302
|
+
__decorate([ description("Stores the creator"), column(), createdBy(), __metadata("design:type", String) ], FabricIdentifiedBaseModel.prototype, "createdBy", void 0);
|
|
1303
|
+
|
|
1304
|
+
__decorate([ description("Stores the user that last updated the model"), column(), updatedBy(), __metadata("design:type", String) ], FabricIdentifiedBaseModel.prototype, "updatedBy", void 0);
|
|
1305
|
+
|
|
1306
|
+
FabricIdentifiedBaseModel = __decorate([ uses(FabricFlavour), __metadata("design:paramtypes", [ Object ]) ], FabricIdentifiedBaseModel);
|
|
1307
|
+
|
|
1308
|
+
Model.prototype.isShared = function isShared() {
|
|
1309
|
+
return Model.isShared(this.constructor);
|
|
1310
|
+
};
|
|
1311
|
+
|
|
1312
|
+
Model.prototype.isPrivate = function isPrivate() {
|
|
1313
|
+
return Model.isPrivate(this.constructor);
|
|
1314
|
+
};
|
|
1315
|
+
|
|
1316
|
+
Model.prototype.segregate = function segregate() {
|
|
1317
|
+
return Model.segregate(this);
|
|
1318
|
+
};
|
|
1319
|
+
|
|
1320
|
+
Model.segregate = function segregate(model) {
|
|
1321
|
+
if (!Model.isTransient(model)) return {
|
|
1322
|
+
model: model
|
|
1323
|
+
};
|
|
1324
|
+
const decoratedProperties = Metadata.validatableProperties(model.constructor);
|
|
1325
|
+
const transientProps = Metadata.get(model.constructor, DBKeys.TRANSIENT);
|
|
1326
|
+
const privateProperties = Metadata.get(model.constructor, FabricModelKeys.PRIVATE);
|
|
1327
|
+
const sharedProperties = Metadata.get(model.constructor, FabricModelKeys.SHARED);
|
|
1328
|
+
const result = {
|
|
1329
|
+
model: {},
|
|
1330
|
+
transient: {},
|
|
1331
|
+
privates: {},
|
|
1332
|
+
shared: {}
|
|
1333
|
+
};
|
|
1334
|
+
const transientKeys = Object.keys(transientProps || {});
|
|
1335
|
+
const privateKeys = Object.keys(privateProperties || {});
|
|
1336
|
+
const sharedKeys = Object.keys(sharedProperties || {});
|
|
1337
|
+
const pkKey = Model.pk(model.constructor);
|
|
1338
|
+
for (const key of decoratedProperties) {
|
|
1339
|
+
const value = model[key];
|
|
1340
|
+
const isTransient = transientKeys.includes(key);
|
|
1341
|
+
const isPrivate = privateKeys.includes(key);
|
|
1342
|
+
const isShared = sharedKeys.includes(key);
|
|
1343
|
+
const isPrimaryKey = key === pkKey;
|
|
1344
|
+
const decoratedValue = isPrimaryKey && typeof value === "string" && !value.endsWith(",") ? `${value},` : value;
|
|
1345
|
+
if (isTransient || isPrivate || isShared) {
|
|
1346
|
+
result.transient = result.transient || {};
|
|
1347
|
+
result.transient[key] = decoratedValue;
|
|
1348
|
+
}
|
|
1349
|
+
if (isPrivate) {
|
|
1350
|
+
result.privates = result.privates || {};
|
|
1351
|
+
result.privates[key] = decoratedValue;
|
|
1352
|
+
}
|
|
1353
|
+
if (isShared) {
|
|
1354
|
+
result.shared = result.shared || {};
|
|
1355
|
+
result.shared[key] = decoratedValue;
|
|
1356
|
+
}
|
|
1357
|
+
const shouldIncludeInModel = !isTransient && !isPrivate && !isShared;
|
|
1358
|
+
if (shouldIncludeInModel) {
|
|
1359
|
+
result.model = result.model || {};
|
|
1360
|
+
result.model[key] = value;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
result.model = Model.build(result.model, model.constructor.name);
|
|
1364
|
+
return result;
|
|
1365
|
+
}.bind(Model);
|
|
1366
|
+
|
|
1367
|
+
Model.isPrivate = function isPrivate(model) {
|
|
1368
|
+
return !!Metadata.get(typeof model !== "function" ? model.constructor : model, FabricModelKeys.PRIVATE);
|
|
1369
|
+
}.bind(Model);
|
|
1370
|
+
|
|
1371
|
+
Model.isShared = function isShared(model) {
|
|
1372
|
+
return !!Metadata.get(typeof model !== "function" ? model.constructor : model, FabricModelKeys.SHARED);
|
|
1373
|
+
}.bind(Model);
|
|
1374
|
+
|
|
1375
|
+
Model.mirrored = function mirrored(model) {
|
|
1376
|
+
return Metadata.get(typeof model !== "function" ? model.constructor : model, Metadata.key(FabricModelKeys.FABRIC, FabricModelKeys.MIRROR));
|
|
1377
|
+
}.bind(Model);
|
|
1378
|
+
|
|
1379
|
+
Model.ownerOf = function ownerOf(model) {
|
|
1380
|
+
const meta = Metadata.get(model.constructor, Metadata.key(FabricModelKeys.FABRIC, FabricModelKeys.OWNED_BY));
|
|
1381
|
+
if (!meta) return undefined;
|
|
1382
|
+
return model[meta];
|
|
1383
|
+
}.bind(Model);
|
|
1384
|
+
|
|
1385
|
+
Model.mirroredAt = function mirroredAt(model) {
|
|
1386
|
+
model = typeof model !== "function" ? model.constructor : model;
|
|
1387
|
+
return Metadata.get(model, Metadata.key(FabricModelKeys.FABRIC, FabricModelKeys.MIRROR));
|
|
1388
|
+
}.bind(Model);
|
|
1389
|
+
|
|
1390
|
+
Model.collectionsFor = function collectionsFor(model) {
|
|
1391
|
+
const privateKeys = [ FabricModelKeys.PRIVATE ];
|
|
1392
|
+
const sharedKeys = [ FabricModelKeys.SHARED ];
|
|
1393
|
+
const privateKey = Metadata.key(...privateKeys);
|
|
1394
|
+
const sharedKey = Metadata.key(...sharedKeys);
|
|
1395
|
+
const constr = typeof model === "function" ? model : model.constructor;
|
|
1396
|
+
const privateMeta = Metadata.get(constr, privateKey);
|
|
1397
|
+
const sharedMeta = Metadata.get(constr, sharedKey);
|
|
1398
|
+
return {
|
|
1399
|
+
privateCols: privateMeta?.collections || [],
|
|
1400
|
+
sharedCols: sharedMeta?.collections || []
|
|
1401
|
+
};
|
|
1402
|
+
}.bind(Model);
|
|
1403
|
+
|
|
1404
|
+
function extractMspId(identity) {
|
|
1405
|
+
if (!identity) return undefined;
|
|
1406
|
+
if (typeof identity === "string") return identity;
|
|
1407
|
+
return identity.getMSPID();
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
function Owner() {
|
|
1411
|
+
return function(target, propertyKey, descriptor) {
|
|
1412
|
+
const originalMethod = descriptor.value;
|
|
1413
|
+
descriptor.value = async function(...args) {
|
|
1414
|
+
const ctx = args[0];
|
|
1415
|
+
const acountId = ctx.clientIdentity.getID();
|
|
1416
|
+
const select = await this["tokenRepository"].select();
|
|
1417
|
+
const tokens = await select.execute(ctx);
|
|
1418
|
+
if (tokens.length == 0) {
|
|
1419
|
+
throw new NotFoundError("No tokens avaialble");
|
|
1420
|
+
}
|
|
1421
|
+
if (tokens.length > 1) {
|
|
1422
|
+
throw new NotFoundError(`To many token available : ${tokens.length}`);
|
|
1423
|
+
}
|
|
1424
|
+
if (tokens[0].owner != acountId) {
|
|
1425
|
+
throw new AuthorizationError(`User not authorized to run ${propertyKey} on the token`);
|
|
1426
|
+
}
|
|
1427
|
+
return await originalMethod.apply(this, args);
|
|
1428
|
+
};
|
|
1429
|
+
return descriptor;
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
async function ownedByOnCreate(context, data, key, model) {
|
|
1434
|
+
const {stub: stub} = context;
|
|
1435
|
+
const creator = await stub.getCreator();
|
|
1436
|
+
const owner = creator.mspid;
|
|
1437
|
+
const setOwnedByKeyValue = function(target, propertyKey, value) {
|
|
1438
|
+
Object.defineProperty(target, propertyKey, {
|
|
1439
|
+
enumerable: true,
|
|
1440
|
+
writable: false,
|
|
1441
|
+
configurable: true,
|
|
1442
|
+
value: value
|
|
1443
|
+
});
|
|
1444
|
+
};
|
|
1445
|
+
setOwnedByKeyValue(model, key, owner);
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
function ownedBy() {
|
|
1449
|
+
function ownedBy() {
|
|
1450
|
+
return function(obj, attribute) {
|
|
1451
|
+
return apply(required(), generated(), readonly(), onCreate(ownedByOnCreate), propMetadata(Metadata.key(FabricModelKeys.FABRIC, FabricModelKeys.OWNED_BY), attribute))(obj, attribute);
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
return Decoration.for(FabricModelKeys.OWNED_BY).define({
|
|
1455
|
+
decorator: ownedBy,
|
|
1456
|
+
args: []
|
|
1457
|
+
}).apply();
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
async function transactionIdOnCreate(context, data, key, model) {
|
|
1461
|
+
const {stub: stub} = context;
|
|
1462
|
+
model[key] = stub.getTxID();
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
function transactionId() {
|
|
1466
|
+
function transactionId() {
|
|
1467
|
+
return function(obj, attribute) {
|
|
1468
|
+
return apply(required(), readonly(), onCreate(transactionIdOnCreate), onUpdate(transactionIdOnCreate), propMetadata(Metadata.key(FabricModelKeys.FABRIC, attribute, FabricModelKeys.TRANSACTION_ID), attribute))(obj, attribute);
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
return Decoration.for(FabricModelKeys.TRANSACTION_ID).define({
|
|
1472
|
+
decorator: transactionId,
|
|
1473
|
+
args: []
|
|
1474
|
+
}).apply();
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
async function evalMirrorMetadata(model, resolver, ctx) {
|
|
1478
|
+
let collection = resolver;
|
|
1479
|
+
if (typeof collection !== "string") {
|
|
1480
|
+
try {
|
|
1481
|
+
const owner = Model.ownerOf(model) || ctx.get("stub").getCreator().toString();
|
|
1482
|
+
if (resolver && typeof resolver === "function") collection = await resolver(model, owner, ctx);
|
|
1483
|
+
} catch (e) {
|
|
1484
|
+
throw new InternalError(`Failed to resolve collection mirror name: ${e}`);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
if (!collection || typeof collection !== "string") throw new InternalError(`No collection found model ${model.constructor.name}`);
|
|
1488
|
+
return collection;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
async function createMirrorHandler(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.create(model, context);
|
|
1499
|
+
context.logger.info(`Mirror for ${Model.tableName(this.class)} created with ${Model.pk(model)}: ${mirror[Model.pk(model)]}`);
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
async function updateMirrorHandler(context, data, key, model) {
|
|
1503
|
+
const collection = await evalMirrorMetadata(model, data.resolver, context);
|
|
1504
|
+
const repo = this.override(Object.assign({}, this._overrides, {
|
|
1505
|
+
segregate: collection,
|
|
1506
|
+
ignoreValidation: true,
|
|
1507
|
+
ignoreHandlers: true
|
|
1508
|
+
}));
|
|
1509
|
+
const mirror = await repo.update(model, context);
|
|
1510
|
+
context.logger.info(`Mirror for ${Model.tableName(this.class)} updated with ${Model.pk(model)}: ${mirror[Model.pk(model)]}`);
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
async function deleteMirrorHandler(context, data, key, model) {
|
|
1514
|
+
const collection = await evalMirrorMetadata(model, data.resolver, context);
|
|
1515
|
+
const repo = this.override(Object.assign({}, this._overrides, {
|
|
1516
|
+
segregate: collection,
|
|
1517
|
+
ignoreValidation: true,
|
|
1518
|
+
ignoreHandlers: true
|
|
1519
|
+
}));
|
|
1520
|
+
const mirror = await repo.delete(Model.pk(model), context);
|
|
1521
|
+
context.logger.info(`Mirror for ${Model.tableName(this.class)} deleted with ${Model.pk(model)}: ${mirror[Model.pk(model)]}`);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
function mirror(collection, condition) {
|
|
1525
|
+
function mirror(resolver, condition) {
|
|
1526
|
+
const meta = {
|
|
1527
|
+
condition: condition,
|
|
1528
|
+
resolver: resolver
|
|
1529
|
+
};
|
|
1530
|
+
return apply(metadata(Metadata.key(FabricModelKeys.FABRIC, FabricModelKeys.MIRROR), meta), privateData(collection), afterCreate(createMirrorHandler, meta, {
|
|
1531
|
+
priority: 95
|
|
1532
|
+
}), afterUpdate(updateMirrorHandler, meta, {
|
|
1533
|
+
priority: 95
|
|
1534
|
+
}), afterDelete(deleteMirrorHandler, meta, {
|
|
1535
|
+
priority: 95
|
|
1536
|
+
}));
|
|
1537
|
+
}
|
|
1538
|
+
return Decoration.for(FabricModelKeys.MIRROR).define({
|
|
1539
|
+
decorator: mirror,
|
|
1540
|
+
args: [ collection, condition ]
|
|
1541
|
+
}).apply();
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
const ModelCollection = (model, mspId) => {
|
|
1545
|
+
const orgName = mspId || (typeof model !== "function" ? Model.ownerOf(model) : undefined);
|
|
1546
|
+
const constr = typeof model === "function" ? model : model.constructor;
|
|
1547
|
+
if (!orgName) throw new InternalError(`Model ${constr.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);
|
|
1548
|
+
return `${toPascalCase(constr.name)}${orgName ? toPascalCase(orgName) : ""}`;
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
function NamespaceCollection(namespace) {
|
|
1552
|
+
return (model, mspId) => {
|
|
1553
|
+
const orgName = mspId || (typeof model !== "function" ? Model.ownerOf(model) : undefined);
|
|
1554
|
+
const constr = typeof model === "function" ? model : model.constructor;
|
|
1555
|
+
if (!orgName) throw new InternalError(`Model ${constr.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);
|
|
1556
|
+
return `${namespace}${orgName ? toPascalCase(orgName) : ""}`;
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
const ImplicitPrivateCollection = (model, mspId) => {
|
|
1561
|
+
const orgName = mspId || (typeof model !== "function" ? Model.ownerOf(model) : undefined);
|
|
1562
|
+
if (!orgName) throw new InternalError(`Model ${model.constructor.name} is not owned by any organization. did you use @ownedBy() (or provide the name)?`);
|
|
1563
|
+
return `__${toPascalCase(orgName)}PrivateCollection`;
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
const SEGREGATED_COLLECTION_EXTRACTION_PRIORITY = 35;
|
|
1567
|
+
|
|
1568
|
+
async function extractSegregatedCollections(context, data, keys, model) {
|
|
1569
|
+
const dataArray = Array.isArray(data) ? data : [ data ];
|
|
1570
|
+
const msp = Model.ownerOf(model) || extractMspId(context.get("identity"));
|
|
1571
|
+
if (!msp) {
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
const collections = [];
|
|
1575
|
+
for (const metadata of dataArray) {
|
|
1576
|
+
const collectionResolver = metadata.collections;
|
|
1577
|
+
const collection = typeof collectionResolver === "string" ? collectionResolver : collectionResolver(model, msp, context);
|
|
1578
|
+
if (collection && !collections.includes(collection)) {
|
|
1579
|
+
collections.push(collection);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
if (collections.length > 0) {
|
|
1583
|
+
context.readFrom(collections);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
async function segregatedDataOnCreate(context, data, keys, model) {
|
|
1588
|
+
const dataArray = Array.isArray(data) ? data : [ data ];
|
|
1589
|
+
const keyArray = Array.isArray(keys) ? keys : [ keys ];
|
|
1590
|
+
if (keyArray.length !== dataArray.length) throw new InternalError(`Segregated data keys and metadata length mismatch`);
|
|
1591
|
+
const msp = Model.ownerOf(model) || extractMspId(context.get("identity"));
|
|
1592
|
+
if (!msp) throw new ValidationError(`There's no assigned organization for model ${model.constructor.name}`);
|
|
1593
|
+
const collectionResolver = dataArray[0].collections;
|
|
1594
|
+
const collection = typeof collectionResolver === "string" ? collectionResolver : collectionResolver(model, msp, context);
|
|
1595
|
+
const rebuilt = keyArray.reduce((acc, k, i) => {
|
|
1596
|
+
const c = typeof dataArray[i].collections === "string" ? dataArray[i].collections : dataArray[i].collections(model, msp, context);
|
|
1597
|
+
if (c !== collection) throw new UnsupportedError(`Segregated data collection mismatch: ${c} vs ${collection}`);
|
|
1598
|
+
acc[k] = model[k];
|
|
1599
|
+
return acc;
|
|
1600
|
+
}, {});
|
|
1601
|
+
const toCreate = new this.class(rebuilt);
|
|
1602
|
+
const segregated = Model.segregate(model);
|
|
1603
|
+
context.writeTo(collection, segregated);
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
async function segregatedDataOnRead(context, data, keys, model) {
|
|
1607
|
+
const dataArray = Array.isArray(data) ? data : [ data ];
|
|
1608
|
+
const keyArray = Array.isArray(keys) ? keys : [ keys ];
|
|
1609
|
+
if (keyArray.length !== dataArray.length) throw new InternalError(`Segregated data keys and metadata length mismatch`);
|
|
1610
|
+
const msp = Model.ownerOf(model) || extractMspId(context.get("identity"));
|
|
1611
|
+
if (!msp) throw new ValidationError(`There's no assigned organization for model ${model.constructor.name}`);
|
|
1612
|
+
const collectionResolver = dataArray[0].collections;
|
|
1613
|
+
const collection = typeof collectionResolver === "string" ? collectionResolver : await collectionResolver(model, msp, context);
|
|
1614
|
+
context.readFrom(collection);
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
async function segregatedDataOnUpdate(context, data, key, model, oldModel) {
|
|
1618
|
+
const dataArray = Array.isArray(data) ? data : [ data ];
|
|
1619
|
+
const keyArray = Array.isArray(key) ? key : [ key ];
|
|
1620
|
+
if (keyArray.length !== dataArray.length) throw new InternalError(`Segregated data keys and metadata length mismatch`);
|
|
1621
|
+
const msp = Model.ownerOf(model) || extractMspId(context.get("identity"));
|
|
1622
|
+
if (!msp) throw new ValidationError(`There's no assigned organization for model ${model.constructor.name}`);
|
|
1623
|
+
const collectionResolver = dataArray[0].collections;
|
|
1624
|
+
const collection = typeof collectionResolver === "string" ? collectionResolver : collectionResolver(model, msp, context);
|
|
1625
|
+
keyArray.forEach((k, i) => {
|
|
1626
|
+
const c = typeof dataArray[i].collections === "string" ? dataArray[i].collections : dataArray[i].collections(model, msp, context);
|
|
1627
|
+
if (c !== collection) throw new UnsupportedError(`Segregated data collection mismatch: ${c} vs ${collection}`);
|
|
1628
|
+
});
|
|
1629
|
+
const segregated = Model.segregate(model);
|
|
1630
|
+
context.writeTo(collection, segregated);
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
async function segregatedDataOnDelete(context, data, key, model) {
|
|
1634
|
+
const dataArray = Array.isArray(data) ? data : [ data ];
|
|
1635
|
+
const keyArray = Array.isArray(key) ? key : [ key ];
|
|
1636
|
+
if (keyArray.length !== dataArray.length) throw new InternalError(`Segregated data keys and metadata length mismatch`);
|
|
1637
|
+
const msp = Model.ownerOf(model) || extractMspId(context.get("identity"));
|
|
1638
|
+
if (!msp) throw new ValidationError(`There's no assigned organization for model ${model.constructor.name}`);
|
|
1639
|
+
const collectionResolver = dataArray[0].collections;
|
|
1640
|
+
const collection = typeof collectionResolver === "string" ? collectionResolver : collectionResolver(model, msp, context);
|
|
1641
|
+
context.readFrom(collection);
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
function segregated(collection, type, filter) {
|
|
1645
|
+
return function innerSegregated(target, propertyKey) {
|
|
1646
|
+
function segregatedDec(target, propertyKey) {
|
|
1647
|
+
const key = Metadata.key(type, propertyKey);
|
|
1648
|
+
const constr = target.constructor;
|
|
1649
|
+
const meta = Metadata.get(constr, key) || {};
|
|
1650
|
+
const collections = new Set(meta.collections || []);
|
|
1651
|
+
collections.add(collection);
|
|
1652
|
+
meta.collections = [ ...collections ];
|
|
1653
|
+
Metadata.set(constr, key, meta);
|
|
1654
|
+
const constrMeta = Metadata.get(constr, type) || {};
|
|
1655
|
+
const constrCollections = new Set(constrMeta.collections || []);
|
|
1656
|
+
constrCollections.add(collection);
|
|
1657
|
+
constrMeta.collections = [ ...constrCollections ];
|
|
1658
|
+
Metadata.set(constr, type, constrMeta);
|
|
1659
|
+
const transientMeta = Metadata.get(constr, DBKeys.TRANSIENT) || {};
|
|
1660
|
+
const updatedTransientMeta = {
|
|
1661
|
+
...transientMeta,
|
|
1662
|
+
[propertyKey]: {}
|
|
1663
|
+
};
|
|
1664
|
+
Metadata.set(constr, DBKeys.TRANSIENT, updatedTransientMeta);
|
|
1665
|
+
}
|
|
1666
|
+
const decs = [];
|
|
1667
|
+
if (!propertyKey) {
|
|
1668
|
+
const properties = Metadata.validatableProperties(target);
|
|
1669
|
+
properties?.forEach(p => {
|
|
1670
|
+
if (!filter || filter(p)) {
|
|
1671
|
+
segregated(collection, type)(target.prototype, p);
|
|
1672
|
+
}
|
|
1673
|
+
});
|
|
1674
|
+
} else {
|
|
1675
|
+
const groupName = typeof collection === "string" ? collection : collection.toString();
|
|
1676
|
+
const earlyExtractionMeta = {
|
|
1677
|
+
collections: collection
|
|
1678
|
+
};
|
|
1679
|
+
const earlyExtractionGroupSort = {
|
|
1680
|
+
priority: SEGREGATED_COLLECTION_EXTRACTION_PRIORITY,
|
|
1681
|
+
group: groupName
|
|
1682
|
+
};
|
|
1683
|
+
decs.push(prop(), transient(), segregatedDec, on(DBOperations.ALL, extractSegregatedCollections, earlyExtractionMeta, earlyExtractionGroupSort), onCreate(segregatedDataOnCreate, {
|
|
1684
|
+
collections: collection
|
|
1685
|
+
}, {
|
|
1686
|
+
priority: 95,
|
|
1687
|
+
group: groupName
|
|
1688
|
+
}), onRead(segregatedDataOnRead, {
|
|
1689
|
+
collections: collection
|
|
1690
|
+
}, {
|
|
1691
|
+
priority: 95,
|
|
1692
|
+
group: groupName
|
|
1693
|
+
}), onUpdate(segregatedDataOnUpdate, {
|
|
1694
|
+
collections: collection
|
|
1695
|
+
}, {
|
|
1696
|
+
priority: 95,
|
|
1697
|
+
group: groupName
|
|
1698
|
+
}), onDelete(segregatedDataOnDelete, {
|
|
1699
|
+
collections: collection
|
|
1700
|
+
}, {
|
|
1701
|
+
priority: 95,
|
|
1702
|
+
group: groupName
|
|
1703
|
+
}));
|
|
1704
|
+
}
|
|
1705
|
+
return apply(...decs)(target, propertyKey);
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
function privateData(collection = ImplicitPrivateCollection) {
|
|
1710
|
+
function privateData(collection) {
|
|
1711
|
+
return segregated(collection, FabricModelKeys.PRIVATE);
|
|
1712
|
+
}
|
|
1713
|
+
return Decoration.for(FabricModelKeys.PRIVATE).define({
|
|
1714
|
+
decorator: privateData,
|
|
1715
|
+
args: [ collection ]
|
|
1716
|
+
}).apply();
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
function sharedData(collection) {
|
|
1720
|
+
function sharedData(collection) {
|
|
1721
|
+
return segregated(collection, FabricModelKeys.SHARED);
|
|
1722
|
+
}
|
|
1723
|
+
return Decoration.for(FabricModelKeys.SHARED).define({
|
|
1724
|
+
decorator: sharedData,
|
|
1725
|
+
args: [ collection ]
|
|
1726
|
+
}).apply();
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
class DeterministicSerializer extends JSONSerializer {
|
|
1730
|
+
constructor() {
|
|
1731
|
+
super();
|
|
1732
|
+
}
|
|
1733
|
+
preSerialize(model) {
|
|
1734
|
+
const toSerialize = Object.assign({}, model);
|
|
1735
|
+
let metadata;
|
|
1736
|
+
try {
|
|
1737
|
+
metadata = Metadata.modelName(model.constructor);
|
|
1738
|
+
} catch (error) {
|
|
1739
|
+
metadata = undefined;
|
|
1740
|
+
}
|
|
1741
|
+
toSerialize[ModelKeys.ANCHOR] = metadata || model.constructor.name;
|
|
1742
|
+
const preSerialize = function preSerialize(obj) {
|
|
1743
|
+
const self = this;
|
|
1744
|
+
if (typeof obj !== "object") return obj;
|
|
1745
|
+
if (Array.isArray(obj)) return obj.map(o => preSerialize.call(self, o));
|
|
1746
|
+
return this.preSerialize.call(this, obj);
|
|
1747
|
+
}.bind(this);
|
|
1748
|
+
Model.relations(model).forEach(r => {
|
|
1749
|
+
toSerialize[r] = preSerialize(toSerialize[r]);
|
|
1750
|
+
});
|
|
1751
|
+
return toSerialize;
|
|
1752
|
+
}
|
|
1753
|
+
deserialize(str) {
|
|
1754
|
+
const deserialization = JSON.parse(str);
|
|
1755
|
+
const className = deserialization[ModelKeys.ANCHOR];
|
|
1756
|
+
if (!className) throw new Error("Could not find class reference in serialized model");
|
|
1757
|
+
const model = Model.build(deserialization, className);
|
|
1758
|
+
return model;
|
|
1759
|
+
}
|
|
1760
|
+
serialize(model) {
|
|
1761
|
+
const stringify = require("json-stringify-deterministic");
|
|
1762
|
+
const sortKeysRecursive = require("sort-keys-recursive");
|
|
1763
|
+
return stringify(sortKeysRecursive(this.preSerialize(model)));
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
function generateFabricEventName(table, event, owner) {
|
|
1768
|
+
const params = [ table, event ];
|
|
1769
|
+
if (owner) params.push(owner);
|
|
1770
|
+
return params.join("_");
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
function parseEventName(name) {
|
|
1774
|
+
const parts = name.split("_");
|
|
1775
|
+
if (parts.length < 2 || parts.length > 3) return {
|
|
1776
|
+
table: undefined,
|
|
1777
|
+
event: name,
|
|
1778
|
+
owner: undefined
|
|
1779
|
+
};
|
|
1780
|
+
return {
|
|
1781
|
+
table: parts[0],
|
|
1782
|
+
event: parts[1],
|
|
1783
|
+
owner: parts[2]
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
function add(a, b) {
|
|
1788
|
+
const c = a + b;
|
|
1789
|
+
if (a !== c - b || b !== c - a) {
|
|
1790
|
+
throw new OverflowError(`Addition overflow: ${a} + ${b}`);
|
|
1791
|
+
}
|
|
1792
|
+
return c;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
function sub(a, b) {
|
|
1796
|
+
const c = a - b;
|
|
1797
|
+
if (a !== c + b || b !== a - c) {
|
|
1798
|
+
throw new OverflowError(`Subtraction overflow: ${a} - ${b}`);
|
|
1799
|
+
}
|
|
1800
|
+
return c;
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
function safeParseInt(string) {
|
|
1804
|
+
const digitRegex = /^\d+$/;
|
|
1805
|
+
if (!digitRegex.test(string)) {
|
|
1806
|
+
throw new ValidationError(stringFormat("Failed to parse: {0}", "string contains digits"));
|
|
1807
|
+
}
|
|
1808
|
+
const parsedint = parseInt(string);
|
|
1809
|
+
if (isNaN(parsedint)) {
|
|
1810
|
+
throw new ValidationError(stringFormat("Failed to parse: {0}", "string is not a parsable integer"));
|
|
1811
|
+
}
|
|
1812
|
+
return parsedint;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
class SimpleDeterministicSerializer extends JSONSerializer {
|
|
1816
|
+
constructor() {
|
|
1817
|
+
super();
|
|
1818
|
+
}
|
|
1819
|
+
deserialize(str, tableName) {
|
|
1820
|
+
const deserialization = JSON.parse(str);
|
|
1821
|
+
return deserialization;
|
|
1822
|
+
}
|
|
1823
|
+
serialize(model, putAnchor = true) {
|
|
1824
|
+
const stringify = require("json-stringify-deterministic");
|
|
1825
|
+
const sortKeysRecursive = require("sort-keys-recursive");
|
|
1826
|
+
const preSerialization = this.preSerialize(model, putAnchor);
|
|
1827
|
+
return stringify(sortKeysRecursive(preSerialization));
|
|
1828
|
+
}
|
|
1829
|
+
preSerialize(model, putAnchor = true) {
|
|
1830
|
+
const toSerialize = Object.assign({}, model);
|
|
1831
|
+
let metadata;
|
|
1832
|
+
try {
|
|
1833
|
+
metadata = Metadata.modelName(model.constructor);
|
|
1834
|
+
} catch (error) {
|
|
1835
|
+
metadata = undefined;
|
|
1836
|
+
}
|
|
1837
|
+
if (putAnchor) toSerialize[ModelKeys.ANCHOR] = metadata || model.constructor.name;
|
|
1838
|
+
function preSerialize(obj) {
|
|
1839
|
+
if (typeof obj !== "object") return obj;
|
|
1840
|
+
if (Array.isArray(obj)) return obj.map(preSerialize);
|
|
1841
|
+
return this.preSerialize(obj);
|
|
1842
|
+
}
|
|
1843
|
+
Model.relations(model).forEach(r => {
|
|
1844
|
+
toSerialize[r] = preSerialize.call(this, toSerialize[r]);
|
|
1845
|
+
});
|
|
1846
|
+
return toSerialize;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
class FabricIdentityService extends ClientBasedService {
|
|
1851
|
+
constructor() {
|
|
1852
|
+
super();
|
|
1853
|
+
}
|
|
1854
|
+
get rootClient() {
|
|
1855
|
+
return this.client["_FabricCaServices"];
|
|
1856
|
+
}
|
|
1857
|
+
get user() {
|
|
1858
|
+
if (!this._user) throw new InternalError("Fabric identity service not properly setup: missing user");
|
|
1859
|
+
return this._user;
|
|
1860
|
+
}
|
|
1861
|
+
get certificates() {
|
|
1862
|
+
return this.rootClient.newCertificateService();
|
|
1863
|
+
}
|
|
1864
|
+
get affiliations() {
|
|
1865
|
+
return this.client.newAffiliationService();
|
|
1866
|
+
}
|
|
1867
|
+
get identities() {
|
|
1868
|
+
return this.client.newIdentityService();
|
|
1869
|
+
}
|
|
1870
|
+
async getUser(cfg, ctx) {
|
|
1871
|
+
const log = ctx.logger.for(this.getUser);
|
|
1872
|
+
const {caName: caName, caCert: caCert, caKey: caKey, url: url, hsm: hsm} = cfg;
|
|
1873
|
+
log.info(`Creating CA user for ${caName} at ${url}`);
|
|
1874
|
+
log.verbose(`Retrieving CA certificate from ${caCert}`);
|
|
1875
|
+
const certificate = await CoreUtils.getFirstDirFileNameContent(caCert);
|
|
1876
|
+
let key;
|
|
1877
|
+
if (!hsm) {
|
|
1878
|
+
if (!caKey) {
|
|
1879
|
+
throw new InternalError(`Missing caKey configuration for CA ${caName}. Provide a key directory or configure HSM support.`);
|
|
1880
|
+
}
|
|
1881
|
+
log.debug(`Retrieving CA key from ${caKey}`);
|
|
1882
|
+
key = await CoreUtils.getFirstDirFileNameContent(caKey);
|
|
1883
|
+
} else {
|
|
1884
|
+
log.debug(`Using HSM configuration for CA ${caName} with library ${hsm.library}`);
|
|
1885
|
+
}
|
|
1886
|
+
log.debug(`Loading Admin user for ca ${caName}`);
|
|
1887
|
+
this._user = await CoreUtils.getCAUser("admin", key, certificate, caName, {
|
|
1888
|
+
hsm: hsm
|
|
1889
|
+
});
|
|
1890
|
+
return this._user;
|
|
1891
|
+
}
|
|
1892
|
+
async initialize(...args) {
|
|
1893
|
+
const {log: log, ctx: ctx} = (await this.logCtx(args, PersistenceKeys.INITIALIZATION, true)).for(this.initialize);
|
|
1894
|
+
const [config] = args;
|
|
1895
|
+
if (!config) throw new InternalError("Missing Fabric CA configuration");
|
|
1896
|
+
const {url: url, tls: tls, caName: caName} = config;
|
|
1897
|
+
log.info(`Initializing CA Client for CA ${config.caName} at ${config.url}`);
|
|
1898
|
+
const {trustedRoots: trustedRoots, verify: verify} = tls;
|
|
1899
|
+
const root = trustedRoots[0];
|
|
1900
|
+
log.debug(`Retrieving CA certificate from ${root}. cwd: ${process.cwd()}`);
|
|
1901
|
+
const certificate = await CoreUtils.getFileContent(root);
|
|
1902
|
+
log.debug(`CA Certificate: ${certificate.toString()}`);
|
|
1903
|
+
const client = new FabricCAServices(url, {
|
|
1904
|
+
trustedRoots: Buffer.from(certificate),
|
|
1905
|
+
verify: verify
|
|
1906
|
+
}, caName);
|
|
1907
|
+
const user = await this.getUser(config, ctx);
|
|
1908
|
+
log.debug(`CA user loaded: ${user.getName()}`);
|
|
1909
|
+
return {
|
|
1910
|
+
config: config,
|
|
1911
|
+
client: client
|
|
1912
|
+
};
|
|
1913
|
+
}
|
|
1914
|
+
async getCertificates(request, doMap = true, ...args) {
|
|
1915
|
+
if (request instanceof Context) {
|
|
1916
|
+
args = [ request ];
|
|
1917
|
+
doMap = true;
|
|
1918
|
+
request = undefined;
|
|
1919
|
+
} else if (typeof request === "boolean") {
|
|
1920
|
+
doMap = request;
|
|
1921
|
+
request = undefined;
|
|
1922
|
+
} else if (typeof doMap !== "boolean") {
|
|
1923
|
+
args = [ doMap, ...args ];
|
|
1924
|
+
doMap = true;
|
|
1925
|
+
}
|
|
1926
|
+
const {log: log} = (await this.logCtx(args, OperationKeys.READ, true)).for(this.getCertificates);
|
|
1927
|
+
log.debug(`Retrieving certificates${request ? ` for ${request.id}` : ""} for CA ${this.config.caName}`);
|
|
1928
|
+
const response = (await this.certificates.getCertificates(request || {}, this.user)).result;
|
|
1929
|
+
log.verbose(`Found ${response.certs.length} certificates`);
|
|
1930
|
+
log.debug(response.certs);
|
|
1931
|
+
return doMap ? response.certs.map(c => c.PEM) : response;
|
|
1932
|
+
}
|
|
1933
|
+
async getIdentities(ctx) {
|
|
1934
|
+
const log = ctx.logger.for(this.getIdentities);
|
|
1935
|
+
log.verbose(`Retrieving Identities under CA ${this.config.caName}`);
|
|
1936
|
+
const response = (await this.identities.getAll(this.user)).result;
|
|
1937
|
+
log.verbose(`Found ${response.identities.length} Identities`);
|
|
1938
|
+
log.debug(response.identities);
|
|
1939
|
+
return response.identities;
|
|
1940
|
+
}
|
|
1941
|
+
async getAffiliations(ctx) {
|
|
1942
|
+
const log = ctx.logger.for(this.getAffiliations);
|
|
1943
|
+
log.verbose(`Retrieving Affiliations under CA ${this.config.caName}`);
|
|
1944
|
+
const response = (await this.affiliations.getAll(this.user)).result;
|
|
1945
|
+
log.verbose(`Found ${response.a.length} Affiliations`);
|
|
1946
|
+
log.debug(JSON.stringify(response));
|
|
1947
|
+
return response;
|
|
1948
|
+
}
|
|
1949
|
+
parseError(e) {
|
|
1950
|
+
const regexp = /.*code:\s(\d+).*?message:\s["'](.+)["']/gs;
|
|
1951
|
+
const match = regexp.exec(e.message);
|
|
1952
|
+
if (!match) return new RegistrationError(e);
|
|
1953
|
+
const [, code, message] = match;
|
|
1954
|
+
switch (code) {
|
|
1955
|
+
case "74":
|
|
1956
|
+
case "71":
|
|
1957
|
+
return new ConflictError(message);
|
|
1958
|
+
|
|
1959
|
+
case "20":
|
|
1960
|
+
return new AuthorizationError(message);
|
|
1961
|
+
|
|
1962
|
+
default:
|
|
1963
|
+
return new RegistrationError(message);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
async read(enrollmentId, ...args) {
|
|
1967
|
+
const {log: log} = (await this.logCtx(args, OperationKeys.READ, true)).for(this.read);
|
|
1968
|
+
log.verbose(`Retrieving identity with enrollment ID ${enrollmentId}`);
|
|
1969
|
+
let result;
|
|
1970
|
+
try {
|
|
1971
|
+
result = await this.identities.getOne(enrollmentId, this.user);
|
|
1972
|
+
} catch (e) {
|
|
1973
|
+
throw new NotFoundError(`Couldn't find enrollment with id ${enrollmentId}: ${e}`);
|
|
1974
|
+
}
|
|
1975
|
+
if (!result.success) throw new NotFoundError(`Couldn't find enrollment with id ${enrollmentId}: ${result.errors.join("\n")}`);
|
|
1976
|
+
return result.result;
|
|
1977
|
+
}
|
|
1978
|
+
async register(model, isSuperUser = false, affiliation = "", userRole, attrs, maxEnrollments, ...args) {
|
|
1979
|
+
const {log: log} = (await this.logCtx(args, "register", true)).for(this.register);
|
|
1980
|
+
let registration;
|
|
1981
|
+
try {
|
|
1982
|
+
const {userName: userName, password: password} = model;
|
|
1983
|
+
const props = {
|
|
1984
|
+
enrollmentID: userName,
|
|
1985
|
+
enrollmentSecret: password,
|
|
1986
|
+
affiliation: affiliation,
|
|
1987
|
+
userRole: userRole,
|
|
1988
|
+
attrs: attrs,
|
|
1989
|
+
maxEnrollments: maxEnrollments
|
|
1990
|
+
};
|
|
1991
|
+
registration = await this.client.register(props, this.user);
|
|
1992
|
+
log.info(`Registration for ${userName} created with user type ${userRole ?? "Undefined Role"} ${isSuperUser ? "as super user" : ""}`);
|
|
1993
|
+
} catch (e) {
|
|
1994
|
+
throw this.parseError(e);
|
|
1995
|
+
}
|
|
1996
|
+
return registration;
|
|
1997
|
+
}
|
|
1998
|
+
static identityFromEnrollment(enrollment, mspId, ctx) {
|
|
1999
|
+
const log = ctx.logger.for(this.identityFromEnrollment);
|
|
2000
|
+
const {certificate: certificate, key: key, rootCertificate: rootCertificate} = enrollment;
|
|
2001
|
+
log.verbose(`Generating Identity from certificate ${certificate} in msp ${mspId}`);
|
|
2002
|
+
const clientId = CryptoUtils.fabricIdFromCertificate(certificate);
|
|
2003
|
+
const id = CryptoUtils.encode(clientId);
|
|
2004
|
+
log.debug(`Identity ${clientId} and encodedId ${id}`);
|
|
2005
|
+
return new Identity({
|
|
2006
|
+
id: id,
|
|
2007
|
+
credentials: {
|
|
2008
|
+
id: id,
|
|
2009
|
+
certificate: certificate,
|
|
2010
|
+
privateKey: key.toBytes(),
|
|
2011
|
+
rootCertificate: rootCertificate
|
|
2012
|
+
},
|
|
2013
|
+
mspId: mspId
|
|
2014
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
async enroll(enrollmentId, registration, ...args) {
|
|
2017
|
+
const {log: log, ctx: ctx} = (await this.logCtx(args, "enroll", true)).for(this.enroll);
|
|
2018
|
+
let identity;
|
|
2019
|
+
try {
|
|
2020
|
+
log.debug(`Enrolling ${enrollmentId}`);
|
|
2021
|
+
const enrollment = await this.client.enroll({
|
|
2022
|
+
enrollmentID: enrollmentId,
|
|
2023
|
+
enrollmentSecret: registration
|
|
2024
|
+
});
|
|
2025
|
+
identity = FabricIdentityService.identityFromEnrollment(enrollment, this.config.caName, ctx);
|
|
2026
|
+
log.info(`Successfully enrolled ${enrollmentId} under ${this.config.caName} as ${identity.id}`);
|
|
2027
|
+
} catch (e) {
|
|
2028
|
+
throw this.parseError(e);
|
|
2029
|
+
}
|
|
2030
|
+
return identity;
|
|
2031
|
+
}
|
|
2032
|
+
async registerAndEnroll(model, isSuperUser = false, affiliation = "", userRole, attrs, maxEnrollments, ...args) {
|
|
2033
|
+
const {ctx: ctx} = (await this.logCtx(args, "register-enroll", true)).for(this.registerAndEnroll);
|
|
2034
|
+
const registration = await this.register(model, isSuperUser, affiliation, userRole, attrs, maxEnrollments, ctx);
|
|
2035
|
+
const {userName: userName} = model;
|
|
2036
|
+
return this.enroll(userName, registration, ctx);
|
|
2037
|
+
}
|
|
2038
|
+
async revoke(enrollmentId, ...args) {
|
|
2039
|
+
const {log: log} = (await this.logCtx(args, "revoke", true)).for(this.revoke);
|
|
2040
|
+
log.verbose(`Revoking identity with enrollment ID ${enrollmentId}`);
|
|
2041
|
+
const identity = await this.read(enrollmentId);
|
|
2042
|
+
if (!identity) throw new NotFoundError(`Could not find enrollment with id ${enrollmentId}`);
|
|
2043
|
+
let result;
|
|
2044
|
+
try {
|
|
2045
|
+
result = await this.client.revoke({
|
|
2046
|
+
enrollmentID: identity.id,
|
|
2047
|
+
reason: "User Deletion"
|
|
2048
|
+
}, this.user);
|
|
2049
|
+
} catch (e) {
|
|
2050
|
+
throw new InternalError(`Could not revoke enrollment with id ${enrollmentId}: ${e}`);
|
|
2051
|
+
}
|
|
2052
|
+
if (!result.success) throw new InternalError(`Could not revoke enrollment with id ${enrollmentId}: ${result.errors.join("\n")}`);
|
|
2053
|
+
return result;
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
const DefaultFabricClientFlags = Object.assign({
|
|
2058
|
+
evaluateTimeout: 5,
|
|
2059
|
+
endorseTimeout: 15,
|
|
2060
|
+
submitTimeout: 5,
|
|
2061
|
+
commitTimeout: 60
|
|
2062
|
+
});
|
|
2063
|
+
|
|
2064
|
+
const log = new MiniLogger("fabric-fs");
|
|
2065
|
+
|
|
2066
|
+
async function contentOfLoadFile(contentOrPath, fileReader) {
|
|
2067
|
+
if (contentOrPath instanceof Uint8Array) return contentOrPath;
|
|
2068
|
+
if (contentOrPath.match(/-----BEGIN (CERTIFICATE|KEY|PRIVATE KEY)-----.+?-----END \1-----$/gms)) return contentOrPath;
|
|
2069
|
+
return await fileReader(contentOrPath);
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
async function readFile(contentOrPath) {
|
|
2073
|
+
if (typeof contentOrPath !== "string") return contentOrPath;
|
|
2074
|
+
const fileReader = async path => {
|
|
2075
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
2076
|
+
return await promises.readFile(path);
|
|
2077
|
+
};
|
|
2078
|
+
return await fileReader(contentOrPath);
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
async function getCAUser(userName, privateKey, certificate, mspId) {
|
|
2082
|
+
log.debug(`Creating a CA ${mspId} user ${userName} with certificate ${certificate}`);
|
|
2083
|
+
const user = new User(userName);
|
|
2084
|
+
const cryptoSuite = User.newCryptoSuite();
|
|
2085
|
+
user.setCryptoSuite(cryptoSuite);
|
|
2086
|
+
const importedKey = cryptoSuite.createKeyFromRaw(privateKey);
|
|
2087
|
+
await user.setEnrollment(importedKey, certificate, mspId);
|
|
2088
|
+
return user;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
async function getIdentity(mspId, certDirectoryPath) {
|
|
2092
|
+
const identityFileReader = async path => {
|
|
2093
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
2094
|
+
const certPath = await getFirstDirFileName(path);
|
|
2095
|
+
const credentials = await promises.readFile(certPath);
|
|
2096
|
+
return credentials;
|
|
2097
|
+
};
|
|
2098
|
+
const credentials = await contentOfLoadFile(certDirectoryPath, identityFileReader);
|
|
2099
|
+
return {
|
|
2100
|
+
mspId: mspId,
|
|
2101
|
+
credentials: credentials
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
async function getFirstDirFileName(dirPath) {
|
|
2106
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
2107
|
+
const {join: join} = await normalizeImport(import("path"));
|
|
2108
|
+
const files = await promises.readdir(dirPath);
|
|
2109
|
+
return join(dirPath, files[0]);
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
async function getFirstDirFileNameContent(dirPath) {
|
|
2113
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
2114
|
+
const {join: join} = await normalizeImport(import("path"));
|
|
2115
|
+
const files = await promises.readdir(dirPath);
|
|
2116
|
+
return (await promises.readFile(join(dirPath, files[0]))).toString();
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
async function getSigner(keyDirectoryPath) {
|
|
2120
|
+
const signerFileReader = async path => {
|
|
2121
|
+
const {promises: promises} = await normalizeImport(import("fs"));
|
|
2122
|
+
const keyPath = await getFirstDirFileName(path);
|
|
2123
|
+
return await promises.readFile(keyPath);
|
|
2124
|
+
};
|
|
2125
|
+
const privateKeyPem = await contentOfLoadFile(keyDirectoryPath, signerFileReader);
|
|
2126
|
+
const privateKey = await extractPrivateKey(privateKeyPem);
|
|
2127
|
+
const keys = Object.getOwnPropertySymbols(privateKey);
|
|
2128
|
+
const k = privateKey[keys[0]];
|
|
2129
|
+
return signers.newPrivateKeySigner(k);
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
async function extractPrivateKey(pem) {
|
|
2133
|
+
const libName = "crypto";
|
|
2134
|
+
let subtle;
|
|
2135
|
+
if (isBrowser()) {
|
|
2136
|
+
subtle = globalThis.crypto.subtle;
|
|
2137
|
+
} else {
|
|
2138
|
+
const lib = await normalizeImport(import(libName));
|
|
2139
|
+
subtle = lib.subtle || lib.webcrypto.subtle;
|
|
2140
|
+
}
|
|
2141
|
+
if (!subtle) throw new Error("Could not load SubtleCrypto module");
|
|
2142
|
+
function str2ab(str) {
|
|
2143
|
+
const buf = new ArrayBuffer(str.length);
|
|
2144
|
+
const bufView = new Uint8Array(buf);
|
|
2145
|
+
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
2146
|
+
bufView[i] = str.charCodeAt(i);
|
|
2147
|
+
}
|
|
2148
|
+
return buf;
|
|
2149
|
+
}
|
|
2150
|
+
const str = pem.toString("utf8").replace("-----BEGIN PRIVATE KEY-----", "").replaceAll("\n", "").replace("-----END PRIVATE KEY-----", "");
|
|
2151
|
+
const decoded = Buffer.from(str, "base64").toString("binary");
|
|
2152
|
+
const binaryDer = str2ab(decoded);
|
|
2153
|
+
try {
|
|
2154
|
+
const key = await subtle.importKey("pkcs8", binaryDer, {
|
|
2155
|
+
name: "ECDSA",
|
|
2156
|
+
namedCurve: "P-256"
|
|
2157
|
+
}, true, [ "sign" ]);
|
|
2158
|
+
return key;
|
|
2159
|
+
} catch (e) {
|
|
2160
|
+
throw new InternalError(e);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
class HSMSignerFactoryCustom {
|
|
2165
|
+
static #pkcs11=null;
|
|
2166
|
+
static #initialized=false;
|
|
2167
|
+
constructor(library) {
|
|
2168
|
+
if (!HSMSignerFactoryCustom.#pkcs11) {
|
|
2169
|
+
HSMSignerFactoryCustom.#pkcs11 = new pkcs11.PKCS11;
|
|
2170
|
+
HSMSignerFactoryCustom.#pkcs11.load(this.findHSMPKCS11Lib(library));
|
|
2171
|
+
}
|
|
2172
|
+
if (!HSMSignerFactoryCustom.#initialized) {
|
|
2173
|
+
try {
|
|
2174
|
+
HSMSignerFactoryCustom.#pkcs11.C_Initialize();
|
|
2175
|
+
} catch (e) {
|
|
2176
|
+
if (e.code !== pkcs11.CKR_CRYPTOKI_ALREADY_INITIALIZED) {
|
|
2177
|
+
throw e;
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
HSMSignerFactoryCustom.#initialized = true;
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
findHSMPKCS11Lib(lib) {
|
|
2184
|
+
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" ];
|
|
2185
|
+
if (lib) commonSoftHSMPathNames.push(lib);
|
|
2186
|
+
for (const pathnameToTry of commonSoftHSMPathNames) {
|
|
2187
|
+
if (fs.existsSync(pathnameToTry)) {
|
|
2188
|
+
return pathnameToTry;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
throw new MissingPKCSS11Lib("Unable to find PKCS11 library");
|
|
2192
|
+
}
|
|
2193
|
+
dispose() {
|
|
2194
|
+
HSMSignerFactoryCustom.#pkcs11.C_Finalize();
|
|
2195
|
+
}
|
|
2196
|
+
sanitizeOptions(hsmSignerOptions) {
|
|
2197
|
+
const options = Object.assign({
|
|
2198
|
+
userType: pkcs11.CKU_USER
|
|
2199
|
+
}, hsmSignerOptions);
|
|
2200
|
+
this.assertNotEmpty(options.label, "label");
|
|
2201
|
+
this.assertNotEmpty(options.pin, "pin");
|
|
2202
|
+
this.assertNotEmpty(options.identifier, "identifier");
|
|
2203
|
+
return options;
|
|
2204
|
+
}
|
|
2205
|
+
assertNotEmpty(property, name) {
|
|
2206
|
+
if (!property || property.toString().trim().length === 0) {
|
|
2207
|
+
throw new Error(`${name} property must be provided`);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
findSlotForLabel(pkcs11Label) {
|
|
2211
|
+
const slots = HSMSignerFactoryCustom.#pkcs11.C_GetSlotList(true);
|
|
2212
|
+
if (slots.length === 0) {
|
|
2213
|
+
throw new Error("No pkcs11 slots can be found");
|
|
2214
|
+
}
|
|
2215
|
+
const slot = slots.find(slotToCheck => {
|
|
2216
|
+
const tokenInfo = HSMSignerFactoryCustom.#pkcs11.C_GetTokenInfo(slotToCheck);
|
|
2217
|
+
return tokenInfo.label.trim() === pkcs11Label;
|
|
2218
|
+
});
|
|
2219
|
+
if (!slot) {
|
|
2220
|
+
throw new Error(`label ${pkcs11Label} cannot be found in the pkcs11 slot list`);
|
|
2221
|
+
}
|
|
2222
|
+
return slot;
|
|
2223
|
+
}
|
|
2224
|
+
login(session, userType, pin) {
|
|
2225
|
+
try {
|
|
2226
|
+
HSMSignerFactoryCustom.#pkcs11.C_Login(session, userType, pin);
|
|
2227
|
+
} catch (err) {
|
|
2228
|
+
const pkcs11err = err;
|
|
2229
|
+
if (pkcs11err.code !== pkcs11.CKR_USER_ALREADY_LOGGED_IN) {
|
|
2230
|
+
throw err;
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
findObjectInHSM(session, keytype, identifier) {
|
|
2235
|
+
const pkcs11Template = [ {
|
|
2236
|
+
type: pkcs11.CKA_ID,
|
|
2237
|
+
value: identifier
|
|
2238
|
+
}, {
|
|
2239
|
+
type: pkcs11.CKA_CLASS,
|
|
2240
|
+
value: keytype
|
|
2241
|
+
}, {
|
|
2242
|
+
type: pkcs11.CKA_KEY_TYPE,
|
|
2243
|
+
value: pkcs11.CKK_EC
|
|
2244
|
+
} ];
|
|
2245
|
+
HSMSignerFactoryCustom.#pkcs11.C_FindObjectsInit(session, pkcs11Template);
|
|
2246
|
+
const hsmObject = HSMSignerFactoryCustom.#pkcs11.C_FindObjects(session, 1)[0];
|
|
2247
|
+
if (!hsmObject) {
|
|
2248
|
+
HSMSignerFactoryCustom.#pkcs11.C_FindObjectsFinal(session);
|
|
2249
|
+
throw new Error(`Unable to find object in HSM with ID ${identifier.toString()}`);
|
|
2250
|
+
}
|
|
2251
|
+
HSMSignerFactoryCustom.#pkcs11.C_FindObjectsFinal(session);
|
|
2252
|
+
return hsmObject;
|
|
2253
|
+
}
|
|
2254
|
+
newSigner(hsmSignerOptions) {
|
|
2255
|
+
const options = this.sanitizeOptions(hsmSignerOptions);
|
|
2256
|
+
const pkcs = HSMSignerFactoryCustom.#pkcs11;
|
|
2257
|
+
const slot = this.findSlotForLabel(options.label);
|
|
2258
|
+
const session = pkcs.C_OpenSession(slot, pkcs11.CKF_SERIAL_SESSION);
|
|
2259
|
+
let privateKeyHandle;
|
|
2260
|
+
try {
|
|
2261
|
+
this.login(session, options.userType, options.pin);
|
|
2262
|
+
privateKeyHandle = this.findObjectInHSM(session, pkcs11.CKO_PRIVATE_KEY, options.identifier);
|
|
2263
|
+
} catch (err) {
|
|
2264
|
+
HSMSignerFactoryCustom.#pkcs11.C_CloseSession(session);
|
|
2265
|
+
throw err;
|
|
2266
|
+
}
|
|
2267
|
+
return {
|
|
2268
|
+
signer: async digest => {
|
|
2269
|
+
HSMSignerFactoryCustom.#pkcs11.C_SignInit(session, {
|
|
2270
|
+
mechanism: pkcs11.CKM_ECDSA
|
|
2271
|
+
}, privateKeyHandle);
|
|
2272
|
+
const compactSignature = await HSMSignerFactoryCustom.#pkcs11.C_SignAsync(session, Buffer.from(digest), Buffer.alloc(p256.Point.Fn.BYTES * 2));
|
|
2273
|
+
return p256.Signature.fromBytes(compactSignature, "compact").normalizeS().toBytes("der");
|
|
2274
|
+
},
|
|
2275
|
+
close: () => {
|
|
2276
|
+
HSMSignerFactoryCustom.#pkcs11.C_CloseSession(session);
|
|
2277
|
+
}
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
assertDefined(value) {
|
|
2281
|
+
if (value === undefined) {
|
|
2282
|
+
throw new Error("required value was undefined");
|
|
2283
|
+
}
|
|
2284
|
+
return value;
|
|
2285
|
+
}
|
|
2286
|
+
getUncompressedPointOnCurve(key) {
|
|
2287
|
+
const jwk = key.export({
|
|
2288
|
+
format: "jwk"
|
|
2289
|
+
});
|
|
2290
|
+
const x = Buffer.from(this.assertDefined(jwk.x), "base64url");
|
|
2291
|
+
const y = Buffer.from(this.assertDefined(jwk.y), "base64url");
|
|
2292
|
+
const prefix = Buffer.from("04", "hex");
|
|
2293
|
+
return Buffer.concat([ prefix, x, y ]);
|
|
2294
|
+
}
|
|
2295
|
+
getSKIFromCertificatePath(certPath) {
|
|
2296
|
+
const p = certPath.endsWith(".pem") ? certPath : path.join(certPath, "cert.pem");
|
|
2297
|
+
const credentials = fs.readFileSync(p);
|
|
2298
|
+
return this.getSKIFromCertificate(credentials);
|
|
2299
|
+
}
|
|
2300
|
+
getSKIFromCertificate(cert) {
|
|
2301
|
+
const certificate = new crypto$1.X509Certificate(cert);
|
|
2302
|
+
const uncompressedPoint = this.getUncompressedPointOnCurve(certificate.publicKey);
|
|
2303
|
+
return crypto$1.createHash("sha256").update(uncompressedPoint).digest();
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
class FabricClientStatement extends Statement {
|
|
2308
|
+
constructor(adapter, overrides) {
|
|
2309
|
+
super(adapter, overrides);
|
|
2310
|
+
}
|
|
2311
|
+
squash(ctx) {
|
|
2312
|
+
const squashed = super.squash(ctx);
|
|
2313
|
+
if (!squashed) return squashed;
|
|
2314
|
+
const {method: method, params: params, args: args} = squashed;
|
|
2315
|
+
const {direction: direction, limit: limit} = params;
|
|
2316
|
+
switch (method) {
|
|
2317
|
+
case PreparedStatementKeys.FIND_BY:
|
|
2318
|
+
break;
|
|
2319
|
+
|
|
2320
|
+
case PreparedStatementKeys.LIST_BY:
|
|
2321
|
+
args.push(direction);
|
|
2322
|
+
break;
|
|
2323
|
+
|
|
2324
|
+
case PreparedStatementKeys.PAGE_BY:
|
|
2325
|
+
args.push(direction, limit);
|
|
2326
|
+
break;
|
|
2327
|
+
|
|
2328
|
+
case PreparedStatementKeys.FIND_ONE_BY:
|
|
2329
|
+
break;
|
|
2330
|
+
|
|
2331
|
+
default:
|
|
2332
|
+
throw new InternalError(`Unsupported method ${method}`);
|
|
2333
|
+
}
|
|
2334
|
+
return squashed;
|
|
2335
|
+
}
|
|
2336
|
+
async executePrepared(...argz) {
|
|
2337
|
+
const repo = Repository.forModel(this.fromSelector, this.adapter.alias);
|
|
2338
|
+
const {method: method, args: args} = this.prepared;
|
|
2339
|
+
return repo.statement(method, ...args, ...argz);
|
|
2340
|
+
}
|
|
2341
|
+
async prepare(ctx) {
|
|
2342
|
+
ctx = ctx || await this.adapter.context(PersistenceKeys.QUERY, this.overrides || {}, this.fromSelector);
|
|
2343
|
+
if (this.isSimpleQuery() && ctx.get("forcePrepareSimpleQueries")) {
|
|
2344
|
+
const squashed = this.squash(ctx);
|
|
2345
|
+
if (squashed) {
|
|
2346
|
+
this.prepared = squashed;
|
|
2347
|
+
return this;
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
const args = [];
|
|
2351
|
+
const params = {};
|
|
2352
|
+
const prepared = {
|
|
2353
|
+
class: this.fromSelector,
|
|
2354
|
+
args: args,
|
|
2355
|
+
params: params
|
|
2356
|
+
};
|
|
2357
|
+
const method = [ QueryClause.FIND_BY ];
|
|
2358
|
+
if (this.whereCondition) {
|
|
2359
|
+
const parsed = this.prepareCondition(this.whereCondition, ctx);
|
|
2360
|
+
method.push(parsed.method);
|
|
2361
|
+
if (parsed.args && parsed.args.length) args.push(...parsed.args);
|
|
2362
|
+
}
|
|
2363
|
+
if (this.selectSelector) method.push(QueryClause.SELECT, this.selectSelector.join(` ${QueryClause.AND.toLowerCase()} `));
|
|
2364
|
+
if (this.orderBySelectors?.length) {
|
|
2365
|
+
method.push(QueryClause.ORDER_BY, this.orderBySelectors[0][0]);
|
|
2366
|
+
args.push(this.orderBySelectors[0][1]);
|
|
2367
|
+
}
|
|
2368
|
+
prepared.method = toCamelCase(method.join(" "));
|
|
2369
|
+
prepared.params = params;
|
|
2370
|
+
this.prepared = prepared;
|
|
2371
|
+
return this;
|
|
2372
|
+
}
|
|
2373
|
+
processRecord(r, pkAttr, sequenceType, ctx) {
|
|
2374
|
+
if (r[CouchDBKeys.ID]) {
|
|
2375
|
+
const [, ...keyArgs] = r[CouchDBKeys.ID].split(CouchDBKeys.SEPARATOR);
|
|
2376
|
+
const id = keyArgs.join("_");
|
|
2377
|
+
return this.adapter.revert(r, this.fromSelector, Sequence.parseValue(sequenceType, id), undefined, ctx);
|
|
2378
|
+
}
|
|
2379
|
+
return r;
|
|
2380
|
+
}
|
|
2381
|
+
async raw(rawInput, ...args) {
|
|
2382
|
+
const {ctx: ctx} = this.logCtx(args, this.raw);
|
|
2383
|
+
const aggregator = rawInput?.aggregateInfo;
|
|
2384
|
+
if (rawInput?.aggregate && aggregator) {
|
|
2385
|
+
return this.executeAggregate(aggregator, ctx);
|
|
2386
|
+
}
|
|
2387
|
+
const results = await this.adapter.raw(rawInput, true, this.fromSelector, ctx);
|
|
2388
|
+
const pkAttr = Model.pk(this.fromSelector);
|
|
2389
|
+
const type = Metadata.get(this.fromSelector, Metadata.key(DBKeys.ID, pkAttr))?.type;
|
|
2390
|
+
if (!this.selectSelector) return results.map(r => this.processRecord(r, pkAttr, type, ctx));
|
|
2391
|
+
return results;
|
|
2392
|
+
}
|
|
2393
|
+
build() {
|
|
2394
|
+
const log = this.log.for(this.build);
|
|
2395
|
+
const aggregateQuery = this.buildAggregateQuery();
|
|
2396
|
+
if (aggregateQuery) return aggregateQuery;
|
|
2397
|
+
const selectors = {};
|
|
2398
|
+
selectors[CouchDBKeys.TABLE] = {};
|
|
2399
|
+
selectors[CouchDBKeys.TABLE] = Model.tableName(this.fromSelector);
|
|
2400
|
+
const query = {
|
|
2401
|
+
selector: selectors
|
|
2402
|
+
};
|
|
2403
|
+
if (this.selectSelector) query.fields = this.selectSelector;
|
|
2404
|
+
if (this.whereCondition) {
|
|
2405
|
+
const condition = this.parseCondition(Condition.and(this.whereCondition, Condition.attribute(CouchDBKeys.TABLE).eq(query.selector[CouchDBKeys.TABLE]))).selector;
|
|
2406
|
+
const selectorKeys = Object.keys(condition);
|
|
2407
|
+
if (selectorKeys.length === 1 && Object.values(CouchDBGroupOperator).indexOf(selectorKeys[0]) !== -1) switch (selectorKeys[0]) {
|
|
2408
|
+
case CouchDBGroupOperator.AND:
|
|
2409
|
+
condition[CouchDBGroupOperator.AND] = [ ...Object.values(condition[CouchDBGroupOperator.AND]).reduce((accum, val) => {
|
|
2410
|
+
const keys = Object.keys(val);
|
|
2411
|
+
if (keys.length !== 1) throw new Error("Too many keys in query selector. should be one");
|
|
2412
|
+
const k = keys[0];
|
|
2413
|
+
if (k === CouchDBGroupOperator.AND) accum.push(...val[k]); else accum.push(val);
|
|
2414
|
+
return accum;
|
|
2415
|
+
}, []) ];
|
|
2416
|
+
query.selector = condition;
|
|
2417
|
+
break;
|
|
2418
|
+
|
|
2419
|
+
case CouchDBGroupOperator.OR:
|
|
2420
|
+
{
|
|
2421
|
+
const s = {};
|
|
2422
|
+
s[CouchDBGroupOperator.AND] = [ condition, ...Object.entries(query.selector).map(([key, val]) => {
|
|
2423
|
+
const result = {};
|
|
2424
|
+
result[key] = val;
|
|
2425
|
+
return result;
|
|
2426
|
+
}) ];
|
|
2427
|
+
query.selector = s;
|
|
2428
|
+
break;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
default:
|
|
2432
|
+
throw new Error("This should be impossible");
|
|
2433
|
+
} else {
|
|
2434
|
+
Object.entries(condition).forEach(([key, val]) => {
|
|
2435
|
+
if (query.selector[key]) log.warn(`A ${key} query param is about to be overridden: ${query.selector[key]} by ${val}`);
|
|
2436
|
+
query.selector[key] = val;
|
|
2437
|
+
});
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
if (this.orderBySelectors?.length) {
|
|
2441
|
+
query.sort = query.sort || [];
|
|
2442
|
+
query.selector = query.selector || {};
|
|
2443
|
+
for (const [selectorKey, direction] of this.orderBySelectors) {
|
|
2444
|
+
const selector = selectorKey;
|
|
2445
|
+
const rec = {};
|
|
2446
|
+
rec[selector] = direction;
|
|
2447
|
+
query.sort.push(rec);
|
|
2448
|
+
if (!query.selector[selector]) {
|
|
2449
|
+
query.selector[selector] = {};
|
|
2450
|
+
query.selector[selector][CouchDBOperator.BIGGER] = null;
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
if (this.limitSelector) {
|
|
2455
|
+
query.limit = this.limitSelector;
|
|
2456
|
+
} else {
|
|
2457
|
+
log.warn(`No limit selector defined. Using default couchdb limit of ${CouchDBQueryLimit}`);
|
|
2458
|
+
query.limit = CouchDBQueryLimit;
|
|
2459
|
+
}
|
|
2460
|
+
if (this.offsetSelector) query.skip = this.offsetSelector;
|
|
2461
|
+
return query;
|
|
2462
|
+
}
|
|
2463
|
+
parseCondition(condition) {
|
|
2464
|
+
function merge(op, obj1, obj2) {
|
|
2465
|
+
const result = {
|
|
2466
|
+
selector: {}
|
|
2467
|
+
};
|
|
2468
|
+
result.selector[op] = [ obj1, obj2 ];
|
|
2469
|
+
return result;
|
|
2470
|
+
}
|
|
2471
|
+
const {attr1: attr1, operator: operator, comparison: comparison} = condition;
|
|
2472
|
+
if (operator === Operator.BETWEEN) {
|
|
2473
|
+
const attr = attr1;
|
|
2474
|
+
if (!Array.isArray(comparison) || comparison.length !== 2) throw new QueryError("BETWEEN operator requires [min, max] comparison");
|
|
2475
|
+
const [min, max] = comparison;
|
|
2476
|
+
const opBetween = {};
|
|
2477
|
+
opBetween[attr] = {};
|
|
2478
|
+
opBetween[attr][translateOperators(Operator.BIGGER_EQ)] = min;
|
|
2479
|
+
opBetween[attr][translateOperators(Operator.SMALLER_EQ)] = max;
|
|
2480
|
+
return {
|
|
2481
|
+
selector: opBetween
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
let op = {};
|
|
2485
|
+
if ([ GroupOperator.AND, GroupOperator.OR, Operator.NOT ].indexOf(operator) === -1) {
|
|
2486
|
+
op[attr1] = {};
|
|
2487
|
+
op[attr1][translateOperators(operator)] = comparison;
|
|
2488
|
+
} else if (operator === Operator.NOT) {
|
|
2489
|
+
op = this.parseCondition(attr1).selector;
|
|
2490
|
+
op[translateOperators(Operator.NOT)] = {};
|
|
2491
|
+
op[translateOperators(Operator.NOT)][attr1.attr1] = comparison;
|
|
2492
|
+
} else {
|
|
2493
|
+
const op1 = this.parseCondition(attr1).selector;
|
|
2494
|
+
const op2 = this.parseCondition(comparison).selector;
|
|
2495
|
+
op = merge(translateOperators(operator), op1, op2).selector;
|
|
2496
|
+
}
|
|
2497
|
+
return {
|
|
2498
|
+
selector: op
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
buildAggregateQuery() {
|
|
2502
|
+
if (!this.fromSelector) return undefined;
|
|
2503
|
+
if (this.avgSelector) {
|
|
2504
|
+
const attribute = String(this.avgSelector);
|
|
2505
|
+
const sumInfo = this.createAggregateDescriptor("sum", attribute);
|
|
2506
|
+
const countInfo = this.createAggregateDescriptor("count", attribute);
|
|
2507
|
+
if (!sumInfo || !countInfo) throw new QueryError(`Avg operation requires sum and count views for attribute ${attribute}`);
|
|
2508
|
+
return this.createAggregateQuery({
|
|
2509
|
+
kind: "avg",
|
|
2510
|
+
attribute: attribute,
|
|
2511
|
+
sumDescriptor: sumInfo.descriptor,
|
|
2512
|
+
countDescriptor: countInfo.descriptor
|
|
2513
|
+
});
|
|
2514
|
+
}
|
|
2515
|
+
if (typeof this.countDistinctSelector !== "undefined") {
|
|
2516
|
+
const attribute = this.countDistinctSelector == null ? undefined : String(this.countDistinctSelector);
|
|
2517
|
+
const info = this.createAggregateDescriptor("distinct", attribute);
|
|
2518
|
+
if (info) {
|
|
2519
|
+
info.countDistinct = true;
|
|
2520
|
+
return this.createAggregateQuery(info);
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
const aggregatorUsed = typeof this.countSelector !== "undefined" || typeof this.countDistinctSelector !== "undefined" || !!this.minSelector || !!this.maxSelector || !!this.sumSelector || !!this.distinctSelector;
|
|
2524
|
+
const aggregatorChecks = [ [ "count", this.countSelector ?? undefined ], [ "max", this.maxSelector ], [ "min", this.minSelector ], [ "sum", this.sumSelector ], [ "distinct", this.distinctSelector ] ];
|
|
2525
|
+
for (const [kind, selector] of aggregatorChecks) {
|
|
2526
|
+
const attribute = selector ? String(selector) : undefined;
|
|
2527
|
+
const info = this.createAggregateDescriptor(kind, attribute);
|
|
2528
|
+
if (info) return this.createAggregateQuery(info);
|
|
2529
|
+
}
|
|
2530
|
+
if (aggregatorUsed) {
|
|
2531
|
+
throw new QueryError(`No CouchDB view metadata found for table ${Model.tableName(this.fromSelector)} aggregator`);
|
|
2532
|
+
}
|
|
2533
|
+
return undefined;
|
|
2534
|
+
}
|
|
2535
|
+
createAggregateDescriptor(kind, attribute) {
|
|
2536
|
+
if (!this.fromSelector) return undefined;
|
|
2537
|
+
const metas = findViewMetadata(this.fromSelector, kind, attribute);
|
|
2538
|
+
if (!metas.length) return undefined;
|
|
2539
|
+
const meta = metas[0];
|
|
2540
|
+
const tableName = Model.tableName(this.fromSelector);
|
|
2541
|
+
const viewName = generateViewName(tableName, meta.attribute, kind, meta);
|
|
2542
|
+
const ddoc = meta.ddoc || generateDesignDocName(tableName, viewName);
|
|
2543
|
+
const options = {
|
|
2544
|
+
reduce: meta.reduce !== undefined ? true : !meta.returnDocs
|
|
2545
|
+
};
|
|
2546
|
+
if (kind === "distinct" || kind === "groupBy") options.group = true;
|
|
2547
|
+
return {
|
|
2548
|
+
kind: kind,
|
|
2549
|
+
meta: meta,
|
|
2550
|
+
descriptor: {
|
|
2551
|
+
ddoc: ddoc,
|
|
2552
|
+
view: viewName,
|
|
2553
|
+
options: options
|
|
2554
|
+
}
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
createAggregateQuery(info) {
|
|
2558
|
+
return {
|
|
2559
|
+
selector: {},
|
|
2560
|
+
aggregate: true,
|
|
2561
|
+
aggregateInfo: info
|
|
2562
|
+
};
|
|
2563
|
+
}
|
|
2564
|
+
getFabricAdapter() {
|
|
2565
|
+
return this.adapter;
|
|
2566
|
+
}
|
|
2567
|
+
async executeAggregate(info, ctx) {
|
|
2568
|
+
if (!this.isViewAggregate(info)) {
|
|
2569
|
+
return this.handleAverage(info, ctx);
|
|
2570
|
+
}
|
|
2571
|
+
const fabricAdapter = this.getFabricAdapter();
|
|
2572
|
+
const viewInfo = info;
|
|
2573
|
+
const response = await fabricAdapter.view(viewInfo.descriptor.ddoc, viewInfo.descriptor.view, viewInfo.descriptor.options, ctx);
|
|
2574
|
+
return this.processViewResponse(info, response);
|
|
2575
|
+
}
|
|
2576
|
+
async handleAverage(info, ctx) {
|
|
2577
|
+
if (info.kind !== "avg") throw new QueryError("Average descriptor is not valid");
|
|
2578
|
+
const fabricAdapter = this.getFabricAdapter();
|
|
2579
|
+
const [sumDesc, countDesc] = [ info.sumDescriptor, info.countDescriptor ];
|
|
2580
|
+
const [sumResponse, countResponse] = await Promise.all([ fabricAdapter.view(sumDesc.ddoc, sumDesc.view, sumDesc.options, ctx), fabricAdapter.view(countDesc.ddoc, countDesc.view, countDesc.options, ctx) ]);
|
|
2581
|
+
const sum = sumResponse.rows?.[0]?.value ?? 0;
|
|
2582
|
+
const count = countResponse.rows?.[0]?.value ?? 0;
|
|
2583
|
+
if (!count) return 0;
|
|
2584
|
+
return sum / count;
|
|
2585
|
+
}
|
|
2586
|
+
processViewResponse(info, response) {
|
|
2587
|
+
if (info.kind === "avg") throw new QueryError("Average results should be handled before processing rows");
|
|
2588
|
+
const rows = response.rows || [];
|
|
2589
|
+
const viewInfo = info;
|
|
2590
|
+
const meta = viewInfo.meta;
|
|
2591
|
+
if (viewInfo.countDistinct) {
|
|
2592
|
+
return rows.length || 0;
|
|
2593
|
+
}
|
|
2594
|
+
if (viewInfo.kind === "distinct" || viewInfo.kind === "groupBy") {
|
|
2595
|
+
return rows.map(row => row.key ?? row.value);
|
|
2596
|
+
}
|
|
2597
|
+
if (meta.returnDocs) {
|
|
2598
|
+
return rows.map(row => row.value ?? row.doc ?? row);
|
|
2599
|
+
}
|
|
2600
|
+
if (!rows.length) {
|
|
2601
|
+
return viewInfo.kind === "count" ? 0 : null;
|
|
2602
|
+
}
|
|
2603
|
+
return rows[0].value ?? rows[0].key ?? null;
|
|
2604
|
+
}
|
|
2605
|
+
isViewAggregate(info) {
|
|
2606
|
+
return info.kind !== "avg";
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
|
|
2610
|
+
class FabricClientPaginator extends Paginator {
|
|
2611
|
+
constructor(adapter, query, size, clazz) {
|
|
2612
|
+
super(adapter, query, size, clazz);
|
|
2613
|
+
}
|
|
2614
|
+
prepare(rawStatement) {
|
|
2615
|
+
throw new UnsupportedError(`Raw query access must be implemented by a subclass. only prepared statements are natively available`);
|
|
2616
|
+
}
|
|
2617
|
+
page(page = 1, ...args) {
|
|
2618
|
+
return super.page(page, ...args);
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
var _a;
|
|
2623
|
+
|
|
2624
|
+
class FabricClientAdapter extends Adapter {
|
|
2625
|
+
static {
|
|
2626
|
+
this.decoder = new TextDecoder("utf8");
|
|
2627
|
+
}
|
|
2628
|
+
static {
|
|
2629
|
+
this.serializer = new ClientSerializer;
|
|
2630
|
+
}
|
|
2631
|
+
static {
|
|
2632
|
+
this.log = Logging.for(FabricClientAdapter);
|
|
2633
|
+
}
|
|
2634
|
+
constructor(config, alias) {
|
|
2635
|
+
super(Object.assign({}, config, {
|
|
2636
|
+
evaluateTimeout: 5,
|
|
2637
|
+
endorseTimeout: 15,
|
|
2638
|
+
submitTimeout: 5,
|
|
2639
|
+
commitTimeout: 60
|
|
2640
|
+
}), FabricFlavour, alias);
|
|
2641
|
+
this.serializer = FabricClientAdapter.serializer;
|
|
2642
|
+
}
|
|
2643
|
+
Statement(overrides) {
|
|
2644
|
+
return new FabricClientStatement(this, overrides);
|
|
2645
|
+
}
|
|
2646
|
+
Paginator(query, size, clazz) {
|
|
2647
|
+
return new FabricClientPaginator(this, query, size, clazz);
|
|
2648
|
+
}
|
|
2649
|
+
async flags(operation, model, flags, ...args) {
|
|
2650
|
+
return Object.assign(await super.flags(operation, model, Object.assign({}, this.config, flags), ...args));
|
|
2651
|
+
}
|
|
2652
|
+
decode(data) {
|
|
2653
|
+
return FabricClientAdapter.decoder.decode(data);
|
|
2654
|
+
}
|
|
2655
|
+
repository() {
|
|
2656
|
+
return FabricClientRepository;
|
|
2657
|
+
}
|
|
2658
|
+
createPrefix(clazz, id, model, ...args) {
|
|
2659
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.createPrefix);
|
|
2660
|
+
const tableName = Model.tableName(clazz);
|
|
2661
|
+
const record = {};
|
|
2662
|
+
record[CouchDBKeys.TABLE] = tableName;
|
|
2663
|
+
Object.assign(record, model);
|
|
2664
|
+
return [ clazz, id, record, ...ctxArgs ];
|
|
2665
|
+
}
|
|
2666
|
+
createAllPrefix(clazz, ids, models, ...args) {
|
|
2667
|
+
const tableName = Model.tableName(clazz);
|
|
2668
|
+
if (ids.length !== models.length) throw new InternalError("Ids and models must have the same length");
|
|
2669
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.createAllPrefix);
|
|
2670
|
+
const records = ids.map((id, count) => {
|
|
2671
|
+
const record = {};
|
|
2672
|
+
record[CouchDBKeys.TABLE] = tableName;
|
|
2673
|
+
Object.assign(record, models[count]);
|
|
2674
|
+
return record;
|
|
2675
|
+
});
|
|
2676
|
+
return [ clazz, ids, records, ...ctxArgs ];
|
|
2677
|
+
}
|
|
2678
|
+
updateAllPrefix(clazz, ids, models, ...args) {
|
|
2679
|
+
const tableName = Model.tableName(clazz);
|
|
2680
|
+
if (ids.length !== models.length) throw new InternalError("Ids and models must have the same length");
|
|
2681
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.updateAllPrefix);
|
|
2682
|
+
const records = ids.map(() => {
|
|
2683
|
+
const record = {};
|
|
2684
|
+
record[CouchDBKeys.TABLE] = tableName;
|
|
2685
|
+
return record;
|
|
2686
|
+
});
|
|
2687
|
+
return [ clazz, ids, records, ...ctxArgs ];
|
|
2688
|
+
}
|
|
2689
|
+
async createAll(clazz, ids, models, ...args) {
|
|
2690
|
+
if (ids.length !== models.length) throw new InternalError("Ids and models must have the same length");
|
|
2691
|
+
const ctxArgs = [ ...args ];
|
|
2692
|
+
const transient = ctxArgs.shift();
|
|
2693
|
+
const {log: log, ctx: ctx} = this.logCtx(ctxArgs, this.createAll);
|
|
2694
|
+
const tableName = Model.tableName(clazz);
|
|
2695
|
+
log.info(`adding ${ids.length} entries to ${tableName} table`);
|
|
2696
|
+
log.verbose(`pks: ${ids}`);
|
|
2697
|
+
const result = await this.submitTransaction(ctx, BulkCrudOperationKeys.CREATE_ALL, [ JSON.stringify(models.map(m => this.serializer.serialize(m, clazz.name))) ], transient, undefined, clazz.name);
|
|
2698
|
+
try {
|
|
2699
|
+
return JSON.parse(this.decode(result)).map(r => JSON.parse(r));
|
|
2700
|
+
} catch (e) {
|
|
2701
|
+
throw new SerializationError(e);
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
async readAll(clazz, ids, ...args) {
|
|
2705
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.readAll);
|
|
2706
|
+
const tableName = Model.tableName(clazz);
|
|
2707
|
+
log.info(`reading ${ids.length} entries to ${tableName} table`);
|
|
2708
|
+
log.verbose(`pks: ${ids}`);
|
|
2709
|
+
const result = await this.evaluateTransaction(ctx, BulkCrudOperationKeys.READ_ALL, [ JSON.stringify(ids) ], undefined, undefined, clazz.name);
|
|
2710
|
+
try {
|
|
2711
|
+
return JSON.parse(this.decode(result)).map(r => JSON.parse(r));
|
|
2712
|
+
} catch (e) {
|
|
2713
|
+
throw new SerializationError(e);
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
async updateAll(clazz, ids, models, ...args) {
|
|
2717
|
+
if (ids.length !== models.length) throw new InternalError("Ids and models must have the same length");
|
|
2718
|
+
const ctxArgs = [ ...args ];
|
|
2719
|
+
const transient = ctxArgs.shift();
|
|
2720
|
+
const {log: log, ctx: ctx} = this.logCtx(ctxArgs, this.updateAll);
|
|
2721
|
+
const tableName = Model.tableName(clazz);
|
|
2722
|
+
log.info(`updating ${ids.length} entries to ${tableName} table`);
|
|
2723
|
+
log.verbose(`pks: ${ids}`);
|
|
2724
|
+
const result = await this.submitTransaction(ctx, BulkCrudOperationKeys.UPDATE_ALL, [ JSON.stringify(models.map(m => this.serializer.serialize(m, clazz.name))) ], transient, undefined, clazz.name);
|
|
2725
|
+
try {
|
|
2726
|
+
return JSON.parse(this.decode(result)).map(r => JSON.parse(r));
|
|
2727
|
+
} catch (e) {
|
|
2728
|
+
throw new SerializationError(e);
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
async deleteAll(clazz, ids, ...args) {
|
|
2732
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.deleteAll);
|
|
2733
|
+
const tableName = Model.tableName(clazz);
|
|
2734
|
+
log.info(`deleting ${ids.length} entries to ${tableName} table`);
|
|
2735
|
+
log.verbose(`pks: ${ids}`);
|
|
2736
|
+
const result = await this.submitTransaction(ctx, BulkCrudOperationKeys.DELETE_ALL, [ JSON.stringify(ids) ], undefined, undefined, clazz.name);
|
|
2737
|
+
try {
|
|
2738
|
+
return JSON.parse(this.decode(result)).map(r => JSON.parse(r));
|
|
2739
|
+
} catch (e) {
|
|
2740
|
+
throw new SerializationError(e);
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
prepare(model, ...args) {
|
|
2744
|
+
const {log: log} = this.logCtx(args, this.prepare);
|
|
2745
|
+
const split = Model.segregate(model);
|
|
2746
|
+
if (model[PersistenceKeys.METADATA]) {
|
|
2747
|
+
log.silly(`Passing along persistence metadata for ${model[PersistenceKeys.METADATA]}`);
|
|
2748
|
+
Object.defineProperty(split.model, PersistenceKeys.METADATA, {
|
|
2749
|
+
enumerable: false,
|
|
2750
|
+
writable: false,
|
|
2751
|
+
configurable: true,
|
|
2752
|
+
value: model[PersistenceKeys.METADATA]
|
|
2753
|
+
});
|
|
2754
|
+
}
|
|
2755
|
+
return {
|
|
2756
|
+
record: split.model,
|
|
2757
|
+
model: split.model,
|
|
2758
|
+
id: model[Model.pk(model.constructor)],
|
|
2759
|
+
transient: split.transient,
|
|
2760
|
+
privates: split.privates,
|
|
2761
|
+
shared: split.shared
|
|
2762
|
+
};
|
|
2763
|
+
}
|
|
2764
|
+
revert(obj, clazz, id, transient, ...args) {
|
|
2765
|
+
const {log: log} = this.logCtx(args, this.revert);
|
|
2766
|
+
if (transient) {
|
|
2767
|
+
log.verbose(`re-adding transient properties: ${Object.keys(transient).join(", ")}`);
|
|
2768
|
+
Object.entries(transient).forEach(([key, val]) => {
|
|
2769
|
+
if (key in obj && typeof obj[key] !== "undefined") throw new InternalError(`Transient property ${key} already exists on model ${typeof clazz === "string" ? clazz : clazz.name}. should be impossible`);
|
|
2770
|
+
obj[key] = val;
|
|
2771
|
+
});
|
|
2772
|
+
}
|
|
2773
|
+
return new clazz(obj);
|
|
2774
|
+
}
|
|
2775
|
+
async create(clazz, id, model, transient = {}, ...args) {
|
|
2776
|
+
const ctxArgs = [ ...args ];
|
|
2777
|
+
const {log: log, ctx: ctx} = this.logCtx(ctxArgs, this.create);
|
|
2778
|
+
const tableName = Model.tableName(clazz);
|
|
2779
|
+
log.verbose(`adding entry to ${tableName} table`);
|
|
2780
|
+
log.debug(`pk: ${id}`);
|
|
2781
|
+
const result = await this.submitTransaction(ctx, OperationKeys.CREATE, [ this.serializer.serialize(model, clazz.name) ], transient, undefined, clazz.name);
|
|
2782
|
+
return this.serializer.deserialize(this.decode(result));
|
|
2783
|
+
}
|
|
2784
|
+
async read(clazz, id, ...args) {
|
|
2785
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.readAll);
|
|
2786
|
+
const tableName = Model.tableName(clazz);
|
|
2787
|
+
log.verbose(`reading entry from ${tableName} table`);
|
|
2788
|
+
log.debug(`pk: ${id}`);
|
|
2789
|
+
const result = await this.evaluateTransaction(ctx, OperationKeys.READ, [ id.toString() ], undefined, undefined, clazz.name);
|
|
2790
|
+
return this.serializer.deserialize(this.decode(result));
|
|
2791
|
+
}
|
|
2792
|
+
updatePrefix(clazz, id, model, ...args) {
|
|
2793
|
+
const tableName = Model.tableName(clazz);
|
|
2794
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.updatePrefix);
|
|
2795
|
+
const record = {};
|
|
2796
|
+
record[CouchDBKeys.TABLE] = tableName;
|
|
2797
|
+
Object.assign(record, model);
|
|
2798
|
+
return [ clazz, id, record, ...ctxArgs ];
|
|
2799
|
+
}
|
|
2800
|
+
async update(clazz, id, model, transient = {}, ...args) {
|
|
2801
|
+
const ctxArgs = [ ...args ];
|
|
2802
|
+
const {log: log, ctx: ctx} = this.logCtx(ctxArgs, this.updateAll);
|
|
2803
|
+
log.info(`CLIENT UPDATE class : ${typeof clazz}`);
|
|
2804
|
+
const tableName = Model.tableName(clazz);
|
|
2805
|
+
log.verbose(`updating entry to ${tableName} table`);
|
|
2806
|
+
log.debug(`pk: ${id}`);
|
|
2807
|
+
const result = await this.submitTransaction(ctx, OperationKeys.UPDATE, [ this.serializer.serialize(model, clazz.name || clazz) ], transient, undefined, clazz.name);
|
|
2808
|
+
return this.serializer.deserialize(this.decode(result));
|
|
2809
|
+
}
|
|
2810
|
+
async delete(clazz, id, ...args) {
|
|
2811
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.delete);
|
|
2812
|
+
const tableName = Model.tableName(clazz);
|
|
2813
|
+
log.verbose(`deleting entry from ${tableName} table`);
|
|
2814
|
+
log.debug(`pk: ${id}`);
|
|
2815
|
+
const result = await this.submitTransaction(ctx, OperationKeys.DELETE, [ id.toString() ], undefined, undefined, clazz.name);
|
|
2816
|
+
return this.serializer.deserialize(this.decode(result));
|
|
2817
|
+
}
|
|
2818
|
+
async raw(rawInput, docsOnly = true, clazz, ...args) {
|
|
2819
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.raw);
|
|
2820
|
+
const tableName = clazz.name;
|
|
2821
|
+
log.info(`Performing raw statement on table ${Model.tableName(clazz)}`);
|
|
2822
|
+
let transactionResult;
|
|
2823
|
+
try {
|
|
2824
|
+
transactionResult = await this.evaluateTransaction(ctx, "raw", [ JSON.stringify(rawInput), docsOnly ], undefined, undefined, tableName);
|
|
2825
|
+
} catch (e) {
|
|
2826
|
+
throw this.parseError(e);
|
|
2827
|
+
}
|
|
2828
|
+
let result;
|
|
2829
|
+
try {
|
|
2830
|
+
result = JSON.parse(this.decode(transactionResult));
|
|
2831
|
+
} catch (e) {
|
|
2832
|
+
throw new SerializationError(`Failed to process result: ${e}`);
|
|
2833
|
+
}
|
|
2834
|
+
const parseRecord = record => {
|
|
2835
|
+
if (Model.isModel(record)) return Model.build(record);
|
|
2836
|
+
return record;
|
|
2837
|
+
};
|
|
2838
|
+
if (Array.isArray(result)) {
|
|
2839
|
+
if (!result.length) return result;
|
|
2840
|
+
const el = result[0];
|
|
2841
|
+
if (Model.isModel(el)) return result.map(el => Model.build(el));
|
|
2842
|
+
return result;
|
|
2843
|
+
}
|
|
2844
|
+
return parseRecord(result);
|
|
2845
|
+
}
|
|
2846
|
+
async view(ddoc, viewName, options, ...args) {
|
|
2847
|
+
const {log: log, ctx: ctx} = this.logCtx(args, this.view);
|
|
2848
|
+
log.info(`Querying view ${ddoc}/${viewName}`);
|
|
2849
|
+
let transactionResult;
|
|
2850
|
+
try {
|
|
2851
|
+
transactionResult = await this.evaluateTransaction(ctx, "view", [ ddoc, viewName, JSON.stringify(options) ], undefined, undefined, undefined);
|
|
2852
|
+
} catch (e) {
|
|
2853
|
+
throw this.parseError(e);
|
|
2854
|
+
}
|
|
2855
|
+
let result;
|
|
2856
|
+
try {
|
|
2857
|
+
result = JSON.parse(this.decode(transactionResult));
|
|
2858
|
+
} catch (e) {
|
|
2859
|
+
throw new SerializationError(`Failed to process view result: ${e}`);
|
|
2860
|
+
}
|
|
2861
|
+
return result;
|
|
2862
|
+
}
|
|
2863
|
+
getClient() {
|
|
2864
|
+
if (!this._client) this._client = FabricClientAdapter.getClient(this.config);
|
|
2865
|
+
return this._client;
|
|
2866
|
+
}
|
|
2867
|
+
async Gateway(ctx) {
|
|
2868
|
+
return FabricClientAdapter.getGateway(ctx, this.config, this.client);
|
|
2869
|
+
}
|
|
2870
|
+
getContractName(className) {
|
|
2871
|
+
if (!className) return undefined;
|
|
2872
|
+
return `${className}Contract`;
|
|
2873
|
+
}
|
|
2874
|
+
async Contract(ctx, contractName) {
|
|
2875
|
+
return FabricClientAdapter.getContract(await this.Gateway(ctx), this.config, contractName);
|
|
2876
|
+
}
|
|
2877
|
+
async transaction(ctx, api, submit = true, args, transientData, endorsingOrganizations, className) {
|
|
2878
|
+
const log = this.log.for(this.transaction);
|
|
2879
|
+
const gateway = await this.Gateway(ctx);
|
|
2880
|
+
try {
|
|
2881
|
+
const contract = await this.Contract(ctx, this.getContractName(className));
|
|
2882
|
+
log.verbose(`${submit ? "Submit" : "Evaluate"}ting transaction ${this.getContractName(className) || this.config.contractName}.${api}`);
|
|
2883
|
+
log.debug(`args: ${args?.map(a => a.toString()).join("\n") || "none"}`);
|
|
2884
|
+
const method = submit ? contract.submit : contract.evaluate;
|
|
2885
|
+
endorsingOrganizations = endorsingOrganizations?.length ? endorsingOrganizations : undefined;
|
|
2886
|
+
const proposalOptions = {
|
|
2887
|
+
arguments: args || [],
|
|
2888
|
+
transientData: transientData
|
|
2889
|
+
};
|
|
2890
|
+
return await method.call(contract, api, proposalOptions);
|
|
2891
|
+
} catch (e) {
|
|
2892
|
+
if (e.code === 10) {
|
|
2893
|
+
throw new Error(`${e.details[0].message}`);
|
|
2894
|
+
}
|
|
2895
|
+
throw this.parseError(e);
|
|
2896
|
+
} finally {
|
|
2897
|
+
this.log.debug(`Closing ${this.config.mspId} gateway connection`);
|
|
2898
|
+
gateway.close();
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
parseError(err) {
|
|
2902
|
+
return FabricClientAdapter.parseError(err);
|
|
2903
|
+
}
|
|
2904
|
+
async submitTransaction(ctx, api, args, transientData, endorsingOrganizations, className) {
|
|
2905
|
+
return this.transaction(ctx, api, true, args, transientData, endorsingOrganizations, className);
|
|
2906
|
+
}
|
|
2907
|
+
async evaluateTransaction(ctx, api, args, transientData, endorsingOrganizations, className) {
|
|
2908
|
+
return this.transaction(ctx, api, false, args, transientData, endorsingOrganizations, className);
|
|
2909
|
+
}
|
|
2910
|
+
async close() {
|
|
2911
|
+
if (this.client) {
|
|
2912
|
+
this.log.verbose(`Closing ${this.config.mspId} gateway client`);
|
|
2913
|
+
this.client.close();
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
static getContract(gateway, config, contractName) {
|
|
2917
|
+
const log = this.log.for(this.getContract);
|
|
2918
|
+
const network = this.getNetwork(gateway, config.channel);
|
|
2919
|
+
let contract;
|
|
2920
|
+
try {
|
|
2921
|
+
log.debug(`Retrieving chaincode ${config.chaincodeName} contract ${contractName || config.contractName} from network ${config.channel}`);
|
|
2922
|
+
contractName = contractName ? contractName : config.contractName;
|
|
2923
|
+
contract = network.getContract(config.chaincodeName, contractName);
|
|
2924
|
+
} catch (e) {
|
|
2925
|
+
throw this.parseError(e);
|
|
2926
|
+
}
|
|
2927
|
+
return contract;
|
|
2928
|
+
}
|
|
2929
|
+
static getNetwork(gateway, channelName) {
|
|
2930
|
+
const log = Logging.for(this.getNetwork);
|
|
2931
|
+
let network;
|
|
2932
|
+
try {
|
|
2933
|
+
log.debug(`Connecting to channel ${channelName}`);
|
|
2934
|
+
network = gateway.getNetwork(channelName);
|
|
2935
|
+
} catch (e) {
|
|
2936
|
+
throw this.parseError(e);
|
|
2937
|
+
}
|
|
2938
|
+
return network;
|
|
2939
|
+
}
|
|
2940
|
+
static async getGateway(ctx, config, client) {
|
|
2941
|
+
return await this.getConnection(client || await this.getClient(config), config, ctx);
|
|
2942
|
+
}
|
|
2943
|
+
static getClient(config) {
|
|
2944
|
+
const log = this.log.for(this.getClient);
|
|
2945
|
+
log.debug(`generating TLS credentials for msp ${config.mspId}`);
|
|
2946
|
+
let pathOrCert = config.tlsCert;
|
|
2947
|
+
if (typeof pathOrCert === "string") {
|
|
2948
|
+
if (pathOrCert.match(/-----BEGIN (CERTIFICATE|KEY|PRIVATE KEY)-----.+?-----END \1-----$/gms)) {
|
|
2949
|
+
pathOrCert = Buffer.from(pathOrCert, "utf8");
|
|
2950
|
+
} else {
|
|
2951
|
+
try {
|
|
2952
|
+
pathOrCert = Buffer.from(fs.readFileSync(pathOrCert, "utf8"));
|
|
2953
|
+
} catch (e) {
|
|
2954
|
+
throw new InternalError(`Failed to read the tls certificate from ${pathOrCert}: ${e}`);
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
const tlsCredentials = grpc.credentials.createSsl(pathOrCert);
|
|
2959
|
+
log.debug(`generating Gateway Client for url ${config.peerEndpoint}`);
|
|
2960
|
+
return new Client(config.peerEndpoint, tlsCredentials, {
|
|
2961
|
+
"grpc.max_receive_message_length": (config.sizeLimit || 15) * 1024 * 1024,
|
|
2962
|
+
"grpc.max_send_message_length": (config.sizeLimit || 15) * 1024 * 1024
|
|
2963
|
+
});
|
|
2964
|
+
}
|
|
2965
|
+
static async getConnection(client, config, ctx) {
|
|
2966
|
+
const log = Logging.for(this.getConnection);
|
|
2967
|
+
log.debug(`Retrieving Peer Identity for ${config.mspId} under ${config.certCertOrDirectoryPath}`);
|
|
2968
|
+
const identity = await getIdentity(config.mspId, config.certCertOrDirectoryPath);
|
|
2969
|
+
log.debug(`Retrieving signer key from ${config.keyCertOrDirectoryPath}`);
|
|
2970
|
+
let signer, close = () => {};
|
|
2971
|
+
if (!config.hsm) {
|
|
2972
|
+
signer = await getSigner(config.keyCertOrDirectoryPath);
|
|
2973
|
+
} else {
|
|
2974
|
+
const hsm = new HSMSignerFactoryCustom(config.hsm.library);
|
|
2975
|
+
const identifier = hsm.getSKIFromCertificatePath(config.certCertOrDirectoryPath);
|
|
2976
|
+
const pkcs11Signer = hsm.newSigner({
|
|
2977
|
+
label: config.hsm.tokenLabel,
|
|
2978
|
+
pin: String(config.hsm.pin),
|
|
2979
|
+
identifier: identifier
|
|
2980
|
+
});
|
|
2981
|
+
signer = pkcs11Signer.signer;
|
|
2982
|
+
close = pkcs11Signer.close;
|
|
2983
|
+
}
|
|
2984
|
+
const options = {
|
|
2985
|
+
client: client,
|
|
2986
|
+
identity: identity,
|
|
2987
|
+
signer: signer,
|
|
2988
|
+
evaluateOptions: () => ({
|
|
2989
|
+
deadline: Date.now() + 1e3 * ctx.get("evaluateTimeout")
|
|
2990
|
+
}),
|
|
2991
|
+
endorseOptions: () => ({
|
|
2992
|
+
deadline: Date.now() + 1e3 * ctx.get("endorseTimeout")
|
|
2993
|
+
}),
|
|
2994
|
+
submitOptions: () => ({
|
|
2995
|
+
deadline: Date.now() + 1e3 * ctx.get("submitTimeout")
|
|
2996
|
+
}),
|
|
2997
|
+
commitStatusOptions: () => ({
|
|
2998
|
+
deadline: Date.now() + 1e3 * ctx.get("commitTimeout")
|
|
2999
|
+
})
|
|
3000
|
+
};
|
|
3001
|
+
log.debug(`Connecting to ${config.mspId}`);
|
|
3002
|
+
const gateway = connect(options);
|
|
3003
|
+
if (config.hsm) {
|
|
3004
|
+
gateway.close = new Proxy(gateway.close, {
|
|
3005
|
+
apply(target, thisArg, argArray) {
|
|
3006
|
+
Reflect.apply(target, thisArg, argArray);
|
|
3007
|
+
close();
|
|
3008
|
+
}
|
|
3009
|
+
});
|
|
3010
|
+
}
|
|
3011
|
+
return gateway;
|
|
3012
|
+
}
|
|
3013
|
+
Dispatch() {
|
|
3014
|
+
return new FabricClientAdapter["_baseDispatch"];
|
|
3015
|
+
}
|
|
3016
|
+
static parseError(err) {
|
|
3017
|
+
const msg = typeof err === "string" ? err : err.message;
|
|
3018
|
+
if (msg.includes("MVCC_READ_CONFLICT")) return new MvccReadConflictError(err);
|
|
3019
|
+
if (msg.includes("ENDORSEMENT_POLICY_FAILURE")) return new EndorsementPolicyError(err);
|
|
3020
|
+
if (msg.includes("PHANTOM_READ_CONFLICT")) return new PhantomReadConflictError(err);
|
|
3021
|
+
if (err instanceof Error && err.code) {
|
|
3022
|
+
switch (err.code) {
|
|
3023
|
+
case 9:
|
|
3024
|
+
return new EndorsementError(err);
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
if (msg.includes(NotFoundError.name)) return new NotFoundError(err);
|
|
3028
|
+
if (msg.includes(ConflictError.name)) return new ConflictError(err);
|
|
3029
|
+
if (msg.includes(BadRequestError.name)) return new BadRequestError(err);
|
|
3030
|
+
if (msg.includes(QueryError.name)) return new QueryError(err);
|
|
3031
|
+
if (msg.includes(PagingError.name)) return new PagingError(err);
|
|
3032
|
+
if (msg.includes(UnsupportedError.name)) return new UnsupportedError(err);
|
|
3033
|
+
if (msg.includes(MigrationError.name)) return new MigrationError(err);
|
|
3034
|
+
if (msg.includes(ObserverError.name)) return new ObserverError(err);
|
|
3035
|
+
if (msg.includes(AuthorizationError.name)) return new AuthorizationError(err);
|
|
3036
|
+
if (msg.includes(ForbiddenError.name)) return new ForbiddenError(err);
|
|
3037
|
+
if (msg.includes(ConnectionError.name)) return new ConnectionError(err);
|
|
3038
|
+
if (msg.includes(SerializationError.name)) return new SerializationError(err);
|
|
3039
|
+
return new InternalError(err);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
__decorate([ debug(), final(), __metadata("design:type", Function), __metadata("design:paramtypes", [ Object, Object, Object, Object, Context ]), __metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "create", null);
|
|
3044
|
+
|
|
3045
|
+
__decorate([ debug(), final(), __metadata("design:type", Function), __metadata("design:paramtypes", [ Object, Object, Context ]), __metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "read", null);
|
|
3046
|
+
|
|
3047
|
+
__decorate([ debug(), final(), __metadata("design:type", Function), __metadata("design:paramtypes", [ Object, Object, Object, Object, Context ]), __metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "update", null);
|
|
3048
|
+
|
|
3049
|
+
__decorate([ debug(), final(), __metadata("design:type", Function), __metadata("design:paramtypes", [ Object, Object, Context ]), __metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "delete", null);
|
|
3050
|
+
|
|
3051
|
+
__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);
|
|
3052
|
+
|
|
3053
|
+
__decorate([ debug(), __metadata("design:type", Function), __metadata("design:paramtypes", [ String, String, Object, Context ]), __metadata("design:returntype", Promise) ], FabricClientAdapter.prototype, "view", null);
|
|
3054
|
+
|
|
3055
|
+
FabricClientAdapter.decoration();
|
|
3056
|
+
|
|
3057
|
+
Adapter.setCurrent(FabricFlavour);
|
|
3058
|
+
|
|
3059
|
+
class FabricClientDispatch extends Dispatch {
|
|
3060
|
+
constructor(client) {
|
|
3061
|
+
super();
|
|
3062
|
+
this.client = client;
|
|
3063
|
+
this.decoder = new TextDecoder("utf8");
|
|
3064
|
+
}
|
|
3065
|
+
async close() {
|
|
3066
|
+
if (this.listeningStack) this.listeningStack.close();
|
|
3067
|
+
}
|
|
3068
|
+
parsePayload(jsonBytes) {
|
|
3069
|
+
const json = this.decoder.decode(jsonBytes);
|
|
3070
|
+
return JSON.parse(json);
|
|
3071
|
+
}
|
|
3072
|
+
observe(observer) {
|
|
3073
|
+
if (!(observer instanceof FabricClientAdapter)) throw new UnsupportedError("Only FabricClientAdapter can be observed by dispatch");
|
|
3074
|
+
super.observe(observer);
|
|
3075
|
+
return () => this.unObserve(observer);
|
|
3076
|
+
}
|
|
3077
|
+
async updateObservers(model, event, id, ...args) {
|
|
3078
|
+
const {log: log, ctxArgs: ctxArgs} = Adapter.logCtx(this.updateObservers, event, false, ...args);
|
|
3079
|
+
if (!this.adapter) {
|
|
3080
|
+
log.verbose(`No adapter observed for dispatch; skipping observer update for ${typeof model === "string" ? model : Model.tableName(model)}:${event}`);
|
|
3081
|
+
return;
|
|
3082
|
+
}
|
|
3083
|
+
try {
|
|
3084
|
+
await this.adapter.refresh(model, event, id, ...ctxArgs);
|
|
3085
|
+
} catch (e) {
|
|
3086
|
+
throw new InternalError(`Failed to refresh dispatch: ${e}`);
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
async handleEvents(ctxArg) {
|
|
3090
|
+
if (!this.listeningStack) throw new InternalError(`Event stack not initialized. Ensure that "startListening" is called before attempting this operation.`);
|
|
3091
|
+
if (!this.adapter || !this.adapter.config) throw new InternalError(`No adapter found. should be impossible`);
|
|
3092
|
+
const ctx = ctxArg || await this.adapter.context(OperationKeys.READ, {
|
|
3093
|
+
correlationId: this.adapter.config.chaincodeName
|
|
3094
|
+
}, this.models && this.models[0] || Model);
|
|
3095
|
+
const log = this.log.for(this.handleEvents);
|
|
3096
|
+
log.info(`Listening for incoming events on chaincode "${this.adapter.config.chaincodeName}" on channel "${this.adapter.config.channel}"...`);
|
|
3097
|
+
try {
|
|
3098
|
+
for await (const evt of this.listeningStack) {
|
|
3099
|
+
const {table: table, event: event, owner: owner} = parseEventName(evt.eventName);
|
|
3100
|
+
if (owner && owner !== this.adapter.config?.mspId) continue;
|
|
3101
|
+
const payload = this.parsePayload(evt.payload);
|
|
3102
|
+
try {
|
|
3103
|
+
const targetModel = table ? Model.get(table) : Model.get(this.models[0].name);
|
|
3104
|
+
const modelRef = targetModel ?? (table || this.models[0]?.name);
|
|
3105
|
+
await this.updateObservers(modelRef, event, payload.id, ctx);
|
|
3106
|
+
} catch (e) {
|
|
3107
|
+
log.error(`Failed update observables for table ${table} event ${event} id: ${payload.id}: ${e}`);
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
} catch (e) {
|
|
3111
|
+
log.error(`Failed to read event for chaincode "${this.adapter.config.chaincodeName}" on channel "${this.adapter.config.channel}": ${e}`);
|
|
3112
|
+
await this.close();
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
async initialize() {
|
|
3116
|
+
if (!this.adapter) throw new InternalError(`No adapter or config observed for dispatch`);
|
|
3117
|
+
const context = await this.adapter.context("dispatch", {
|
|
3118
|
+
correlationId: this.adapter.config.chaincodeName
|
|
3119
|
+
}, Model);
|
|
3120
|
+
const {ctx: ctx} = this.logCtx([ context ], this.initialize);
|
|
3121
|
+
const gateway = await FabricClientAdapter.getGateway(ctx, this.adapter.config, this.client);
|
|
3122
|
+
const network = gateway.getNetwork(this.adapter.config.channel);
|
|
3123
|
+
if (!this.adapter) throw new InternalError(`No adapter observed for dispatch`);
|
|
3124
|
+
this.listeningStack = await network.getChaincodeEvents(this.adapter.config.chaincodeName);
|
|
3125
|
+
this.handleEvents(ctx);
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
if (FabricClientAdapter) FabricClientAdapter["_baseDispatch"] = FabricClientDispatch;
|
|
3130
|
+
|
|
3131
|
+
const VERSION = "0.1.78";
|
|
3132
|
+
|
|
3133
|
+
const PACKAGE_NAME = "@decaf-ts/for-fabric";
|
|
3134
|
+
|
|
3135
|
+
Metadata.registerLibrary(PACKAGE_NAME, VERSION);
|
|
3136
|
+
|
|
3137
|
+
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, NamespaceCollection, NotInitializedError, OverflowError, Owner, PACKAGE_NAME, PhantomReadConflictError, RegistrationError, RegistrationRequestBuilder, SEGREGATED_COLLECTION_EXTRACTION_PRIORITY, SimpleDeterministicSerializer, UnauthorizedPrivateDataAccess, VERSION, add, contentOfLoadFile, createMirrorHandler, deleteMirrorHandler, evalMirrorMetadata, extractPrivateKey, extractSegregatedCollections, generateFabricEventName, generateModelDesignDocs, generateModelIndexes, getCAUser, getFirstDirFileName, getFirstDirFileNameContent, getIdentity, getSigner, mirror, ownedBy, ownedByOnCreate, parseEventName, privateData, readFile, readModelFile, readModelFolders, safeParseInt, segregatedDataOnCreate, segregatedDataOnDelete, segregatedDataOnRead, segregatedDataOnUpdate, sharedData, sub, transactionId, transactionIdOnCreate, updateMirrorHandler, writeDesignDocs, writeIndexes };
|
|
3138
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yLWZhYnJpYy5qcyIsInNvdXJjZXMiOlsiLi4vc3JjL2NsaWVudC9GYWJyaWNDbGllbnRSZXBvc2l0b3J5LnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9lcmMyMC9tb2RlbHMudHMiLCIuLi9zcmMvc2hhcmVkL0NsaWVudFNlcmlhbGl6ZXIudHMiLCIuLi9zcmMvY2xpZW50L2VyYzIwL0ZhYnJpY0VSQzIwQ2xpZW50UmVwb3NpdG9yeS50cyIsIi4uL3NyYy9jbGllbnQvaW5kZXhlcy9nZW5lcmF0aW9uLnRzIiwiLi4vc3JjL3NoYXJlZC9tb2RlbC9JZGVudGl0eUNyZWRlbnRpYWxzLnRzIiwiLi4vc3JjL3NoYXJlZC9jb25zdGFudHMudHMiLCIuLi9zcmMvc2hhcmVkL21vZGVsL0lkZW50aXR5LnRzIiwiLi4vc3JjL2NsaWVudC91dGlscy50cyIsIi4uL3NyYy9jbGllbnQvY3J5cHRvLnRzIiwiLi4vc3JjL3NoYXJlZC9lcnJvcnMudHMiLCIuLi9zcmMvY2xpZW50L3NlcnZpY2VzL0ZhYnJpY0Vucm9sbG1lbnRTZXJ2aWNlLnRzIiwiLi4vc3JjL2NsaWVudC9zZXJ2aWNlcy9SZWdpc3RyYXRpb25SZXF1ZXN0QnVpbGRlci50cyIsIi4uL3NyYy9zaGFyZWQvZXJjMjAvZXJjMjAtY29uc3RhbnRzLnRzIiwiLi4vc3JjL3NoYXJlZC9tb2RlbC9GYWJyaWNCYXNlTW9kZWwudHMiLCIuLi9zcmMvc2hhcmVkL21vZGVsL0ZhYnJpY0lkZW50aWZpZWRCYXNlTW9kZWwudHMiLCIuLi9zcmMvc2hhcmVkL292ZXJyaWRlcy9vdmVycmlkZXMudHMiLCIuLi9zcmMvc2hhcmVkL2RlY29yYXRvcnMudHMiLCIuLi9zcmMvc2hhcmVkL0RldGVybWluaXN0aWNTZXJpYWxpemVyLnRzIiwiLi4vc3JjL3NoYXJlZC9ldmVudHMudHMiLCIuLi9zcmMvc2hhcmVkL21hdGgudHMiLCIuLi9zcmMvc2hhcmVkL1NpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyLnRzIiwiLi4vc3JjL2NsaWVudC9zZXJ2aWNlcy9GYWJyaWNJZGVudGl0eVNlcnZpY2UudHMiLCIuLi9zcmMvY2xpZW50L2NvbnN0YW50cy50cyIsIi4uL3NyYy9jbGllbnQvZmFicmljLWZzLnRzIiwiLi4vc3JjL2NsaWVudC9mYWJyaWMtaHNtLnRzIiwiLi4vc3JjL2NsaWVudC9GYWJyaWNDbGllbnRTdGF0ZW1lbnQudHMiLCIuLi9zcmMvY2xpZW50L0ZhYnJpY0NsaWVudFBhZ2luYXRvci50cyIsIi4uL3NyYy9jbGllbnQvRmFicmljQ2xpZW50QWRhcHRlci50cyIsIi4uL3NyYy9jbGllbnQvRmFicmljQ2xpZW50RGlzcGF0Y2gudHMiLCIuLi9zcmMvdmVyc2lvbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBPcmRlckRpcmVjdGlvbixcbiAgUGVyc2lzdGVuY2VLZXlzLFxuICBSZXBvc2l0b3J5LFxuICBDb250ZXh0T2YsXG4gIFByZXBhcmVkU3RhdGVtZW50S2V5cyxcbiAgU2VyaWFsaXplZFBhZ2UsXG4gIERpcmVjdGlvbkxpbWl0T2Zmc2V0LFxuICBQYWdpbmF0b3IsXG4gIEZsYWdzT2YsXG4gIE9ic2VydmVySGFuZGxlcixcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgdHlwZSB7IE1heWJlQ29udGV4dHVhbEFyZyB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgdHlwZSBGYWJyaWNDbGllbnRBZGFwdGVyIH0gZnJvbSBcIi4vRmFicmljQ2xpZW50QWRhcHRlclwiO1xuaW1wb3J0IHtcbiAgT3BlcmF0aW9uS2V5cyxcbiAgUHJpbWFyeUtleVR5cGUsXG4gIFZhbGlkYXRpb25FcnJvcixcbiAgcmVkdWNlRXJyb3JzVG9QcmludCxcbiAgZW5mb3JjZURCRGVjb3JhdG9ycyxcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDb3VjaERCS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLWNvdWNoZGJcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmVwb3NpdG9yeSBpbXBsZW1lbnRhdGlvbiBmb3IgRmFicmljIGNsaWVudCBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBFeHRlbmRzIHRoZSBnZW5lcmljIFJlcG9zaXRvcnkgdG8gcHJlcGFyZSBjb250ZXh0IGFuZCBhcmd1bWVudHMgZm9yIENSVUQgb3BlcmF0aW9ucyBleGVjdXRlZCB2aWEgYSBGYWJyaWMgY2xpZW50IEFkYXB0ZXIsIHdpcmluZyBSZXBvc2l0b3J5RmxhZ3MgYW5kIEZhYnJpYy1zcGVjaWZpYyBvdmVycmlkZXMuXG4gKiBAdGVtcGxhdGUgTSBleHRlbmRzIE1vZGVsIC0gVGhlIG1vZGVsIHR5cGUgaGFuZGxlZCBieSB0aGlzIHJlcG9zaXRvcnlcbiAqIEBwYXJhbSB7QWRhcHRlcjxhbnksIE1hbmdvUXVlcnksIEZhYnJpY0ZsYWdzLCBDb250ZXh0PEZhYnJpY0ZsYWdzPj59IFthZGFwdGVyXSAtIE9wdGlvbmFsIGFkYXB0ZXIgaW5zdGFuY2UgdXNlZCB0byBleGVjdXRlIG9wZXJhdGlvbnNcbiAqIEBwYXJhbSB7Q29uc3RydWN0b3I8TT59IFtjbGF6el0gLSBPcHRpb25hbCBtb2RlbCBjb25zdHJ1Y3RvciB1c2VkIGJ5IHRoZSByZXBvc2l0b3J5XG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGNsYXNzIEZhYnJpY0NsaWVudFJlcG9zaXRvcnlcbiAqIEBleGFtcGxlXG4gKiBpbXBvcnQgeyBSZXBvc2l0b3J5IH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG4gKiBpbXBvcnQgeyBGYWJyaWNDbGllbnRSZXBvc2l0b3J5IH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItZmFicmljXCI7XG4gKlxuICogY2xhc3MgVXNlciBleHRlbmRzIE1vZGVsIHsgaWQhOiBzdHJpbmc7IG5hbWUhOiBzdHJpbmc7IH1cbiAqIGNvbnN0IHJlcG8gPSBuZXcgRmFicmljQ2xpZW50UmVwb3NpdG9yeTxVc2VyPigpO1xuICogY29uc3QgY3JlYXRlZCA9IGF3YWl0IHJlcG8uY3JlYXRlKG5ldyBVc2VyKHsgaWQ6IFwiMVwiLCBuYW1lOiBcIkFsaWNlXCIgfSkpO1xuICogY29uc3QgbG9hZGVkID0gYXdhaXQgcmVwby5yZWFkKFwiMVwiKTtcbiAqXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBSZXBvIGFzIEZhYnJpY0NsaWVudFJlcG9zaXRvcnlcbiAqICAgcGFydGljaXBhbnQgQWRhcHRlclxuICogICBBcHAtPj5SZXBvOiBjcmVhdGUobW9kZWwpXG4gKiAgIFJlcG8tPj5SZXBvOiBjcmVhdGVQcmVmaXgobW9kZWwsIC4uLmFyZ3MpXG4gKiAgIFJlcG8tPj5BZGFwdGVyOiBjcmVhdGUodGFibGUsIGlkLCBtb2RlbCwgZmxhZ3MpXG4gKiAgIEFkYXB0ZXItLT4+UmVwbzogcmVzdWx0XG4gKiAgIFJlcG8tLT4+QXBwOiBtb2RlbFxuICovXG5leHBvcnQgY2xhc3MgRmFicmljQ2xpZW50UmVwb3NpdG9yeTxcbiAgTSBleHRlbmRzIE1vZGVsLFxuICBBIGV4dGVuZHMgRmFicmljQ2xpZW50QWRhcHRlciA9IEZhYnJpY0NsaWVudEFkYXB0ZXIsXG4+IGV4dGVuZHMgUmVwb3NpdG9yeTxNLCBBPiB7XG4gIHByb3RlY3RlZCBvdmVycmlkZSBfb3ZlcnJpZGVzID0gT2JqZWN0LmFzc2lnbih7fSwgc3VwZXJbXCJfb3ZlcnJpZGVzXCJdLCB7XG4gICAgaWdub3JlVmFsaWRhdGlvbjogdHJ1ZSxcbiAgICBpZ25vcmVIYW5kbGVyczogdHJ1ZSxcbiAgICBhbGxvd1Jhd1N0YXRlbWVudHM6IGZhbHNlLFxuICAgIGZvcmNlUHJlcGFyZVNpbXBsZVF1ZXJpZXM6IHRydWUsXG4gICAgZm9yY2VQcmVwYXJlQ29tcGxleFF1ZXJpZXM6IHRydWUsXG4gICAgYWxsb3dHZW5lcmF0aW9uT3ZlcnJpZGU6IGZhbHNlLFxuICB9KTtcblxuICBjb25zdHJ1Y3RvcihhZGFwdGVyPzogQSwgY2xheno/OiBDb25zdHJ1Y3RvcjxNPikge1xuICAgIHN1cGVyKGFkYXB0ZXIsIGNsYXp6KTtcbiAgfVxuXG4gIG92ZXJyaWRlIG92ZXJyaWRlKGZsYWdzOiBQYXJ0aWFsPEZsYWdzT2Y8Q29udGV4dE9mPEE+Pj4pOiB0aGlzIHtcbiAgICByZXR1cm4gc3VwZXIub3ZlcnJpZGUoZmxhZ3MpLmZvcihmbGFncyBhcyBhbnkpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIE9ic2VydmVySGFuZGxlcigpOiBPYnNlcnZlckhhbmRsZXIge1xuICAgIHJldHVybiBzdXBlci5PYnNlcnZlckhhbmRsZXIoKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIHBhZ2luYXRlQnkoXG4gICAga2V5OiBrZXlvZiBNLFxuICAgIG9yZGVyOiBPcmRlckRpcmVjdGlvbixcbiAgICByZWY6IE9taXQ8RGlyZWN0aW9uTGltaXRPZmZzZXQsIFwiZGlyZWN0aW9uXCI+ID0ge1xuICAgICAgb2Zmc2V0OiAxLFxuICAgICAgbGltaXQ6IDEwLFxuICAgIH0sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj5cbiAgKTogUHJvbWlzZTxTZXJpYWxpemVkUGFnZTxNPj4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHhBcmdzIH0gPSAoXG4gICAgICBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBQcmVwYXJlZFN0YXRlbWVudEtleXMuUEFHRV9CWSwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLnBhZ2luYXRlQnkpO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYHBhZ2luYXRpbmcgJHtNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcyl9IHdpdGggcGFnZSBzaXplICR7cmVmLmxpbWl0fWBcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnN0YXRlbWVudChcbiAgICAgIHRoaXMucGFnaW5hdGVCeS5uYW1lLFxuICAgICAga2V5LFxuICAgICAgb3JkZXIsXG4gICAgICB7IGxpbWl0OiByZWYubGltaXQsIG9mZnNldDogcmVmLm9mZnNldCwgYm9va21hcms6IHJlZi5ib29rbWFyayB9LFxuICAgICAgLi4uY3R4QXJnc1xuICAgICk7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBsaXN0QnkoXG4gICAga2V5OiBrZXlvZiBNLFxuICAgIG9yZGVyOiBPcmRlckRpcmVjdGlvbixcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPE1bXT4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHhBcmdzIH0gPSAoXG4gICAgICBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBQcmVwYXJlZFN0YXRlbWVudEtleXMuTElTVF9CWSwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLmxpc3RCeSk7XG4gICAgbG9nLnZlcmJvc2UoXG4gICAgICBgbGlzdGluZyAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX0gYnkgJHtrZXkgYXMgc3RyaW5nfSAke29yZGVyfWBcbiAgICApO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5zdGF0ZW1lbnQoXG4gICAgICB0aGlzLmxpc3RCeS5uYW1lLFxuICAgICAga2V5LFxuICAgICAgb3JkZXIsXG4gICAgICAuLi5jdHhBcmdzXG4gICAgKSkgYXMgYW55O1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgZmluZEJ5KFxuICAgIGtleToga2V5b2YgTSxcbiAgICB2YWx1ZTogYW55LFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8TVtdPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IChcbiAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZLCB0cnVlKVxuICAgICkuZm9yKHRoaXMuZmluZEJ5KTtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBmaW5kaW5nIGFsbCAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX0gd2l0aCAke2tleSBhcyBzdHJpbmd9ICR7dmFsdWV9YFxuICAgICk7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLnN0YXRlbWVudChcbiAgICAgIHRoaXMuZmluZEJ5Lm5hbWUsXG4gICAgICBrZXksXG4gICAgICB2YWx1ZSxcbiAgICAgIC4uLmN0eEFyZ3NcbiAgICApKSBhcyBhbnk7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBmaW5kT25lQnkoXG4gICAga2V5OiBrZXlvZiBNLFxuICAgIHZhbHVlOiBhbnksXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj5cbiAgKTogUHJvbWlzZTxNPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IChcbiAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX09ORV9CWSwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLmZpbmRPbmVCeSk7XG4gICAgbG9nLnZlcmJvc2UoXG4gICAgICBgZmluZGluZyBPbmUgJHtNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcyl9IHdpdGggJHtrZXkgYXMgc3RyaW5nfSAke3ZhbHVlfWBcbiAgICApO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5zdGF0ZW1lbnQoXG4gICAgICB0aGlzLmZpbmRPbmVCeS5uYW1lLFxuICAgICAga2V5LFxuICAgICAgdmFsdWUsXG4gICAgICAuLi5jdHhBcmdzXG4gICAgKSkgYXMgYW55O1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgc3RhdGVtZW50KFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHgsIGN0eEFyZ3MgfSA9IChcbiAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFBlcnNpc3RlbmNlS2V5cy5TVEFURU1FTlQsIHRydWUpXG4gICAgKS5mb3IodGhpcy5zdGF0ZW1lbnQpO1xuICAgIGxvZy52ZXJib3NlKGBFeGVjdXRpbmcgcHJlcGFyZWQgc3RhdGVtZW50ICR7bmFtZX1gKTtcbiAgICBjb25zdCBjYWxsQXJncyA9IGN0eEFyZ3Muc2xpY2UoMCwgLTEpO1xuICAgIGNvbnN0IHJlc3VsdCA9IEpTT04ucGFyc2UoXG4gICAgICB0aGlzLmFkYXB0ZXIuZGVjb2RlKFxuICAgICAgICBhd2FpdCB0aGlzLmFkYXB0ZXIuZXZhbHVhdGVUcmFuc2FjdGlvbihcbiAgICAgICAgICBjdHgsXG4gICAgICAgICAgUGVyc2lzdGVuY2VLZXlzLlNUQVRFTUVOVCxcbiAgICAgICAgICBbbmFtZSwgSlNPTi5zdHJpbmdpZnkoY2FsbEFyZ3MpXSxcbiAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgIHRoaXMuY2xhc3MubmFtZVxuICAgICAgICApXG4gICAgICApXG4gICAgKTtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KHJlc3VsdCkpIHtcbiAgICAgIHJldHVybiByZXN1bHQubWFwKChyOiBhbnkpID0+XG4gICAgICAgIChyIGFzIGFueSlbQ291Y2hEQktleXMuVEFCTEVdICYmXG4gICAgICAgIChyIGFzIGFueSlbQ291Y2hEQktleXMuVEFCTEVdID09PSBNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcylcbiAgICAgICAgICA/IG5ldyB0aGlzLmNsYXNzKHIpXG4gICAgICAgICAgOiByXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gKHJlc3VsdCBhcyBhbnkpW0NvdWNoREJLZXlzLlRBQkxFXSAmJlxuICAgICAgKHJlc3VsdCBhcyBhbnkpW0NvdWNoREJLZXlzLlRBQkxFXSA9PT0gTW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpXG4gICAgICA/IG5ldyB0aGlzLmNsYXNzKHJlc3VsdClcbiAgICAgIDogUGFnaW5hdG9yLmlzU2VyaWFsaXplZFBhZ2UocmVzdWx0KVxuICAgICAgICA/IE9iamVjdC5hc3NpZ24ocmVzdWx0LCB7XG4gICAgICAgICAgICBkYXRhOiByZXN1bHQuZGF0YS5tYXAoKGQ6IGFueSkgPT4gbmV3IHRoaXMuY2xhc3MoZCkpLFxuICAgICAgICAgIH0pXG4gICAgICAgIDogcmVzdWx0O1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgY291bnRPZihcbiAgICBrZXk/OiBrZXlvZiBNLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IChcbiAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFByZXBhcmVkU3RhdGVtZW50S2V5cy5DT1VOVF9PRiwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLmNvdW50T2YpO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYGNvdW50aW5nICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfSR7a2V5ID8gYCBieSAke2tleSBhcyBzdHJpbmd9YCA6IFwiXCJ9YFxuICAgICk7XG4gICAgY29uc3Qgc3RtdEFyZ3MgPSBrZXkgPyBba2V5LCAuLi5jdHhBcmdzXSA6IGN0eEFyZ3M7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGVtZW50KFByZXBhcmVkU3RhdGVtZW50S2V5cy5DT1VOVF9PRiwgLi4uc3RtdEFyZ3MpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgbWF4T2Y8SyBleHRlbmRzIGtleW9mIE0+KFxuICAgIGtleTogSyxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPE1bS10+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gKFxuICAgICAgYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLk1BWF9PRiwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLm1heE9mKTtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBmaW5kaW5nIG1heCBvZiAke2tleSBhcyBzdHJpbmd9IGluICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfWBcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnN0YXRlbWVudChQcmVwYXJlZFN0YXRlbWVudEtleXMuTUFYX09GLCBrZXksIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgbWluT2Y8SyBleHRlbmRzIGtleW9mIE0+KFxuICAgIGtleTogSyxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPE1bS10+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gKFxuICAgICAgYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLk1JTl9PRiwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLm1pbk9mKTtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBmaW5kaW5nIG1pbiBvZiAke2tleSBhcyBzdHJpbmd9IGluICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfWBcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnN0YXRlbWVudChQcmVwYXJlZFN0YXRlbWVudEtleXMuTUlOX09GLCBrZXksIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgYXZnT2Y8SyBleHRlbmRzIGtleW9mIE0+KFxuICAgIGtleTogSyxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHhBcmdzIH0gPSAoXG4gICAgICBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBQcmVwYXJlZFN0YXRlbWVudEtleXMuQVZHX09GLCB0cnVlKVxuICAgICkuZm9yKHRoaXMuYXZnT2YpO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYGNhbGN1bGF0aW5nIGF2ZyBvZiAke2tleSBhcyBzdHJpbmd9IGluICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfWBcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnN0YXRlbWVudChQcmVwYXJlZFN0YXRlbWVudEtleXMuQVZHX09GLCBrZXksIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgc3VtT2Y8SyBleHRlbmRzIGtleW9mIE0+KFxuICAgIGtleTogSyxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHhBcmdzIH0gPSAoXG4gICAgICBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBQcmVwYXJlZFN0YXRlbWVudEtleXMuU1VNX09GLCB0cnVlKVxuICAgICkuZm9yKHRoaXMuc3VtT2YpO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYGNhbGN1bGF0aW5nIHN1bSBvZiAke2tleSBhcyBzdHJpbmd9IGluICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfWBcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnN0YXRlbWVudChQcmVwYXJlZFN0YXRlbWVudEtleXMuU1VNX09GLCBrZXksIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgZGlzdGluY3RPZjxLIGV4dGVuZHMga2V5b2YgTT4oXG4gICAga2V5OiBLLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8TVtLXVtdPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IChcbiAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFByZXBhcmVkU3RhdGVtZW50S2V5cy5ESVNUSU5DVF9PRiwgdHJ1ZSlcbiAgICApLmZvcih0aGlzLmRpc3RpbmN0T2YpO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYGZpbmRpbmcgZGlzdGluY3QgdmFsdWVzIG9mICR7a2V5IGFzIHN0cmluZ30gaW4gJHtNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcyl9YFxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGVtZW50KFByZXBhcmVkU3RhdGVtZW50S2V5cy5ESVNUSU5DVF9PRiwga2V5LCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGdyb3VwT2Y8SyBleHRlbmRzIGtleW9mIE0+KFxuICAgIGtleTogSyxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIE1bXT4+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gKFxuICAgICAgYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkdST1VQX09GLCB0cnVlKVxuICAgICkuZm9yKHRoaXMuZ3JvdXBPZik7XG4gICAgbG9nLnZlcmJvc2UoYGdyb3VwaW5nICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfSBieSAke2tleSBhcyBzdHJpbmd9YCk7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGVtZW50KFByZXBhcmVkU3RhdGVtZW50S2V5cy5HUk9VUF9PRiwga2V5LCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGNyZWF0ZShcbiAgICBtb2RlbDogTSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPE0+IHtcbiAgICBjb25zdCB7IGN0eCwgbG9nLCBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLmNyZWF0ZSk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYENyZWF0aW5nIG5ldyAke3RoaXMuY2xhc3MubmFtZX0gaW4gdGFibGUgJHtNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcyl9YFxuICAgICk7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHByZWZlci1jb25zdFxuICAgIGxldCB7IHJlY29yZCwgaWQsIHRyYW5zaWVudCB9ID0gdGhpcy5hZGFwdGVyLnByZXBhcmUobW9kZWwsIGN0eCk7XG4gICAgcmVjb3JkID0gYXdhaXQgdGhpcy5hZGFwdGVyLmNyZWF0ZShcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBpZCxcbiAgICAgIHJlY29yZCxcbiAgICAgIHRyYW5zaWVudCxcbiAgICAgIC4uLmN0eEFyZ3NcbiAgICApO1xuICAgIHJldHVybiB0aGlzLmFkYXB0ZXIucmV2ZXJ0PE0+KHJlY29yZCwgdGhpcy5jbGFzcywgaWQsIHRyYW5zaWVudCwgY3R4KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIHVwZGF0ZShcbiAgICBtb2RlbDogTSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPE0+IHtcbiAgICBjb25zdCB7IGN0eEFyZ3MsIGxvZywgY3R4IH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnVwZGF0ZSk7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHByZWZlci1jb25zdFxuICAgIGxldCB7IHJlY29yZCwgaWQsIHRyYW5zaWVudCB9ID0gdGhpcy5hZGFwdGVyLnByZXBhcmUobW9kZWwsIGN0eCk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYHVwZGF0aW5nICR7dGhpcy5jbGFzcy5uYW1lfSBpbiB0YWJsZSAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX0gd2l0aCBpZCAke2lkfWBcbiAgICApO1xuICAgIHJlY29yZCA9IGF3YWl0IHRoaXMuYWRhcHRlci51cGRhdGUoXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgaWQsXG4gICAgICByZWNvcmQsXG4gICAgICB0cmFuc2llbnQsXG4gICAgICAuLi5jdHhBcmdzXG4gICAgKTtcbiAgICByZXR1cm4gdGhpcy5hZGFwdGVyLnJldmVydDxNPihyZWNvcmQsIHRoaXMuY2xhc3MsIGlkLCB0cmFuc2llbnQsIGN0eCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlQWxsUHJlZml4KFxuICAgIG1vZGVsczogTVtdLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8W01bXSwgLi4uYW55W10sIENvbnRleHRPZjxBPl0+IHtcbiAgICBjb25zdCB7IGN0eCwgY3R4QXJncyB9ID0gKFxuICAgICAgYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgT3BlcmF0aW9uS2V5cy5DUkVBVEUsIHRydWUpXG4gICAgKS5mb3IodGhpcy5jcmVhdGVBbGxQcmVmaXgpO1xuICAgIGNvbnN0IGlnbm9yZUhhbmRsZXJzID0gY3R4LmdldChcImlnbm9yZUhhbmRsZXJzXCIpO1xuICAgIGNvbnN0IGlnbm9yZVZhbGlkYXRlID0gY3R4LmdldChcImlnbm9yZVZhbGlkYXRpb25cIik7XG4gICAgaWYgKCFtb2RlbHMubGVuZ3RoKSByZXR1cm4gW21vZGVscywgLi4uY3R4QXJnc10gYXMgYW55O1xuXG4gICAgbW9kZWxzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBtb2RlbHMubWFwKGFzeW5jIChtKSA9PiB7XG4gICAgICAgIG0gPSBuZXcgdGhpcy5jbGFzcyhtKTtcbiAgICAgICAgaWYgKCFpZ25vcmVIYW5kbGVycylcbiAgICAgICAgICBhd2FpdCBlbmZvcmNlREJEZWNvcmF0b3JzPE0sIFJlcG9zaXRvcnk8TSwgQT4sIGFueT4oXG4gICAgICAgICAgICB0aGlzLFxuICAgICAgICAgICAgY3R4LFxuICAgICAgICAgICAgbSxcbiAgICAgICAgICAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICAgICAgICAgICAgT3BlcmF0aW9uS2V5cy5PTlxuICAgICAgICAgICk7XG4gICAgICAgIHJldHVybiBtO1xuICAgICAgfSlcbiAgICApO1xuXG4gICAgaWYgKCFpZ25vcmVWYWxpZGF0ZSkge1xuICAgICAgY29uc3QgaWdub3JlZFByb3BzID0gY3R4LmdldChcImlnbm9yZWRWYWxpZGF0aW9uUHJvcGVydGllc1wiKSB8fCBbXTtcblxuICAgICAgY29uc3QgZXJyb3JzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIG1vZGVscy5tYXAoKG0pID0+IFByb21pc2UucmVzb2x2ZShtLmhhc0Vycm9ycyguLi5pZ25vcmVkUHJvcHMpKSlcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IGVycm9yTWVzc2FnZXMgPSByZWR1Y2VFcnJvcnNUb1ByaW50KGVycm9ycyk7XG5cbiAgICAgIGlmIChlcnJvck1lc3NhZ2VzKSB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKGVycm9yTWVzc2FnZXMpO1xuICAgIH1cbiAgICByZXR1cm4gW21vZGVscywgLi4uY3R4QXJnc10gYXMgYW55O1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlQWxsKFxuICAgIG1vZGVsczogTVtdLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8TVtdPiB7XG4gICAgaWYgKCFtb2RlbHMubGVuZ3RoKSByZXR1cm4gbW9kZWxzO1xuICAgIGNvbnN0IHsgY3R4LCBsb2csIGN0eEFyZ3MgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuY3JlYXRlQWxsKTtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgQ3JlYXRpbmcgJHttb2RlbHMubGVuZ3RofSBuZXcgJHt0aGlzLmNsYXNzLm5hbWV9IGluIHRhYmxlICR7TW9kZWwudGFibGVOYW1lKHRoaXMuY2xhc3MpfWBcbiAgICApO1xuXG4gICAgY29uc3QgcHJlcGFyZWQgPSBtb2RlbHMubWFwKChtKSA9PiB0aGlzLmFkYXB0ZXIucHJlcGFyZShtLCBjdHgpKTtcbiAgICBjb25zdCBpZHMgPSBwcmVwYXJlZC5tYXAoKHApID0+IHAuaWQpO1xuICAgIGxldCByZWNvcmRzID0gcHJlcGFyZWQubWFwKChwKSA9PiBwLnJlY29yZCk7XG4gICAgY29uc3QgdHJhbnNpZW50ID0gcHJlcGFyZWQubWFwKChwKSA9PiBwLnRyYW5zaWVudCk7XG4gICAgcmVjb3JkcyA9IGF3YWl0IHRoaXMuYWRhcHRlci5jcmVhdGVBbGwoXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgaWRzIGFzIFByaW1hcnlLZXlUeXBlW10sXG4gICAgICByZWNvcmRzLFxuICAgICAgdHJhbnNpZW50LFxuICAgICAgLi4uY3R4QXJnc1xuICAgICk7XG4gICAgcmV0dXJuIHJlY29yZHMubWFwKChyLCBpKSA9PlxuICAgICAgdGhpcy5hZGFwdGVyLnJldmVydChcbiAgICAgICAgcixcbiAgICAgICAgdGhpcy5jbGFzcyxcbiAgICAgICAgaWRzW2ldLFxuICAgICAgICBjdHguZ2V0KFwicmVidWlsZFdpdGhUcmFuc2llbnRcIikgPyBwcmVwYXJlZFtpXS50cmFuc2llbnQgOiB1bmRlZmluZWQsXG4gICAgICAgIGN0eFxuICAgICAgKVxuICAgICk7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyB1cGRhdGVBbGwoXG4gICAgbW9kZWxzOiBNW10sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj5cbiAgKTogUHJvbWlzZTxNW10+IHtcbiAgICBjb25zdCB7IGN0eCwgbG9nLCBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnVwZGF0ZUFsbCk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYFVwZGF0aW5nICR7bW9kZWxzLmxlbmd0aH0gbmV3ICR7dGhpcy5jbGFzcy5uYW1lfSBpbiB0YWJsZSAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX1gXG4gICAgKTtcblxuICAgIGNvbnN0IHJlY29yZHMgPSBtb2RlbHMubWFwKChtKSA9PiB0aGlzLmFkYXB0ZXIucHJlcGFyZShtLCBjdHgpKTtcbiAgICBjb25zdCB1cGRhdGVkID0gYXdhaXQgdGhpcy5hZGFwdGVyLnVwZGF0ZUFsbChcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICByZWNvcmRzLm1hcCgocikgPT4gci5pZCksXG4gICAgICByZWNvcmRzLm1hcCgocikgPT4gci5yZWNvcmQpLFxuICAgICAgcmVjb3Jkcy5tYXAoKHIpID0+IHIudHJhbnNpZW50KSxcbiAgICAgIC4uLmN0eEFyZ3NcbiAgICApO1xuICAgIHJldHVybiB1cGRhdGVkLm1hcCgodSwgaSkgPT5cbiAgICAgIHRoaXMuYWRhcHRlci5yZXZlcnQoXG4gICAgICAgIHUsXG4gICAgICAgIHRoaXMuY2xhc3MsXG4gICAgICAgIHJlY29yZHNbaV0uaWQsXG4gICAgICAgIGN0eC5nZXQoXCJyZWJ1aWxkV2l0aFRyYW5zaWVudFwiKSA/IHJlY29yZHNbaV0udHJhbnNpZW50IDogdW5kZWZpbmVkLFxuICAgICAgICBjdHhcbiAgICAgIClcbiAgICApO1xuICB9XG59XG4iLCJpbXBvcnQgeyBCYXNlTW9kZWwsIGNvbHVtbiwgcGssIHRhYmxlIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBtb2RlbCwgdHlwZSBNb2RlbEFyZywgcmVxdWlyZWQgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVSQzIwIHRva2VuIG1ldGFkYXRhIG1vZGVsXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGFuIEVSQzIwIHRva2VuIGRlZmluaXRpb24gd2l0aGluIHRoZSBGYWJyaWMgRVJDMjAgc2FtcGxlLCBpbmNsdWRpbmcgbmFtZSwgc3ltYm9sLCBkZWNpbWFscywgYW5kIHRoZSBvd25pbmcgaWRlbnRpdHkuIFVzZWQgdG8gZGVmaW5lIHRoZSB1bmlxdWUgdG9rZW4gbWFuYWdlZCBieSB0aGUgY29udHJhY3QuXG4gKiBAcGFyYW0ge01vZGVsQXJnPEVSQzIwVG9rZW4+fSBbbV0gLSBPcHRpb25hbCBwYXJ0aWFsIGRhdGEgb3IgYW5vdGhlciBpbnN0YW5jZSB0byBpbml0aWFsaXplIHRoZSBtb2RlbFxuICogQHJldHVybiB7dm9pZH1cbiAqIEBjbGFzcyBFUkMyMFRva2VuXG4gKiBAZXhhbXBsZVxuICogY29uc3QgdG9rZW4gPSBuZXcgRVJDMjBUb2tlbih7IG5hbWU6IFwiTXlUb2tlblwiLCBzeW1ib2w6IFwiTVRLXCIsIGRlY2ltYWxzOiAxOCwgb3duZXI6IFwieDUwOTo6Li4uXCIgfSk7XG4gKiAvLyBQZXJzaXN0IHRocm91Z2ggYSByZXBvc2l0b3J5OiBhd2FpdCByZXBvLmNyZWF0ZSh0b2tlbiwgY3R4KVxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBBcHBcbiAqICAgcGFydGljaXBhbnQgUmVwb1xuICogICBwYXJ0aWNpcGFudCBBZGFwdGVyXG4gKiAgIEFwcC0+PlJlcG86IGNyZWF0ZShuZXcgRVJDMjBUb2tlbih7Li4ufSksIGN0eClcbiAqICAgUmVwby0+PkFkYXB0ZXI6IGNyZWF0ZSh0YWJsZSwgaWQ9bmFtZSwgcmVjb3JkLCBmbGFncylcbiAqICAgQWRhcHRlci0tPj5SZXBvOiBzdG9yZWRcbiAqICAgUmVwby0tPj5BcHA6IG1vZGVsXG4gKi9cbkB0YWJsZShcImVyYzIwX3Rva2Vuc1wiKVxuQG1vZGVsKClcbmV4cG9ydCBjbGFzcyBFUkMyMFRva2VuIGV4dGVuZHMgQmFzZU1vZGVsIHtcbiAgQHBrKHsgdHlwZTogU3RyaW5nIH0pXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVG9rZW4gdW5pcXVlIG5hbWVcbiAgICogQHN1bW1hcnkgU2VydmVzIGFzIHRoZSBwcmltYXJ5IGtleSBmb3IgdGhlIEVSQzIwIHRva2VuIGRlZmluaXRpb247IHR5cGljYWxseSBhIGh1bWFuLXJlYWRhYmxlIGlkZW50aWZpZXJcbiAgICovXG4gIG5hbWUhOiBzdHJpbmc7XG5cbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gT3duaW5nIGlkZW50aXR5IG9mIHRoZSB0b2tlblxuICAgKiBAc3VtbWFyeSBYLjUwOSBzdWJqZWN0IG9yIE1TUCBpZGVudGl0eSBzdHJpbmcgdGhhdCBkZW5vdGVzIHdobyBvd25zL2NvbnRyb2xzIHRoZSB0b2tlbiBkZWZpbml0aW9uXG4gICAqL1xuICBvd25lciE6IHN0cmluZztcbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVG9rZW4gc3ltYm9sXG4gICAqIEBzdW1tYXJ5IFNob3J0IHRpY2tlci1saWtlIHN5bWJvbCB1c2VkIHRvIHJlcHJlc2VudCB0aGUgdG9rZW4gKGUuZy4sIE1USylcbiAgICovXG4gIHN5bWJvbCE6IHN0cmluZztcbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVjaW1hbCBwcmVjaXNpb24gZm9yIHRva2VuIGFtb3VudHNcbiAgICogQHN1bW1hcnkgTnVtYmVyIG9mIGRpZ2l0cyBhZnRlciB0aGUgZGVjaW1hbCBzZXBhcmF0b3IgdXNlZCB3aGVuIGZvcm1hdHRpbmcgdG9rZW4gYmFsYW5jZXNcbiAgICovXG4gIGRlY2ltYWxzITogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKG0/OiBNb2RlbEFyZzxFUkMyMFdhbGxldD4pIHtcbiAgICBzdXBlcihtKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFUkMyMCB3YWxsZXQgbW9kZWxcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYSBob2xkZXIgYWNjb3VudCBmb3IgYW4gRVJDMjAgdG9rZW4gd2l0aGluIHRoZSBGYWJyaWMgbmV0d29yaywgdHJhY2tpbmcgYmFsYW5jZSBhbmQgdG9rZW4gYXNzb2NpYXRpb24uXG4gKiBAcGFyYW0ge01vZGVsQXJnPEVSQzIwV2FsbGV0Pn0gW21dIC0gT3B0aW9uYWwgcGFydGlhbCBkYXRhIG9yIGFub3RoZXIgaW5zdGFuY2UgdG8gaW5pdGlhbGl6ZSB0aGUgbW9kZWxcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgRVJDMjBXYWxsZXRcbiAqIEBleGFtcGxlXG4gKiBjb25zdCB3YWxsZXQgPSBuZXcgRVJDMjBXYWxsZXQoeyBpZDogXCJhY2N0MVwiLCB0b2tlbjogXCJNeVRva2VuXCIsIGJhbGFuY2U6IDEwMDAgfSk7XG4gKiAvLyBVcGRhdGUgYmFsYW5jZSB2aWEgcmVwb3NpdG9yeTogYXdhaXQgcmVwby51cGRhdGUod2FsbGV0LCBjdHgpXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBSZXBvXG4gKiAgIEFwcC0+PlJlcG86IHJlYWQoXCJhY2N0MVwiLCBjdHgpXG4gKiAgIFJlcG8tLT4+QXBwOiBFUkMyMFdhbGxldFxuICovXG5AdGFibGUoXCJlcmMyMF93YWxsZXRzXCIpXG5AbW9kZWwoKVxuZXhwb3J0IGNsYXNzIEVSQzIwV2FsbGV0IGV4dGVuZHMgQmFzZU1vZGVsIHtcbiAgQHBrKHsgdHlwZTogU3RyaW5nIH0pXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gV2FsbGV0IHVuaXF1ZSBpZGVudGlmaWVyXG4gICAqIEBzdW1tYXJ5IFByaW1hcnkga2V5IGZvciB0aGUgd2FsbGV0OyBjb21tb25seSByZWZlcmVuY2VzIGFuIGFjY291bnQgb3IgaWRlbnRpdHlcbiAgICovXG4gIGlkITogc3RyaW5nO1xuXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFzc29jaWF0ZWQgdG9rZW4gbmFtZVxuICAgKiBAc3VtbWFyeSBSZWZlcmVuY2VzIHRoZSBFUkMyMFRva2VuIHRoaXMgd2FsbGV0IGhvbGRzOyBtYWludGFpbmVkIGFzIGEgcmVsYXRpb25zaGlwIGZvciBjYXNjYWRpbmcgdXBkYXRlcy9kZWxldGVzXG4gICAqL1xuICB0b2tlbiE6IHN0cmluZztcblxuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUb2tlbiBiYWxhbmNlIGZvciB0aGlzIHdhbGxldFxuICAgKiBAc3VtbWFyeSBDdXJyZW50IGFtb3VudCBvZiB0aGUgYXNzb2NpYXRlZCB0b2tlbiBoZWxkIGJ5IHRoaXMgd2FsbGV0XG4gICAqL1xuICBiYWxhbmNlITogbnVtYmVyO1xuXG4gIEBjb2x1bW4oKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENhcHRpdmUgZmxhZyBvciBpZGVudGlmaWVyXG4gICAqIEBzdW1tYXJ5IE9wdGlvbmFsIGZpZWxkIHVzZWQgYnkgc29tZSBmbG93cyB0byBtYXJrIG5vbi10cmFuc2ZlcmFibGUgZnVuZHMgb3IgbWFuYWdlZCBjdXN0b2R5XG4gICAqL1xuICBjYXB0aXZlITogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKG0/OiBNb2RlbEFyZzxFUkMyMFdhbGxldD4pIHtcbiAgICBzdXBlcihtKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFUkMyMCBhbGxvd2FuY2UgbW9kZWxcbiAqIEBzdW1tYXJ5IENhcHR1cmVzIGFuIGFwcHJvdmFsIHJlbGF0aW9uc2hpcCB3aGVyZSBhbiBvd25lciBhbGxvd3MgYSBzcGVuZGVyIHRvIHRyYW5zZmVyIHVwIHRvIGEgY2VydGFpbiB2YWx1ZSBmcm9tIHRoZSBvd25lcidzIHdhbGxldC5cbiAqIEBwYXJhbSB7TW9kZWxBcmc8QWxsb3dhbmNlPn0gW21dIC0gT3B0aW9uYWwgcGFydGlhbCBkYXRhIG9yIGFub3RoZXIgaW5zdGFuY2UgdG8gaW5pdGlhbGl6ZSB0aGUgbW9kZWxcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgQWxsb3dhbmNlXG4gKiBAZXhhbXBsZVxuICogY29uc3QgYWxsb3dhbmNlID0gbmV3IEFsbG93YW5jZSh7IG93bmVyOiBcImFjY3QxXCIsIHNwZW5kZXI6IFwiYWNjdDJcIiwgdmFsdWU6IDUwIH0pO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBBcHBcbiAqICAgQXBwLT4+QXBwOiBuZXcgQWxsb3dhbmNlKHsgb3duZXIsIHNwZW5kZXIsIHZhbHVlIH0pXG4gKi9cbkB0YWJsZShcImVyYzIwX2FsbG93YW5jZXNcIilcbkBtb2RlbCgpXG5leHBvcnQgY2xhc3MgQWxsb3dhbmNlIGV4dGVuZHMgQmFzZU1vZGVsIHtcbiAgQHBrKHsgdHlwZTogU3RyaW5nIH0pXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQWxsb3dhbmNlIHVuaXF1ZSBpZGVudGlmaWVyXG4gICAqIEBzdW1tYXJ5IFByaW1hcnkga2V5IGZvciB0aGUgYWxsb3dhbmNlOyB0eXBpY2FsbHkgYSB1bmlxdWUgaWRlbnRpZmllciBmb3IgdGhlIGFwcHJvdmFsIHJlbGF0aW9uc2hpcFxuICAgKi9cbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gT3duZXIgd2FsbGV0IGlkZW50aWZpZXJcbiAgICogQHN1bW1hcnkgV2FsbGV0IHRoYXQgYXV0aG9yaXplcyB0aGUgYWxsb3dhbmNlXG4gICAqL1xuICBvd25lciE6IHN0cmluZztcblxuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTcGVuZGVyIHdhbGxldCBpZGVudGlmaWVyXG4gICAqIEBzdW1tYXJ5IFdhbGxldCBhbGxvd2VkIHRvIHNwZW5kIHVwIHRvIHRoZSBhcHByb3ZlZCB2YWx1ZSBmcm9tIHRoZSBvd25lclxuICAgKi9cbiAgc3BlbmRlciE6IHN0cmluZztcblxuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBcHByb3ZlZCB2YWx1ZVxuICAgKiBAc3VtbWFyeSBNYXhpbXVtIHRva2VuIGFtb3VudCB0aGUgc3BlbmRlciBtYXkgdHJhbnNmZXIgb24gYmVoYWxmIG9mIHRoZSBvd25lclxuICAgKi9cbiAgdmFsdWUhOiBudW1iZXI7XG5cbiAgY29uc3RydWN0b3IobT86IE1vZGVsQXJnPEFsbG93YW5jZT4pIHtcbiAgICBzdXBlcihtKTtcbiAgfVxufVxuIiwiaW1wb3J0IHtcbiAgSlNPTlNlcmlhbGl6ZXIsXG4gIE1vZGVsLFxuICBNb2RlbEtleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IFNlcmlhbGl6YXRpb25FcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IsIE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENsaWVudC1zaWRlIEpTT04gc2VyaWFsaXplciBmb3IgRGVjYWYgbW9kZWxzIHRhcmdldGluZyBIeXBlcmxlZGdlciBGYWJyaWNcbiAqIEBzdW1tYXJ5IEV4dGVuZHMgdGhlIGJhc2UgSlNPTlNlcmlhbGl6ZXIgdG8gZW1iZWQgbW9kZWwgbWV0YWRhdGEgKGFuY2hvcikgcmVxdWlyZWQgdG8gcmVjb25zdHJ1Y3QgaW5zdGFuY2VzIG9uIHRoZSBjbGllbnQsIGFuZCB0byBzYWZlbHkgc2VyaWFsaXplL2Rlc2VyaWFsaXplIEZhYnJpYy1ib3VuZCBtb2RlbHMuXG4gKiBAdGVtcGxhdGUgTSBleHRlbmRzIE1vZGVsIC0gVGhlIERlY2FmIG1vZGVsIHR5cGUgaGFuZGxlZCBieSB0aGlzIHNlcmlhbGl6ZXJcbiAqIEBwYXJhbSB7dm9pZH0gW2NvbnN0cnVjdG9yXSBObyBwdWJsaWMgY29uc3RydWN0b3IgYXJndW1lbnRzOyBwcm92aWRlZCBmb3IgZG9jdW1lbnRhdGlvbiBjb21wbGV0ZW5lc3NcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgQ2xpZW50U2VyaWFsaXplclxuICogQGV4YW1wbGVcbiAqIGNvbnN0IHNlcmlhbGl6ZXIgPSBuZXcgQ2xpZW50U2VyaWFsaXplcjxVc2VyPigpO1xuICogY29uc3QganNvbiA9IHNlcmlhbGl6ZXIuc2VyaWFsaXplKG5ldyBVc2VyKHsgaWQ6IFwiMVwiLCBuYW1lOiBcIkFsaWNlXCIgfSkpO1xuICogY29uc3QgdXNlciA9IHNlcmlhbGl6ZXIuZGVzZXJpYWxpemUoanNvbik7XG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBTZXJpYWxpemVyIGFzIENsaWVudFNlcmlhbGl6ZXJcbiAqICAgcGFydGljaXBhbnQgTW9kZWxcbiAqICAgQXBwLT4+U2VyaWFsaXplcjogc2VyaWFsaXplKG1vZGVsKVxuICogICBTZXJpYWxpemVyLT4+U2VyaWFsaXplcjogcHJlU2VyaWFsaXplKG1vZGVsKVxuICogICBTZXJpYWxpemVyLS0+PkFwcDogSlNPTiBzdHJpbmdcbiAqICAgQXBwLT4+U2VyaWFsaXplcjogZGVzZXJpYWxpemUoanNvbilcbiAqICAgU2VyaWFsaXplci0+PlNlcmlhbGl6ZXI6IEpTT04ucGFyc2UoanNvbilcbiAqICAgU2VyaWFsaXplci0+Pk1vZGVsOiBNb2RlbC5idWlsZChwYXJzZWQsIGFuY2hvcilcbiAqICAgTW9kZWwtLT4+QXBwOiBpbnN0YW5jZVxuICovXG5leHBvcnQgY2xhc3MgQ2xpZW50U2VyaWFsaXplcjxNIGV4dGVuZHMgTW9kZWw+IGV4dGVuZHMgSlNPTlNlcmlhbGl6ZXI8TT4ge1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcigpO1xuICB9XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJlcGFyZSBhIG1vZGVsIGZvciBKU09OIHNlcmlhbGl6YXRpb24gZW1iZWRkaW5nIGNsYXNzIGFuY2hvclxuICAgKiBAc3VtbWFyeSBDbG9uZXMgdGhlIG1vZGVsIGFuZCBpbmplY3RzIHRoZSBjbGFzcyBtZXRhZGF0YSBhbmNob3Igc28gaXQgY2FuIGJlIHJlY29uc3RydWN0ZWQgZHVyaW5nIGRlc2VyaWFsaXphdGlvbi4gRmFsbHMgYmFjayB0byBwcm92aWRlZCB0YWJsZSBuYW1lIGlmIG1ldGFkYXRhIGlzIG5vdCBhdmFpbGFibGUuXG4gICAqIEB0ZW1wbGF0ZSBNIC0gTW9kZWwgdHlwZSBoYW5kbGVkIGJ5IHRoaXMgc2VyaWFsaXplclxuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHRvIHNlcmlhbGl6ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW21vZGVsTmFtZV0gLSBPcHRpb25hbCB0YWJsZSBuYW1lIHRvIHVzZSB3aGVuIG1ldGFkYXRhIGNhbm5vdCBiZSBkZXJpdmVkXG4gICAqIEByZXR1cm4ge1JlY29yZDxzdHJpbmcsIGFueT59IEEgcGxhaW4gb2JqZWN0IHJlYWR5IHRvIGJlIEpTT04uc3RyaW5naWZ5J2RcbiAgICovXG4gIHByb3RlY3RlZCBvdmVycmlkZSBwcmVTZXJpYWxpemUobW9kZWw6IE0sIG1vZGVsTmFtZT86IHN0cmluZykge1xuICAgIC8vIFRPRE86IG5lc3RlZCBwcmVzZXJpYWxpemF0aW9uIChzbyBpbmNyZWFzZSBwZXJmb3JtYW5jZSB3aGVuIGRlc2VyaWFsaXppbmcpXG4gICAgY29uc3QgdG9TZXJpYWxpemU6IFJlY29yZDxzdHJpbmcsIGFueT4gPSBPYmplY3QuYXNzaWduKHt9LCBtb2RlbCk7XG4gICAgbGV0IG1ldGFkYXRhID0gTWV0YWRhdGEubW9kZWxOYW1lKG1vZGVsLmNvbnN0cnVjdG9yIGFzIENvbnN0cnVjdG9yPE0+KTtcblxuICAgIGlmICghbWV0YWRhdGEgfHwgbWV0YWRhdGEgPT09IFwiT2JqZWN0XCIpXG4gICAgICBpZiAobW9kZWxOYW1lKSBtZXRhZGF0YSA9IG1vZGVsTmFtZTtcbiAgICAgIGVsc2VcbiAgICAgICAgdGhyb3cgbmV3IFNlcmlhbGl6YXRpb25FcnJvcihcbiAgICAgICAgICBgQ291bGQgbm90IGZpbmQgbWV0YWRhdGEgZm9yICR7bW9kZWwuY29uc3RydWN0b3IubmFtZX1gXG4gICAgICAgICk7XG4gICAgdG9TZXJpYWxpemVbTW9kZWxLZXlzLkFOQ0hPUl0gPSBtZXRhZGF0YTtcbiAgICByZXR1cm4gdG9TZXJpYWxpemU7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlYnVpbGRzIGEgbW9kZWwgZnJvbSBpdHMgSlNPTiBzZXJpYWxpemF0aW9uXG4gICAqIEBzdW1tYXJ5IFBhcnNlcyB0aGUgSlNPTiBzdHJpbmcsIHJldHJpZXZlcyB0aGUgZW1iZWRkZWQgbW9kZWwgYW5jaG9yLCBhbmQgdXNlcyBNb2RlbC5idWlsZCB0byByZWNvbnN0cnVjdCB0aGUgb3JpZ2luYWwgaW5zdGFuY2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHN0ciAtIFRoZSBKU09OIHN0cmluZyBwcmV2aW91c2x5IHByb2R1Y2VkIGJ5IHNlcmlhbGl6ZVxuICAgKiBAcmV0dXJuIHtNfSBUaGUgcmVjb25zdHJ1Y3RlZCBtb2RlbCBpbnN0YW5jZVxuICAgKi9cbiAgb3ZlcnJpZGUgZGVzZXJpYWxpemUoc3RyOiBzdHJpbmcpOiBNIHtcbiAgICBjb25zdCBkZXNlcmlhbGl6YXRpb24gPSBKU09OLnBhcnNlKHN0cik7XG4gICAgY29uc3QgY2xhc3NOYW1lID0gZGVzZXJpYWxpemF0aW9uW01vZGVsS2V5cy5BTkNIT1JdO1xuICAgIGlmICghY2xhc3NOYW1lKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGQgbm90IGZpbmQgY2xhc3MgcmVmZXJlbmNlIGluIHNlcmlhbGl6ZWQgbW9kZWxcIik7XG4gICAgY29uc3QgbW9kZWw6IE0gPSBNb2RlbC5idWlsZChkZXNlcmlhbGl6YXRpb24sIGNsYXNzTmFtZSkgYXMgdW5rbm93biBhcyBNO1xuICAgIHJldHVybiBtb2RlbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2VyaWFsaXplcyBhIG1vZGVsIHRvIGEgSlNPTiBzdHJpbmdcbiAgICogQHN1bW1hcnkgUHJlcGFyZXMgdGhlIG1vZGVsIHZpYSBwcmVTZXJpYWxpemUsIGVtYmVkZGluZyBtZXRhZGF0YSBuZWVkZWQgZm9yIHJlY29uc3RydWN0aW9uLCBhbmQgcmV0dXJucyBhIEpTT04gc3RyaW5nIHJlcHJlc2VudGF0aW9uXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgdG8gc2VyaWFsaXplXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbdGFibGVdIC0gT3B0aW9uYWwgdGFibGUgbmFtZSB0byBpbmNsdWRlIGFzIGFuY2hvciB3aGVuIG1ldGFkYXRhIGlzIHVuYXZhaWxhYmxlXG4gICAqIEByZXR1cm4ge3N0cmluZ30gQSBKU09OIHN0cmluZyBjb250YWluaW5nIHRoZSBzZXJpYWxpemVkIG1vZGVsIHdpdGggYW5jaG9yIG1ldGFkYXRhXG4gICAqL1xuICBvdmVycmlkZSBzZXJpYWxpemUobW9kZWw6IE0sIG1vZGVsTmFtZT86IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHRoaXMucHJlU2VyaWFsaXplKG1vZGVsLCBtb2RlbE5hbWUpKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgRmFicmljQ2xpZW50UmVwb3NpdG9yeSB9IGZyb20gXCIuLi9GYWJyaWNDbGllbnRSZXBvc2l0b3J5XCI7XG5pbXBvcnQgeyBFUkMyMFRva2VuLCBFUkMyMFdhbGxldCB9IGZyb20gXCIuLi8uLi9jb250cmFjdHMvZXJjMjAvbW9kZWxzXCI7XG5pbXBvcnQgeyBNb2RlbCwgU2VyaWFsaXplciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudEFkYXB0ZXIgfSBmcm9tIFwiLi4vRmFicmljQ2xpZW50QWRhcHRlclwiO1xuaW1wb3J0IHsgQ2xpZW50U2VyaWFsaXplciB9IGZyb20gXCIuLi8uLi9zaGFyZWQvQ2xpZW50U2VyaWFsaXplclwiO1xuaW1wb3J0IHtcbiAgQ29udGV4dCxcbiAgQ29udGV4dE9mLFxuICBDb250ZXh0dWFsQXJncyxcbiAgRXZlbnRJZHMsXG4gIE1heWJlQ29udGV4dHVhbEFyZyxcbiAgU2VxdWVuY2UsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHtcbiAgQnVsa0NydWRPcGVyYXRpb25LZXlzLFxuICBJbnRlcm5hbEVycm9yLFxuICBPcGVyYXRpb25LZXlzLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG4vKipcbiAqIFJlcG9zaXRvcnkgZm9yIGludGVyYWN0aW5nIHdpdGggRVJDMjAgY29udHJhY3RzIG9uIGEgSHlwZXJsZWRnZXIgRmFicmljIG5ldHdvcmsuXG4gKiBFeHRlbmRzIHRoZSBiYXNlIEZhYnJpY0NsaWVudFJlcG9zaXRvcnkgY2xhc3MgYW5kIHV0aWxpemVzIHRoZSBDbGllbnRTZXJpYWxpemVyIGZvciBkYXRhIHNlcmlhbGl6YXRpb24uXG4gKi9cbmV4cG9ydCBjbGFzcyBGYWJyaWNFUkMyMENsaWVudFJlcG9zaXRvcnk8XG4gIEEgZXh0ZW5kcyBGYWJyaWNDbGllbnRBZGFwdGVyLFxuPiBleHRlbmRzIEZhYnJpY0NsaWVudFJlcG9zaXRvcnk8RVJDMjBXYWxsZXQsIEE+IHtcbiAgcHJpdmF0ZSBzdGF0aWMgc2VyaWFsaXplciA9IG5ldyBDbGllbnRTZXJpYWxpemVyKCk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHNlcmlhbGl6ZXI6IFNlcmlhbGl6ZXI8YW55PiA9XG4gICAgRmFicmljRVJDMjBDbGllbnRSZXBvc2l0b3J5LnNlcmlhbGl6ZXI7XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlcihcInV0ZjhcIik7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBOb3RpZmllcyBhbGwgb2JzZXJ2ZXJzIG9mIGFuIGV2ZW50LlxuICAgKiBAc3VtbWFyeSBVcGRhdGVzIGFsbCByZWdpc3RlcmVkIG9ic2VydmVycyB3aXRoIGluZm9ybWF0aW9uIGFib3V0IGEgZGF0YWJhc2UgZXZlbnQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZSAtIFRoZSB0YWJsZSBuYW1lIHdoZXJlIHRoZSBldmVudCBvY2N1cnJlZC5cbiAgICogQHBhcmFtIHtPcGVyYXRpb25LZXlzfEJ1bGtDcnVkT3BlcmF0aW9uS2V5c3xzdHJpbmd9IGV2ZW50IC0gVGhlIHR5cGUgb2YgZXZlbnQgdGhhdCBvY2N1cnJlZC5cbiAgICogQHBhcmFtIHtFdmVudElkc30gaWQgLSBUaGUgSUQgb3IgSURzIG9mIHRoZSBhZmZlY3RlZCByZWNvcmRzLlxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gYWxsIG9ic2VydmVycyBoYXZlIGJlZW4gbm90aWZpZWQuXG4gICAqIEB0aHJvd3Mge0ludGVybmFsRXJyb3J9IElmIHRoZSBvYnNlcnZlciBoYW5kbGVyIGlzIG5vdCBpbml0aWFsaXplZC5cbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHVwZGF0ZU9ic2VydmVyczxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIHRhYmxlOiBDb25zdHJ1Y3RvcjxNPiB8IHN0cmluZyxcbiAgICBldmVudDogT3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZyxcbiAgICBpZDogRXZlbnRJZHMsXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dE9mPEE+PlxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMub2JzZXJ2ZXJIYW5kbGVyKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIFwiT2JzZXJ2ZXJIYW5kbGVyIG5vdCBpbml0aWFsaXplZC4gRGlkIHlvdSByZWdpc3RlciBhbnkgb2JzZXJ2YWJsZXM/XCJcbiAgICAgICk7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMudXBkYXRlT2JzZXJ2ZXJzKTtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBVcGRhdGluZyAke3RoaXMub2JzZXJ2ZXJIYW5kbGVyLmNvdW50KCl9IG9ic2VydmVycyBmb3IgJHt0aGlzfWBcbiAgICApO1xuXG4gICAgdGFibGUgPSAoXG4gICAgICB0eXBlb2YgdGFibGUgPT09IFwic3RyaW5nXCIgPyBNb2RlbC5nZXQodGFibGUpIDogdGFibGVcbiAgICApIGFzIENvbnN0cnVjdG9yPE0+O1xuICAgIGxldCBwYXJzZWRJZDogc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ7XG5cbiAgICBpZiAoaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcGFyc2VkSWQgPSB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KGlkKSkge1xuICAgICAgcGFyc2VkSWQgPSBpZC5tYXAoXG4gICAgICAgIChpKSA9PiBTZXF1ZW5jZS5wYXJzZVZhbHVlKE1vZGVsLnNlcXVlbmNlRm9yKHRhYmxlKS50eXBlLCBpKSBhcyBzdHJpbmdcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHBhcnNlZElkID0gU2VxdWVuY2UucGFyc2VWYWx1ZShcbiAgICAgICAgTW9kZWwuc2VxdWVuY2VGb3IodGFibGUpLnR5cGUsXG4gICAgICAgIGlkXG4gICAgICApIGFzIHN0cmluZztcbiAgICB9XG4gICAgYXdhaXQgdGhpcy5vYnNlcnZlckhhbmRsZXIudXBkYXRlT2JzZXJ2ZXJzKFxuICAgICAgdGFibGUsXG4gICAgICBldmVudCxcbiAgICAgIHBhcnNlZElkISxcbiAgICAgIC4uLmN0eEFyZ3NcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIERlY29kZXMgYSBVaW50OEFycmF5IGludG8gYSBzdHJpbmcgdXNpbmcgdGhlIFRleHREZWNvZGVyLlxuICAgKlxuICAgKiBAcGFyYW0gZGF0YSAtIFRoZSBVaW50OEFycmF5IHRvIGRlY29kZS5cbiAgICogQHJldHVybnMgVGhlIGRlY29kZWQgc3RyaW5nLlxuICAgKi9cbiAgZGVjb2RlKGRhdGE6IFVpbnQ4QXJyYXkpOiBzdHJpbmcge1xuICAgIHJldHVybiBGYWJyaWNFUkMyMENsaWVudFJlcG9zaXRvcnkuZGVjb2Rlci5kZWNvZGUoZGF0YSk7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihhZGFwdGVyPzogQSkge1xuICAgIHN1cGVyKGFkYXB0ZXIsIEVSQzIwV2FsbGV0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgdGhlIG5hbWUgb2YgdGhlIEVSQzIwIHRva2VuLlxuICAgKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIGZldGNoIHRoZSBuYW1lIG9mIHRoZSBFUkMyMCB0b2tlbi5cbiAgICogSXQgY2FsbHMgdGhlIFwiVG9rZW5OYW1lXCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0IGFuZCBkZWNvZGVzIHRoZSByZXR1cm5lZCBkYXRhLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBuYW1lIG9mIHRoZSBFUkMyMCB0b2tlbi5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscyBvciB0aGUgZGVjb2RpbmcgcHJvY2VzcyBmYWlscy5cbiAgICovXG4gIGFzeW5jIHRva2VuTmFtZSguLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dE9mPEE+Pik6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IChhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBcInRva2VuTmFtZVwiLCB0cnVlKSkuZm9yKFxuICAgICAgdGhpcy50b2tlbk5hbWVcbiAgICApO1xuICAgIGNvbnN0IG5hbWUgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuZXZhbHVhdGVUcmFuc2FjdGlvbihjdHgsIFwiVG9rZW5OYW1lXCIpO1xuICAgIHJldHVybiB0aGlzLmRlY29kZShuYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgdGhlIHN5bWJvbCBvZiB0aGUgRVJDMjAgdG9rZW4uXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byBmZXRjaCB0aGUgc3ltYm9sIG9mIHRoZSBFUkMyMCB0b2tlbi5cbiAgICogSXQgY2FsbHMgdGhlIFwiU3ltYm9sXCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0IGFuZCBkZWNvZGVzIHRoZSByZXR1cm5lZCBkYXRhLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBzeW1ib2wgb2YgdGhlIEVSQzIwIHRva2VuLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzIG9yIHRoZSBkZWNvZGluZyBwcm9jZXNzIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgc3ltYm9sKC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gKGF3YWl0IHRoaXMubG9nQ3R4KGFyZ3MsIFwic3ltYm9sXCIsIHRydWUpKS5mb3IodGhpcy5zeW1ib2wpO1xuICAgIGNvbnN0IHN5bWJvbCA9IGF3YWl0IHRoaXMuYWRhcHRlci5ldmFsdWF0ZVRyYW5zYWN0aW9uKGN0eCwgXCJTeW1ib2xcIik7XG4gICAgcmV0dXJuIHRoaXMuZGVjb2RlKHN5bWJvbCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgZm9yIHRoZSBFUkMyMCB0b2tlbi5cbiAgICpcbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIGZldGNoIHRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgZm9yIHRoZSBFUkMyMCB0b2tlbi5cbiAgICogSXQgY2FsbHMgdGhlIFwiRGVjaW1hbHNcIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3QgYW5kIGRlY29kZXMgdGhlIHJldHVybmVkIGRhdGEuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyBmb3IgdGhlIEVSQzIwIHRva2VuLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzIG9yIHRoZSBkZWNvZGluZyBwcm9jZXNzIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgZGVjaW1hbHMoLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHRPZjxBPj4pOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSAoYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgXCJkZWNpbWFsc1wiLCB0cnVlKSkuZm9yKFxuICAgICAgdGhpcy5kZWNpbWFsc1xuICAgICk7XG4gICAgY29uc3QgZGVjaW1hbHMgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuZXZhbHVhdGVUcmFuc2FjdGlvbihjdHgsIFwiRGVjaW1hbHNcIik7XG4gICAgcmV0dXJuIE51bWJlcih0aGlzLmRlY29kZShkZWNpbWFscykpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyB0aGUgdG90YWwgc3VwcGx5IG9mIHRoZSBFUkMyMCB0b2tlbi5cbiAgICpcbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIGZldGNoIHRoZSB0b3RhbCBzdXBwbHkgb2YgdGhlIEVSQzIwIHRva2VuLlxuICAgKiBJdCBjYWxscyB0aGUgXCJUb3RhbFN1cHBseVwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCBhbmQgZGVjb2RlcyB0aGUgcmV0dXJuZWQgZGF0YS5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8bnVtYmVyPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgdG90YWwgc3VwcGx5IG9mIHRoZSBFUkMyMCB0b2tlbi5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscyBvciB0aGUgZGVjb2RpbmcgcHJvY2VzcyBmYWlscy5cbiAgICovXG4gIGFzeW5jIHRvdGFsU3VwcGx5KFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IChhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBcInRvdGFsU3VwcGx5XCIsIHRydWUpKS5mb3IoXG4gICAgICB0aGlzLnRvdGFsU3VwcGx5XG4gICAgKTtcbiAgICBjb25zdCB0b3RhbCA9IGF3YWl0IHRoaXMuYWRhcHRlci5ldmFsdWF0ZVRyYW5zYWN0aW9uKGN0eCwgXCJUb3RhbFN1cHBseVwiKTtcbiAgICByZXR1cm4gTnVtYmVyKHRoaXMuZGVjb2RlKHRvdGFsKSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHRoZSBiYWxhbmNlIG9mIHRoZSBFUkMyMCB0b2tlbiBmb3IgYSBzcGVjaWZpZWQgb3duZXIuXG4gICAqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gZmV0Y2ggdGhlIGJhbGFuY2Ugb2YgdGhlIEVSQzIwIHRva2VuIGZvciBhIGdpdmVuIG93bmVyLlxuICAgKiBJdCBjYWxscyB0aGUgXCJCYWxhbmNlT2ZcIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3Qgd2l0aCB0aGUgcHJvdmlkZWQgb3duZXIncyBhZGRyZXNzIGFzIGEgcGFyYW1ldGVyLlxuICAgKiBUaGUgcmV0dXJuZWQgZGF0YSBpcyB0aGVuIGRlY29kZWQgYW5kIGNvbnZlcnRlZCB0byBhIG51bWJlci5cbiAgICpcbiAgICogQHBhcmFtIG93bmVyIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIEVSQzIwIHRva2VuIG93bmVyLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxudW1iZXI+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBiYWxhbmNlIG9mIHRoZSBFUkMyMCB0b2tlbiBmb3IgdGhlIHNwZWNpZmllZCBvd25lci5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscyBvciB0aGUgZGVjb2RpbmcgcHJvY2VzcyBmYWlscy5cbiAgICovXG4gIGFzeW5jIGJhbGFuY2VPZihcbiAgICBvd25lcjogc3RyaW5nLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IChhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBcImJhbGFuY2VcIiwgdHJ1ZSkpLmZvcihcbiAgICAgIHRoaXMuYmFsYW5jZU9mXG4gICAgKTtcbiAgICBjb25zdCBiYWxhbmNlID0gYXdhaXQgdGhpcy5hZGFwdGVyLmV2YWx1YXRlVHJhbnNhY3Rpb24oY3R4LCBcIkJhbGFuY2VPZlwiLCBbXG4gICAgICBvd25lcixcbiAgICBdKTtcbiAgICByZXR1cm4gTnVtYmVyKHRoaXMuZGVjb2RlKGJhbGFuY2UpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2ZlcnMgYSBzcGVjaWZpZWQgYW1vdW50IG9mIEVSQzIwIHRva2VucyB0byBhIHJlY2lwaWVudC5cbiAgICpcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byB0cmFuc2ZlciBhIHNwZWNpZmllZCBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIHRvIGEgcmVjaXBpZW50LlxuICAgKiBJdCBjYWxscyB0aGUgXCJUcmFuc2ZlclwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCB3aXRoIHRoZSByZWNpcGllbnQncyBhZGRyZXNzIGFuZCB0aGUgdHJhbnNmZXIgYW1vdW50IGFzIHBhcmFtZXRlcnMuXG4gICAqIFRoZSByZXR1cm5lZCBkYXRhIGlzIHRoZW4gZGVjb2RlZCBhbmQgY2hlY2tlZCB0byBkZXRlcm1pbmUgaWYgdGhlIHRyYW5zZmVyIHdhcyBzdWNjZXNzZnVsLlxuICAgKlxuICAgKiBAcGFyYW0gdG8gLSBUaGUgYWRkcmVzcyBvZiB0aGUgcmVjaXBpZW50LlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgYW1vdW50IG9mIEVSQzIwIHRva2VucyB0byB0cmFuc2Zlci5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggYHRydWVgIGlmIHRoZSB0cmFuc2ZlciB3YXMgc3VjY2Vzc2Z1bCwgYW5kIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzIG9yIHRoZSBkZWNvZGluZyBwcm9jZXNzIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgdHJhbnNmZXIoXG4gICAgdG86IHN0cmluZyxcbiAgICB2YWx1ZTogbnVtYmVyLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxDb250ZXh0T2Y8QT4+XG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSAoYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgXCJ0cmFuc2ZlclwiLCB0cnVlKSkuZm9yKFxuICAgICAgdGhpcy50cmFuc2ZlclxuICAgICk7XG4gICAgY29uc3QgdHJhbnNmZXJyZWQgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuc3VibWl0VHJhbnNhY3Rpb24oY3R4LCBcIlRyYW5zZmVyXCIsIFtcbiAgICAgIHRvLFxuICAgICAgdmFsdWUudG9TdHJpbmcoKSxcbiAgICBdKTtcbiAgICByZXR1cm4gdGhpcy5kZWNvZGUodHJhbnNmZXJyZWQpID09PSBcInRydWVcIiA/IHRydWUgOiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2ZlcnMgYSBzcGVjaWZpZWQgYW1vdW50IG9mIEVSQzIwIHRva2VucyBmcm9tIG9uZSBhY2NvdW50IHRvIGFub3RoZXIuXG4gICAqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gdHJhbnNmZXIgYSBzcGVjaWZpZWQgYW1vdW50IG9mIEVSQzIwIHRva2VucyBmcm9tIG9uZSBhY2NvdW50IHRvIGFub3RoZXIuXG4gICAqIEZvciB0aGlzIHRyYW5zZmVyIHRvIHdvcmsgdGhlIHNwZW5kZXIgKCBhY2NvdW50IHRoYXQgd2lsbCB0cmlnZ2VyIHRoaXMgZnVuY3Rpb24gKSBuZWVkIHRvIGhhdmUgdGhlIHZhbHVlIGFwcHJvdmVkIGFzIGFuIGFsbG93YW5jZSBieSB0aGUgc2VuZGVyLlxuICAgKiBJdCBjYWxscyB0aGUgXCJUcmFuc2ZlckZyb21cIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3Qgd2l0aCB0aGUgc2VuZGVyJ3MgYWRkcmVzcywgcmVjaXBpZW50J3MgYWRkcmVzcywgYW5kIHRoZSB0cmFuc2ZlciBhbW91bnQgYXMgcGFyYW1ldGVycy5cbiAgICogVGhlIHJldHVybmVkIGRhdGEgaXMgdGhlbiBkZWNvZGVkIGFuZCBjaGVja2VkIHRvIGRldGVybWluZSBpZiB0aGUgdHJhbnNmZXIgd2FzIHN1Y2Nlc3NmdWwuXG4gICAqXG4gICAqIEBwYXJhbSBmcm9tIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHNlbmRlci5cbiAgICogQHBhcmFtIHRvIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHJlY2lwaWVudC5cbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMgdG8gdHJhbnNmZXIuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIGB0cnVlYCBpZiB0aGUgdHJhbnNmZXIgd2FzIHN1Y2Nlc3NmdWwsIGFuZCBgZmFsc2VgIG90aGVyd2lzZS5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscyBvciB0aGUgZGVjb2RpbmcgcHJvY2VzcyBmYWlscy5cbiAgICovXG4gIGFzeW5jIHRyYW5zZmVyRnJvbShcbiAgICBmcm9tOiBzdHJpbmcsXG4gICAgdG86IHN0cmluZyxcbiAgICB2YWx1ZTogbnVtYmVyXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgXCJ0cmFuc2ZlckZyb21cIixcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBbXSxcbiAgICAgIHRoaXMuYWRhcHRlcixcbiAgICAgIHRoaXMuX292ZXJyaWRlcyB8fCB7fVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGNvbnRleHRBcmdzLmFyZ3MsIHRoaXMudHJhbnNmZXJGcm9tKTtcbiAgICBjb25zdCB0cmFuc2ZlcnJlZCA9IGF3YWl0IHRoaXMuYWRhcHRlci5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIFwiVHJhbnNmZXJGcm9tXCIsXG4gICAgICBbZnJvbSwgdG8sIHZhbHVlLnRvU3RyaW5nKCldXG4gICAgKTtcblxuICAgIHJldHVybiB0aGlzLmRlY29kZSh0cmFuc2ZlcnJlZCkgPT09IFwidHJ1ZVwiID8gdHJ1ZSA6IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFwcHJvdmVzIGEgc3BlY2lmaWVkIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMgdG8gYmUgc3BlbnQgYnkgYSBzcGVjaWZpZWQgc3BlbmRlci5cbiAgICpcbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIGFwcHJvdmUgYSBzcGVjaWZpZWQgYW1vdW50IG9mIEVSQzIwIHRva2VucyB0byBiZSBzcGVudCBieSBhIHNwZWNpZmllZCBzcGVuZGVyLlxuICAgKiBJdCBjYWxscyB0aGUgXCJBcHByb3ZlXCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0IHdpdGggdGhlIHNwZW5kZXIncyBhZGRyZXNzIGFuZCB0aGUgYXBwcm92YWwgYW1vdW50IGFzIHBhcmFtZXRlcnMuXG4gICAqIFRoZSByZXR1cm5lZCBkYXRhIGlzIHRoZW4gZGVjb2RlZCBhbmQgY2hlY2tlZCB0byBkZXRlcm1pbmUgaWYgdGhlIGFwcHJvdmFsIHdhcyBzdWNjZXNzZnVsLlxuICAgKlxuICAgKiBAcGFyYW0gc3BlbmRlciAtIFRoZSBhZGRyZXNzIG9mIHRoZSBzcGVuZGVyLlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgYW1vdW50IG9mIEVSQzIwIHRva2VucyB0byBhcHByb3ZlIGZvciB0aGUgc3BlbmRlci5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggYHRydWVgIGlmIHRoZSBhcHByb3ZhbCB3YXMgc3VjY2Vzc2Z1bCwgYW5kIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzIG9yIHRoZSBkZWNvZGluZyBwcm9jZXNzIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgYXBwcm92ZShzcGVuZGVyOiBzdHJpbmcsIHZhbHVlOiBudW1iZXIpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJncyhcbiAgICAgIFwiYXBwcm92ZVwiLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIFtdLFxuICAgICAgdGhpcy5hZGFwdGVyLFxuICAgICAgdGhpcy5fb3ZlcnJpZGVzIHx8IHt9XG4gICAgKTtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcy5sb2dDdHgoY29udGV4dEFyZ3MuYXJncywgdGhpcy5hcHByb3ZlKTtcbiAgICBjb25zdCBhcHByb3ZlZCA9IGF3YWl0IHRoaXMuYWRhcHRlci5zdWJtaXRUcmFuc2FjdGlvbihjdHgsIFwiQXBwcm92ZVwiLCBbXG4gICAgICBzcGVuZGVyLFxuICAgICAgdmFsdWUudG9TdHJpbmcoKSxcbiAgICBdKTtcbiAgICByZXR1cm4gdGhpcy5kZWNvZGUoYXBwcm92ZWQpID09PSBcInRydWVcIiA/IHRydWUgOiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgdGhlIGFsbG93YW5jZSBvZiBFUkMyMCB0b2tlbnMgdGhhdCB0aGUgc3BlY2lmaWVkIG93bmVyIGhhcyBhcHByb3ZlZCBmb3IgYSBzcGVuZGVyLlxuICAgKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIGZldGNoIHRoZSBhbGxvd2FuY2Ugb2YgRVJDMjAgdG9rZW5zIHRoYXQgdGhlIHNwZWNpZmllZCBvd25lciBoYXMgYXBwcm92ZWQgZm9yIGEgc3BlbmRlci5cbiAgICogSXQgY2FsbHMgdGhlIFwiQWxsb3dhbmNlXCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0IHdpdGggdGhlIG93bmVyJ3MgYWRkcmVzcyBhbmQgdGhlIHNwZW5kZXIncyBhZGRyZXNzIGFzIHBhcmFtZXRlcnMuXG4gICAqIFRoZSByZXR1cm5lZCBkYXRhIGlzIHRoZW4gZGVjb2RlZCBhbmQgY29udmVydGVkIHRvIGEgbnVtYmVyLlxuICAgKlxuICAgKiBAcGFyYW0gb3duZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgRVJDMjAgdG9rZW4gb3duZXIuXG4gICAqIEBwYXJhbSBzcGVuZGVyIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHNwZW5kZXIuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGFsbG93YW5jZSBvZiBFUkMyMCB0b2tlbnMgdGhhdCB0aGUgc3BlY2lmaWVkIG93bmVyIGhhcyBhcHByb3ZlZCBmb3IgdGhlIHNwZW5kZXIuXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZmFpbHMgb3IgdGhlIGRlY29kaW5nIHByb2Nlc3MgZmFpbHMuXG4gICAqL1xuICBhc3luYyBhbGxvd2FuY2Uob3duZXI6IHN0cmluZywgc3BlbmRlcjogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJncyhcbiAgICAgIFwiYWxsb3dhbmNlXCIsXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgW10sXG4gICAgICB0aGlzLmFkYXB0ZXIsXG4gICAgICB0aGlzLl9vdmVycmlkZXMgfHwge31cbiAgICApO1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzLmxvZ0N0eChjb250ZXh0QXJncy5hcmdzLCB0aGlzLmFsbG93YW5jZSk7XG4gICAgY29uc3QgYWxsb3dhbmNlID0gYXdhaXQgdGhpcy5hZGFwdGVyLnN1Ym1pdFRyYW5zYWN0aW9uKGN0eCwgXCJBbGxvd2FuY2VcIiwgW1xuICAgICAgb3duZXIsXG4gICAgICBzcGVuZGVyLFxuICAgIF0pO1xuICAgIHJldHVybiBOdW1iZXIodGhpcy5kZWNvZGUoYWxsb3dhbmNlKSk7XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgdGhlIEVSQzIwIGNvbnRyYWN0IHdpdGggdGhlIHByb3ZpZGVkIHRva2VuIGluZm9ybWF0aW9uLlxuICAgKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogVGhpcyBmdW5jdGlvbiBpbnRlcmFjdHMgd2l0aCB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrIHRvIGluaXRpYWxpemUgdGhlIEVSQzIwIGNvbnRyYWN0IHdpdGggdGhlIGdpdmVuIHRva2VuIGluZm9ybWF0aW9uLlxuICAgKiBJdCBjYWxscyB0aGUgXCJJbml0aWFsaXplXCIgdHJhbnNhY3Rpb24gb24gdGhlIHNtYXJ0IGNvbnRyYWN0IHdpdGggdGhlIHNlcmlhbGl6ZWQgdG9rZW4gZGF0YSBhcyBhIHBhcmFtZXRlci5cbiAgICogVGhlIHJldHVybmVkIGRhdGEgaXMgdGhlbiBkZWNvZGVkIGFuZCBjaGVja2VkIHRvIGRldGVybWluZSBpZiB0aGUgaW5pdGlhbGl6YXRpb24gd2FzIHN1Y2Nlc3NmdWwuXG4gICAqXG4gICAqIEBwYXJhbSB0b2tlbiAtIFRoZSBFUkMyMCB0b2tlbiBpbmZvcm1hdGlvbiB0byBpbml0aWFsaXplIHRoZSBjb250cmFjdCB3aXRoLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCBgdHJ1ZWAgaWYgdGhlIGluaXRpYWxpemF0aW9uIHdhcyBzdWNjZXNzZnVsLCBhbmQgYGZhbHNlYCBvdGhlcndpc2UuXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZmFpbHMgb3IgdGhlIGRlY29kaW5nIHByb2Nlc3MgZmFpbHMuXG4gICAqL1xuICBhc3luYyBpbml0aWFsaXplKHRva2VuOiBFUkMyMFRva2VuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3MoXG4gICAgICBcImluaXRpYWxpemVcIixcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBbXSxcbiAgICAgIHRoaXMuYWRhcHRlcixcbiAgICAgIHRoaXMuX292ZXJyaWRlcyB8fCB7fVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGNvbnRleHRBcmdzLmFyZ3MsIHRoaXMuaW5pdGlhbGl6ZSk7XG4gICAgY29uc3QgaW5pdGlsaWF6ZWQgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuc3VibWl0VHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBcIkluaXRpYWxpemVcIixcbiAgICAgIFtGYWJyaWNFUkMyMENsaWVudFJlcG9zaXRvcnkuc2VyaWFsaXplci5zZXJpYWxpemUodG9rZW4pXVxuICAgICk7XG5cbiAgICByZXR1cm4gdGhpcy5kZWNvZGUoaW5pdGlsaWF6ZWQpID09PSBcInRydWVcIiA/IHRydWUgOiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhlIEVSQzIwIGNvbnRyYWN0IGhhcyBiZWVuIGluaXRpYWxpemVkLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gdmVyaWZ5IGlmIHRoZSBFUkMyMCBjb250cmFjdCBoYXMgYmVlbiBpbml0aWFsaXplZC5cbiAgICogSXQgY2FsbHMgdGhlIFwiQ2hlY2tJbml0aWFsaXplZFwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCwgd2hpY2ggZG9lcyBub3QgcmVxdWlyZSBhbnkgcGFyYW1ldGVycy5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGluaXRpYWxpemF0aW9uIGNoZWNrIGlzIGNvbXBsZXRlZC5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscy5cbiAgICovXG4gIGFzeW5jIGNoZWNrSW5pdGlhbGl6ZWQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3MoXG4gICAgICBcImNoZWNrSW5pdGlhbGl6ZWRcIixcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBbXSxcbiAgICAgIHRoaXMuYWRhcHRlcixcbiAgICAgIHRoaXMuX292ZXJyaWRlcyB8fCB7fVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGNvbnRleHRBcmdzLmFyZ3MsIHRoaXMuY2hlY2tJbml0aWFsaXplZCk7XG4gICAgYXdhaXQgdGhpcy5hZGFwdGVyLmV2YWx1YXRlVHJhbnNhY3Rpb24oY3R4LCBcIkNoZWNrSW5pdGlhbGl6ZWRcIik7XG4gIH1cblxuICAvKipcbiAgICogTWludHMgYSBzcGVjaWZpZWQgYW1vdW50IG9mIEVSQzIwIHRva2Vucy5cbiAgICpcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byBtaW50IGEgc3BlY2lmaWVkIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMuXG4gICAqIEl0IGNhbGxzIHRoZSBcIk1pbnRcIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3Qgd2l0aCB0aGUgbWludGluZyBhbW91bnQgYXMgYSBwYXJhbWV0ZXIuXG4gICAqIFRoZSBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYW55IHZhbHVlLCBidXQgaXQgdXBkYXRlcyB0aGUgbWludGVyJ3MgbnVtYmVyIG9mIHRva2Vucy5cbiAgICpcbiAgICogQHBhcmFtIGFtb3VudCAtIFRoZSBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIHRvIG1pbnQuXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBtaW50aW5nIHByb2Nlc3MgaXMgY29tcGxldGVkLlxuICAgKlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHRyYW5zYWN0aW9uIGZhaWxzLlxuICAgKi9cbiAgYXN5bmMgbWludChhbW91bnQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgXCJtaW50XCIsXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgW10sXG4gICAgICB0aGlzLmFkYXB0ZXIsXG4gICAgICB0aGlzLl9vdmVycmlkZXMgfHwge31cbiAgICApO1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzLmxvZ0N0eChjb250ZXh0QXJncy5hcmdzLCB0aGlzLm1pbnQpO1xuICAgIGF3YWl0IHRoaXMuYWRhcHRlci5zdWJtaXRUcmFuc2FjdGlvbihjdHgsIFwiTWludFwiLCBbYW1vdW50LnRvU3RyaW5nKCldKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdXJucyBhIHNwZWNpZmllZCBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIGZyb20gdGhlIG1pbnRlcidzIGFjY291bnQuXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gaW50ZXJhY3RzIHdpdGggdGhlIGJsb2NrY2hhaW4gbmV0d29yayB0byBidXJuIGEgc3BlY2lmaWVkIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMuXG4gICAqIEl0IGNhbGxzIHRoZSBcIkJ1cm5cIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3Qgd2l0aCB0aGUgYnVybmluZyBhbW91bnQgYXMgYSBwYXJhbWV0ZXIuXG4gICAqIFRoZSBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYW55IHZhbHVlLCBidXQgaXQgZGVjcmVhc2VzIHRoZSBtaW50ZXIncyBudW1iZXIgb2YgdG9rZW5zLlxuICAgKlxuICAgKiBAcGFyYW0gYW1vdW50IC0gVGhlIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMgdG8gYnVybi5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGJ1cm5pbmcgcHJvY2VzcyBpcyBjb21wbGV0ZWQuXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZmFpbHMuXG4gICAqL1xuICBhc3luYyBidXJuKGFtb3VudDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3MoXG4gICAgICBcImJ1cm5cIixcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBbXSxcbiAgICAgIHRoaXMuYWRhcHRlcixcbiAgICAgIHRoaXMuX292ZXJyaWRlcyB8fCB7fVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGNvbnRleHRBcmdzLmFyZ3MsIHRoaXMuYnVybik7XG4gICAgYXdhaXQgdGhpcy5hZGFwdGVyLnN1Ym1pdFRyYW5zYWN0aW9uKGN0eCwgXCJCdXJuXCIsIFthbW91bnQudG9TdHJpbmcoKV0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1cm5zIGEgc3BlY2lmaWVkIGFtb3VudCBvZiBFUkMyMCB0b2tlbnMgZnJvbSBhIHNwZWNpZmllZCBhY2NvdW50LlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gYnVybiBhIHNwZWNpZmllZCBhbW91bnQgb2YgRVJDMjAgdG9rZW5zIGZyb20gYSBnaXZlbiBhY2NvdW50LlxuICAgKiBJdCBjYWxscyB0aGUgXCJCdXJuRnJvbVwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCB3aXRoIHRoZSBhY2NvdW50J3MgYWRkcmVzcyBhbmQgdGhlIGJ1cm5pbmcgYW1vdW50IGFzIHBhcmFtZXRlcnMuXG4gICAqIFRoZSBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYW55IHZhbHVlLCBidXQgaXQgZGVjcmVhc2VzIHRoZSBzcGVjaWZpZWQgYWNjb3VudCdzIG51bWJlciBvZiB0b2tlbnMuXG4gICAqXG4gICAqIEBwYXJhbSBhY2NvdW50IC0gVGhlIGFkZHJlc3Mgb2YgdGhlIGFjY291bnQgZnJvbSB3aGljaCB0byBidXJuIHRoZSBFUkMyMCB0b2tlbnMuXG4gICAqIEBwYXJhbSBhbW91bnQgLSBUaGUgYW1vdW50IG9mIEVSQzIwIHRva2VucyB0byBidXJuLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgYnVybmluZyBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscy5cbiAgICovXG4gIGFzeW5jIGJ1cm5Gcm9tKGFjY291bnQ6IHN0cmluZywgYW1vdW50OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJncyhcbiAgICAgIFwiYnVybkZyb21cIixcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBbXSxcbiAgICAgIHRoaXMuYWRhcHRlcixcbiAgICAgIHRoaXMuX292ZXJyaWRlcyB8fCB7fVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGNvbnRleHRBcmdzLmFyZ3MsIHRoaXMuYnVybkZyb20pO1xuICAgIGF3YWl0IHRoaXMuYWRhcHRlci5zdWJtaXRUcmFuc2FjdGlvbihjdHgsIFwiQnVybkZyb21cIiwgW1xuICAgICAgYWNjb3VudCxcbiAgICAgIGFtb3VudC50b1N0cmluZygpLFxuICAgIF0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyB0aGUgYmFsYW5jZSBvZiBFUkMyMCB0b2tlbnMgYXNzb2NpYXRlZCB3aXRoIHRoZSBjbGllbnQncyBhY2NvdW50LlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gZmV0Y2ggdGhlIGJhbGFuY2Ugb2YgRVJDMjAgdG9rZW5zIGFzc29jaWF0ZWQgd2l0aCB0aGUgY2xpZW50J3MgYWNjb3VudC5cbiAgICogSXQgY2FsbHMgdGhlIFwiQ2xpZW50QWNjb3VudEJhbGFuY2VcIiB0cmFuc2FjdGlvbiBvbiB0aGUgc21hcnQgY29udHJhY3QsIHdoaWNoIGRvZXMgbm90IHJlcXVpcmUgYW55IHBhcmFtZXRlcnMuXG4gICAqIFRoZSByZXR1cm5lZCBkYXRhIGlzIHRoZW4gZGVjb2RlZCBhbmQgY29udmVydGVkIHRvIGEgbnVtYmVyLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxudW1iZXI+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBiYWxhbmNlIG9mIEVSQzIwIHRva2VucyBhc3NvY2lhdGVkIHdpdGggdGhlIGNsaWVudCdzIGFjY291bnQuXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdHJhbnNhY3Rpb24gZmFpbHMgb3IgdGhlIGRlY29kaW5nIHByb2Nlc3MgZmFpbHMuXG4gICAqL1xuICBhc3luYyBjbGllbnRBY2NvdW50QmFsYW5jZSgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgXCJhY2NvdW50QmFsYW5jZVwiLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIFtdLFxuICAgICAgdGhpcy5hZGFwdGVyLFxuICAgICAgdGhpcy5fb3ZlcnJpZGVzIHx8IHt9XG4gICAgKTtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcy5sb2dDdHgoY29udGV4dEFyZ3MuYXJncywgdGhpcy5jbGllbnRBY2NvdW50QmFsYW5jZSk7XG4gICAgY29uc3Qgc2VyaWFsaXplZEFjY291bnRCYWxhbmNlID0gYXdhaXQgdGhpcy5hZGFwdGVyLmV2YWx1YXRlVHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBcIkNsaWVudEFjY291bnRCYWxhbmNlXCJcbiAgICApO1xuXG4gICAgcmV0dXJuIE51bWJlcih0aGlzLmRlY29kZShzZXJpYWxpemVkQWNjb3VudEJhbGFuY2UpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgdGhlIGNsaWVudCdzIGFjY291bnQgSUQgZnJvbSB0aGUgYmxvY2tjaGFpbiBuZXR3b3JrLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGludGVyYWN0cyB3aXRoIHRoZSBibG9ja2NoYWluIG5ldHdvcmsgdG8gZmV0Y2ggdGhlIGNsaWVudCdzIGFjY291bnQgSUQuXG4gICAqIEl0IGNhbGxzIHRoZSBcIkNsaWVudEFjY291bnRJRFwiIHRyYW5zYWN0aW9uIG9uIHRoZSBzbWFydCBjb250cmFjdCwgd2hpY2ggZG9lcyBub3QgcmVxdWlyZSBhbnkgcGFyYW1ldGVycy5cbiAgICogVGhlIHJldHVybmVkIGRhdGEgaXMgdGhlbiBkZWNvZGVkIGFuZCByZXR1cm5lZCBhcyBhIHN0cmluZy5cbiAgICpcbiAgICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgY2xpZW50J3MgYWNjb3VudCBJRC5cbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIHRoZSB0cmFuc2FjdGlvbiBmYWlscyBvciB0aGUgZGVjb2RpbmcgcHJvY2VzcyBmYWlscy5cbiAgICovXG4gIGFzeW5jIGNsaWVudEFjY291bnRJRCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgXCJhY2NvdW50SWRcIixcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBbXSxcbiAgICAgIHRoaXMuYWRhcHRlcixcbiAgICAgIHRoaXMuX292ZXJyaWRlcyB8fCB7fVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGNvbnRleHRBcmdzLmFyZ3MsIHRoaXMuY2xpZW50QWNjb3VudElEKTtcbiAgICBjb25zdCBjbGllbnRBY2NvdW50SUQgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuZXZhbHVhdGVUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIFwiQ2xpZW50QWNjb3VudElEXCJcbiAgICApO1xuXG4gICAgcmV0dXJuIHRoaXMuZGVjb2RlKGNsaWVudEFjY291bnRJRCk7XG4gIH1cbn1cbiIsImltcG9ydCB7IENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQge1xuICBDcmVhdGVJbmRleFJlcXVlc3QsXG4gIENvdWNoREJEZXNpZ25Eb2MsXG4gIGdlbmVyYXRlSW5kZXhlcyxcbiAgZ2VuZXJhdGVWaWV3cyxcbn0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuaW1wb3J0IHsgTW9kZWwsIE1vZGVsQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5cbmV4cG9ydCB0eXBlIEluZGV4ID0gQ3JlYXRlSW5kZXhSZXF1ZXN0O1xuXG5mdW5jdGlvbiBlbnN1cmVEaXJlY3RvcnlFeGlzdGVuY2UoZmlsZVBhdGg6IHN0cmluZykge1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICBjb25zdCBmcyA9IHJlcXVpcmUoXCJmc1wiKTtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgY29uc3QgcGF0aCA9IHJlcXVpcmUoXCJwYXRoXCIpO1xuICBjb25zdCBkaXJuYW1lOiBzdHJpbmcgPSBwYXRoLmRpcm5hbWUoZmlsZVBhdGgpO1xuICBpZiAoZnMuZXhpc3RzU3luYyhkaXJuYW1lKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIGVuc3VyZURpcmVjdG9yeUV4aXN0ZW5jZShkaXJuYW1lKTtcbiAgZnMubWtkaXJTeW5jKGRpcm5hbWUpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVNb2RlbEluZGV4ZXM8TSBleHRlbmRzIE1vZGVsPihcbiAgbTogQ29uc3RydWN0b3I8TT5cbik6IEluZGV4W10ge1xuICByZXR1cm4gZ2VuZXJhdGVJbmRleGVzKFttXSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZU1vZGVsRGVzaWduRG9jczxNIGV4dGVuZHMgTW9kZWw+KFxuICBtOiBDb25zdHJ1Y3RvcjxNPixcbiAgYWNjdW0/OiBSZWNvcmQ8c3RyaW5nLCBDb3VjaERCRGVzaWduRG9jPlxuKTogQ291Y2hEQkRlc2lnbkRvY1tdIHtcbiAgY29uc3Qgdmlld3MgPSBnZW5lcmF0ZVZpZXdzKFttXSk7XG4gIGNvbnN0IHN0b3JhZ2U6IFJlY29yZDxzdHJpbmcsIENvdWNoREJEZXNpZ25Eb2M+ID0gYWNjdW0gfHwge307XG4gIHZpZXdzLmZvckVhY2goKGRvYykgPT4ge1xuICAgIHN0b3JhZ2VbZG9jLl9pZF0gPSBkb2M7XG4gIH0pO1xuICByZXR1cm4gdmlld3M7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWFkTW9kZWxGaWxlKGZpbGU6IGFueSkge1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICBjb25zdCBwYXRoID0gcmVxdWlyZShcInBhdGhcIik7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG4gIGNvbnN0IGV4cG9ydHMgPSByZXF1aXJlKHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCBmaWxlLnBhcmVudFBhdGgsIGZpbGUubmFtZSkpO1xuXG4gIGNvbnN0IHZhbHVlcyA9IE9iamVjdC52YWx1ZXMoZXhwb3J0cykuZmlsdGVyKChlKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IG0gPSBuZXcgKGUgYXMgQ29uc3RydWN0b3IpKCk7XG4gICAgICByZXR1cm4gbSBpbnN0YW5jZW9mIE1vZGVsO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH0pIGFzIE1vZGVsQ29uc3RydWN0b3I8YW55PltdO1xuICByZXR1cm4gdmFsdWVzO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZE1vZGVsRm9sZGVycyhcbiAgLi4uZm9sZGVyczogc3RyaW5nW11cbik6IFByb21pc2U8TW9kZWxDb25zdHJ1Y3Rvcjxhbnk+W10+IHtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgY29uc3QgZnMgPSByZXF1aXJlKFwiZnNcIik7XG5cbiAgY29uc3QgcmVzdWx0OiBNb2RlbENvbnN0cnVjdG9yPGFueT5bXSA9IFtdO1xuXG4gIGZvciAoY29uc3QgZm9sZGVyIG9mIGZvbGRlcnMpIHtcbiAgICBjb25zdCBmaWxlcyA9IGZzXG4gICAgICAucmVhZGRpclN5bmMoZm9sZGVyLCB7XG4gICAgICAgIHdpdGhGaWxlVHlwZXM6IHRydWUsXG4gICAgICAgIHJlY3Vyc2l2ZTogdHJ1ZSxcbiAgICAgIH0pXG4gICAgICAuZmlsdGVyKChmOiBhbnkpID0+IGYuaXNGaWxlKCkgJiYgZi5uYW1lLmVuZHNXaXRoKFwianNcIikpO1xuICAgIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgICAgcmVzdWx0LnB1c2goLi4ucmVhZE1vZGVsRmlsZShmaWxlKSk7XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB3cml0ZUluZGV4ZXMoXG4gIGluZGV4ZXM6IEluZGV4W10sXG4gIHA6IHN0cmluZyA9IHByb2Nlc3MuY3dkKCksXG4gIGNvbGxlY3Rpb24/OiBzdHJpbmdcbikge1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICBjb25zdCBmcyA9IHJlcXVpcmUoXCJmc1wiKTtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgY29uc3QgcGF0aCA9IHJlcXVpcmUoXCJwYXRoXCIpO1xuXG4gIGluZGV4ZXMuZm9yRWFjaCgoaW5kZXgpID0+IHtcbiAgICBjb25zdCBmaWxlID0gcGF0aC5yZXNvbHZlKFxuICAgICAgcGF0aC5qb2luKFxuICAgICAgICBwLFxuICAgICAgICBgLi9NRVRBLUlORi9zdGF0ZWRiL2NvdWNoZGIvJHtjb2xsZWN0aW9uID8gYGNvbGxlY3Rpb25zLyR7Y29sbGVjdGlvbn0vYCA6IFwiXCJ9aW5kZXhlcy8ke2luZGV4Lm5hbWV9Lmpzb25gXG4gICAgICApXG4gICAgKTtcbiAgICBlbnN1cmVEaXJlY3RvcnlFeGlzdGVuY2UoZmlsZSk7XG4gICAgZnMud3JpdGVGaWxlU3luYyhmaWxlLCBKU09OLnN0cmluZ2lmeShpbmRleCwgdW5kZWZpbmVkLCAyKSk7XG4gIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gd3JpdGVEZXNpZ25Eb2NzKFxuICBkZXNpZ25Eb2NzOiBDb3VjaERCRGVzaWduRG9jW10sXG4gIHA6IHN0cmluZyA9IHByb2Nlc3MuY3dkKCksXG4gIGNvbGxlY3Rpb24/OiBzdHJpbmdcbikge1xuICBpZiAoIWRlc2lnbkRvY3MubGVuZ3RoKSByZXR1cm47XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG4gIGNvbnN0IGZzID0gcmVxdWlyZShcImZzXCIpO1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICBjb25zdCBwYXRoID0gcmVxdWlyZShcInBhdGhcIik7XG5cbiAgZGVzaWduRG9jcy5mb3JFYWNoKChkb2MpID0+IHtcbiAgICBjb25zdCBkb2NJZCA9IGRvYy5faWQucmVwbGFjZSgvXl9kZXNpZ25cXC8vLCBcIlwiKTtcbiAgICBjb25zdCBmaWxlID0gcGF0aC5yZXNvbHZlKFxuICAgICAgcGF0aC5qb2luKFxuICAgICAgICBwLFxuICAgICAgICBgLi9NRVRBLUlORi9zdGF0ZWRiL2NvdWNoZGIvJHtjb2xsZWN0aW9uID8gYGNvbGxlY3Rpb25zLyR7Y29sbGVjdGlvbn0vYCA6IFwiXCJ9ZGVzaWduX2RvY3MvJHtkb2NJZH0uanNvbmBcbiAgICAgIClcbiAgICApO1xuICAgIGVuc3VyZURpcmVjdG9yeUV4aXN0ZW5jZShmaWxlKTtcbiAgICBjb25zdCBwYXlsb2FkID0geyAuLi5kb2MgfTtcbiAgICBkZWxldGUgcGF5bG9hZC5fcmV2O1xuICAgIGZzLndyaXRlRmlsZVN5bmMoZmlsZSwgSlNPTi5zdHJpbmdpZnkocGF5bG9hZCwgdW5kZWZpbmVkLCAyKSk7XG4gIH0pO1xufVxuIiwiaW1wb3J0IHsgQmFzZU1vZGVsLCBjb2x1bW4sIHBrIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBtb2RlbCwgdHlwZSBNb2RlbEFyZywgcmVxdWlyZWQgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBkZXNjcmlwdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBJZGVudGl0eSBjcmVkZW50aWFsIG1vZGVsIHN0b3JpbmcgY3J5cHRvZ3JhcGhpYyBtYXRlcmlhbHNcbiAqIEBzdW1tYXJ5IEhvbGRzIGNlcnRpZmljYXRlIGNoYWluIGFuZCBwcml2YXRlIGtleSBpbmZvcm1hdGlvbiBmb3IgYSBGYWJyaWMgaWRlbnRpdHksIG1hbmFnZWQgYXMgYSBzZXBhcmF0ZSBlbnRpdHkgbGlua2VkIGZyb20gSWRlbnRpdHlcbiAqIEBwYXJhbSB7TW9kZWxBcmc8SWRlbnRpdHlDcmVkZW50aWFscz59IFthcmddIC0gT3B0aW9uYWwgaW5pdGlhbGl6YXRpb24gb2JqZWN0IHVzZWQgdG8gcG9wdWxhdGUgbW9kZWwgZmllbGRzXG4gKiBAY2xhc3MgSWRlbnRpdHlDcmVkZW50aWFsc1xuICogQGV4YW1wbGVcbiAqIC8vIENyZWF0ZSBjcmVkZW50aWFscyBlbnRyeVxuICogY29uc3QgY3JlZHMgPSBuZXcgSWRlbnRpdHlDcmVkZW50aWFscyh7IGlkOiBcImNyZWRzMVwiLCBjZXJ0aWZpY2F0ZTogXCIuLi5cIiwgcm9vdENlcnRpZmljYXRlOiBcIi4uLlwiLCBwcml2YXRlS2V5OiBcIi4uLlwiIH0pO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBBcHBcbiAqICAgcGFydGljaXBhbnQgTW9kZWwgYXMgSWRlbnRpdHlDcmVkZW50aWFsc1xuICogICBBcHAtPj5Nb2RlbDogbmV3IElkZW50aXR5Q3JlZGVudGlhbHMoeyBpZCwgY2VydGlmaWNhdGUsIHJvb3RDZXJ0aWZpY2F0ZSwgcHJpdmF0ZUtleSB9KVxuICogICBNb2RlbC0tPj5BcHA6IGluc3RhbmNlXG4gKiBAc2VlIG1vZGVsXG4gKi9cbkBtb2RlbCgpXG5leHBvcnQgY2xhc3MgSWRlbnRpdHlDcmVkZW50aWFscyBleHRlbmRzIEJhc2VNb2RlbCB7XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVW5pcXVlIGlkZW50aWZpZXIgb2YgdGhlIGNyZWRlbnRpYWxzIHJlY29yZFxuICAgKiBAc3VtbWFyeSBQcmltYXJ5IGtleSBmb3IgcmVmZXJlbmNpbmcgdGhpcyBjcmVkZW50aWFscyBlbnRyeVxuICAgKi9cbiAgQGRlc2NyaXB0aW9uKFwiVW5pcXVlIGlkZW50aWZpZXIgb2YgdGhlIGNyZWRlbnRpYWxzIHJlY29yZFwiKVxuICBAY29sdW1uKClcbiAgQHBrKClcbiAgaWQhOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQRU0tZW5jb2RlZCBYLjUwOSBjZXJ0aWZpY2F0ZSBmb3IgdGhlIGlkZW50aXR5XG4gICAqIEBzdW1tYXJ5IExlYWYgY2VydGlmaWNhdGUgYXNzb2NpYXRlZCB3aXRoIHRoZSBpZGVudGl0eVxuICAgKi9cbiAgQGRlc2NyaXB0aW9uKFwiUEVNLWVuY29kZWQgWC41MDkgY2VydGlmaWNhdGUgZm9yIHRoZSBpZGVudGl0eVwiKVxuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgY2VydGlmaWNhdGUhOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQRU0tZW5jb2RlZCByb290IG9yIGludGVybWVkaWF0ZSBjZXJ0aWZpY2F0ZVxuICAgKiBAc3VtbWFyeSBSb290IG9mIHRydXN0IHVzZWQgdG8gdmFsaWRhdGUgdGhlIGxlYWYgY2VydGlmaWNhdGVcbiAgICovXG4gIEBkZXNjcmlwdGlvbihcIlBFTS1lbmNvZGVkIHJvb3Qgb3IgaW50ZXJtZWRpYXRlIGNlcnRpZmljYXRlXCIpXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICByb290Q2VydGlmaWNhdGUhOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQRU0tZW5jb2RlZCBwcml2YXRlIGtleSBtYXRlcmlhbFxuICAgKiBAc3VtbWFyeSBQcml2YXRlIGtleSBjb3JyZXNwb25kaW5nIHRvIHRoZSBpZGVudGl0eSBjZXJ0aWZpY2F0ZVxuICAgKi9cbiAgQGRlc2NyaXB0aW9uKFwiUEVNLWVuY29kZWQgcHJpdmF0ZSBrZXlcIilcbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIHByaXZhdGVLZXkhOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IoYXJnPzogTW9kZWxBcmc8SWRlbnRpdHlDcmVkZW50aWFscz4pIHtcbiAgICBzdXBlcihhcmcpO1xuICB9XG59XG4iLCIvKipcbiAqIEBkZXNjcmlwdGlvbiBLZXlzIHVzZWQgdG8gbWFyayBGYWJyaWMtc3BlY2lmaWMgbW9kZWwgbWV0YWRhdGFcbiAqIEBzdW1tYXJ5IEVudW1lcmF0aW9uIG9mIHNwZWNpYWwga2V5cyB1c2VkIGJ5IHRoZSBzZXJpYWxpemF0aW9uIGxheWVyIHRvIHBlcnNpc3QgRmFicmljLXJlbGF0ZWQgZmxhZ3Mgb24gbW9kZWxzXG4gKiBAZW51bSB7c3RyaW5nfVxuICogQHJlYWRvbmx5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBlbnVtIEZhYnJpY01vZGVsS2V5cyB7XG4gIC8qKiBQcml2YXRlIGRhdGEgbWFya2VyIHVzZWQgdG8gdGFnIHByb3BlcnRpZXMgb3IgbW9kZWxzIGZvciBGYWJyaWMgcHJpdmF0ZSBjb2xsZWN0aW9ucyAqL1xuICBQUklWQVRFID0gXCJwcml2YXRlXCIsXG4gIFNIQVJFRCA9IFwic2hhcmVkXCIsXG4gIC8qKiBOYW1lc3BhY2UgcHJlZml4IHVzZWQgZm9yIEZhYnJpYy1zcGVjaWZpYyBtZXRhZGF0YSBrZXlzICovXG4gIEZBQlJJQyA9IFwiZmFicmljXCIsXG4gIE9XTkVEX0JZID0gXCJvd25lZC1ieVwiLFxuICBUUkFOU0FDVElPTl9JRCA9IFwidHJhbnNhY3Rpb24taWRcIixcbiAgTUlSUk9SID0gXCJtaXJyb3JcIixcbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIFN1cHBvcnRlZCBpZGVudGl0eSB0eXBlcyBmb3IgRmFicmljIGNyZWRlbnRpYWxzXG4gKiBAc3VtbWFyeSBFbnVtZXJhdGlvbiBvZiBpZGVudGl0eSBmb3JtYXRzIHJlY29nbml6ZWQgYnkgdGhpcyBsaWJyYXJ5XG4gKiBAZW51bSB7c3RyaW5nfVxuICogQHJlYWRvbmx5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBlbnVtIElkZW50aXR5VHlwZSB7XG4gIC8qKiBTdGFuZGFyZCBYLjUwOSBpZGVudGl0eSBmb3JtYXQgdXNlZCBieSBIeXBlcmxlZGdlciBGYWJyaWMgKi9cbiAgWDUwOSA9IFwiWC41MDlcIixcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU3RyaW5nIGlkZW50aWZpZXIgZm9yIHRoZSBGYWJyaWMgYWRhcHRlciBmbGF2b3VyXG4gKiBAc3VtbWFyeSBVc2VkIHRvIHRhZyBhZGFwdGVycy9yZXBvc2l0b3JpZXMgdGhhdCBvcGVyYXRlIGFnYWluc3QgSHlwZXJsZWRnZXIgRmFicmljXG4gKiBAY29uc3QgRmFicmljRmxhdm91clxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgY29uc3QgRmFicmljRmxhdm91ciA9IFwiaGxmLWZhYnJpY1wiO1xuIiwiaW1wb3J0IHtcbiAgQmFzZU1vZGVsLFxuICBDYXNjYWRlLFxuICBjb2x1bW4sXG4gIGluZGV4LFxuICBvbmVUb09uZSxcbiAgcGssXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgbW9kZWwsIHR5cGUgTW9kZWxBcmcsIHJlcXVpcmVkIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgSWRlbnRpdHlDcmVkZW50aWFscyB9IGZyb20gXCIuL0lkZW50aXR5Q3JlZGVudGlhbHNcIjtcbmltcG9ydCB7IElkZW50aXR5VHlwZSB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGRlc2NyaXB0aW9uIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIElkZW50aXR5IG1vZGVsIHJlcHJlc2VudGluZyBhIEZhYnJpYyB3YWxsZXQgZW50cnlcbiAqIEBzdW1tYXJ5IEVuY2Fwc3VsYXRlcyBhbiBpZGVudGl0eSBzdG9yZWQgaW4gYSBGYWJyaWMgd2FsbGV0LCBpbmNsdWRpbmcgaXRzIE1TUCBpZGVudGlmaWVyLCBjcmVkZW50aWFsIGxpbmthZ2UsIGFuZCB0eXBlIGluZm9ybWF0aW9uLiBCdWlsdCBvbiBCYXNlTW9kZWwgZm9yIGludGVncmF0aW9uIHdpdGggRGVjYWYgdmFsaWRhdGlvbiBhbmQgcGVyc2lzdGVuY2UuXG4gKiBAcGFyYW0ge01vZGVsQXJnPElkZW50aXR5Pn0gW2FyZ10gLSBPcHRpb25hbCBpbml0aWFsaXphdGlvbiBvYmplY3QgdXNlZCB0byBwb3B1bGF0ZSBtb2RlbCBmaWVsZHNcbiAqIEBjbGFzcyBJZGVudGl0eVxuICogQGV4YW1wbGVcbiAqIC8vIENyZWF0ZSBhIG5ldyBpZGVudGl0eSByZWZlcmVuY2luZyBleGlzdGluZyBjcmVkZW50aWFsc1xuICogY29uc3QgaWQgPSBuZXcgSWRlbnRpdHkoeyBpZDogXCJ1c2VyMVwiLCBtc3BJZDogXCJPcmcxTVNQXCIsIHR5cGU6IElkZW50aXR5VHlwZS5YNTA5IH0pO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBBcHBcbiAqICAgcGFydGljaXBhbnQgTW9kZWwgYXMgSWRlbnRpdHlcbiAqICAgQXBwLT4+TW9kZWw6IG5ldyBJZGVudGl0eSh7IGlkLCBtc3BJZCwgdHlwZSB9KVxuICogICBNb2RlbC0tPj5BcHA6IGluc3RhbmNlXG4gKi9cbkBtb2RlbCgpXG5leHBvcnQgY2xhc3MgSWRlbnRpdHkgZXh0ZW5kcyBCYXNlTW9kZWwge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVuaXF1ZSBpZGVudGlmaWVyIG9mIHRoZSBpZGVudGl0eSBpbiB0aGUgd2FsbGV0XG4gICAqIEBzdW1tYXJ5IFByaW1hcnkga2V5IHVzZWQgdG8gcmVmZXJlbmNlIHRoaXMgaWRlbnRpdHkgcmVjb3JkXG4gICAqL1xuICBAZGVzY3JpcHRpb24oXCJVbmlxdWUgaWRlbnRpZmllciBvZiB0aGUgaWRlbnRpdHlcIilcbiAgQHBrKClcbiAgaWQhOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMaW5rIHRvIHRoZSBpZGVudGl0eSBjcmVkZW50aWFscyBzdG9yZWQgc2VwYXJhdGVseVxuICAgKiBAc3VtbWFyeSBPbmUtdG8tb25lIHJlbGF0aW9uc2hpcCB0byB0aGUgY3JlZGVudGlhbHMgZW50aXR5OyBjYXNjYWRlcyBvbiB1cGRhdGUgYW5kIGRlbGV0ZVxuICAgKi9cbiAgQG9uZVRvT25lKElkZW50aXR5Q3JlZGVudGlhbHMsIHtcbiAgICB1cGRhdGU6IENhc2NhZGUuQ0FTQ0FERSxcbiAgICBkZWxldGU6IENhc2NhZGUuQ0FTQ0FERSxcbiAgfSlcbiAgY3JlZGVudGlhbHMhOiBJZGVudGl0eUNyZWRlbnRpYWxzO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gTWVtYmVyc2hpcCBTZXJ2aWNlIFByb3ZpZGVyIGlkZW50aWZpZXJcbiAgICogQHN1bW1hcnkgVGhlIE1TUCBJRCBjb3JyZXNwb25kaW5nIHRvIHRoZSBvcmdhbml6YXRpb24gdGhhdCBpc3N1ZWQgdGhpcyBpZGVudGl0eVxuICAgKi9cbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIEBpbmRleCgpXG4gIG1zcElkITogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVHlwZSBvZiBpZGVudGl0eVxuICAgKiBAc3VtbWFyeSBJbmRpY2F0ZXMgdGhlIGlkZW50aXR5IGVuY29kaW5nL2Zvcm1hdDsgZGVmYXVsdHMgdG8gWC41MDlcbiAgICovXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICB0eXBlOiBJZGVudGl0eVR5cGUgPSBJZGVudGl0eVR5cGUuWDUwOTtcblxuICBjb25zdHJ1Y3Rvcihhcmc6IE1vZGVsQXJnPElkZW50aXR5Pikge1xuICAgIHN1cGVyKGFyZyk7XG4gIH1cbn1cbiIsImltcG9ydCB7IHN0cmluZ0Zvcm1hdCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IExvZ2dlciwgTWluaUxvZ2dlciB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgSWRlbnRpdHksIFNpZ25lciwgc2lnbmVycyB9IGZyb20gXCJAaHlwZXJsZWRnZXIvZmFicmljLWdhdGV3YXlcIjtcbmltcG9ydCB7IENyeXB0b1NldHRpbmcsIElDcnlwdG9TdWl0ZSwgVXNlciB9IGZyb20gXCJmYWJyaWMtY29tbW9uXCI7XG5pbXBvcnQgeyBIU01PcHRpb25zIH0gZnJvbSBcIi4uL3NoYXJlZC90eXBlc1wiO1xuaW1wb3J0IHsgbm9ybWFsaXplSW1wb3J0IH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgY3J5cHRvLCB7IFg1MDlDZXJ0aWZpY2F0ZSB9IGZyb20gXCJjcnlwdG9cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ29yZSB1dGlsaXRpZXMgZm9yIGludGVyYWN0aW5nIHdpdGggZmlsZXMsIGNyeXB0byBpZGVudGl0aWVzLCBhbmQgRmFicmljIFNESyBoZWxwZXJzXG4gKiBAc3VtbWFyeSBQcm92aWRlcyBzdGF0aWMgaGVscGVyIG1ldGhvZHMgdG8gcmVhZCBjcmVkZW50aWFscyBhbmQga2V5cyBmcm9tIGRpc2sgb3IgcmF3IGNvbnRlbnQsIGNvbnN0cnVjdCBGYWJyaWMgZ2F0ZXdheSBJZGVudGl0aWVzIGFuZCBTaWduZXJzLCBhbmQgcGVyZm9ybSBjb21tb24gZmlsZXN5c3RlbSBvcGVyYXRpb25zIHVzZWQgYnkgdGhlIEZhYnJpYyBjbGllbnQgdG9vbGluZy5cbiAqIEBjbGFzcyBDb3JlVXRpbHNcbiAqIEBleGFtcGxlXG4gKiAvLyBSZWFkIGFuIGlkZW50aXR5IGFuZCBzaWduZXIgZnJvbSBkaXJlY3Rvcmllc1xuICogY29uc3QgaWRlbnRpdHkgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0SWRlbnRpdHkoJ09yZzFNU1AnLCAnL21zcC9zaWduY2VydHMnKTtcbiAqIGNvbnN0IHNpZ25lciA9IGF3YWl0IENvcmVVdGlscy5nZXRTaWduZXIoJy9tc3Ava2V5c3RvcmUnKTtcbiAqIC8vIEJ1aWxkIGEgQ0EgdXNlclxuICogY29uc3QgdXNlciA9IGF3YWl0IENvcmVVdGlscy5nZXRDQVVzZXIoJ2FwcFVzZXInLCBwZW1LZXksIHBlbUNlcnQsICdPcmcxTVNQJyk7XG4gKi9cbmV4cG9ydCBjbGFzcyBDb3JlVXRpbHMge1xuICBwcml2YXRlIHN0YXRpYyBsb2dnZXI6IExvZ2dlciA9IG5ldyBNaW5pTG9nZ2VyKENvcmVVdGlscy5uYW1lKTtcblxuICBwcml2YXRlIHN0YXRpYyBjcnlwdG9TdWl0ZTogSUNyeXB0b1N1aXRlO1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IoKSB7fVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVzb2x2ZSBmaWxlIGNvbnRlbnQgZnJvbSBhIHBhdGggb3IgcmV0dXJuIHByb3ZpZGVkIHJhdyBjb250ZW50XG4gICAqIEBzdW1tYXJ5IElmIHRoZSBpbnB1dCBpcyBhIFVpbnQ4QXJyYXkgb3IgUEVNIGNvbnRlbnQsIHJldHVybnMgaXQgYXMtaXM7IG90aGVyd2lzZSB1c2VzIGEgcHJvdmlkZWQgYXN5bmMgZmlsZVJlYWRlciB0byBsb2FkIHRoZSBjb250ZW50IGZyb20gZGlzay5cbiAgICogQHBhcmFtIHtzdHJpbmd8VWludDhBcnJheX0gY29udGVudE9yUGF0aCAtIEVpdGhlciBhIHJhdyBjb250ZW50IGJ1ZmZlci9zdHJpbmcgb3IgYSBmaWxlc3lzdGVtIHBhdGhcbiAgICogQHBhcmFtIHtmdW5jdGlvbihzdHJpbmcpOiBQcm9taXNlPHN0cmluZ3xVaW50OEFycmF5fEJ1ZmZlcj59IGZpbGVSZWFkZXIgLSBBc3luYyBmdW5jdGlvbiB0byByZWFkIGZpbGUgY29udGVudCB3aGVuIGEgcGF0aCBpcyBwcm92aWRlZFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZ3xVaW50OEFycmF5fEJ1ZmZlcj59IFRoZSBjb250ZW50IHRvIGJlIHVzZWQgZG93bnN0cmVhbVxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgYXN5bmMgY29udGVudE9mTG9hZEZpbGUoXG4gICAgY29udGVudE9yUGF0aDogc3RyaW5nIHwgVWludDhBcnJheSxcbiAgICBmaWxlUmVhZGVyOiAocGF0aDogc3RyaW5nKSA9PiBQcm9taXNlPHN0cmluZyB8IFVpbnQ4QXJyYXkgfCBCdWZmZXI+XG4gICkge1xuICAgIGlmIChjb250ZW50T3JQYXRoIGluc3RhbmNlb2YgVWludDhBcnJheSkgcmV0dXJuIGNvbnRlbnRPclBhdGg7XG4gICAgaWYgKFxuICAgICAgY29udGVudE9yUGF0aC5tYXRjaChcbiAgICAgICAgLy0tLS0tQkVHSU4gKENFUlRJRklDQVRFfEtFWXxQUklWQVRFIEtFWSktLS0tLS4rPy0tLS0tRU5EIFxcMS0tLS0tJC9nbXNcbiAgICAgIClcbiAgICApXG4gICAgICByZXR1cm4gY29udGVudE9yUGF0aDtcbiAgICByZXR1cm4gYXdhaXQgZmlsZVJlYWRlcihjb250ZW50T3JQYXRoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVhZCBmaWxlIGNvbnRlbnQgZnJvbSBhIHBhdGggb3IgcmV0dXJuIHByb3ZpZGVkIEJ1ZmZlclxuICAgKiBAc3VtbWFyeSBDb252ZW5pZW5jZSB3cmFwcGVyIHRoYXQgbG9hZHMgYSBmaWxlIHVzaW5nIGZzLnByb21pc2VzIHdoZW4gYSBwYXRoIHN0cmluZyBpcyBwcm92aWRlZDsgb3RoZXJ3aXNlIHJldHVybnMgdGhlIGdpdmVuIEJ1ZmZlciBkaXJlY3RseS5cbiAgICogQHBhcmFtIHtzdHJpbmd8QnVmZmVyfSBjb250ZW50T3JQYXRoIC0gUGF0aCB0byBhIGZpbGUgb24gZGlzayBvciBhbiBhbHJlYWR5LWxvYWRlZCBCdWZmZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmd8VWludDhBcnJheXxCdWZmZXI+fSBUaGUgZmlsZSBjb250ZW50IGFzIGEgQnVmZmVyL3N0cmluZyBkZXBlbmRpbmcgb24gcmVhZGVyXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgcmVhZEZpbGUoY29udGVudE9yUGF0aDogc3RyaW5nIHwgQnVmZmVyKSB7XG4gICAgaWYgKHR5cGVvZiBjb250ZW50T3JQYXRoICE9PSBcInN0cmluZ1wiKSByZXR1cm4gY29udGVudE9yUGF0aDtcblxuICAgIGNvbnN0IGZpbGVSZWFkZXIgPSBhc3luYyAocGF0aDogc3RyaW5nKSA9PiB7XG4gICAgICBjb25zdCB7IHByb21pc2VzIH0gPSBhd2FpdCBub3JtYWxpemVJbXBvcnQoaW1wb3J0KFwiZnNcIikpO1xuICAgICAgcmV0dXJuIGF3YWl0IHByb21pc2VzLnJlYWRGaWxlKHBhdGgpO1xuICAgIH07XG5cbiAgICByZXR1cm4gYXdhaXQgZmlsZVJlYWRlcihjb250ZW50T3JQYXRoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlIGEgRmFicmljIENBIFVzZXIgb2JqZWN0IHdpdGggZW5yb2xsbWVudFxuICAgKiBAc3VtbWFyeSBDb25zdHJ1Y3RzIGEgZmFicmljLWNvbW1vbiBVc2VyLCBzZXRzIGEgY3J5cHRvIHN1aXRlLCBpbXBvcnRzIHRoZSBwcm92aWRlZCBwcml2YXRlIGtleSwgYW5kIHNldHMgZW5yb2xsbWVudCB3aXRoIGNlcnRpZmljYXRlIGFuZCBNU1AgSUQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1c2VyTmFtZSAtIFRoZSB1c2VyIG5hbWUgZm9yIHRoZSBDQSB1c2VyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwcml2YXRlS2V5IC0gUEVNLWVuY29kZWQgcHJpdmF0ZSBrZXlcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNlcnRpZmljYXRlIC0gUEVNLWVuY29kZWQgWC41MDkgY2VydGlmaWNhdGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1zcElkIC0gTWVtYmVyc2hpcCBTZXJ2aWNlIFByb3ZpZGVyIGlkZW50aWZpZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTxVc2VyPn0gVGhlIGVucm9sbGVkIEZhYnJpYyBVc2VyIGluc3RhbmNlXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2V0Q0FVc2VyKFxuICAgIHVzZXJOYW1lOiBzdHJpbmcsXG4gICAgcHJpdmF0ZUtleTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIGNlcnRpZmljYXRlOiBzdHJpbmcsXG4gICAgbXNwSWQ6IHN0cmluZyxcbiAgICBvcHRpb25zPzogeyBoc20/OiBIU01PcHRpb25zIH1cbiAgKTogUHJvbWlzZTxVc2VyPiB7XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoXG4gICAgICBzdHJpbmdGb3JtYXQoXG4gICAgICAgIFwiQ3JlYXRpbmcgQ0EgezB9IHVzZXIgezF9IHdpdGggY2VydGlmaWNhdGUgezJ9XCIsXG4gICAgICAgIG1zcElkLFxuICAgICAgICB1c2VyTmFtZSxcbiAgICAgICAgY2VydGlmaWNhdGVcbiAgICAgIClcbiAgICApO1xuICAgIGNvbnN0IHVzZXIgPSBuZXcgVXNlcih1c2VyTmFtZSk7XG4gICAgY29uc3QgY29uZmlnID0gb3B0aW9ucz8uaHNtXG4gICAgICA/IHtcbiAgICAgICAgICBzb2Z0d2FyZTogZmFsc2UsXG4gICAgICAgICAgbGliOiBvcHRpb25zLmhzbS5saWJyYXJ5LFxuICAgICAgICAgIHNsb3Q6IG9wdGlvbnMuaHNtLnNsb3QsXG4gICAgICAgICAgbGFiZWw6IG9wdGlvbnMuaHNtLnRva2VuTGFiZWwsXG4gICAgICAgICAgcGluOiBTdHJpbmcob3B0aW9ucy5oc20ucGluKSxcbiAgICAgICAgfVxuICAgICAgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgY3J5cHRvU3VpdGUgPSB0aGlzLmdldENyeXB0b1N1aXRlKGNvbmZpZyk7XG5cbiAgICB1c2VyLnNldENyeXB0b1N1aXRlKGNyeXB0b1N1aXRlKTtcbiAgICBjb25zdCBlbnJvbGxtZW50S2V5ID0gb3B0aW9ucz8uaHNtXG4gICAgICA/IGF3YWl0IHRoaXMuZ2V0SFNNRW5yb2xsbWVudEtleShjcnlwdG9TdWl0ZSwgY2VydGlmaWNhdGUsIG9wdGlvbnMuaHNtKVxuICAgICAgOiB0aGlzLmdldFNvZnR3YXJlRW5yb2xsbWVudEtleShjcnlwdG9TdWl0ZSwgcHJpdmF0ZUtleSk7XG4gICAgYXdhaXQgdXNlci5zZXRFbnJvbGxtZW50KGVucm9sbG1lbnRLZXksIGNlcnRpZmljYXRlLCBtc3BJZCk7XG4gICAgcmV0dXJuIHVzZXI7XG4gIH1cblxuICBzdGF0aWMgZ2V0Q3J5cHRvU3VpdGUob3B0aW9ucz86IENyeXB0b1NldHRpbmcpOiBJQ3J5cHRvU3VpdGUge1xuICAgIGlmICghb3B0aW9ucykgcmV0dXJuIFVzZXIubmV3Q3J5cHRvU3VpdGUoKTtcbiAgICBpZiAoQ29yZVV0aWxzLmNyeXB0b1N1aXRlKSByZXR1cm4gQ29yZVV0aWxzLmNyeXB0b1N1aXRlO1xuXG4gICAgQ29yZVV0aWxzLmNyeXB0b1N1aXRlID0gVXNlci5uZXdDcnlwdG9TdWl0ZShvcHRpb25zKTtcbiAgICByZXR1cm4gQ29yZVV0aWxzLmNyeXB0b1N1aXRlO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0U29mdHdhcmVFbnJvbGxtZW50S2V5KFxuICAgIGNyeXB0b1N1aXRlOiBhbnksXG4gICAgcHJpdmF0ZUtleT86IHN0cmluZ1xuICApIHtcbiAgICBpZiAoIXByaXZhdGVLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJQcml2YXRlIGtleSBtdXN0IGJlIHByb3ZpZGVkIHdoZW4gSFNNIGNvbmZpZ3VyYXRpb24gaXMgbm90IHN1cHBsaWVkXCJcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBjcnlwdG9TdWl0ZS5jcmVhdGVLZXlGcm9tUmF3KHByaXZhdGVLZXkpO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgYXN5bmMgZ2V0SFNNRW5yb2xsbWVudEtleShcbiAgICBjcnlwdG9TdWl0ZTogYW55LFxuICAgIGNlcnRpZmljYXRlOiBzdHJpbmcsXG4gICAgaHNtOiBIU01PcHRpb25zXG4gICkge1xuICAgIGNvbnN0IHNraSA9XG4gICAgICBoc20ua2V5SWRIZXggJiYgaHNtLmtleUlkSGV4LnRyaW0oKS5sZW5ndGggPiAwXG4gICAgICAgID8gQnVmZmVyLmZyb20oaHNtLmtleUlkSGV4LCBcImhleFwiKVxuICAgICAgICA6IGF3YWl0IHRoaXMuZ2V0Q2VydGlmaWNhdGVTS0koY2VydGlmaWNhdGUpO1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IGNyeXB0b1N1aXRlLmdldEtleShza2kpO1xuICAgIGlmICgha2V5IHx8ICh0eXBlb2Yga2V5LmlzUHJpdmF0ZSA9PT0gXCJmdW5jdGlvblwiICYmICFrZXkuaXNQcml2YXRlKCkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbmFibGUgdG8gcmVzb2x2ZSBwcml2YXRlIGtleSBmcm9tIEhTTVwiKTtcbiAgICB9XG4gICAgcmV0dXJuIGtleTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBnZXRDZXJ0aWZpY2F0ZVNLSShjZXJ0aWZpY2F0ZTogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBjb25zdCB4NTA5ID0gbmV3IFg1MDlDZXJ0aWZpY2F0ZShjZXJ0aWZpY2F0ZSk7XG4gICAgY29uc3QgandrID0geDUwOS5wdWJsaWNLZXkuZXhwb3J0KHsgZm9ybWF0OiBcImp3a1wiIH0pO1xuICAgIGNvbnN0IHByZWZpeCA9IEJ1ZmZlci5mcm9tKFsweDA0XSk7XG4gICAgY29uc3QgeCA9IEJ1ZmZlci5mcm9tKGp3ay54IHx8IFwiXCIsIFwiYmFzZTY0dXJsXCIpO1xuICAgIGNvbnN0IHkgPSBCdWZmZXIuZnJvbShqd2sueSB8fCBcIlwiLCBcImJhc2U2NHVybFwiKTtcbiAgICByZXR1cm4gY3J5cHRvXG4gICAgICAuY3JlYXRlSGFzaChcInNoYTI1NlwiKVxuICAgICAgLnVwZGF0ZShCdWZmZXIuY29uY2F0KFtwcmVmaXgsIHgsIHldKSlcbiAgICAgIC5kaWdlc3QoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQnVpbGQgYSBGYWJyaWMgR2F0ZXdheSBJZGVudGl0eSBmcm9tIGFuIE1TUCBJRCBhbmQgY2VydGlmaWNhdGVcbiAgICogQHN1bW1hcnkgUmVhZHMgYSBjZXJ0aWZpY2F0ZSBmcm9tIGEgZGlyZWN0b3J5IHBhdGggb3IgYWNjZXB0cyByYXcgY29udGVudCBhbmQgcmV0dXJucyBhbiBJZGVudGl0eSBvYmplY3Qgc3VpdGFibGUgZm9yIHRoZSBGYWJyaWMgR2F0ZXdheS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG1zcElkIC0gTWVtYmVyc2hpcCBTZXJ2aWNlIFByb3ZpZGVyIElEXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjZXJ0RGlyZWN0b3J5UGF0aCAtIFBhdGggdG8gYSBkaXJlY3RvcnkgY29udGFpbmluZyB0aGUgY2VydGlmaWNhdGUgZmlsZSwgb3IgUEVNIGNvbnRlbnRcbiAgICogQHJldHVybiB7UHJvbWlzZTxJZGVudGl0eT59IFRoZSBpZGVudGl0eSBjb250YWluaW5nIG1zcElkIGFuZCBjZXJ0aWZpY2F0ZSBjcmVkZW50aWFsc1xuICAgKi9cbiAgc3RhdGljIGFzeW5jIGdldElkZW50aXR5KFxuICAgIG1zcElkOiBzdHJpbmcsXG4gICAgY2VydERpcmVjdG9yeVBhdGg6IHN0cmluZ1xuICApOiBQcm9taXNlPElkZW50aXR5PiB7XG4gICAgY29uc3QgaWRlbnRpdHlGaWxlUmVhZGVyID0gYXN5bmMgKHBhdGg6IHN0cmluZykgPT4ge1xuICAgICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICAgIGNvbnN0IGNlcnRQYXRoID0gYXdhaXQgdGhpcy5nZXRGaXJzdERpckZpbGVOYW1lKHBhdGgpO1xuICAgICAgY29uc3QgY3JlZGVudGlhbHMgPSBhd2FpdCBwcm9taXNlcy5yZWFkRmlsZShjZXJ0UGF0aCk7XG4gICAgICByZXR1cm4gY3JlZGVudGlhbHM7XG4gICAgfTtcblxuICAgIGNvbnN0IGNyZWRlbnRpYWxzOiBVaW50OEFycmF5ID0gKGF3YWl0IHRoaXMuY29udGVudE9mTG9hZEZpbGUoXG4gICAgICBjZXJ0RGlyZWN0b3J5UGF0aCxcbiAgICAgIGlkZW50aXR5RmlsZVJlYWRlclxuICAgICkpIGFzIFVpbnQ4QXJyYXk7XG5cbiAgICByZXR1cm4geyBtc3BJZCwgY3JlZGVudGlhbHMgfTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBnZXRGaXJzdERpckZpbGVOYW1lKGRpclBhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICBjb25zdCB7IGpvaW4gfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJwYXRoXCIpKTtcbiAgICBjb25zdCBmaWxlcyA9IGF3YWl0IHByb21pc2VzLnJlYWRkaXIoZGlyUGF0aCk7XG4gICAgcmV0dXJuIGpvaW4oZGlyUGF0aCwgZmlsZXNbMF0pO1xuICB9XG5cbiAgc3RhdGljIGFzeW5jIGdldEZpcnN0RGlyRmlsZU5hbWVDb250ZW50KGRpclBhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICBjb25zdCB7IGpvaW4gfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJwYXRoXCIpKTtcbiAgICBjb25zdCBmaWxlcyA9IGF3YWl0IHByb21pc2VzLnJlYWRkaXIoZGlyUGF0aCk7XG4gICAgcmV0dXJuIChhd2FpdCBwcm9taXNlcy5yZWFkRmlsZShqb2luKGRpclBhdGgsIGZpbGVzWzBdKSkpLnRvU3RyaW5nKCk7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgZ2V0RmlsZUNvbnRlbnQoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICByZXR1cm4gKGF3YWl0IHByb21pc2VzLnJlYWRGaWxlKGZpbGVQYXRoKSkudG9TdHJpbmcoKTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBnZXRTaWduZXIoa2V5RGlyZWN0b3J5UGF0aDogc3RyaW5nKTogUHJvbWlzZTxTaWduZXI+IHtcbiAgICBjb25zdCBzaWduZXJGaWxlUmVhZGVyID0gYXN5bmMgKHBhdGg6IHN0cmluZykgPT4ge1xuICAgICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICAgIGNvbnN0IGtleVBhdGggPSBhd2FpdCB0aGlzLmdldEZpcnN0RGlyRmlsZU5hbWUocGF0aCk7XG4gICAgICByZXR1cm4gYXdhaXQgcHJvbWlzZXMucmVhZEZpbGUoa2V5UGF0aCk7XG4gICAgfTtcblxuICAgIGNvbnN0IHByaXZhdGVLZXlQZW0gPSAoYXdhaXQgdGhpcy5jb250ZW50T2ZMb2FkRmlsZShcbiAgICAgIGtleURpcmVjdG9yeVBhdGgsXG4gICAgICBzaWduZXJGaWxlUmVhZGVyXG4gICAgKSkgYXMgQnVmZmVyO1xuICAgIGNvbnN0IHByaXZhdGVLZXkgPSBhd2FpdCB0aGlzLmV4dHJhY3RQcml2YXRlS2V5KHByaXZhdGVLZXlQZW0pO1xuICAgIGNvbnN0IGtleXMgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHByaXZhdGVLZXkpO1xuICAgIGNvbnN0IGsgPSAocHJpdmF0ZUtleSBhcyBhbnkpW2tleXNbMF1dO1xuICAgIC8vIC0tXG5cbiAgICByZXR1cm4gc2lnbmVycy5uZXdQcml2YXRlS2V5U2lnbmVyKGsgYXMgYW55KTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGFzeW5jIGV4dHJhY3RQcml2YXRlS2V5KHBlbTogQnVmZmVyKSB7XG4gICAgY29uc3QgbGliTmFtZSA9IFwiY3J5cHRvXCI7XG4gICAgbGV0IHN1YnRsZTogYW55O1xuICAgIGlmIChcbiAgICAgIChnbG9iYWxUaGlzIGFzIGFueSkud2luZG93ICYmXG4gICAgICAoKGdsb2JhbFRoaXMgYXMgYW55KS53aW5kb3cgYXMgeyBDcnlwdG86IGFueSB9KS5DcnlwdG9cbiAgICApIHtcbiAgICAgIHN1YnRsZSA9ICgoZ2xvYmFsVGhpcyBhcyBhbnkpLkNyeXB0byBhcyBhbnkpLnN1YnRsZTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbGliID0gKGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQobGliTmFtZSkpKSBhcyBhbnk7XG4gICAgICBzdWJ0bGUgPSBsaWIuc3VidGxlIHx8IGxpYi53ZWJjcnlwdG8uc3VidGxlO1xuICAgIH1cblxuICAgIGlmICghc3VidGxlKSB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgbG9hZCBTdWJ0bGVDcnlwdG8gbW9kdWxlXCIpO1xuXG4gICAgZnVuY3Rpb24gc3RyMmFiKHN0cjogc3RyaW5nKSB7XG4gICAgICBjb25zdCBidWYgPSBuZXcgQXJyYXlCdWZmZXIoc3RyLmxlbmd0aCk7XG4gICAgICBjb25zdCBidWZWaWV3ID0gbmV3IFVpbnQ4QXJyYXkoYnVmKTtcbiAgICAgIGZvciAobGV0IGkgPSAwLCBzdHJMZW4gPSBzdHIubGVuZ3RoOyBpIDwgc3RyTGVuOyBpKyspIHtcbiAgICAgICAgYnVmVmlld1tpXSA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1ZjtcbiAgICB9XG5cbiAgICBjb25zdCBzdHIgPSBwZW1cbiAgICAgIC50b1N0cmluZyhcInV0ZjhcIilcbiAgICAgIC5yZXBsYWNlKFwiLS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tXCIsIFwiXCIpXG4gICAgICAucmVwbGFjZUFsbChcIlxcblwiLCBcIlwiKVxuICAgICAgLnJlcGxhY2UoXCItLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXCIsIFwiXCIpO1xuICAgIGNvbnN0IGRlY29kZWQgPSBCdWZmZXIuZnJvbShzdHIsIFwiYmFzZTY0XCIpLnRvU3RyaW5nKFwiYmluYXJ5XCIpO1xuICAgIGNvbnN0IGJpbmFyeURlciA9IHN0cjJhYihkZWNvZGVkKTtcbiAgICBjb25zdCBrZXkgPSBhd2FpdCBzdWJ0bGUuaW1wb3J0S2V5KFxuICAgICAgXCJwa2NzOFwiLFxuICAgICAgYmluYXJ5RGVyLFxuICAgICAge1xuICAgICAgICBuYW1lOiBcIkVDRFNBXCIsXG4gICAgICAgIG5hbWVkQ3VydmU6IFwiUC0yNTZcIixcbiAgICAgIH0sXG4gICAgICB0cnVlLFxuICAgICAgW1wic2lnblwiXVxuICAgICk7XG5cbiAgICByZXR1cm4ga2V5O1xuICB9XG59XG4iLCJpbXBvcnQgKiBhcyB4NTA5IGZyb20gXCJAcGVjdWxpYXIveDUwOVwiO1xuaW1wb3J0IHsgQ3J5cHRvLCBDcnlwdG9LZXkgfSBmcm9tIFwiQHBlY3VsaWFyL3dlYmNyeXB0b1wiO1xuaW1wb3J0IHsgc3RyaW5nRm9ybWF0IH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgaXNCcm93c2VyLCBNaW5pTG9nZ2VyIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5cbmNvbnN0IGNyeXB0byA9IG5ldyBDcnlwdG8oKTtcbng1MDkuY3J5cHRvUHJvdmlkZXIuc2V0KGNyeXB0byk7XG5cbmV4cG9ydCBlbnVtIEJBU0VfQUxQSEFCRVQge1xuICBCQVNFMiA9IFwiMDFcIixcbiAgQkFTRTggPSBcIjAxMjM0NTY3XCIsXG4gIEJBU0UxMSA9IFwiMDEyMzQ1Njc4OWFcIixcbiAgQkFTRTE2ID0gXCIwMTIzNDU2Nzg5YWJjZGVmXCIsXG4gIEJBU0UzMiA9IFwiMDEyMzQ1Njc4OUFCQ0RFRkdISktNTlBRUlNUVldYWVpcIixcbiAgQkFTRTMyX1ogPSBcInlibmRyZmc4ZWprbWNwcXhvdDF1d2lzemEzNDVoNzY5XCIsXG4gIEJBU0UzNiA9IFwiMDEyMzQ1Njc4OWFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6XCIsXG4gIEJBU0U1OCA9IFwiMTIzNDU2Nzg5QUJDREVGR0hKS0xNTlBRUlNUVVZXWFlaYWJjZGVmZ2hpamttbm9wcXJzdHV2d3h5elwiLFxuICBCQVNFNjIgPSBcIjAxMjM0NTY3ODlhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaXCIsXG4gIEJBU0U2NCA9IFwiQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrL1wiLFxuICBCQVNFNjcgPSBcIkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5LV8uIX5cIixcbn1cblxuZXhwb3J0IHR5cGUga2V5T2JqZWN0ID0ge1xuICBpdjogQXJyYXlCdWZmZXI7XG4gIGtleTogQ3J5cHRvS2V5O1xufTtcblxuZXhwb3J0IGVudW0gQ1JZUFRPIHtcbiAgSEFTSCA9IFwiU0hBLTI1NlwiLFxuICBJVEVSQVRJT05TID0gMTAwMCxcbiAgS0VZTEVOR1RIID0gNDgsXG4gIERFUklWRURfSVZfTEVOR1RIID0gMTYsXG4gIERFUklWRURfS0VZX0xFTkdUSCA9IDMyLCAvLyBCZWNhdXNlIFNIQS0yNTYgdXNlZCBoYXMgYSBuYXRpdmUgc2l6ZSBvZiAzMiBieXRlc1xuICBBTEdPUllUSE0gPSBcIkFFUy1HQ01cIixcbiAgS0VZX0FMR09SWVRITSA9IFwiUEJLREYyXCIsXG59XG5cbmV4cG9ydCBjbGFzcyBCYXNlRW5jb2RlciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgYmFzZU1hcDogVWludDhBcnJheSA9IG5ldyBVaW50OEFycmF5KDI1Nik7XG4gIHByaXZhdGUgcmVhZG9ubHkgYmFzZTogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGxlYWRlcjogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IGZhY3RvcjogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGlGYWN0b3I6IG51bWJlcjtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGFscGhhYmV0OiBCQVNFX0FMUEhBQkVUKSB7XG4gICAgaWYgKHRoaXMuYWxwaGFiZXQubGVuZ3RoID49IDI1NSkgdGhyb3cgbmV3IEVycm9yKFwiQWxwaGFiZXQgdG9vIGxvbmdcIik7XG5cbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMuYmFzZU1hcC5sZW5ndGg7IGorKykgdGhpcy5iYXNlTWFwW2pdID0gMjU1O1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhbHBoYWJldC5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgeCA9IGFscGhhYmV0LmNoYXJBdChpKTtcbiAgICAgIGNvbnN0IHhjID0geC5jaGFyQ29kZUF0KDApO1xuICAgICAgaWYgKHRoaXMuYmFzZU1hcFt4Y10gIT09IDI1NSkgdGhyb3cgbmV3IEVycm9yKHggKyBcIiBpcyBhbWJpZ3VvdXNcIik7XG5cbiAgICAgIHRoaXMuYmFzZU1hcFt4Y10gPSBpO1xuICAgIH1cblxuICAgIHRoaXMuYmFzZSA9IHRoaXMuYWxwaGFiZXQubGVuZ3RoO1xuICAgIHRoaXMubGVhZGVyID0gdGhpcy5hbHBoYWJldC5jaGFyQXQoMCk7XG4gICAgdGhpcy5mYWN0b3IgPSBNYXRoLmxvZyh0aGlzLmJhc2UpIC8gTWF0aC5sb2coMjU2KTsgLy8gbG9nKEJBU0UpIC8gbG9nKDI1NiksIHJvdW5kZWQgdXBcbiAgICB0aGlzLmlGYWN0b3IgPSBNYXRoLmxvZygyNTYpIC8gTWF0aC5sb2codGhpcy5iYXNlKTsgLy8gbG9nKDI1NikgLyBsb2coQkFTRSksIHJvdW5kZWQgdXBcbiAgfVxuXG4gIGVuY29kZShzb3VyY2U6IFVpbnQ4QXJyYXkgfCBEYXRhVmlldyB8IGFueVtdIHwgc3RyaW5nKSB7XG4gICAgaWYgKHR5cGVvZiBzb3VyY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHNvdXJjZSA9IEJ1ZmZlci5mcm9tKHNvdXJjZSk7XG4gICAgfSBlbHNlIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcoc291cmNlKSkge1xuICAgICAgc291cmNlID0gbmV3IFVpbnQ4QXJyYXkoXG4gICAgICAgIHNvdXJjZS5idWZmZXIsXG4gICAgICAgIHNvdXJjZS5ieXRlT2Zmc2V0LFxuICAgICAgICBzb3VyY2UuYnl0ZUxlbmd0aFxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoc291cmNlKSkge1xuICAgICAgc291cmNlID0gVWludDhBcnJheS5mcm9tKHNvdXJjZSk7XG4gICAgfVxuXG4gICAgaWYgKHNvdXJjZS5sZW5ndGggPT09IDApIHJldHVybiBcIlwiO1xuXG4gICAgLy8gU2tpcCAmIGNvdW50IGxlYWRpbmcgemVyb2VzLlxuICAgIGxldCB6ZXJvZXMgPSAwO1xuICAgIGxldCBsZW5ndGggPSAwO1xuICAgIGxldCBwYmVnaW4gPSAwO1xuICAgIGNvbnN0IHBlbmQgPSBzb3VyY2UubGVuZ3RoO1xuICAgIHdoaWxlIChwYmVnaW4gIT09IHBlbmQgJiYgc291cmNlW3BiZWdpbl0gPT09IDApIHtcbiAgICAgIHBiZWdpbisrO1xuICAgICAgemVyb2VzKys7XG4gICAgfVxuICAgIC8vIEFsbG9jYXRlIGVub3VnaCBzcGFjZSBpbiBiaWctZW5kaWFuIGJhc2U1OCByZXByZXNlbnRhdGlvbi5cbiAgICBjb25zdCBzaXplID0gKChwZW5kIC0gcGJlZ2luKSAqIHRoaXMuaUZhY3RvciArIDEpID4+PiAwO1xuICAgIGNvbnN0IGI1OCA9IG5ldyBVaW50OEFycmF5KHNpemUpO1xuICAgIC8vIFByb2Nlc3MgdGhlIGJ5dGVzLlxuICAgIHdoaWxlIChwYmVnaW4gIT09IHBlbmQpIHtcbiAgICAgIGxldCBjYXJyeSA9IHNvdXJjZVtwYmVnaW5dO1xuICAgICAgLy8gQXBwbHkgXCJiNTggPSBiNTggKiAyNTYgKyBjaFwiLlxuICAgICAgbGV0IGkgPSAwO1xuICAgICAgZm9yIChcbiAgICAgICAgbGV0IGl0MSA9IHNpemUgLSAxO1xuICAgICAgICAoY2FycnkgIT09IDAgfHwgaSA8IGxlbmd0aCkgJiYgaXQxICE9PSAtMTtcbiAgICAgICAgaXQxLS0sIGkrK1xuICAgICAgKSB7XG4gICAgICAgIGNhcnJ5ICs9ICgyNTYgKiBiNThbaXQxXSkgPj4+IDA7XG4gICAgICAgIGI1OFtpdDFdID0gY2FycnkgJSB0aGlzLmJhc2UgPj4+IDA7XG4gICAgICAgIGNhcnJ5ID0gKGNhcnJ5IC8gdGhpcy5iYXNlKSA+Pj4gMDtcbiAgICAgIH1cbiAgICAgIGlmIChjYXJyeSAhPT0gMCkgdGhyb3cgbmV3IEVycm9yKFwiTm9uLXplcm8gY2FycnlcIik7XG5cbiAgICAgIGxlbmd0aCA9IGk7XG4gICAgICBwYmVnaW4rKztcbiAgICB9XG4gICAgLy8gU2tpcCBsZWFkaW5nIHplcm9lcyBpbiBiYXNlNTggcmVzdWx0LlxuICAgIGxldCBpdDIgPSBzaXplIC0gbGVuZ3RoO1xuICAgIHdoaWxlIChpdDIgIT09IHNpemUgJiYgYjU4W2l0Ml0gPT09IDApIGl0MisrO1xuXG4gICAgLy8gVHJhbnNsYXRlIHRoZSByZXN1bHQgaW50byBhIHN0cmluZy5cbiAgICBsZXQgc3RyID0gdGhpcy5sZWFkZXIucmVwZWF0KHplcm9lcyk7XG4gICAgZm9yICg7IGl0MiA8IHNpemU7ICsraXQyKSB7XG4gICAgICBzdHIgKz0gdGhpcy5hbHBoYWJldC5jaGFyQXQoYjU4W2l0Ml0pO1xuICAgIH1cbiAgICByZXR1cm4gc3RyO1xuICB9XG5cbiAgcHJpdmF0ZSBkZWNvZGVVbnNhZmUoc291cmNlOiBzdHJpbmcpOiBVaW50OEFycmF5IHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoc291cmNlLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG5ldyBVaW50OEFycmF5KDApO1xuXG4gICAgbGV0IHBzeiA9IDA7XG4gICAgLy8gU2tpcCBhbmQgY291bnQgbGVhZGluZyAnMSdzLlxuICAgIGxldCB6ZXJvZXMgPSAwO1xuICAgIGxldCBsZW5ndGggPSAwO1xuICAgIHdoaWxlIChzb3VyY2VbcHN6XSA9PT0gdGhpcy5sZWFkZXIpIHtcbiAgICAgIHplcm9lcysrO1xuICAgICAgcHN6Kys7XG4gICAgfVxuICAgIC8vIEFsbG9jYXRlIGVub3VnaCBzcGFjZSBpbiBiaWctZW5kaWFuIGJhc2UyNTYgcmVwcmVzZW50YXRpb24uXG4gICAgY29uc3Qgc2l6ZSA9ICgoc291cmNlLmxlbmd0aCAtIHBzeikgKiB0aGlzLmZhY3RvciArIDEpID4+PiAwOyAvLyBsb2coNTgpIC8gbG9nKDI1NiksIHJvdW5kZWQgdXAuXG4gICAgY29uc3QgYjI1NiA9IG5ldyBVaW50OEFycmF5KHNpemUpO1xuICAgIC8vIFByb2Nlc3MgdGhlIGNoYXJhY3RlcnMuXG4gICAgd2hpbGUgKHNvdXJjZVtwc3pdKSB7XG4gICAgICAvLyBEZWNvZGUgY2hhcmFjdGVyXG4gICAgICBsZXQgY2FycnkgPSB0aGlzLmJhc2VNYXBbc291cmNlLmNoYXJDb2RlQXQocHN6KV07XG4gICAgICAvLyBJbnZhbGlkIGNoYXJhY3RlclxuICAgICAgaWYgKGNhcnJ5ID09PSAyNTUpIHJldHVybjtcblxuICAgICAgbGV0IGkgPSAwO1xuICAgICAgZm9yIChcbiAgICAgICAgbGV0IGl0MyA9IHNpemUgLSAxO1xuICAgICAgICAoY2FycnkgIT09IDAgfHwgaSA8IGxlbmd0aCkgJiYgaXQzICE9PSAtMTtcbiAgICAgICAgaXQzLS0sIGkrK1xuICAgICAgKSB7XG4gICAgICAgIGNhcnJ5ICs9ICh0aGlzLmJhc2UgKiBiMjU2W2l0M10pID4+PiAwO1xuICAgICAgICBiMjU2W2l0M10gPSBjYXJyeSAlIDI1NiA+Pj4gMDtcbiAgICAgICAgY2FycnkgPSAoY2FycnkgLyAyNTYpID4+PiAwO1xuICAgICAgfVxuICAgICAgaWYgKGNhcnJ5ICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoXCJOb24temVybyBjYXJyeVwiKTtcblxuICAgICAgbGVuZ3RoID0gaTtcbiAgICAgIHBzeisrO1xuICAgIH1cbiAgICAvLyBTa2lwIGxlYWRpbmcgemVyb2VzIGluIGIyNTYuXG4gICAgbGV0IGl0NCA9IHNpemUgLSBsZW5ndGg7XG4gICAgd2hpbGUgKGl0NCAhPT0gc2l6ZSAmJiBiMjU2W2l0NF0gPT09IDApIGl0NCsrO1xuXG4gICAgY29uc3QgdmNoID0gbmV3IFVpbnQ4QXJyYXkoemVyb2VzICsgKHNpemUgLSBpdDQpKTtcbiAgICBsZXQgaiA9IHplcm9lcztcbiAgICB3aGlsZSAoaXQ0ICE9PSBzaXplKSB2Y2hbaisrXSA9IGIyNTZbaXQ0KytdO1xuXG4gICAgcmV0dXJuIHZjaDtcbiAgfVxuXG4gIGRlY29kZShzb3VyY2U6IHN0cmluZykge1xuICAgIGNvbnN0IGJ1ZmZlciA9IHRoaXMuZGVjb2RlVW5zYWZlKHNvdXJjZSk7XG4gICAgaWYgKGJ1ZmZlcikgcmV0dXJuIGJ1ZmZlcjtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJOb24tYmFzZVwiICsgdGhpcy5iYXNlICsgXCIgY2hhcmFjdGVyXCIpO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBDcnlwdG9VdGlscyB7XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IGI1OGVuY29kZXIgPSBuZXcgQmFzZUVuY29kZXIoQkFTRV9BTFBIQUJFVC5CQVNFNTgpO1xuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBsb2dnZXIgPSBuZXcgTWluaUxvZ2dlcihDcnlwdG9VdGlscy5uYW1lKTtcbiAgcHJpdmF0ZSBjb25zdHJ1Y3RvcigpIHt9XG5cbiAgc3RhdGljIGZhYnJpY0lkRnJvbUNlcnRpZmljYXRlKGNlcnRpZmljYXRlOiBzdHJpbmcpIHtcbiAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhzdHJpbmdGb3JtYXQoXCJQYXJzaW5nIGNlcnRpZmljYXRlOiB7MH1cIiwgY2VydGlmaWNhdGUpKTtcbiAgICBjb25zdCBjZXJ0ID0gbmV3IHg1MDkuWDUwOUNlcnRpZmljYXRlKGNlcnRpZmljYXRlKTtcbiAgICBjb25zdCB7IHN1YmplY3QsIGlzc3VlciB9ID0gY2VydDtcbiAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcbiAgICAgIHN0cmluZ0Zvcm1hdChcbiAgICAgICAgXCJDZXJ0aWZpY2F0ZSBwYXJzZWQgd2l0aCBzdWJqZWN0IHswfSBhbmQgaXNzdWVyIHsxfVwiLFxuICAgICAgICBzdWJqZWN0LFxuICAgICAgICBpc3N1ZXJcbiAgICAgIClcbiAgICApO1xuICAgIHJldHVybiBgeDUwOTo6LyR7c3ViamVjdC5yZXBsYWNlQWxsKFwiLCBcIiwgXCIvXCIpfTo6LyR7aXNzdWVyLnJlcGxhY2VBbGwoXCIsIFwiLCBcIi9cIil9YDtcbiAgfVxuXG4gIHN0YXRpYyBlbmNvZGUoc3RyOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmI1OGVuY29kZXIuZW5jb2RlKHN0cik7XG4gIH1cbiAgc3RhdGljIGRlY29kZShzdHI6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgZGVjb2RlZCA9IHRoaXMuYjU4ZW5jb2Rlci5kZWNvZGUoc3RyKTtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoZGVjb2RlZCk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHN0YXRpYyBzdHJpbmdUb0FycmF5QnVmZmVyKHN0cjogc3RyaW5nKSB7XG4gICAgY29uc3QgYnVmID0gbmV3IEFycmF5QnVmZmVyKHN0ci5sZW5ndGgpO1xuICAgIGNvbnN0IGJ1ZlZpZXcgPSBuZXcgVWludDhBcnJheShidWYpO1xuICAgIGZvciAobGV0IGkgPSAwLCBzdHJMZW4gPSBzdHIubGVuZ3RoOyBpIDwgc3RyTGVuOyBpKyspIHtcbiAgICAgIGJ1ZlZpZXdbaV0gPSBzdHIuY2hhckNvZGVBdChpKTtcbiAgICB9XG4gICAgcmV0dXJuIGJ1ZjtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGFzeW5jIGV4dHJhY3RLZXkoXG4gICAgdHlwZTogXCJwcml2YXRlXCIgfCBcInB1YmxpY1wiLFxuICAgIHBlbTogQnVmZmVyIHwgc3RyaW5nLFxuICAgIHVzYWdlcz86IGFueVtdXG4gICkge1xuICAgIGNvbnN0IHN1YnRsZSA9IGNyeXB0by5zdWJ0bGU7XG5cbiAgICBjb25zdCBzdHIgPSBwZW1cbiAgICAgIC50b1N0cmluZyhcInV0ZjhcIilcbiAgICAgIC5yZXBsYWNlKFxuICAgICAgICBuZXcgUmVnRXhwKGAtLS0tLUJFR0lOICgke3R5cGUudG9VcHBlckNhc2UoKX0gS0VZfENFUlRJRklDQVRFKS0tLS0tYCksXG4gICAgICAgIFwiXCJcbiAgICAgIClcbiAgICAgIC5yZXBsYWNlQWxsKFwiXFxuXCIsIFwiXCIpXG4gICAgICAucmVwbGFjZShcbiAgICAgICAgbmV3IFJlZ0V4cChgLS0tLS1FTkQgKCR7dHlwZS50b1VwcGVyQ2FzZSgpfSBLRVl8Q0VSVElGSUNBVEUpLS0tLS1gKSxcbiAgICAgICAgXCJcIlxuICAgICAgKTtcbiAgICBjb25zdCBkZWNvZGVkID0gQnVmZmVyLmZyb20oc3RyLCBcImJhc2U2NFwiKS50b1N0cmluZyhcImJpbmFyeVwiKTtcbiAgICBjb25zdCBiaW5hcnlEZXIgPSB0aGlzLnN0cmluZ1RvQXJyYXlCdWZmZXIoZGVjb2RlZCk7XG4gICAgY29uc3Qga2V5ID0gYXdhaXQgc3VidGxlLmltcG9ydEtleShcbiAgICAgIFwicGtjczhcIixcbiAgICAgIGJpbmFyeURlcixcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJFQ0RTQVwiLFxuICAgICAgICBuYW1lZEN1cnZlOiBcIlAtMjU2XCIsXG4gICAgICB9LFxuICAgICAgdHJ1ZSxcbiAgICAgIHVzYWdlcyA/IHVzYWdlcyA6IFtcInNpZ25cIl1cbiAgICApO1xuXG4gICAgcmV0dXJuIGtleTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBleHRyYWN0UHJpdmF0ZUtleShwZW06IEJ1ZmZlciB8IHN0cmluZywgdXNhZ2VzPzogYW55W10pIHtcbiAgICByZXR1cm4gdGhpcy5leHRyYWN0S2V5KFwicHJpdmF0ZVwiLCBwZW0sIHVzYWdlcyk7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgZXh0cmFjdFB1YmxpY0tleShwZW06IEJ1ZmZlciB8IHN0cmluZywgdXNhZ2VzPzogYW55W10pIHtcbiAgICByZXR1cm4gdGhpcy5leHRyYWN0S2V5KFwicHVibGljXCIsIHBlbSwgdXNhZ2VzKTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBzaWduKHByaXZhdGVLZXk6IHN0cmluZywgZGF0YTogQnVmZmVyKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBrZXkgPSBhd2FpdCB0aGlzLmV4dHJhY3RQcml2YXRlS2V5KHByaXZhdGVLZXkpO1xuICAgIGNvbnN0IGJ1ZmYgPSAoYXdhaXQgY3J5cHRvLnN1YnRsZS5zaWduKFxuICAgICAge1xuICAgICAgICBuYW1lOiBcIkVDRFNBXCIsXG4gICAgICAgIGhhc2g6IFwiU0hBLTI1NlwiLFxuICAgICAgfSxcbiAgICAgIGtleSxcbiAgICAgIGRhdGFcbiAgICApKSBhcyBBcnJheUJ1ZmZlcjtcblxuICAgIHJldHVybiBBcnJheS5mcm9tKG5ldyBVaW50OEFycmF5KGJ1ZmYpKVxuICAgICAgLm1hcCgoYikgPT4gYi50b1N0cmluZygxNikucGFkU3RhcnQoMiwgXCIwXCIpKVxuICAgICAgLmpvaW4oXCJcIik7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgdmVyaWZ5KFxuICAgIGNlcnRpZmljYXRlOiBzdHJpbmcsXG4gICAgc2lnbmF0dXJlOiBCdWZmZXIgfCBzdHJpbmcsXG4gICAgZGF0YTogQnVmZmVyIHwgc3RyaW5nXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGNlcnQgPSBuZXcgeDUwOS5YNTA5Q2VydGlmaWNhdGUoY2VydGlmaWNhdGUpO1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IGNlcnQucHVibGljS2V5LmV4cG9ydCgpO1xuICAgIHNpZ25hdHVyZSA9IChcbiAgICAgIHR5cGVvZiBzaWduYXR1cmUgPT09IFwic3RyaW5nXCIgPyBCdWZmZXIuZnJvbShzaWduYXR1cmUsIFwiaGV4XCIpIDogc2lnbmF0dXJlXG4gICAgKSBhcyBCdWZmZXI7XG4gICAgZGF0YSA9ICh0eXBlb2YgZGF0YSA9PT0gXCJzdHJpbmdcIiA/IEJ1ZmZlci5mcm9tKGRhdGEpIDogZGF0YSkgYXMgQnVmZmVyO1xuICAgIHJldHVybiBjcnlwdG8uc3VidGxlLnZlcmlmeShcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJFQ0RTQVwiLFxuICAgICAgICBoYXNoOiBcIlNIQS0yNTZcIixcbiAgICAgIH0sXG4gICAgICBrZXksXG4gICAgICBzaWduYXR1cmUsXG4gICAgICBkYXRhXG4gICAgKTtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBlbmNyeXB0KGNlcnRpZmljYXRlOiBzdHJpbmcsIGRhdGE6IHN0cmluZyB8IEJ1ZmZlcikge1xuICAgIGNvbnN0IGNlcnQgPSBuZXcgeDUwOS5YNTA5Q2VydGlmaWNhdGUoY2VydGlmaWNhdGUpO1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IGNlcnQucHVibGljS2V5LmV4cG9ydCgpO1xuICAgIGRhdGEgPSAodHlwZW9mIGRhdGEgPT09IFwic3RyaW5nXCIgPyBCdWZmZXIuZnJvbShkYXRhKSA6IGRhdGEpIGFzIEJ1ZmZlcjtcbiAgICBjb25zdCBidWZmID0gYXdhaXQgdGhpcy5nZXRTdWJ0bGVDcnlwdG8oKS5lbmNyeXB0KFxuICAgICAge1xuICAgICAgICBuYW1lOiBcIkVDRFNBXCIsXG4gICAgICB9LFxuICAgICAga2V5LFxuICAgICAgZGF0YVxuICAgICk7XG5cbiAgICByZXR1cm4gQXJyYXkuZnJvbShuZXcgVWludDhBcnJheShidWZmKSlcbiAgICAgIC5tYXAoKGIpID0+IGIudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsIFwiMFwiKSlcbiAgICAgIC5qb2luKFwiXCIpO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0U3VidGxlQ3J5cHRvKCkge1xuICAgIHJldHVybiBpc0Jyb3dzZXIoKVxuICAgICAgPyAoZ2xvYmFsVGhpcyBhcyBhbnkpLndpbmRvdy5jcnlwdG8uc3VidGxlXG4gICAgICA6IGNyeXB0by5zdWJ0bGU7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgZGVjcnlwdChwcml2YXRlS2V5OiBzdHJpbmcsIGRhdGE6IHN0cmluZyB8IEJ1ZmZlcikge1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IHRoaXMuZXh0cmFjdFByaXZhdGVLZXkocHJpdmF0ZUtleSk7XG4gICAgZGF0YSA9IChcbiAgICAgIHR5cGVvZiBkYXRhID09PSBcInN0cmluZ1wiID8gQnVmZmVyLmZyb20oZGF0YSwgXCJoZXhcIikgOiBkYXRhXG4gICAgKSBhcyBCdWZmZXI7XG4gICAgcmV0dXJuIHRoaXMuZ2V0U3VidGxlQ3J5cHRvKCkuZGVjcnlwdChcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJFQ0RTQVwiLFxuICAgICAgfSxcbiAgICAgIGtleSxcbiAgICAgIGRhdGFcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gZ2V0IGEgcmFuZG9tIG1hc3RlciBrZXlcbiAgICpcbiAgICogQGRlc2NyaXB0aW9uIElmIGRhdGEgaXMgbm90IHBhc3NlZCwgYSByYW5kb20gQXJyYXlCdWZmZXIgd2lsbCBiZSBnZW5lcmF0ZWRcbiAgICpcbiAgICogQHBhcmFtIHtBcnJheUJ1ZmZlcn0gZGF0YSBlbmNyeXRpb24gZGF0YVxuICAgKlxuICAgKiBAZnVuY3Rpb24gZ2V0TWFzdGVyXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2V0TWFzdGVyKGRhdGE/OiBBcnJheUJ1ZmZlcik6IFByb21pc2U8a2V5T2JqZWN0PiB7XG4gICAgY29uc3QgdGV4dEVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKTtcbiAgICBpZiAoZGF0YSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBnZW5HZW5lc2lzID0gY3J5cHRvLnJhbmRvbVVVSUQoKTtcbiAgICAgIGRhdGEgPSB0ZXh0RW5jb2Rlci5lbmNvZGUoZ2VuR2VuZXNpcykuYnVmZmVyO1xuICAgIH1cblxuICAgIGNvbnN0IGltcG9ydGVkS2V5ID0gYXdhaXQgdGhpcy5nZXRTdWJ0bGVDcnlwdG8oKS5pbXBvcnRLZXkoXG4gICAgICBcInJhd1wiLFxuICAgICAgZGF0YSxcbiAgICAgIENSWVBUTy5LRVlfQUxHT1JZVEhNIGFzIHN0cmluZyxcbiAgICAgIGZhbHNlLFxuICAgICAgW1wiZGVyaXZlQml0c1wiXVxuICAgICk7XG5cbiAgICByZXR1cm4ge1xuICAgICAga2V5OiBpbXBvcnRlZEtleSxcbiAgICAgIGl2OiBkYXRhISxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gZGVyaXZlIGEga2V5IGZyb20gYW5vdGhlciBrZXlcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNhbHRcbiAgICogQHBhcmFtIHtDcnlwdG9LZXl9IGtleSBPcmlnaW5hbCBrZXlcbiAgICpcbiAgICogQGZ1bmN0aW9uIGdldERlcml2YXRpb25LZXlcbiAgICovXG4gIHN0YXRpYyBhc3luYyBnZXREZXJpdmF0aW9uS2V5KHNhbHQ6IHN0cmluZywga2V5OiBDcnlwdG9LZXkpIHtcbiAgICBjb25zdCB0ZXh0RW5jb2RlciA9IG5ldyBUZXh0RW5jb2RlcigpO1xuICAgIGNvbnN0IHNhbHRCdWZmZXIgPSB0ZXh0RW5jb2Rlci5lbmNvZGUoc2FsdCk7XG4gICAgY29uc3Qgc2FsdEhhc2hlZCA9IGF3YWl0IHRoaXMuZ2V0U3VidGxlQ3J5cHRvKCkuZGlnZXN0KFxuICAgICAgXCJTSEEtMjU2XCIsXG4gICAgICBzYWx0QnVmZmVyXG4gICAgKTtcbiAgICBjb25zdCBwYXJhbXMgPSB7XG4gICAgICBuYW1lOiBDUllQVE8uS0VZX0FMR09SWVRITSBhcyBzdHJpbmcsXG4gICAgICBoYXNoOiBDUllQVE8uSEFTSCxcbiAgICAgIHNhbHQ6IHNhbHRIYXNoZWQsXG4gICAgICBpdGVyYXRpb25zOiBDUllQVE8uSVRFUkFUSU9OUyxcbiAgICB9O1xuICAgIGNvbnN0IGRlcml2YXRpb24gPSBhd2FpdCB0aGlzLmdldFN1YnRsZUNyeXB0bygpLmRlcml2ZUJpdHMoXG4gICAgICBwYXJhbXMsXG4gICAgICBrZXksXG4gICAgICBDUllQVE8uS0VZTEVOR1RIICogOFxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuZ2V0S2V5KGRlcml2YXRpb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gZ2V0IHRoZSBrZXkgYW5kIElWIGZyb20gdGhlIENyeXRvS2V5IGFycmF5XG4gICAqXG4gICAqIEBwYXJhbSB7QXJyYXlCdWZmZXJ9IGRlcml2YXRpb25cbiAgICpcbiAgICogQGZ1bmN0aW9uIGdldEtleVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGdldEtleShkZXJpdmF0aW9uOiBBcnJheUJ1ZmZlcikge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBjb25zdCBpdmxlbiA9IDE2O1xuICAgIGNvbnN0IGtleWxlbiA9IDMyO1xuICAgIGNvbnN0IGRlcml2ZWRLZXkgPSBkZXJpdmF0aW9uLnNsaWNlKDAsIGtleWxlbik7XG4gICAgY29uc3QgaXYgPSBkZXJpdmF0aW9uLnNsaWNlKGtleWxlbik7XG4gICAgY29uc3QgaW1wb3J0ZWRFbmNyeXB0aW9uS2V5ID0gYXdhaXQgdGhpcy5nZXRTdWJ0bGVDcnlwdG8oKS5pbXBvcnRLZXkoXG4gICAgICBcInJhd1wiLFxuICAgICAgZGVyaXZlZEtleSxcbiAgICAgIHsgbmFtZTogQ1JZUFRPLkFMR09SWVRITSBhcyBzdHJpbmcgfSxcbiAgICAgIGZhbHNlLFxuICAgICAgW1wiZW5jcnlwdFwiLCBcImRlY3J5cHRcIl1cbiAgICApO1xuICAgIHJldHVybiB7XG4gICAgICBrZXk6IGltcG9ydGVkRW5jcnlwdGlvbktleSxcbiAgICAgIGl2OiBpdixcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFV0aWwgZnVuY3Rpb24gdG8gZGVjcnlwdCBkYXRhXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0XG4gICAqIEBwYXJhbSB7a2V5T2JqZWN0fSBrZXlPYmplY3RcbiAgICpcbiAgICogQGZ1bmN0aW9uIGVuY3J5cHRcbiAgICovXG4gIHN0YXRpYyBhc3luYyBlbmNyeXB0UGluKFxuICAgIHRleHQ6IHN0cmluZyxcbiAgICBrZXlPYmplY3Q6IGtleU9iamVjdFxuICApOiBQcm9taXNlPEFycmF5QnVmZmVyPiB7XG4gICAgY29uc3QgdGV4dEVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKTtcbiAgICBjb25zdCB0ZXh0QnVmZmVyID0gdGV4dEVuY29kZXIuZW5jb2RlKHRleHQpO1xuICAgIGNvbnN0IGVuY3J5cHRlZFRleHQgPSBhd2FpdCB0aGlzLmdldFN1YnRsZUNyeXB0bygpLmVuY3J5cHQoXG4gICAgICB7IG5hbWU6IENSWVBUTy5BTEdPUllUSE0gYXMgc3RyaW5nLCBpdjoga2V5T2JqZWN0Lml2IH0sXG4gICAgICBrZXlPYmplY3Qua2V5LFxuICAgICAgdGV4dEJ1ZmZlclxuICAgICk7XG4gICAgcmV0dXJuIGVuY3J5cHRlZFRleHQ7XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgVXRpbCBmdW5jdGlvbiB0byBkZWNyeXB0IGRhdGFcbiAgICpcbiAgICogQHBhcmFtIHtCdWZmZXJTb3VyY2V9IGVuY3J5cHRlZFRleHRcbiAgICogQHBhcmFtIHtrZXlPYmplY3R9IGtleU9iamVjdFxuICAgKlxuICAgKiBAZnVuY3Rpb24gZGVjcnlwdFxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGRlY3J5cHRQaW4oXG4gICAgZW5jcnlwdGVkVGV4dDogQXJyYXlCdWZmZXIsXG4gICAga2V5T2JqZWN0OiBrZXlPYmplY3RcbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB0ZXh0RGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlcigpO1xuICAgIGNvbnN0IGRlY3J5cHRlZFRleHQgPSBhd2FpdCB0aGlzLmdldFN1YnRsZUNyeXB0bygpLmRlY3J5cHQoXG4gICAgICB7IG5hbWU6IENSWVBUTy5BTEdPUllUSE0gYXMgc3RyaW5nLCBpdjoga2V5T2JqZWN0Lml2IH0sXG4gICAgICBrZXlPYmplY3Qua2V5LFxuICAgICAgZW5jcnlwdGVkVGV4dFxuICAgICk7XG4gICAgcmV0dXJuIHRleHREZWNvZGVyLmRlY29kZShkZWNyeXB0ZWRUZXh0KTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgQmFzZUVycm9yLCBJbnRlcm5hbEVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBBdXRob3JpemF0aW9uRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbi8vIGltcG9ydCB7IE1JU1NJTkdfUFJJVkFURV9EQVRBX0VSUk9SX01FU1NBR0UgfSBmcm9tIFwiLi4vY29udHJhY3RzL3ByaXZhdGUtZGF0YVwiO1xuLyoqXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGFuIG92ZXJmbG93IGVycm9yIGluIGFyaXRobWV0aWMgb3BlcmF0aW9ucyBpbiBTbWFydCBDb250cmFjdHNcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbXNnIHRoZSBlcnJvciBtZXNzYWdlXG4gKlxuICogQGNsYXNzIE92ZXJmbG93RXJyb3JcbiAqIEBleHRlbmRzIEludGVybmFsRXJyb3JcbiAqXG4gKiBAY2F0ZWdvcnkgRXJyb3JzXG4gKi9cbmV4cG9ydCBjbGFzcyBPdmVyZmxvd0Vycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIE92ZXJmbG93RXJyb3IubmFtZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGEgZmFpbHVyZSBpbiBiYWxhbmNlIHRvIHBlcmZvcm0gYSB0cmFuc2FjdGlvbiBpbiBTbWFydCBDb250cmFjdHNcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbXNnIHRoZSBlcnJvciBtZXNzYWdlXG4gKlxuICogQGNsYXNzIEJhbGFuY2VFcnJvclxuICogQGV4dGVuZHMgSW50ZXJuYWxFcnJvclxuICpcbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIEJhbGFuY2VFcnJvciBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBCYWxhbmNlRXJyb3IubmFtZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGEgZmFpbHVyZSBpbiBiYWxhbmNlIHRvIHBlcmZvcm0gYSB0cmFuc2FjdGlvbiBpbiBTbWFydCBDb250cmFjdHNcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbXNnIHRoZSBlcnJvciBtZXNzYWdlXG4gKlxuICogQGNsYXNzIEJhbGFuY2VFcnJvclxuICogQGV4dGVuZHMgSW50ZXJuYWxFcnJvclxuICpcbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIEFsbG93YW5jZUVycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIEFsbG93YW5jZUVycm9yLm5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBhIGZhaWx1cmUgcmVnaXN0cmF0aW5nIG5ldyBlbnRpdGllc1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBtc2cgdGhlIGVycm9yIG1lc3NhZ2VcbiAqXG4gKiBAY2xhc3MgUmVnaXN0cmF0aW9uRXJyb3JcbiAqXG4gKiBAY2F0ZWdvcnQgRXJyb3JzXG4gKi9cbmV4cG9ydCBjbGFzcyBSZWdpc3RyYXRpb25FcnJvciBleHRlbmRzIEF1dGhvcml6YXRpb25FcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIFJlZ2lzdHJhdGlvbkVycm9yLm5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVycm9yIHRocm93biB3aGVuIGFuIHVuc3VwcG9ydGVkIG9wZXJhdGlvbiBpcyBhdHRlbXB0ZWRcbiAqIEBzdW1tYXJ5IFRoaXMgZXJyb3IgaXMgdGhyb3duIHdoZW4gYW4gb3BlcmF0aW9uIGlzIHJlcXVlc3RlZCB0aGF0IGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGN1cnJlbnRcbiAqIHBlcnNpc3RlbmNlIGFkYXB0ZXIgb3IgY29uZmlndXJhdGlvbi4gSXQgZXh0ZW5kcyB0aGUgQmFzZUVycm9yIGNsYXNzIGFuZCBzZXRzIGEgNTAwIHN0YXR1cyBjb2RlLlxuICogQHBhcmFtIHtzdHJpbmd8RXJyb3J9IG1zZyAtIFRoZSBlcnJvciBtZXNzYWdlIG9yIGFuIEVycm9yIG9iamVjdCB0byB3cmFwXG4gKiBAY2xhc3MgVW5zdXBwb3J0ZWRFcnJvclxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIFRocm93aW5nIGFuIFVuc3VwcG9ydGVkRXJyb3JcbiAqIGlmICghYWRhcHRlci5zdXBwb3J0c1RyYW5zYWN0aW9ucygpKSB7XG4gKiAgIHRocm93IG5ldyBVbnN1cHBvcnRlZEVycm9yKCdUcmFuc2FjdGlvbnMgYXJlIG5vdCBzdXBwb3J0ZWQgYnkgdGhpcyBhZGFwdGVyJyk7XG4gKiB9XG4gKlxuICogLy8gQ2F0Y2hpbmcgYW4gVW5zdXBwb3J0ZWRFcnJvclxuICogdHJ5IHtcbiAqICAgYXdhaXQgYWRhcHRlci5iZWdpblRyYW5zYWN0aW9uKCk7XG4gKiB9IGNhdGNoIChlcnJvcikge1xuICogICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBVbnN1cHBvcnRlZEVycm9yKSB7XG4gKiAgICAgY29uc29sZS5lcnJvcignT3BlcmF0aW9uIG5vdCBzdXBwb3J0ZWQ6JywgZXJyb3IubWVzc2FnZSk7XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIE1pc3NpbmdDb250ZXh0RXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1zZywgTWlzc2luZ0NvbnRleHRFcnJvci5uYW1lLCA1MDApO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBVbmF1dGhvcml6ZWRQcml2YXRlRGF0YUFjY2VzcyBleHRlbmRzIEJhc2VFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IgPSBcIk1JU1NJTkdfUFJJVkFURV9EQVRBX0VSUk9SX01FU1NBR0VcIikge1xuICAgIHN1cGVyKFVuYXV0aG9yaXplZFByaXZhdGVEYXRhQWNjZXNzLm5hbWUsIG1zZywgNDAzKTtcbiAgfVxufVxuXG4vKipcbiAqIFJlcHJlc2VudHMgYW4gZXJyb3IgdGhhdCBvY2N1cnMgd2hlbiBhIHJlcXVpcmVkIGluaXRpYWxpemF0aW9uIHN0ZXAgaXMgbm90IHBlcmZvcm1lZC5cbiAqXG4gKiBAY2xhc3MgTm90SW5pdGlhbGl6ZWRFcnJvclxuICogQGV4dGVuZHMgQmFzZUVycm9yXG4gKlxuICogQGNhdGVnb3J5IEVycm9yc1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nIHwgRXJyb3J9IG1zZyAtIFRoZSBlcnJvciBtZXNzYWdlIG9yIGFuIEVycm9yIG9iamVjdCB0byB3cmFwLlxuICpcbiAqIEB0aHJvd3Mge05vdEluaXRpYWxpemVkRXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIHdoZW4gYSByZXF1aXJlZCBpbml0aWFsaXphdGlvbiBzdGVwIGlzIG5vdCBwZXJmb3JtZWQuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIEluaXRpYWxpemUgdGhlIGFwcGxpY2F0aW9uXG4gKiBpZiAoIWlzSW5pdGlhbGl6ZWQpIHtcbiAqICAgdGhyb3cgbmV3IE5vdEluaXRpYWxpemVkRXJyb3IoJ0FwcGxpY2F0aW9uIGlzIG5vdCBpbml0aWFsaXplZCcpO1xuICogfVxuICpcbiAqIC8vIENhdGNoaW5nIGFuIE5vdEluaXRpYWxpemVkRXJyb3JcbiAqIHRyeSB7XG4gKiAgIC8vIFBlcmZvcm0gb3BlcmF0aW9ucyB0aGF0IHJlcXVpcmUgaW5pdGlhbGl6YXRpb25cbiAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gKiAgIGlmIChlcnJvciBpbnN0YW5jZW9mIE5vdEluaXRpYWxpemVkRXJyb3IpIHtcbiAqICAgICBjb25zb2xlLmVycm9yKCdJbml0aWFsaXphdGlvbiBlcnJvcjonLCBlcnJvci5tZXNzYWdlKTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBOb3RJbml0aWFsaXplZEVycm9yIGV4dGVuZHMgQmFzZUVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKE5vdEluaXRpYWxpemVkRXJyb3IubmFtZSwgbXNnLCA0MDkpO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBNaXNzaW5nUEtDU1MxMUxpYiBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBNaXNzaW5nUEtDU1MxMUxpYi5uYW1lLCA1MDApO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBFbmRvcnNlbWVudEVycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobWVzc2FnZSwgRW5kb3JzZW1lbnRFcnJvci5uYW1lLCA1MDApO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBNdmNjUmVhZENvbmZsaWN0RXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtZXNzYWdlLCBNdmNjUmVhZENvbmZsaWN0RXJyb3IubmFtZSwgNTAwKTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgUGhhbnRvbVJlYWRDb25mbGljdEVycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobWVzc2FnZSwgUGhhbnRvbVJlYWRDb25mbGljdEVycm9yLm5hbWUsIDUwMCk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIEVuZG9yc2VtZW50UG9saWN5RXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtZXNzYWdlLCBFbmRvcnNlbWVudFBvbGljeUVycm9yLm5hbWUsIDUwMCk7XG4gIH1cbn1cbiIsImltcG9ydCBGYWJyaWNDQVNlcnZpY2VzIGZyb20gXCJmYWJyaWMtY2EtY2xpZW50XCI7XG5pbXBvcnQge1xuICBBZmZpbGlhdGlvblNlcnZpY2UsXG4gIElkZW50aXR5U2VydmljZSxcbiAgSUVucm9sbFJlc3BvbnNlLFxuICBJUmVnaXN0ZXJSZXF1ZXN0LFxuICBJU2VydmljZVJlc3BvbnNlLFxuICBUTFNPcHRpb25zLFxufSBmcm9tIFwiZmFicmljLWNhLWNsaWVudFwiO1xuaW1wb3J0IHsgVXNlciB9IGZyb20gXCJmYWJyaWMtY29tbW9uXCI7XG5pbXBvcnQgeyBDQUNvbmZpZywgQ3JlZGVudGlhbHMgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL3R5cGVzXCI7XG5pbXBvcnQgeyBJZGVudGl0eSB9IGZyb20gXCIuLi8uLi9zaGFyZWQvbW9kZWwvSWRlbnRpdHlcIjtcbmltcG9ydCB7IEF1dGhvcml6YXRpb25FcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHtcbiAgQ29uZmxpY3RFcnJvcixcbiAgSW50ZXJuYWxFcnJvcixcbiAgTm90Rm91bmRFcnJvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDb3JlVXRpbHMgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IENBX1JPTEUgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IENyeXB0b1V0aWxzIH0gZnJvbSBcIi4uL2NyeXB0b1wiO1xuaW1wb3J0IHtcbiAgQ2VydGlmaWNhdGVSZXNwb25zZSxcbiAgRmFicmljSWRlbnRpdHksXG4gIEdldENlcnRpZmljYXRlc1JlcXVlc3QsXG4gIElkZW50aXR5UmVzcG9uc2UsXG59IGZyb20gXCIuLi8uLi9zaGFyZWQvZmFicmljLXR5cGVzXCI7XG5pbXBvcnQgeyBSZWdpc3RyYXRpb25FcnJvciB9IGZyb20gXCIuLi8uLi9zaGFyZWQvZXJyb3JzXCI7XG5pbXBvcnQgeyBMb2dnZWRDbGFzcywgTG9nZ2luZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBIeXBlcmxlZGdlciBGYWJyaWMgQ0EgaWRlbnRpdHkgdHlwZXMuXG4gKiBAc3VtbWFyeSBFbnVtZXJhdGVzIHRoZSBzdXBwb3J0ZWQgaWRlbnRpdHkgdHlwZXMgcmVjb2duaXplZCBieSBGYWJyaWMgQ0EgZm9yIHJlZ2lzdHJhdGlvbiBhbmQgaWRlbnRpdHkgbWFuYWdlbWVudC5cbiAqIEBlbnVtIHtzdHJpbmd9XG4gKiBAcmVhZG9ubHlcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGVudW0gSEZDQUlkZW50aXR5VHlwZSB7XG4gIFBFRVIgPSBcInBlZXJcIixcbiAgT1JERVJFUiA9IFwib3JkZXJlclwiLFxuICBDTElFTlQgPSBcImNsaWVudFwiLFxuICBVU0VSID0gXCJ1c2VyXCIsXG4gIEFETUlOID0gXCJhZG1pblwiLFxufVxuLyoqXG4gKiBAZGVzY3JpcHRpb24gS2V5L3ZhbHVlIGF0dHJpYnV0ZSB1c2VkIGR1cmluZyBDQSByZWdpc3RyYXRpb24uXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGFuIGF0dHJpYnV0ZSBlbnRyeSB0aGF0IGNhbiBiZSBhdHRhY2hlZCB0byBhIEZhYnJpYyBDQSBpZGVudGl0eSBkdXJpbmcgcmVnaXN0cmF0aW9uLCBvcHRpb25hbGx5IG1hcmtpbmcgaXQgZm9yIGluY2x1c2lvbiBpbiBlY2VydC5cbiAqIEBpbnRlcmZhY2UgSUtleVZhbHVlQXR0cmlidXRlXG4gKiBAdGVtcGxhdGUgVFxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBBdHRyaWJ1dGUgbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIEF0dHJpYnV0ZSB2YWx1ZS5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2VjZXJ0XSAtIFdoZXRoZXIgdGhlIGF0dHJpYnV0ZSBzaG91bGQgYmUgaW5jbHVkZWQgaW4gdGhlIGVucm9sbG1lbnQgY2VydGlmaWNhdGUgKEVDZXJ0KS5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJS2V5VmFsdWVBdHRyaWJ1dGUge1xuICBuYW1lOiBzdHJpbmc7XG4gIHZhbHVlOiBzdHJpbmc7XG4gIGVjZXJ0PzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU3RhbmRhcmQgRmFicmljIENBIGlkZW50aXR5IGF0dHJpYnV0ZSBrZXlzLlxuICogQHN1bW1hcnkgRW51bWVyYXRlcyB3ZWxsLWtub3duIEZhYnJpYyBDQSBhdHRyaWJ1dGUga2V5cyB0aGF0IGNhbiBiZSBhc3NpZ25lZCB0byBpZGVudGl0aWVzIGZvciBkZWxlZ2F0aW9ucyBhbmQgcGVybWlzc2lvbnMuXG4gKiBAZW51bSB7c3RyaW5nfVxuICogQHJlYWRvbmx5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuY2xpZW50XG4gKi9cbmV4cG9ydCBlbnVtIEhGQ0FJZGVudGl0eUF0dHJpYnV0ZXMge1xuICBIRlJFR0lTVFJBUlJPTEVTID0gXCJoZi5SZWdpc3RyYXIuUm9sZXNcIixcbiAgSEZSRUdJU1RSQVJERUxFR0FURVJPTEVTID0gXCJoZi5SZWdpc3RyYXIuRGVsZWdhdGVSb2xlc1wiLFxuICBIRlJFR0lTVFJBUkFUVFJJQlVURVMgPSBcImhmLlJlZ2lzdHJhci5BdHRyaWJ1dGVzXCIsXG4gIEhGSU5URVJNRURJQVRFQ0EgPSBcImhmLkludGVybWVkaWF0ZUNBXCIsXG4gIEhGUkVWT0tFUiA9IFwiaGYuUmV2b2tlclwiLFxuICBIRkFGRklMSUFUSU9OTUdSID0gXCJoZi5BZmZpbGlhdGlvbk1nclwiLFxuICBIRkdFTkNSTCA9IFwiaGYuR2VuQ1JMXCIsXG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFNlcnZpY2Ugd3JhcHBlciBmb3IgaW50ZXJhY3Rpbmcgd2l0aCBhIEZhYnJpYyBDQS5cbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIGhpZ2gtbGV2ZWwgb3BlcmF0aW9ucyBmb3IgbWFuYWdpbmcgaWRlbnRpdGllcyBhZ2FpbnN0IGEgSHlwZXJsZWRnZXIgRmFicmljIENlcnRpZmljYXRlIEF1dGhvcml0eSwgaW5jbHVkaW5nIHJlZ2lzdHJhdGlvbiwgZW5yb2xsbWVudCwgcmV2b2NhdGlvbiwgYW5kIGFkbWluaXN0cmF0aXZlIHF1ZXJpZXMuIEVuY2Fwc3VsYXRlcyBsb3dlci1sZXZlbCBGYWJyaWMgQ0EgY2xpZW50IGNhbGxzIHdpdGggY29uc2lzdGVudCBsb2dnaW5nIGFuZCBlcnJvciBtYXBwaW5nLlxuICogQHBhcmFtIHtDQUNvbmZpZ30gY2FDb25maWcgLSBDb25uZWN0aW9uIGFuZCBUTFMgY29uZmlndXJhdGlvbiBmb3IgdGhlIHRhcmdldCBDQS5cbiAqIEBjbGFzcyBGYWJyaWNFbnJvbGxtZW50U2VydmljZVxuICogQGV4YW1wbGVcbiAqIC8vIFJlZ2lzdGVyIGFuZCBlbnJvbGwgYSBuZXcgdXNlclxuICogY29uc3Qgc3ZjID0gbmV3IEZhYnJpY0Vucm9sbG1lbnRTZXJ2aWNlKHtcbiAqICAgdXJsOiAnaHR0cHM6Ly9sb2NhbGhvc3Q6NzA1NCcsXG4gKiAgIGNhTmFtZTogJ09yZzFDQScsXG4gKiAgIHRsczogeyB0cnVzdGVkUm9vdHM6IFsnL3BhdGgvdG8vY2EucGVtJ10sIHZlcmlmeTogZmFsc2UgfSxcbiAqICAgY2FDZXJ0OiAnL3BhdGgvdG8vYWRtaW4vY2VydERpcicsXG4gKiAgIGNhS2V5OiAnL3BhdGgvdG8vYWRtaW4va2V5RGlyJ1xuICogfSk7XG4gKiBhd2FpdCBzdmMucmVnaXN0ZXIoeyB1c2VyTmFtZTogJ2FsaWNlJywgcGFzc3dvcmQ6ICdzM2NyM3QnIH0sIGZhbHNlLCAnb3JnMS5kZXBhcnRtZW50MScsIENBX1JPTEUuVVNFUik7XG4gKiBjb25zdCBpZCA9IGF3YWl0IHN2Yy5lbnJvbGwoJ2FsaWNlJywgJ3MzY3IzdCcpO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBhdXRvbnVtYmVyXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBTdmMgYXMgRmFicmljRW5yb2xsbWVudFNlcnZpY2VcbiAqICAgcGFydGljaXBhbnQgQ0EgYXMgRmFicmljIENBXG4gKiAgIEFwcC0+PlN2YzogcmVnaXN0ZXIoY3JlZGVudGlhbHMsIC4uLilcbiAqICAgU3ZjLT4+Q0E6IHJlZ2lzdGVyKHJlcXVlc3QsIGFkbWluVXNlcilcbiAqICAgQ0EtLT4+U3ZjOiBlbnJvbGxtZW50U2VjcmV0XG4gKiAgIFN2Yy0tPj5BcHA6IHNlY3JldFxuICogICBBcHAtPj5TdmM6IGVucm9sbChlbnJvbGxtZW50SWQsIHNlY3JldClcbiAqICAgU3ZjLT4+Q0E6IGVucm9sbCh7ZW5yb2xsbWVudElELCBzZWNyZXR9KVxuICogICBDQS0tPj5TdmM6IGNlcnRpZmljYXRlc1xuICogICBTdmMtLT4+QXBwOiBJZGVudGl0eVxuICovXG5leHBvcnQgY2xhc3MgRmFicmljRW5yb2xsbWVudFNlcnZpY2UgZXh0ZW5kcyBMb2dnZWRDbGFzcyB7XG4gIHByaXZhdGUgY2E/OiBGYWJyaWNDQVNlcnZpY2VzO1xuXG4gIHByaXZhdGUgY2VydGlmaWNhdGVTZXJ2aWNlPzogYW55O1xuXG4gIHByaXZhdGUgYWZmaWxpYXRpb25TZXJ2aWNlPzogQWZmaWxpYXRpb25TZXJ2aWNlO1xuXG4gIHByaXZhdGUgaWRlbnRpdHlTZXJ2aWNlPzogSWRlbnRpdHlTZXJ2aWNlO1xuXG4gIHByaXZhdGUgY2xpZW50PzogYW55O1xuXG4gIHByaXZhdGUgdXNlcj86IFVzZXI7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjYUNvbmZpZzogQ0FDb25maWcpIHtcbiAgICBDb3JlVXRpbHMuZ2V0Q3J5cHRvU3VpdGUoXG4gICAgICBjYUNvbmZpZy5oc21cbiAgICAgICAgPyB7XG4gICAgICAgICAgICBzb2Z0d2FyZTogZmFsc2UsXG4gICAgICAgICAgICBsaWI6IGNhQ29uZmlnLmhzbS5saWJyYXJ5LFxuICAgICAgICAgICAgc2xvdDogY2FDb25maWcuaHNtLnNsb3QsXG4gICAgICAgICAgICBsYWJlbDogY2FDb25maWcuaHNtLnRva2VuTGFiZWwsXG4gICAgICAgICAgICBwaW46IFN0cmluZyhjYUNvbmZpZy5oc20ucGluKSxcbiAgICAgICAgICB9XG4gICAgICAgIDogdW5kZWZpbmVkXG4gICAgKTtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIFVzZXIoKTogUHJvbWlzZTxVc2VyPiB7XG4gICAgaWYgKHRoaXMudXNlcikgcmV0dXJuIHRoaXMudXNlcjtcbiAgICBjb25zdCB7IGNhTmFtZSwgY2FDZXJ0LCBjYUtleSwgdXJsLCBoc20gfSA9IHRoaXMuY2FDb25maWc7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuVXNlcik7XG4gICAgbG9nLmRlYnVnKGBDcmVhdGluZyBDQSB1c2VyIGZvciAke2NhTmFtZX0gYXQgJHt1cmx9YCk7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIENBIGNlcnRpZmljYXRlIGZyb20gJHtjYUNlcnR9YCk7XG4gICAgY29uc3QgY2VydGlmaWNhdGUgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0Rmlyc3REaXJGaWxlTmFtZUNvbnRlbnQoY2FDZXJ0KTtcbiAgICBsZXQga2V5OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgaWYgKCFoc20pIHtcbiAgICAgIGlmICghY2FLZXkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgICAgYE1pc3NpbmcgY2FLZXkgY29uZmlndXJhdGlvbiBmb3IgQ0EgJHtjYU5hbWV9LiBQcm92aWRlIGEga2V5IGRpcmVjdG9yeSBvciBjb25maWd1cmUgSFNNIHN1cHBvcnQuYFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIENBIGtleSBmcm9tICR7Y2FLZXl9YCk7XG4gICAgICBrZXkgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0Rmlyc3REaXJGaWxlTmFtZUNvbnRlbnQoY2FLZXkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBVc2luZyBIU00gY29uZmlndXJhdGlvbiBmb3IgQ0EgJHtjYU5hbWV9IHdpdGggbGlicmFyeSAke2hzbS5saWJyYXJ5fWBcbiAgICAgICk7XG4gICAgfVxuICAgIGxvZy5kZWJ1ZyhgTG9hZGluZyBBZG1pbiB1c2VyIGZvciBjYSAke2NhTmFtZX1gKTtcbiAgICB0aGlzLnVzZXIgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0Q0FVc2VyKFwiYWRtaW5cIiwga2V5LCBjZXJ0aWZpY2F0ZSwgY2FOYW1lLCB7XG4gICAgICBoc20sXG4gICAgfSk7XG4gICAgcmV0dXJuIHRoaXMudXNlcjtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBDQSgpOiBQcm9taXNlPEZhYnJpY0NBU2VydmljZXM+IHtcbiAgICBpZiAodGhpcy5jYSkgcmV0dXJuIHRoaXMuY2E7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuQ0EpO1xuICAgIGNvbnN0IHsgdXJsLCB0bHMsIGNhTmFtZSB9ID0gdGhpcy5jYUNvbmZpZztcblxuICAgIC8vIEZPUiBTb21lIFJlYXNvbiB0aGUgdmVyaWZpY2F0aW9uIGZhaWxzIG5lZWQgdG8gaW52ZXN0aWdhdGUgdGhpcyB3b3JrcyBmb3Igbm93XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHByZWZlci1jb25zdFxuICAgIGxldCB7IHRydXN0ZWRSb290cywgdmVyaWZ5IH0gPSB0bHMgYXMgVExTT3B0aW9ucztcblxuICAgIGNvbnN0IHJvb3QgPSAodHJ1c3RlZFJvb3RzIGFzIHN0cmluZ1tdKVswXSBhcyBzdHJpbmc7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIENBIGNlcnRpZmljYXRlIGZyb20gJHtyb290fS4gY3dkOiAke3Byb2Nlc3MuY3dkKCl9YCk7XG5cbiAgICBjb25zdCBjZXJ0aWZpY2F0ZSA9IGF3YWl0IENvcmVVdGlscy5nZXRGaWxlQ29udGVudChyb290KTtcbiAgICBsb2cuZGVidWcoYENyZWF0aW5nIENBIENsaWVudCBmb3IgQ0EgJHtjYU5hbWV9IHVuZGVyICR7dXJsfWApO1xuICAgIHRoaXMuY2EgPSBuZXcgRmFicmljQ0FTZXJ2aWNlcyhcbiAgICAgIHVybCxcbiAgICAgIHtcbiAgICAgICAgdHJ1c3RlZFJvb3RzOiBCdWZmZXIuZnJvbShjZXJ0aWZpY2F0ZSksXG4gICAgICAgIHZlcmlmeSxcbiAgICAgIH0gYXMgVExTT3B0aW9ucyxcbiAgICAgIGNhTmFtZVxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuY2E7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgQ2xpZW50KCk6IFByb21pc2U8eyBuZXdDZXJ0aWZpY2F0ZVNlcnZpY2U6IGFueSB9PiB7XG4gICAgaWYgKHRoaXMuY2xpZW50KSByZXR1cm4gdGhpcy5jbGllbnQ7XG4gICAgY29uc3QgY2EgPSBhd2FpdCB0aGlzLkNBKCk7XG4gICAgdGhpcy5jbGllbnQgPSAoY2EgYXMgYW55KVtcIl9GYWJyaWNDQVNlcnZpY2VzXCJdO1xuICAgIHJldHVybiB0aGlzLmNsaWVudDtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBDZXJ0aWZpY2F0ZSgpIHtcbiAgICBpZiAoIXRoaXMuY2VydGlmaWNhdGVTZXJ2aWNlKVxuICAgICAgdGhpcy5jZXJ0aWZpY2F0ZVNlcnZpY2UgPSAoYXdhaXQgdGhpcy5DbGllbnQoKSkubmV3Q2VydGlmaWNhdGVTZXJ2aWNlKCk7XG4gICAgcmV0dXJuIHRoaXMuY2VydGlmaWNhdGVTZXJ2aWNlO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIEFmZmlsaWF0aW9ucygpIHtcbiAgICBpZiAoIXRoaXMuYWZmaWxpYXRpb25TZXJ2aWNlKVxuICAgICAgdGhpcy5hZmZpbGlhdGlvblNlcnZpY2UgPSAoYXdhaXQgdGhpcy5DQSgpKS5uZXdBZmZpbGlhdGlvblNlcnZpY2UoKTtcbiAgICByZXR1cm4gdGhpcy5hZmZpbGlhdGlvblNlcnZpY2U7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgSWRlbnRpdGllcygpIHtcbiAgICBpZiAoIXRoaXMuaWRlbnRpdHlTZXJ2aWNlKVxuICAgICAgdGhpcy5pZGVudGl0eVNlcnZpY2UgPSAoYXdhaXQgdGhpcy5DQSgpKS5uZXdJZGVudGl0eVNlcnZpY2UoKTtcbiAgICByZXR1cm4gdGhpcy5pZGVudGl0eVNlcnZpY2U7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJldHJpZXZlIGNlcnRpZmljYXRlcyBmcm9tIHRoZSBDQS5cbiAgICogQHN1bW1hcnkgQ2FsbHMgdGhlIENBIGNlcnRpZmljYXRlIHNlcnZpY2UgdG8gbGlzdCBjZXJ0aWZpY2F0ZXMsIG9wdGlvbmFsbHkgbWFwcGluZyB0byBQRU0gc3RyaW5ncyBvbmx5LlxuICAgKiBAcGFyYW0ge0dldENlcnRpZmljYXRlc1JlcXVlc3R9IFtyZXF1ZXN0XSAtIE9wdGlvbmFsIGZpbHRlciByZXF1ZXN0IGZvciBjZXJ0aWZpY2F0ZSBsb29rdXAuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2RvTWFwPXRydWVdIC0gV2hlbiB0cnVlLCByZXR1cm5zIGFycmF5IG9mIFBFTSBzdHJpbmdzOyBvdGhlcndpc2UgcmV0dXJucyBmdWxsIHJlc3BvbnNlIG9iamVjdC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmdbXSB8IENlcnRpZmljYXRlUmVzcG9uc2U+fSBBcnJheSBvZiBQRU0gc3RyaW5ncyBvciB0aGUgZnVsbCBjZXJ0aWZpY2F0ZSByZXNwb25zZS5cbiAgICovXG4gIGFzeW5jIGdldENlcnRpZmljYXRlcyhcbiAgICByZXF1ZXN0PzogR2V0Q2VydGlmaWNhdGVzUmVxdWVzdCxcbiAgICBkb01hcCA9IHRydWVcbiAgKTogUHJvbWlzZTxzdHJpbmdbXSB8IENlcnRpZmljYXRlUmVzcG9uc2U+IHtcbiAgICBjb25zdCBjZXJ0aWZpY2F0ZVNlcnZpY2UgPSBhd2FpdCB0aGlzLkNlcnRpZmljYXRlKCk7XG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuVXNlcigpO1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmdldENlcnRpZmljYXRlcyk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYFJldHJpZXZpbmcgY2VydGlmaWNhdGVzJHtyZXF1ZXN0ID8gYCBmb3IgJHtyZXF1ZXN0LmlkfWAgOiBcIlwifSBmb3IgQ0EgJHt0aGlzLmNhQ29uZmlnLmNhTmFtZX1gXG4gICAgKTtcbiAgICBjb25zdCByZXNwb25zZTogQ2VydGlmaWNhdGVSZXNwb25zZSA9IChcbiAgICAgIGF3YWl0IGNlcnRpZmljYXRlU2VydmljZS5nZXRDZXJ0aWZpY2F0ZXMocmVxdWVzdCB8fCB7fSwgdXNlcilcbiAgICApLnJlc3VsdDtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgRm91bmQgJHtyZXNwb25zZS5jZXJ0cy5sZW5ndGh9IGNlcnRpZmljYXRlczogJHtKU09OLnN0cmluZ2lmeShyZXNwb25zZSl9YFxuICAgICk7XG4gICAgcmV0dXJuIGRvTWFwID8gcmVzcG9uc2UuY2VydHMubWFwKChjKSA9PiBjLlBFTSkgOiByZXNwb25zZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gTGlzdCBpZGVudGl0aWVzIHJlZ2lzdGVyZWQgaW4gdGhlIENBLlxuICAgKiBAc3VtbWFyeSBRdWVyaWVzIHRoZSBDQSBpZGVudGl0eSBzZXJ2aWNlIHRvIGZldGNoIGFsbCBpZGVudGl0aWVzIGFuZCByZXR1cm5zIHRoZSBsaXN0IGFzIEZhYnJpY0lkZW50aXR5IG9iamVjdHMuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8RmFicmljSWRlbnRpdHlbXT59IFRoZSBsaXN0IG9mIGlkZW50aXRpZXMgcmVnaXN0ZXJlZCBpbiB0aGUgQ0EuXG4gICAqL1xuICBhc3luYyBnZXRJZGVudGl0aWVzKCk6IFByb21pc2U8RmFicmljSWRlbnRpdHlbXT4ge1xuICAgIGNvbnN0IGlkZW50aXRpZXNTZXJ2aWNlID0gYXdhaXQgdGhpcy5JZGVudGl0aWVzKCk7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuZ2V0SWRlbnRpdGllcyk7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIElkZW50aXRpZXMgdW5kZXIgQ0EgJHt0aGlzLmNhQ29uZmlnLmNhTmFtZX1gKTtcbiAgICBjb25zdCByZXNwb25zZTogSWRlbnRpdHlSZXNwb25zZSA9IChcbiAgICAgIGF3YWl0IGlkZW50aXRpZXNTZXJ2aWNlLmdldEFsbChhd2FpdCB0aGlzLlVzZXIoKSlcbiAgICApLnJlc3VsdDtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgRm91bmQgJHtyZXNwb25zZS5pZGVudGl0aWVzLmxlbmd0aH0gSWRlbnRpdGllczogJHtKU09OLnN0cmluZ2lmeShyZXNwb25zZSl9YFxuICAgICk7XG4gICAgcmV0dXJuIHJlc3BvbnNlLmlkZW50aXRpZXM7XG4gIH1cblxuICBwcm90ZWN0ZWQgcGFyc2VFcnJvcihlOiBFcnJvcikge1xuICAgIGNvbnN0IHJlZ2V4cCA9IC8uKmNvZGU6XFxzKFxcZCspLio/bWVzc2FnZTpcXHNbXCInXSguKylbXCInXS9ncztcbiAgICBjb25zdCBtYXRjaCA9IHJlZ2V4cC5leGVjKGUubWVzc2FnZSk7XG4gICAgaWYgKCFtYXRjaCkgcmV0dXJuIG5ldyBSZWdpc3RyYXRpb25FcnJvcihlKTtcbiAgICBjb25zdCBbLCBjb2RlLCBtZXNzYWdlXSA9IG1hdGNoO1xuICAgIHN3aXRjaCAoY29kZSkge1xuICAgICAgY2FzZSBcIjc0XCI6XG4gICAgICBjYXNlIFwiNzFcIjpcbiAgICAgICAgcmV0dXJuIG5ldyBDb25mbGljdEVycm9yKG1lc3NhZ2UpO1xuICAgICAgY2FzZSBcIjIwXCI6XG4gICAgICAgIHJldHVybiBuZXcgQXV0aG9yaXphdGlvbkVycm9yKG1lc3NhZ2UpO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIG5ldyBSZWdpc3RyYXRpb25FcnJvcihtZXNzYWdlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJldHJpZXZlIGFmZmlsaWF0aW9ucyBmcm9tIHRoZSBDQS5cbiAgICogQHN1bW1hcnkgUXVlcmllcyB0aGUgQ0EgZm9yIHRoZSBsaXN0IG9mIGFmZmlsaWF0aW9ucyBhdmFpbGFibGUgdW5kZXIgdGhlIGNvbmZpZ3VyZWQgQ0EuXG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGFmZmlsaWF0aW9ucyByZXN1bHQgcGF5bG9hZC5cbiAgICovXG4gIGFzeW5jIGdldEFmZmlsaWF0aW9ucygpIHtcbiAgICBjb25zdCBhZmZpbGlhdGlvblNlcnZpY2UgPSBhd2FpdCB0aGlzLkFmZmlsaWF0aW9ucygpO1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmdldEFmZmlsaWF0aW9ucyk7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIEFmZmlsaWF0aW9ucyB1bmRlciBDQSAke3RoaXMuY2FDb25maWcuY2FOYW1lfWApO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gKGF3YWl0IGFmZmlsaWF0aW9uU2VydmljZS5nZXRBbGwoYXdhaXQgdGhpcy5Vc2VyKCkpKVxuICAgICAgLnJlc3VsdDtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgRm91bmQgJHtyZXNwb25zZS5hLmxlbmd0aH0gQWZmaWxpYXRpb25zOiAke0pTT04uc3RyaW5naWZ5KHJlc3BvbnNlKX1gXG4gICAgKTtcbiAgICByZXR1cm4gcmVzcG9uc2U7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlYWQgaWRlbnRpdHkgZGV0YWlscyBmcm9tIHRoZSBDQSBieSBlbnJvbGxtZW50IElELlxuICAgKiBAc3VtbWFyeSBSZXRyaWV2ZXMgYW5kIHZhbGlkYXRlcyBhIHNpbmdsZSBpZGVudGl0eSwgdGhyb3dpbmcgTm90Rm91bmRFcnJvciB3aGVuIG1pc3NpbmcuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBlbnJvbGxtZW50SWQgLSBFbnJvbGxtZW50IElEIHRvIGxvb2t1cC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxGYWJyaWNJZGVudGl0eT59IFRoZSBpZGVudGl0eSBkZXRhaWxzIHN0b3JlZCBpbiB0aGUgQ0EuXG4gICAqL1xuICBhc3luYyByZWFkKGVucm9sbG1lbnRJZDogc3RyaW5nKSB7XG4gICAgY29uc3QgY2EgPSBhd2FpdCB0aGlzLkNBKCk7XG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuVXNlcigpO1xuICAgIGxldCByZXN1bHQ6IElTZXJ2aWNlUmVzcG9uc2U7XG4gICAgdHJ5IHtcbiAgICAgIHJlc3VsdCA9IGF3YWl0IGNhLm5ld0lkZW50aXR5U2VydmljZSgpLmdldE9uZShlbnJvbGxtZW50SWQsIHVzZXIpO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXJyb3IoXG4gICAgICAgIGBDb3VsZG4ndCBmaW5kIGVucm9sbG1lbnQgd2l0aCBpZCAke2Vucm9sbG1lbnRJZH06ICR7ZX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICghcmVzdWx0LnN1Y2Nlc3MpXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihcbiAgICAgICAgYENvdWxkbid0IGZpbmQgZW5yb2xsbWVudCB3aXRoIGlkICR7ZW5yb2xsbWVudElkfTogJHtyZXN1bHQuZXJyb3JzLmpvaW4oXCJcXG5cIil9YFxuICAgICAgKTtcblxuICAgIHJldHVybiByZXN1bHQucmVzdWx0IGFzIEZhYnJpY0lkZW50aXR5O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWdpc3RlciBhIG5ldyBpZGVudGl0eSB3aXRoIHRoZSBDQS5cbiAgICogQHN1bW1hcnkgU3VibWl0cyBhIHJlZ2lzdHJhdGlvbiByZXF1ZXN0IGZvciBhIG5ldyBlbnJvbGxtZW50IElELCByZXR1cm5pbmcgdGhlIGVucm9sbG1lbnQgc2VjcmV0IHVwb24gc3VjY2Vzcy5cbiAgICogQHBhcmFtIHtDcmVkZW50aWFsc30gbW9kZWwgLSBDcmVkZW50aWFscyBjb250YWluaW5nIHVzZXJOYW1lIGFuZCBwYXNzd29yZCBmb3IgdGhlIG5ldyBpZGVudGl0eS5cbiAgICogQHBhcmFtIHtib29sZWFufSBbaXNTdXBlclVzZXI9ZmFsc2VdIC0gV2hldGhlciB0byByZWdpc3RlciB0aGUgaWRlbnRpdHkgYXMgYSBzdXBlciB1c2VyLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FmZmlsaWF0aW9uPVwiXCJdIC0gQWZmaWxpYXRpb24gc3RyaW5nIChlLmcuLCBvcmcxLmRlcGFydG1lbnQxKS5cbiAgICogQHBhcmFtIHtDQV9ST0xFIHwgc3RyaW5nfSBbdXNlclJvbGVdIC0gUm9sZSB0byBhc3NpZ24gdG8gdGhlIGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge0lLZXlWYWx1ZUF0dHJpYnV0ZX0gW2F0dHJzXSAtIE9wdGlvbmFsIGF0dHJpYnV0ZXMgdG8gYXR0YWNoIHRvIHRoZSBpZGVudGl0eS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhFbnJvbGxtZW50c10gLSBNYXhpbXVtIG51bWJlciBvZiBlbnJvbGxtZW50cyBhbGxvd2VkIGZvciB0aGUgaWRlbnRpdHkuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gVGhlIGVucm9sbG1lbnQgc2VjcmV0IGZvciB0aGUgcmVnaXN0ZXJlZCBpZGVudGl0eS5cbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyKFxuICAgIG1vZGVsOiBDcmVkZW50aWFscyxcbiAgICBpc1N1cGVyVXNlcjogYm9vbGVhbiA9IGZhbHNlLFxuICAgIGFmZmlsaWF0aW9uOiBzdHJpbmcgPSBcIlwiLFxuICAgIHVzZXJSb2xlPzogQ0FfUk9MRSB8IHN0cmluZyxcbiAgICBhdHRycz86IElLZXlWYWx1ZUF0dHJpYnV0ZSxcbiAgICBtYXhFbnJvbGxtZW50cz86IG51bWJlclxuICApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGxldCByZWdpc3RyYXRpb246IHN0cmluZztcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5yZWdpc3Rlcik7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgdXNlck5hbWUsIHBhc3N3b3JkIH0gPSBtb2RlbDtcbiAgICAgIGNvbnN0IGNhID0gYXdhaXQgdGhpcy5DQSgpO1xuICAgICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuVXNlcigpO1xuICAgICAgY29uc3QgcHJvcHMgPSB7XG4gICAgICAgIGVucm9sbG1lbnRJRDogdXNlck5hbWUgYXMgc3RyaW5nLFxuICAgICAgICBlbnJvbGxtZW50U2VjcmV0OiBwYXNzd29yZCxcbiAgICAgICAgYWZmaWxpYXRpb246IGFmZmlsaWF0aW9uLFxuICAgICAgICB1c2VyUm9sZTogdXNlclJvbGUsXG4gICAgICAgIGF0dHJzOiBhdHRycyxcbiAgICAgICAgbWF4RW5yb2xsbWVudHM6IG1heEVucm9sbG1lbnRzLFxuICAgICAgfSBhcyBJUmVnaXN0ZXJSZXF1ZXN0O1xuICAgICAgcmVnaXN0cmF0aW9uID0gYXdhaXQgY2EucmVnaXN0ZXIocHJvcHMsIHVzZXIpO1xuICAgICAgbG9nLmluZm8oXG4gICAgICAgIGBSZWdpc3RyYXRpb24gZm9yICR7dXNlck5hbWV9IGNyZWF0ZWQgd2l0aCB1c2VyIHR5cGUgJHt1c2VyUm9sZSA/PyBcIlVuZGVmaW5lZCBSb2xlXCJ9ICR7aXNTdXBlclVzZXIgPyBcImFzIHN1cGVyIHVzZXJcIiA6IFwiXCJ9YFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlZ2lzdHJhdGlvbjtcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGF0aWMgaWRlbnRpdHlGcm9tRW5yb2xsbWVudChcbiAgICBlbnJvbGxtZW50OiBJRW5yb2xsUmVzcG9uc2UsXG4gICAgbXNwSWQ6IHN0cmluZ1xuICApOiBJZGVudGl0eSB7XG4gICAgY29uc3QgeyBjZXJ0aWZpY2F0ZSwga2V5LCByb290Q2VydGlmaWNhdGUgfSA9IGVucm9sbG1lbnQ7XG4gICAgY29uc3QgbG9nID0gTG9nZ2luZy5mb3IoRmFicmljRW5yb2xsbWVudFNlcnZpY2UsIHt9KS5mb3IoXG4gICAgICB0aGlzLmlkZW50aXR5RnJvbUVucm9sbG1lbnRcbiAgICApO1xuICAgIGxvZy5kZWJ1ZyhcbiAgICAgIGBHZW5lcmF0aW5nIElkZW50aXR5IGZyb20gY2VydGlmaWNhdGUgJHtjZXJ0aWZpY2F0ZX0gaW4gbXNwICR7bXNwSWR9YFxuICAgICk7XG4gICAgY29uc3QgY2xpZW50SWQgPSBDcnlwdG9VdGlscy5mYWJyaWNJZEZyb21DZXJ0aWZpY2F0ZShjZXJ0aWZpY2F0ZSk7XG4gICAgY29uc3QgaWQgPSBDcnlwdG9VdGlscy5lbmNvZGUoY2xpZW50SWQpO1xuICAgIGxvZy5kZWJ1ZyhgSWRlbnRpdHkgJHtjbGllbnRJZH0gYW5kIGVuY29kZWRJZCAke2lkfWApO1xuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgcmV0dXJuIG5ldyBJZGVudGl0eSh7XG4gICAgICBpZDogaWQsXG4gICAgICBjcmVkZW50aWFsczoge1xuICAgICAgICBpZDogaWQsXG4gICAgICAgIGNlcnRpZmljYXRlOiBjZXJ0aWZpY2F0ZSxcbiAgICAgICAgcHJpdmF0ZUtleToga2V5LnRvQnl0ZXMoKSxcbiAgICAgICAgcm9vdENlcnRpZmljYXRlOiByb290Q2VydGlmaWNhdGUsXG4gICAgICAgIGNyZWF0ZWRPbjogbm93LFxuICAgICAgICB1cGRhdGVkT246IG5vdyxcbiAgICAgIH0sXG4gICAgICBtc3BJZDogbXNwSWQsXG4gICAgICBjcmVhdGVkT246IG5vdyxcbiAgICAgIHVwZGF0ZWRPbjogbm93LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFbnJvbGwgYW4gaWRlbnRpdHkgd2l0aCB0aGUgQ0EgdXNpbmcgYSByZWdpc3RyYXRpb24gc2VjcmV0LlxuICAgKiBAc3VtbWFyeSBFeGNoYW5nZXMgdGhlIGVucm9sbG1lbnQgSUQgYW5kIHNlY3JldCBmb3IgY2VydGlmaWNhdGVzLCByZXR1cm5pbmcgYSBjb25zdHJ1Y3RlZCBJZGVudGl0eSBtb2RlbC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGVucm9sbG1lbnRJZCAtIEVucm9sbG1lbnQgSUQgdG8gZW5yb2xsLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVnaXN0cmF0aW9uIC0gRW5yb2xsbWVudCBzZWNyZXQgcmV0dXJuZWQgYXQgcmVnaXN0cmF0aW9uIHRpbWUuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8SWRlbnRpdHk+fSBUaGUgZW5yb2xsZWQgaWRlbnRpdHkgb2JqZWN0IHdpdGggY3JlZGVudGlhbHMuXG4gICAqL1xuICBhc3luYyBlbnJvbGwoZW5yb2xsbWVudElkOiBzdHJpbmcsIHJlZ2lzdHJhdGlvbjogc3RyaW5nKSB7XG4gICAgbGV0IGlkZW50aXR5OiBJZGVudGl0eTtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5lbnJvbGwpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjYSA9IGF3YWl0IHRoaXMuQ0EoKTtcbiAgICAgIGxvZy5kZWJ1ZyhgRW5yb2xsaW5nICR7ZW5yb2xsbWVudElkfWApO1xuICAgICAgY29uc3QgZW5yb2xsbWVudDogSUVucm9sbFJlc3BvbnNlID0gYXdhaXQgY2EuZW5yb2xsKHtcbiAgICAgICAgZW5yb2xsbWVudElEOiBlbnJvbGxtZW50SWQsXG4gICAgICAgIGVucm9sbG1lbnRTZWNyZXQ6IHJlZ2lzdHJhdGlvbixcbiAgICAgIH0pO1xuICAgICAgaWRlbnRpdHkgPSBGYWJyaWNFbnJvbGxtZW50U2VydmljZS5pZGVudGl0eUZyb21FbnJvbGxtZW50KFxuICAgICAgICBlbnJvbGxtZW50LFxuICAgICAgICB0aGlzLmNhQ29uZmlnLmNhTmFtZVxuICAgICAgKTtcbiAgICAgIGxvZy5pbmZvKFxuICAgICAgICBgU3VjY2Vzc2Z1bGx5IGVucm9sbGVkICR7ZW5yb2xsbWVudElkfSB1bmRlciAke3RoaXMuY2FDb25maWcuY2FOYW1lfSBhcyAke2lkZW50aXR5LmlkfWBcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSk7XG4gICAgfVxuICAgIHJldHVybiBpZGVudGl0eTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVnaXN0ZXIgYW5kIGVucm9sbCBhIG5ldyBpZGVudGl0eSBpbiBvbmUgc3RlcC5cbiAgICogQHN1bW1hcnkgUmVnaXN0ZXJzIGEgbmV3IGVucm9sbG1lbnQgSUQgd2l0aCB0aGUgQ0EgYW5kIGltbWVkaWF0ZWx5IGV4Y2hhbmdlcyB0aGUgc2VjcmV0IHRvIGVucm9sbCwgcmV0dXJuaW5nIHRoZSBjcmVhdGVkIElkZW50aXR5LlxuICAgKiBAcGFyYW0ge0NyZWRlbnRpYWxzfSBtb2RlbCAtIENyZWRlbnRpYWxzIGZvciB0aGUgbmV3IGlkZW50aXR5IGNvbnRhaW5pbmcgdXNlck5hbWUgYW5kIHBhc3N3b3JkLlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtpc1N1cGVyVXNlcj1mYWxzZV0gLSBXaGV0aGVyIHRvIHJlZ2lzdGVyIHRoZSBpZGVudGl0eSBhcyBhIHN1cGVyIHVzZXIuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYWZmaWxpYXRpb249XCJcIl0gLSBBZmZpbGlhdGlvbiBzdHJpbmcgKGUuZy4sIG9yZzEuZGVwYXJ0bWVudDEpLlxuICAgKiBAcGFyYW0ge0NBX1JPTEUgfCBzdHJpbmd9IFt1c2VyUm9sZV0gLSBSb2xlIHRvIGFzc2lnbiB0byB0aGUgaWRlbnRpdHkuXG4gICAqIEBwYXJhbSB7SUtleVZhbHVlQXR0cmlidXRlfSBbYXR0cnNdIC0gT3B0aW9uYWwgYXR0cmlidXRlcyB0byBhdHRhY2ggdG8gdGhlIGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge251bWJlcn0gW21heEVucm9sbG1lbnRzXSAtIE1heGltdW0gbnVtYmVyIG9mIGVucm9sbG1lbnRzIGFsbG93ZWQgZm9yIHRoZSBpZGVudGl0eS5cbiAgICogQHJldHVybiB7UHJvbWlzZTxJZGVudGl0eT59IFRoZSBlbnJvbGxlZCBpZGVudGl0eS5cbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyQW5kRW5yb2xsKFxuICAgIG1vZGVsOiBDcmVkZW50aWFscyxcbiAgICBpc1N1cGVyVXNlcjogYm9vbGVhbiA9IGZhbHNlLFxuICAgIGFmZmlsaWF0aW9uOiBzdHJpbmcgPSBcIlwiLFxuICAgIHVzZXJSb2xlPzogQ0FfUk9MRSB8IHN0cmluZyxcbiAgICBhdHRycz86IElLZXlWYWx1ZUF0dHJpYnV0ZSxcbiAgICBtYXhFbnJvbGxtZW50cz86IG51bWJlclxuICApOiBQcm9taXNlPElkZW50aXR5PiB7XG4gICAgY29uc3QgcmVnaXN0cmF0aW9uID0gYXdhaXQgdGhpcy5yZWdpc3RlcihcbiAgICAgIG1vZGVsLFxuICAgICAgaXNTdXBlclVzZXIsXG4gICAgICBhZmZpbGlhdGlvbixcbiAgICAgIHVzZXJSb2xlLFxuICAgICAgYXR0cnMsXG4gICAgICBtYXhFbnJvbGxtZW50c1xuICAgICk7XG4gICAgY29uc3QgeyB1c2VyTmFtZSB9ID0gbW9kZWw7XG4gICAgcmV0dXJuIHRoaXMuZW5yb2xsKHVzZXJOYW1lIGFzIHN0cmluZywgcmVnaXN0cmF0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXZva2VzIHRoZSBlbnJvbGxtZW50IG9mIGFuIGlkZW50aXR5IHdpdGggdGhlIHNwZWNpZmllZCBlbnJvbGxtZW50IElELlxuICAgKlxuICAgKiBAcGFyYW0gZW5yb2xsbWVudElkIC0gVGhlIGVucm9sbG1lbnQgSUQgb2YgdGhlIGlkZW50aXR5IHRvIGJlIHJldm9rZWQuXG4gICAqXG4gICAqIEByZXR1cm5zIEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXN1bHQgb2YgdGhlIHJldm9jYXRpb24gb3BlcmF0aW9uLlxuICAgKlxuICAgKiBAdGhyb3dzIHtOb3RGb3VuZEVycm9yfSBJZiB0aGUgZW5yb2xsbWVudCB3aXRoIHRoZSBzcGVjaWZpZWQgSUQgZG9lcyBub3QgZXhpc3QuXG4gICAqIEB0aHJvd3Mge0ludGVybmFsRXJyb3J9IElmIHRoZXJlIGlzIGFuIGVycm9yIGR1cmluZyB0aGUgcmV2b2NhdGlvbiBwcm9jZXNzLlxuICAgKi9cbiAgYXN5bmMgcmV2b2tlKGVucm9sbG1lbnRJZDogc3RyaW5nKSB7XG4gICAgY29uc3QgY2EgPSBhd2FpdCB0aGlzLkNBKCk7XG4gICAgY29uc3QgdXNlciA9IGF3YWl0IHRoaXMuVXNlcigpO1xuICAgIGNvbnN0IGlkZW50aXR5ID0gYXdhaXQgdGhpcy5yZWFkKGVucm9sbG1lbnRJZCk7XG4gICAgaWYgKCFpZGVudGl0eSlcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEVycm9yKFxuICAgICAgICBgQ291bGQgbm90IGZpbmQgZW5yb2xsbWVudCB3aXRoIGlkICR7ZW5yb2xsbWVudElkfWBcbiAgICAgICk7XG4gICAgbGV0IHJlc3VsdDogSVNlcnZpY2VSZXNwb25zZTtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gYXdhaXQgY2EucmV2b2tlKFxuICAgICAgICB7IGVucm9sbG1lbnRJRDogaWRlbnRpdHkuaWQsIHJlYXNvbjogXCJVc2VyIERlbGV0YXRpb25cIiB9LFxuICAgICAgICB1c2VyXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBgQ291bGQgbm90IHJldm9rZSBlbnJvbGxtZW50IHdpdGggaWQgJHtlbnJvbGxtZW50SWR9OiAke2V9YFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCFyZXN1bHQuc3VjY2VzcylcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBgQ291bGQgbm90IHJldm9rZSBlbnJvbGxtZW50IHdpdGggaWQgJHtlbnJvbGxtZW50SWR9OiAke3Jlc3VsdC5lcnJvcnMuam9pbihcIlxcblwiKX1gXG4gICAgICApO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbn1cbiIsImltcG9ydCB7IElSZWdpc3RlclJlcXVlc3QsIElLZXlWYWx1ZUF0dHJpYnV0ZSB9IGZyb20gXCJmYWJyaWMtY2EtY2xpZW50XCI7XG5pbXBvcnQgeyBDQV9ST0xFIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQge1xuICBtaW4sXG4gIG1pbmxlbmd0aCxcbiAgTW9kZWwsXG4gIHJlcXVpcmVkLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBWYWxpZGF0aW9uRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuZXhwb3J0IGNsYXNzIFJlZ2lzdHJhdGlvblJlcXVlc3RCdWlsZGVyIGV4dGVuZHMgTW9kZWwge1xuICBAcmVxdWlyZWQoKVxuICBhZmZpbGlhdGlvbjogc3RyaW5nID0gXCJcIjtcbiAgQG1pbmxlbmd0aCgxKVxuICBhdHRycz86IElLZXlWYWx1ZUF0dHJpYnV0ZVtdO1xuICBAcmVxdWlyZWQoKVxuICBlbnJvbGxtZW50SUQhOiBzdHJpbmc7XG4gIEByZXF1aXJlZCgpXG4gIGVucm9sbG1lbnRTZWNyZXQhOiBzdHJpbmc7XG4gIEBtaW4oMClcbiAgbWF4RW5yb2xsbWVudHM/OiBudW1iZXI7XG4gIEByZXF1aXJlZCgpXG4gIHJvbGUhOiBzdHJpbmc7XG5cbiAgYnVpbGQoKTogSVJlZ2lzdGVyUmVxdWVzdCB7XG4gICAgY29uc3QgZXJycyA9IHRoaXMuaGFzRXJyb3JzKCk7XG4gICAgaWYgKGVycnMpIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoZXJycy50b1N0cmluZygpKTtcbiAgICBjb25zdCByZXNwb25zZTogSVJlZ2lzdGVyUmVxdWVzdCA9IHtcbiAgICAgIGVucm9sbG1lbnRJRDogdGhpcy5lbnJvbGxtZW50SUQsXG4gICAgICBlbnJvbGxtZW50U2VjcmV0OiB0aGlzLmVucm9sbG1lbnRTZWNyZXQsXG4gICAgICByb2xlOiB0aGlzLnJvbGUsXG4gICAgICBhZmZpbGlhdGlvbjogdGhpcy5hZmZpbGlhdGlvbixcbiAgICB9O1xuICAgIGlmICh0eXBlb2YgdGhpcy5tYXhFbnJvbGxtZW50cyAhPT0gXCJ1bmRlZmluZWRcIilcbiAgICAgIHJlc3BvbnNlLm1heEVucm9sbG1lbnRzID0gdGhpcy5tYXhFbnJvbGxtZW50cztcbiAgICBpZiAodGhpcy5hdHRycykgcmVzcG9uc2UuYXR0cnMgPSB0aGlzLmF0dHJzO1xuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIHNldEFmZmlsaWF0aW9uKHZhbHVlOiBzdHJpbmcpIHtcbiAgICB0aGlzLmFmZmlsaWF0aW9uID0gdmFsdWU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBhZGRBdHRyKGF0dHI6IElLZXlWYWx1ZUF0dHJpYnV0ZSkge1xuICAgIHRoaXMuYXR0cnMgPSB0aGlzLmF0dHJzIHx8IFtdO1xuICAgIHRoaXMuYXR0cnMucHVzaChhdHRyKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEF0dHJzKHZhbHVlOiBJS2V5VmFsdWVBdHRyaWJ1dGVbXSkge1xuICAgIHRoaXMuYXR0cnMgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEVucm9sbG1lbnRJRCh2YWx1ZTogc3RyaW5nKSB7XG4gICAgdGhpcy5lbnJvbGxtZW50SUQgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEVucm9sbG1lbnRTZWNyZXQodmFsdWU6IHN0cmluZykge1xuICAgIHRoaXMuZW5yb2xsbWVudFNlY3JldCA9IHZhbHVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0TWF4RW5yb2xsbWVudHModmFsdWU6IG51bWJlcikge1xuICAgIHRoaXMubWF4RW5yb2xsbWVudHMgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFJvbGUodmFsdWU6IENBX1JPTEUgfCBzdHJpbmcpIHtcbiAgICB0aGlzLnJvbGUgPSB2YWx1ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuIiwiLyoqXG4gKiBFbnVtIHJlcHJlc2VudGluZyB0aGUgZXZlbnRzIGVtaXR0ZWQgYnkgYW4gRVJDMjAgY29udHJhY3QuXG4gKlxuICogQHJlbWFya3NcbiAqIFRoaXMgZW51bSBpcyB1c2VkIHRvIGlkZW50aWZ5IHRoZSBzcGVjaWZpYyBldmVudHMgdGhhdCBjYW4gYmUgZW1pdHRlZCBieSBhbiBFUkMyMCBjb250cmFjdC5cbiAqIFRoZSBldmVudHMgYXJlIG5hbWVkIGFjY29yZGluZyB0byB0aGUgRUlQLTIwIHN0YW5kYXJkLlxuICovXG5leHBvcnQgZW51bSBFUkMyMEV2ZW50cyB7XG4gIC8qKlxuICAgKiBFbWl0dGVkIHdoZW4gYSBgdHJhbnNmZXJgIGZ1bmN0aW9uIGlzIGNhbGxlZCBzdWNjZXNzZnVsbHkuXG4gICAqXG4gICAqIEBwYXJhbSBmcm9tIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHNlbmRlci5cbiAgICogQHBhcmFtIHRvIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHJlY2lwaWVudC5cbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGFtb3VudCBvZiB0b2tlbnMgdHJhbnNmZXJyZWQuXG4gICAqL1xuICBUUkFOU0ZFUiA9IFwiVHJhbnNmZXJcIixcblxuICAvKipcbiAgICogRW1pdHRlZCB3aGVuIGFuIGBhcHByb3ZlYCBmdW5jdGlvbiBpcyBjYWxsZWQgc3VjY2Vzc2Z1bGx5LlxuICAgKlxuICAgKiBAcGFyYW0gb3duZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgdG9rZW4gb3duZXIuXG4gICAqIEBwYXJhbSBzcGVuZGVyIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIGFwcHJvdmVkIHNwZW5kZXIuXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBhbW91bnQgb2YgdG9rZW5zIGFwcHJvdmVkIGZvciB0aGUgc3BlbmRlci5cbiAgICovXG4gIEFQUFJPVkFMID0gXCJBcHByb3ZhbFwiLFxufVxuIiwiaW1wb3J0IHsgTW9kZWwsIHR5cGUgTW9kZWxBcmcgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBjb2x1bW4sIGNyZWF0ZWRBdCwgdXBkYXRlZEF0IH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyB2ZXJzaW9uIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBkZXNjcmlwdGlvbiwgdXNlcyB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljRmxhdm91ciB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IFByb3BlcnR5IH0gZnJvbSBcImZhYnJpYy1jb250cmFjdC1hcGlcIjtcblxuQHVzZXMoRmFicmljRmxhdm91cilcbmV4cG9ydCBjbGFzcyBGYWJyaWNCYXNlTW9kZWwgZXh0ZW5kcyBNb2RlbCB7XG4gIEBkZXNjcmlwdGlvbihcIlN0b3JlcyB0aGUgb3JpZ2luYWwgdGltZXN0YW1wIG9mIGNyZWF0aW9uXCIpXG4gIEBjb2x1bW4oKVxuICBAY3JlYXRlZEF0KClcbiAgY3JlYXRlZEF0ITogRGF0ZTtcblxuICBAZGVzY3JpcHRpb24oXCJTdG9yZXMgdGhlIHRpbWVzdGFtcCBvZiB0aGUgbGFzdCB1cGRhdGVcIilcbiAgQGNvbHVtbigpXG4gIEB1cGRhdGVkQXQoKVxuICB1cGRhdGVkQXQhOiBEYXRlO1xuXG4gIEBkZXNjcmlwdGlvbihcIlN0b3JlcyB0aGUgdmVyc2lvbiBvZiB0aGUgbW9kZWxcIilcbiAgQGNvbHVtbigpXG4gIEB2ZXJzaW9uKClcbiAgdmVyc2lvbiE6IG51bWJlcjtcblxuICBjb25zdHJ1Y3Rvcihhcmc/OiBNb2RlbEFyZzxGYWJyaWNCYXNlTW9kZWw+KSB7XG4gICAgc3VwZXIoYXJnKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgdHlwZSBNb2RlbEFyZyB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IGNvbHVtbiwgY3JlYXRlZEJ5LCB1cGRhdGVkQnkgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IGRlc2NyaXB0aW9uLCB1c2VzIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBGYWJyaWNGbGF2b3VyIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgRmFicmljQmFzZU1vZGVsIH0gZnJvbSBcIi4vRmFicmljQmFzZU1vZGVsXCI7XG5cbkB1c2VzKEZhYnJpY0ZsYXZvdXIpXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRmFicmljSWRlbnRpZmllZEJhc2VNb2RlbCBleHRlbmRzIEZhYnJpY0Jhc2VNb2RlbCB7XG4gIEBkZXNjcmlwdGlvbihcIlN0b3JlcyB0aGUgY3JlYXRvclwiKVxuICBAY29sdW1uKClcbiAgQGNyZWF0ZWRCeSgpXG4gIGNyZWF0ZWRCeSE6IHN0cmluZztcblxuICBAZGVzY3JpcHRpb24oXCJTdG9yZXMgdGhlIHVzZXIgdGhhdCBsYXN0IHVwZGF0ZWQgdGhlIG1vZGVsXCIpXG4gIEBjb2x1bW4oKVxuICBAdXBkYXRlZEJ5KClcbiAgdXBkYXRlZEJ5ITogc3RyaW5nO1xuXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3Rvcihhcmc/OiBNb2RlbEFyZzxGYWJyaWNJZGVudGlmaWVkQmFzZU1vZGVsPikge1xuICAgIHN1cGVyKGFyZyk7XG4gIH1cbn1cbiIsImltcG9ydCB7IE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IsIE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBGYWJyaWNNb2RlbEtleXMgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBTZWdyZWdhdGVkTW9kZWwgfSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IERCS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQ29sbGVjdGlvblJlc29sdmVyLCBNaXJyb3JNZXRhZGF0YSB9IGZyb20gXCIuLi9kZWNvcmF0b3JzXCI7XG5cbk1vZGVsLnByb3RvdHlwZS5pc1NoYXJlZCA9IGZ1bmN0aW9uIGlzU2hhcmVkPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIHRoaXM6IE1cbik6IGJvb2xlYW4ge1xuICByZXR1cm4gTW9kZWwuaXNTaGFyZWQodGhpcy5jb25zdHJ1Y3RvciBhcyBDb25zdHJ1Y3RvcjxNPik7XG59O1xuXG5Nb2RlbC5wcm90b3R5cGUuaXNQcml2YXRlID0gZnVuY3Rpb24gaXNQcml2YXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIHRoaXM6IE1cbik6IGJvb2xlYW4ge1xuICByZXR1cm4gTW9kZWwuaXNQcml2YXRlKHRoaXMuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3I8TT4pO1xufTtcblxuTW9kZWwucHJvdG90eXBlLnNlZ3JlZ2F0ZSA9IGZ1bmN0aW9uIHNlZ3JlZ2F0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICB0aGlzOiBNXG4pOiBTZWdyZWdhdGVkTW9kZWw8TT4ge1xuICByZXR1cm4gTW9kZWwuc2VncmVnYXRlKHRoaXMpO1xufTtcblxuKE1vZGVsIGFzIGFueSkuc2VncmVnYXRlID0gZnVuY3Rpb24gc2VncmVnYXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNXG4pOiBTZWdyZWdhdGVkTW9kZWw8TT4ge1xuICBpZiAoIU1vZGVsLmlzVHJhbnNpZW50KG1vZGVsKSkgcmV0dXJuIHsgbW9kZWw6IG1vZGVsIH07XG4gIGNvbnN0IGRlY29yYXRlZFByb3BlcnRpZXMgPSBNZXRhZGF0YS52YWxpZGF0YWJsZVByb3BlcnRpZXMoXG4gICAgbW9kZWwuY29uc3RydWN0b3IgYXMgYW55XG4gICk7XG5cbiAgY29uc3QgdHJhbnNpZW50UHJvcHMgPSBNZXRhZGF0YS5nZXQoXG4gICAgbW9kZWwuY29uc3RydWN0b3IgYXMgYW55LFxuICAgIERCS2V5cy5UUkFOU0lFTlRcbiAgKTtcbiAgY29uc3QgcHJpdmF0ZVByb3BlcnRpZXMgPSBNZXRhZGF0YS5nZXQoXG4gICAgbW9kZWwuY29uc3RydWN0b3IgYXMgYW55LFxuICAgIEZhYnJpY01vZGVsS2V5cy5QUklWQVRFXG4gICk7XG4gIGNvbnN0IHNoYXJlZFByb3BlcnRpZXMgPSBNZXRhZGF0YS5nZXQoXG4gICAgbW9kZWwuY29uc3RydWN0b3IgYXMgYW55LFxuICAgIEZhYnJpY01vZGVsS2V5cy5TSEFSRURcbiAgKTtcblxuICBjb25zdCByZXN1bHQ6IFNlZ3JlZ2F0ZWRNb2RlbDxNPiA9IHtcbiAgICBtb2RlbDoge30gYXMgUmVjb3JkPGtleW9mIE0sIGFueT4sXG4gICAgdHJhbnNpZW50OiB7fSBhcyBSZWNvcmQ8a2V5b2YgTSwgYW55PixcbiAgICBwcml2YXRlczoge30gYXMgUmVjb3JkPGtleW9mIE0sIGFueT4sXG4gICAgc2hhcmVkOiB7fSBhcyBSZWNvcmQ8a2V5b2YgTSwgYW55PixcbiAgfTtcblxuICBjb25zdCB0cmFuc2llbnRLZXlzID0gT2JqZWN0LmtleXModHJhbnNpZW50UHJvcHMgfHwge30pO1xuICBjb25zdCBwcml2YXRlS2V5cyA9IE9iamVjdC5rZXlzKHByaXZhdGVQcm9wZXJ0aWVzIHx8IHt9KTtcbiAgY29uc3Qgc2hhcmVkS2V5cyA9IE9iamVjdC5rZXlzKHNoYXJlZFByb3BlcnRpZXMgfHwge30pO1xuXG4gIGNvbnN0IHBrS2V5ID0gTW9kZWwucGsobW9kZWwuY29uc3RydWN0b3IgYXMgYW55KTtcbiAgZm9yIChjb25zdCBrZXkgb2YgZGVjb3JhdGVkUHJvcGVydGllcykge1xuICAgIGNvbnN0IHZhbHVlID0gbW9kZWxba2V5IGFzIGtleW9mIE1dO1xuICAgIGNvbnN0IGlzVHJhbnNpZW50ID0gdHJhbnNpZW50S2V5cy5pbmNsdWRlcyhrZXkpO1xuICAgIGNvbnN0IGlzUHJpdmF0ZSA9IHByaXZhdGVLZXlzLmluY2x1ZGVzKGtleSk7XG4gICAgY29uc3QgaXNTaGFyZWQgPSBzaGFyZWRLZXlzLmluY2x1ZGVzKGtleSk7XG4gICAgY29uc3QgaXNQcmltYXJ5S2V5ID0ga2V5ID09PSBwa0tleTtcbiAgICBjb25zdCBkZWNvcmF0ZWRWYWx1ZSA9XG4gICAgICBpc1ByaW1hcnlLZXkgJiYgdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICYmICF2YWx1ZS5lbmRzV2l0aChcIixcIilcbiAgICAgICAgPyBgJHt2YWx1ZX0sYFxuICAgICAgICA6IHZhbHVlO1xuICAgIGlmIChpc1RyYW5zaWVudCB8fCBpc1ByaXZhdGUgfHwgaXNTaGFyZWQpIHtcbiAgICAgIHJlc3VsdC50cmFuc2llbnQgPSByZXN1bHQudHJhbnNpZW50IHx8ICh7fSBhcyBhbnkpO1xuICAgICAgKHJlc3VsdC50cmFuc2llbnQgYXMgYW55KVtrZXldID0gZGVjb3JhdGVkVmFsdWU7XG4gICAgfVxuICAgIGlmIChpc1ByaXZhdGUpIHtcbiAgICAgIHJlc3VsdC5wcml2YXRlcyA9IHJlc3VsdC5wcml2YXRlcyB8fCAoe30gYXMgYW55KTtcbiAgICAgIChyZXN1bHQucHJpdmF0ZXMgYXMgYW55KVtrZXldID0gZGVjb3JhdGVkVmFsdWU7XG4gICAgfVxuICAgIGlmIChpc1NoYXJlZCkge1xuICAgICAgcmVzdWx0LnNoYXJlZCA9IHJlc3VsdC5zaGFyZWQgfHwgKHt9IGFzIGFueSk7XG4gICAgICAocmVzdWx0LnNoYXJlZCBhcyBhbnkpW2tleV0gPSBkZWNvcmF0ZWRWYWx1ZTtcbiAgICB9XG4gICAgY29uc3Qgc2hvdWxkSW5jbHVkZUluTW9kZWwgPSAhaXNUcmFuc2llbnQgJiYgIWlzUHJpdmF0ZSAmJiAhaXNTaGFyZWQ7XG4gICAgaWYgKHNob3VsZEluY2x1ZGVJbk1vZGVsKSB7XG4gICAgICByZXN1bHQubW9kZWwgPSByZXN1bHQubW9kZWwgfHwge307XG4gICAgICAocmVzdWx0Lm1vZGVsIGFzIGFueSlba2V5XSA9IHZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIHJlc3VsdC5tb2RlbCA9IE1vZGVsLmJ1aWxkKHJlc3VsdC5tb2RlbCwgbW9kZWwuY29uc3RydWN0b3IubmFtZSk7XG4gIHJldHVybiByZXN1bHQgYXMgU2VncmVnYXRlZE1vZGVsPE0+O1xufS5iaW5kKE1vZGVsKTtcblxuKE1vZGVsIGFzIGFueSkuaXNQcml2YXRlID0gZnVuY3Rpb24gaXNQcml2YXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNIHwgQ29uc3RydWN0b3I8TT5cbik6IGJvb2xlYW4ge1xuICByZXR1cm4gISFNZXRhZGF0YS5nZXQoXG4gICAgdHlwZW9mIG1vZGVsICE9PSBcImZ1bmN0aW9uXCIgPyAobW9kZWwuY29uc3RydWN0b3IgYXMgYW55KSA6IG1vZGVsLFxuICAgIEZhYnJpY01vZGVsS2V5cy5QUklWQVRFXG4gICk7XG59LmJpbmQoTW9kZWwpO1xuXG4oTW9kZWwgYXMgYW55KS5pc1NoYXJlZCA9IGZ1bmN0aW9uIGlzU2hhcmVkPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNIHwgQ29uc3RydWN0b3I8TT5cbik6IGJvb2xlYW4ge1xuICByZXR1cm4gISFNZXRhZGF0YS5nZXQoXG4gICAgdHlwZW9mIG1vZGVsICE9PSBcImZ1bmN0aW9uXCIgPyAobW9kZWwuY29uc3RydWN0b3IgYXMgYW55KSA6IG1vZGVsLFxuICAgIEZhYnJpY01vZGVsS2V5cy5TSEFSRURcbiAgKTtcbn0uYmluZChNb2RlbCk7XG5cbihNb2RlbCBhcyBhbnkpLm1pcnJvcmVkID0gZnVuY3Rpb24gbWlycm9yZWQ8TSBleHRlbmRzIE1vZGVsPihcbiAgbW9kZWw6IE0gfCBDb25zdHJ1Y3RvcjxNPlxuKTogYm9vbGVhbiB7XG4gIHJldHVybiBNZXRhZGF0YS5nZXQoXG4gICAgdHlwZW9mIG1vZGVsICE9PSBcImZ1bmN0aW9uXCIgPyAobW9kZWwuY29uc3RydWN0b3IgYXMgYW55KSA6IG1vZGVsLFxuICAgIE1ldGFkYXRhLmtleShGYWJyaWNNb2RlbEtleXMuRkFCUklDLCBGYWJyaWNNb2RlbEtleXMuTUlSUk9SKVxuICApO1xufS5iaW5kKE1vZGVsKTtcblxuKE1vZGVsIGFzIGFueSkub3duZXJPZiA9IGZ1bmN0aW9uIG93bmVyT2Y8TSBleHRlbmRzIE1vZGVsPihcbiAgbW9kZWw6IE1cbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG1ldGEgPSBNZXRhZGF0YS5nZXQoXG4gICAgbW9kZWwuY29uc3RydWN0b3IgYXMgYW55LFxuICAgIE1ldGFkYXRhLmtleShGYWJyaWNNb2RlbEtleXMuRkFCUklDLCBGYWJyaWNNb2RlbEtleXMuT1dORURfQlkpXG4gICk7XG4gIGlmICghbWV0YSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIG1vZGVsW21ldGEgYXMga2V5b2YgTV0gYXMgc3RyaW5nO1xufS5iaW5kKE1vZGVsKTtcblxuKE1vZGVsIGFzIGFueSkubWlycm9yZWRBdCA9IGZ1bmN0aW9uIG1pcnJvcmVkQXQ8TSBleHRlbmRzIE1vZGVsPihcbiAgbW9kZWw6IE0gfCBDb25zdHJ1Y3RvcjxNPlxuKTogTWlycm9yTWV0YWRhdGEgfCB1bmRlZmluZWQge1xuICBtb2RlbCA9IHR5cGVvZiBtb2RlbCAhPT0gXCJmdW5jdGlvblwiID8gKG1vZGVsLmNvbnN0cnVjdG9yIGFzIGFueSkgOiBtb2RlbDtcbiAgcmV0dXJuIE1ldGFkYXRhLmdldChcbiAgICBtb2RlbCBhcyBhbnksXG4gICAgTWV0YWRhdGEua2V5KEZhYnJpY01vZGVsS2V5cy5GQUJSSUMsIEZhYnJpY01vZGVsS2V5cy5NSVJST1IpXG4gICk7XG59LmJpbmQoTW9kZWwpO1xuXG4oTW9kZWwgYXMgYW55KS5jb2xsZWN0aW9uc0ZvciA9IGZ1bmN0aW9uIGNvbGxlY3Rpb25zRm9yPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNIHwgQ29uc3RydWN0b3I8TT5cbik6IHtcbiAgcHJpdmF0ZUNvbHM6IChzdHJpbmcgfCBDb2xsZWN0aW9uUmVzb2x2ZXIpW107XG4gIHNoYXJlZENvbHM6IChzdHJpbmcgfCBDb2xsZWN0aW9uUmVzb2x2ZXIpW107XG59IHtcbiAgY29uc3QgcHJpdmF0ZUtleXM6IHN0cmluZ1tdID0gW0ZhYnJpY01vZGVsS2V5cy5QUklWQVRFXSBhcyBzdHJpbmdbXTtcbiAgY29uc3Qgc2hhcmVkS2V5czogc3RyaW5nW10gPSBbRmFicmljTW9kZWxLZXlzLlNIQVJFRF0gYXMgc3RyaW5nW107XG5cbiAgY29uc3QgcHJpdmF0ZUtleSA9IE1ldGFkYXRhLmtleSguLi5wcml2YXRlS2V5cyk7XG4gIGNvbnN0IHNoYXJlZEtleSA9IE1ldGFkYXRhLmtleSguLi5zaGFyZWRLZXlzKTtcblxuICBjb25zdCBjb25zdHIgPSB0eXBlb2YgbW9kZWwgPT09IFwiZnVuY3Rpb25cIiA/IG1vZGVsIDogbW9kZWwuY29uc3RydWN0b3I7XG5cbiAgY29uc3QgcHJpdmF0ZU1ldGE6IHsgY29sbGVjdGlvbnM6IHN0cmluZ1tdIH0gPSBNZXRhZGF0YS5nZXQoXG4gICAgY29uc3RyIGFzIGFueSxcbiAgICBwcml2YXRlS2V5XG4gICk7XG4gIGNvbnN0IHNoYXJlZE1ldGE6IHsgY29sbGVjdGlvbnM6IHN0cmluZ1tdIH0gPSBNZXRhZGF0YS5nZXQoXG4gICAgY29uc3RyIGFzIGFueSxcbiAgICBzaGFyZWRLZXlcbiAgKTtcblxuICByZXR1cm4ge1xuICAgIHByaXZhdGVDb2xzOiBwcml2YXRlTWV0YT8uY29sbGVjdGlvbnMgfHwgW10sXG4gICAgc2hhcmVkQ29sczogc2hhcmVkTWV0YT8uY29sbGVjdGlvbnMgfHwgW10sXG4gIH07XG59LmJpbmQoTW9kZWwpO1xuIiwiaW1wb3J0IHtcbiAgQXV0aG9yaXphdGlvbkVycm9yLFxuICBSZXBvLFxuICBDb250ZXh0LFxuICBVbnN1cHBvcnRlZEVycm9yLFxuICBSZXBvc2l0b3J5LFxuICBDb250ZXh0T2YsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHtcbiAgYWZ0ZXJDcmVhdGUsXG4gIGFmdGVyRGVsZXRlLFxuICBhZnRlclVwZGF0ZSxcbiAgZ2VuZXJhdGVkLFxuICBJbnRlcm5hbEVycm9yLFxuICBOb3RGb3VuZEVycm9yLFxuICBvbkNyZWF0ZSxcbiAgb25EZWxldGUsXG4gIG9uUmVhZCxcbiAgb25VcGRhdGUsXG4gIHJlYWRvbmx5LFxuICB0cmFuc2llbnQsXG4gIFZhbGlkYXRpb25FcnJvcixcbiAgREJLZXlzLFxuICBEQk9wZXJhdGlvbnMsXG4gIG9uLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IE1vZGVsLCByZXF1aXJlZCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY01vZGVsS2V5cyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0IGFzIEhMQ29udGV4dCB9IGZyb20gXCJmYWJyaWMtY29udHJhY3QtYXBpXCI7XG5pbXBvcnQgeyBDbGllbnRJZGVudGl0eSB9IGZyb20gXCJmYWJyaWMtc2hpbS1hcGlcIjtcbmltcG9ydCB7IEZhYnJpY0VSQzIwQ29udHJhY3QgfSBmcm9tIFwiLi4vY29udHJhY3RzL2VyYzIwL2VyYzIwY29udHJhY3RcIjtcbmltcG9ydCB7XG4gIGFwcGx5LFxuICBDb25zdHJ1Y3RvcixcbiAgRGVjb3JhdGlvbixcbiAgbWV0YWRhdGEsXG4gIE1ldGFkYXRhLFxuICBwcm9wLFxuICBwcm9wTWV0YWRhdGEsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljRmxhZ3MgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgdG9QYXNjYWxDYXNlIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdEZsYWdzIH0gZnJvbSBcIi4uL2NvbnRyYWN0cy90eXBlc1wiO1xuaW1wb3J0IFwiLi4vc2hhcmVkL292ZXJyaWRlc1wiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RDb250ZXh0IH0gZnJvbSBcIi4uL2NvbnRyYWN0cy9pbmRleFwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFeHRyYWN0cyB0aGUgTVNQIElEIGZyb20gZWl0aGVyIGEgc3RyaW5nIG9yIENsaWVudElkZW50aXR5IG9iamVjdFxuICogQHBhcmFtIGlkZW50aXR5IC0gVGhlIGlkZW50aXR5IHZhbHVlIHdoaWNoIGNhbiBiZSBhIHN0cmluZyBNU1AgSUQgb3IgQ2xpZW50SWRlbnRpdHkgb2JqZWN0XG4gKiBAcmV0dXJucyBUaGUgTVNQIElEIGFzIGEgc3RyaW5nLCBvciB1bmRlZmluZWQgaWYgbm90IGF2YWlsYWJsZVxuICovXG5mdW5jdGlvbiBleHRyYWN0TXNwSWQoXG4gIGlkZW50aXR5OiBzdHJpbmcgfCBDbGllbnRJZGVudGl0eSB8IHVuZGVmaW5lZFxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgaWYgKCFpZGVudGl0eSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgaWYgKHR5cGVvZiBpZGVudGl0eSA9PT0gXCJzdHJpbmdcIikgcmV0dXJuIGlkZW50aXR5O1xuICByZXR1cm4gaWRlbnRpdHkuZ2V0TVNQSUQoKTtcbn1cblxuLyoqXG4gKiBEZWNvcmF0b3IgZm9yIG1hcmtpbmcgbWV0aG9kcyB0aGF0IHJlcXVpcmUgb3duZXJzaGlwIGF1dGhvcml6YXRpb24uXG4gKiBDaGVja3MgdGhlIG93bmVyIG9mIHRoZSB0b2tlbiBiZWZvcmUgYWxsb3dpbmcgdGhlIG1ldGhvZCB0byBiZSBleGVjdXRlZC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY2xhc3MgVG9rZW5Db250cmFjdCBleHRlbmRzIENvbnRyYWN0IHtcbiAqICAgQE93bmVyKClcbiAqICAgYXN5bmMgTWludChjdHg6IENvbnRleHQsIGFtb3VudDogbnVtYmVyKSB7XG4gKiAgICAgLy8gTWludCB0b2tlbiBsb2dpY1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAcmV0dXJucyB7TWV0aG9kRGVjb3JhdG9yfSBBIG1ldGhvZCBkZWNvcmF0b3IgdGhhdCBjaGVja3Mgb3duZXJzaGlwIGF1dGhvcml6YXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPd25lcigpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBwcm9wZXJ0eUtleTogc3RyaW5nLFxuICAgIGRlc2NyaXB0b3I6IFByb3BlcnR5RGVzY3JpcHRvclxuICApIHtcbiAgICBjb25zdCBvcmlnaW5hbE1ldGhvZCA9IGRlc2NyaXB0b3IudmFsdWU7XG5cbiAgICBkZXNjcmlwdG9yLnZhbHVlID0gYXN5bmMgZnVuY3Rpb24gKFxuICAgICAgdGhpczogRmFicmljRVJDMjBDb250cmFjdCxcbiAgICAgIC4uLmFyZ3M6IGFueVtdXG4gICAgKSB7XG4gICAgICBjb25zdCBjdHg6IEhMQ29udGV4dCA9IGFyZ3NbMF07XG4gICAgICBjb25zdCBhY291bnRJZCA9IGN0eC5jbGllbnRJZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgICBjb25zdCBzZWxlY3QgPSBhd2FpdCAodGhpcyBhcyBGYWJyaWNFUkMyMENvbnRyYWN0KVtcbiAgICAgICAgXCJ0b2tlblJlcG9zaXRvcnlcIlxuICAgICAgXS5zZWxlY3QoKTtcblxuICAgICAgY29uc3QgdG9rZW5zID0gYXdhaXQgc2VsZWN0LmV4ZWN1dGUoY3R4KTtcblxuICAgICAgaWYgKHRva2Vucy5sZW5ndGggPT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihcIk5vIHRva2VucyBhdmFpYWxibGVcIik7XG4gICAgICB9XG5cbiAgICAgIGlmICh0b2tlbnMubGVuZ3RoID4gMSkge1xuICAgICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihgVG8gbWFueSB0b2tlbiBhdmFpbGFibGUgOiAke3Rva2Vucy5sZW5ndGh9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0b2tlbnNbMF0ub3duZXIgIT0gYWNvdW50SWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEF1dGhvcml6YXRpb25FcnJvcihcbiAgICAgICAgICBgVXNlciBub3QgYXV0aG9yaXplZCB0byBydW4gJHtwcm9wZXJ0eUtleX0gb24gdGhlIHRva2VuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gYXdhaXQgb3JpZ2luYWxNZXRob2QuYXBwbHkodGhpcywgYXJncyk7XG4gICAgfTtcblxuICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICB9O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gb3duZWRCeU9uQ3JlYXRlPFxuICBNIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4sXG4gIFIgZXh0ZW5kcyBSZXBvPE0+LFxuICBWLFxuPihcbiAgdGhpczogUixcbiAgY29udGV4dDogQ29udGV4dE9mPFI+LFxuICBkYXRhOiBWLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgeyBzdHViIH0gPSBjb250ZXh0IGFzIGFueTtcblxuICBjb25zdCBjcmVhdG9yID0gYXdhaXQgc3R1Yi5nZXRDcmVhdG9yKCk7XG4gIGNvbnN0IG93bmVyID0gY3JlYXRvci5tc3BpZDtcblxuICBjb25zdCBzZXRPd25lZEJ5S2V5VmFsdWUgPSBmdW5jdGlvbiA8TSBleHRlbmRzIE1vZGVsPihcbiAgICB0YXJnZXQ6IE0sXG4gICAgcHJvcGVydHlLZXk6IHN0cmluZyxcbiAgICB2YWx1ZTogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50XG4gICkge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIHByb3BlcnR5S2V5LCB7XG4gICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgdmFsdWU6IHZhbHVlLFxuICAgIH0pO1xuICB9O1xuXG4gIHNldE93bmVkQnlLZXlWYWx1ZShtb2RlbCwga2V5IGFzIHN0cmluZywgb3duZXIpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gb3duZWRCeSgpIHtcbiAgZnVuY3Rpb24gb3duZWRCeSgpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKG9iajogYW55LCBhdHRyaWJ1dGU/OiBhbnkpIHtcbiAgICAgIHJldHVybiBhcHBseShcbiAgICAgICAgcmVxdWlyZWQoKSxcbiAgICAgICAgZ2VuZXJhdGVkKCksXG4gICAgICAgIHJlYWRvbmx5KCksXG4gICAgICAgIG9uQ3JlYXRlKG93bmVkQnlPbkNyZWF0ZSksXG4gICAgICAgIHByb3BNZXRhZGF0YShcbiAgICAgICAgICBNZXRhZGF0YS5rZXkoRmFicmljTW9kZWxLZXlzLkZBQlJJQywgRmFicmljTW9kZWxLZXlzLk9XTkVEX0JZKSxcbiAgICAgICAgICBhdHRyaWJ1dGVcbiAgICAgICAgKVxuICAgICAgKShvYmosIGF0dHJpYnV0ZSk7XG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiBEZWNvcmF0aW9uLmZvcihGYWJyaWNNb2RlbEtleXMuT1dORURfQlkpXG4gICAgLmRlZmluZSh7XG4gICAgICBkZWNvcmF0b3I6IG93bmVkQnksXG4gICAgICBhcmdzOiBbXSxcbiAgICB9KVxuICAgIC5hcHBseSgpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdHJhbnNhY3Rpb25JZE9uQ3JlYXRlPFxuICBNIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4sXG4gIFIgZXh0ZW5kcyBSZXBvPE0+LFxuICBWLFxuPihcbiAgdGhpczogUixcbiAgY29udGV4dDogQ29udGV4dE9mPFI+LFxuICBkYXRhOiBWLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgeyBzdHViIH0gPSBjb250ZXh0IGFzIGFueTtcbiAgbW9kZWxba2V5XSA9IHN0dWIuZ2V0VHhJRCgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdHJhbnNhY3Rpb25JZCgpIHtcbiAgZnVuY3Rpb24gdHJhbnNhY3Rpb25JZCgpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKG9iajogYW55LCBhdHRyaWJ1dGU/OiBhbnkpIHtcbiAgICAgIHJldHVybiBhcHBseShcbiAgICAgICAgcmVxdWlyZWQoKSxcbiAgICAgICAgcmVhZG9ubHkoKSxcbiAgICAgICAgb25DcmVhdGUodHJhbnNhY3Rpb25JZE9uQ3JlYXRlKSxcbiAgICAgICAgb25VcGRhdGUodHJhbnNhY3Rpb25JZE9uQ3JlYXRlKSxcbiAgICAgICAgcHJvcE1ldGFkYXRhKFxuICAgICAgICAgIE1ldGFkYXRhLmtleShcbiAgICAgICAgICAgIEZhYnJpY01vZGVsS2V5cy5GQUJSSUMsXG4gICAgICAgICAgICBhdHRyaWJ1dGUsXG4gICAgICAgICAgICBGYWJyaWNNb2RlbEtleXMuVFJBTlNBQ1RJT05fSURcbiAgICAgICAgICApLFxuICAgICAgICAgIGF0dHJpYnV0ZVxuICAgICAgICApXG4gICAgICApKG9iaiwgYXR0cmlidXRlKTtcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKEZhYnJpY01vZGVsS2V5cy5UUkFOU0FDVElPTl9JRClcbiAgICAuZGVmaW5lKHtcbiAgICAgIGRlY29yYXRvcjogdHJhbnNhY3Rpb25JZCxcbiAgICAgIGFyZ3M6IFtdLFxuICAgIH0pXG4gICAgLmFwcGx5KCk7XG59XG5cbmV4cG9ydCB0eXBlIE1pcnJvckNvbmRpdGlvbiA9IChtc3A6IHN0cmluZykgPT4gYm9vbGVhbjtcblxuZXhwb3J0IHR5cGUgTWlycm9yTWV0YWRhdGEgPSB7XG4gIGNvbmRpdGlvbjogTWlycm9yQ29uZGl0aW9uO1xuICByZXNvbHZlcjogQ29sbGVjdGlvblJlc29sdmVyIHwgc3RyaW5nO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGV2YWxNaXJyb3JNZXRhZGF0YTxNIGV4dGVuZHMgTW9kZWw+KFxuICBtb2RlbDogTSxcbiAgcmVzb2x2ZXI6IHVuZGVmaW5lZCB8IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlcixcbiAgY3R4OiBDb250ZXh0PEZhYnJpY0NvbnRyYWN0RmxhZ3M+XG4pIHtcbiAgbGV0IGNvbGxlY3Rpb246IENvbGxlY3Rpb25SZXNvbHZlciB8IHN0cmluZyB8IHVuZGVmaW5lZCA9IHJlc29sdmVyO1xuICBpZiAodHlwZW9mIGNvbGxlY3Rpb24gIT09IFwic3RyaW5nXCIpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgb3duZXIgPVxuICAgICAgICBNb2RlbC5vd25lck9mKG1vZGVsKSB8fCBjdHguZ2V0KFwic3R1YlwiKS5nZXRDcmVhdG9yKCkudG9TdHJpbmcoKTtcbiAgICAgIGlmIChyZXNvbHZlciAmJiB0eXBlb2YgcmVzb2x2ZXIgPT09IFwiZnVuY3Rpb25cIilcbiAgICAgICAgY29sbGVjdGlvbiA9IGF3YWl0IHJlc29sdmVyKG1vZGVsLCBvd25lciwgY3R4KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihgRmFpbGVkIHRvIHJlc29sdmUgY29sbGVjdGlvbiBtaXJyb3IgbmFtZTogJHtlfWApO1xuICAgIH1cbiAgfVxuXG4gIGlmICghY29sbGVjdGlvbiB8fCB0eXBlb2YgY29sbGVjdGlvbiAhPT0gXCJzdHJpbmdcIilcbiAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgIGBObyBjb2xsZWN0aW9uIGZvdW5kIG1vZGVsICR7bW9kZWwuY29uc3RydWN0b3IubmFtZX1gXG4gICAgKTtcbiAgcmV0dXJuIGNvbGxlY3Rpb247XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVNaXJyb3JIYW5kbGVyPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBSZXBvc2l0b3J5PE0sIGFueT4sXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBDb250ZXh0PEZhYnJpY0NvbnRyYWN0RmxhZ3M+LFxuICBkYXRhOiBNaXJyb3JNZXRhZGF0YSxcbiAga2V5OiBrZXlvZiBNLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGNvbGxlY3Rpb24gPSBhd2FpdCBldmFsTWlycm9yTWV0YWRhdGEobW9kZWwsIGRhdGEucmVzb2x2ZXIsIGNvbnRleHQpO1xuXG4gIGNvbnN0IHJlcG8gPSB0aGlzLm92ZXJyaWRlKFxuICAgIE9iamVjdC5hc3NpZ24oe30sIHRoaXMuX292ZXJyaWRlcywge1xuICAgICAgc2VncmVnYXRlOiBjb2xsZWN0aW9uLFxuICAgICAgaWdub3JlVmFsaWRhdGlvbjogdHJ1ZSxcbiAgICAgIGlnbm9yZUhhbmRsZXJzOiB0cnVlLFxuICAgIH0gYXMgYW55KVxuICApO1xuXG4gIGNvbnN0IG1pcnJvciA9IGF3YWl0IHJlcG8uY3JlYXRlKG1vZGVsLCBjb250ZXh0KTtcbiAgY29udGV4dC5sb2dnZXIuaW5mbyhcbiAgICBgTWlycm9yIGZvciAke01vZGVsLnRhYmxlTmFtZSh0aGlzLmNsYXNzKX0gY3JlYXRlZCB3aXRoICR7TW9kZWwucGsobW9kZWwpIGFzIHN0cmluZ306ICR7bWlycm9yW01vZGVsLnBrKG1vZGVsKV19YFxuICApO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlTWlycm9ySGFuZGxlcjxcbiAgTSBleHRlbmRzIE1vZGVsLFxuICBSIGV4dGVuZHMgUmVwb3NpdG9yeTxNLCBhbnk+LFxuPihcbiAgdGhpczogUixcbiAgY29udGV4dDogQ29udGV4dDxGYWJyaWNDb250cmFjdEZsYWdzPixcbiAgZGF0YTogTWlycm9yTWV0YWRhdGEsXG4gIGtleToga2V5b2YgTSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBjb2xsZWN0aW9uID0gYXdhaXQgZXZhbE1pcnJvck1ldGFkYXRhKG1vZGVsLCBkYXRhLnJlc29sdmVyLCBjb250ZXh0KTtcblxuICBjb25zdCByZXBvID0gdGhpcy5vdmVycmlkZShcbiAgICBPYmplY3QuYXNzaWduKHt9LCB0aGlzLl9vdmVycmlkZXMsIHtcbiAgICAgIHNlZ3JlZ2F0ZTogY29sbGVjdGlvbixcbiAgICAgIGlnbm9yZVZhbGlkYXRpb246IHRydWUsXG4gICAgICBpZ25vcmVIYW5kbGVyczogdHJ1ZSxcbiAgICB9IGFzIGFueSlcbiAgKTtcblxuICBjb25zdCBtaXJyb3IgPSBhd2FpdCByZXBvLnVwZGF0ZShtb2RlbCwgY29udGV4dCk7XG4gIGNvbnRleHQubG9nZ2VyLmluZm8oXG4gICAgYE1pcnJvciBmb3IgJHtNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcyl9IHVwZGF0ZWQgd2l0aCAke01vZGVsLnBrKG1vZGVsKSBhcyBzdHJpbmd9OiAke21pcnJvcltNb2RlbC5wayhtb2RlbCldfWBcbiAgKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRlbGV0ZU1pcnJvckhhbmRsZXI8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIFJlcG9zaXRvcnk8TSwgYW55Pixcbj4oXG4gIHRoaXM6IFIsXG4gIGNvbnRleHQ6IENvbnRleHQ8RmFicmljQ29udHJhY3RGbGFncz4sXG4gIGRhdGE6IE1pcnJvck1ldGFkYXRhLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgY29sbGVjdGlvbiA9IGF3YWl0IGV2YWxNaXJyb3JNZXRhZGF0YShtb2RlbCwgZGF0YS5yZXNvbHZlciwgY29udGV4dCk7XG5cbiAgY29uc3QgcmVwbyA9IHRoaXMub3ZlcnJpZGUoXG4gICAgT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5fb3ZlcnJpZGVzLCB7XG4gICAgICBzZWdyZWdhdGU6IGNvbGxlY3Rpb24sXG4gICAgICBpZ25vcmVWYWxpZGF0aW9uOiB0cnVlLFxuICAgICAgaWdub3JlSGFuZGxlcnM6IHRydWUsXG4gICAgfSBhcyBhbnkpXG4gICk7XG5cbiAgY29uc3QgbWlycm9yID0gYXdhaXQgcmVwby5kZWxldGUoTW9kZWwucGsobW9kZWwpIGFzIHN0cmluZywgY29udGV4dCk7XG4gIGNvbnRleHQubG9nZ2VyLmluZm8oXG4gICAgYE1pcnJvciBmb3IgJHtNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcyl9IGRlbGV0ZWQgd2l0aCAke01vZGVsLnBrKG1vZGVsKSBhcyBzdHJpbmd9OiAke21pcnJvcltNb2RlbC5wayhtb2RlbCldfWBcbiAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG1pcnJvcihcbiAgY29sbGVjdGlvbjogQ29sbGVjdGlvblJlc29sdmVyIHwgc3RyaW5nLFxuICBjb25kaXRpb24/OiBNaXJyb3JDb25kaXRpb25cbikge1xuICBmdW5jdGlvbiBtaXJyb3IoXG4gICAgcmVzb2x2ZXI6IENvbGxlY3Rpb25SZXNvbHZlciB8IHN0cmluZyxcbiAgICBjb25kaXRpb246IE1pcnJvckNvbmRpdGlvblxuICApIHtcbiAgICBjb25zdCBtZXRhOiBNaXJyb3JNZXRhZGF0YSA9IHtcbiAgICAgIGNvbmRpdGlvbjogY29uZGl0aW9uLFxuICAgICAgcmVzb2x2ZXI6IHJlc29sdmVyLFxuICAgIH07XG4gICAgcmV0dXJuIGFwcGx5KFxuICAgICAgbWV0YWRhdGEoXG4gICAgICAgIE1ldGFkYXRhLmtleShGYWJyaWNNb2RlbEtleXMuRkFCUklDLCBGYWJyaWNNb2RlbEtleXMuTUlSUk9SKSxcbiAgICAgICAgbWV0YVxuICAgICAgKSxcbiAgICAgIHByaXZhdGVEYXRhKGNvbGxlY3Rpb24pLFxuICAgICAgYWZ0ZXJDcmVhdGUoY3JlYXRlTWlycm9ySGFuZGxlciBhcyBhbnksIG1ldGEsIHsgcHJpb3JpdHk6IDk1IH0pLFxuICAgICAgYWZ0ZXJVcGRhdGUodXBkYXRlTWlycm9ySGFuZGxlciBhcyBhbnksIG1ldGEsIHsgcHJpb3JpdHk6IDk1IH0pLFxuICAgICAgYWZ0ZXJEZWxldGUoZGVsZXRlTWlycm9ySGFuZGxlciBhcyBhbnksIG1ldGEsIHsgcHJpb3JpdHk6IDk1IH0pXG4gICAgKTtcbiAgfVxuXG4gIHJldHVybiBEZWNvcmF0aW9uLmZvcihGYWJyaWNNb2RlbEtleXMuTUlSUk9SKVxuICAgIC5kZWZpbmUoe1xuICAgICAgZGVjb3JhdG9yOiBtaXJyb3IsXG4gICAgICBhcmdzOiBbY29sbGVjdGlvbiwgY29uZGl0aW9uXSxcbiAgICB9KVxuICAgIC5hcHBseSgpO1xufVxuXG5leHBvcnQgdHlwZSBDb2xsZWN0aW9uUmVzb2x2ZXIgPSA8TSBleHRlbmRzIE1vZGVsPihcbiAgbW9kZWw6IE0gfCBDb25zdHJ1Y3RvcjxNPixcbiAgbXNwPzogc3RyaW5nLFxuICAuLi5hcmdzOiBhbnlbXVxuKSA9PiBzdHJpbmc7XG5cbmV4cG9ydCBjb25zdCBNb2RlbENvbGxlY3Rpb246IENvbGxlY3Rpb25SZXNvbHZlciA9IDxNIGV4dGVuZHMgTW9kZWw+KFxuICBtb2RlbDogTSB8IENvbnN0cnVjdG9yPE0+LFxuICBtc3BJZD86IHN0cmluZ1xuKSA9PiB7XG4gIGNvbnN0IG9yZ05hbWUgPVxuICAgIG1zcElkIHx8ICh0eXBlb2YgbW9kZWwgIT09IFwiZnVuY3Rpb25cIiA/IE1vZGVsLm93bmVyT2YobW9kZWwpIDogdW5kZWZpbmVkKTtcbiAgY29uc3QgY29uc3RyID0gdHlwZW9mIG1vZGVsID09PSBcImZ1bmN0aW9uXCIgPyBtb2RlbCA6IG1vZGVsLmNvbnN0cnVjdG9yO1xuICBpZiAoIW9yZ05hbWUpXG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICBgTW9kZWwgJHtjb25zdHIubmFtZX0gaXMgbm90IG93bmVkIGJ5IGFueSBvcmdhbml6YXRpb24uIGRpZCB5b3UgdXNlIEBvd25lZEJ5KCkgKG9yIHByb3ZpZGUgdGhlIG5hbWUpP2BcbiAgICApO1xuICByZXR1cm4gYCR7dG9QYXNjYWxDYXNlKGNvbnN0ci5uYW1lKX0ke29yZ05hbWUgPyB0b1Bhc2NhbENhc2Uob3JnTmFtZSkgOiBcIlwifWA7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gTmFtZXNwYWNlQ29sbGVjdGlvbihuYW1lc3BhY2U6IHN0cmluZyk6IENvbGxlY3Rpb25SZXNvbHZlciB7XG4gIHJldHVybiA8TSBleHRlbmRzIE1vZGVsPihtb2RlbDogTSB8IENvbnN0cnVjdG9yPE0+LCBtc3BJZD86IHN0cmluZykgPT4ge1xuICAgIGNvbnN0IG9yZ05hbWUgPVxuICAgICAgbXNwSWQgfHwgKHR5cGVvZiBtb2RlbCAhPT0gXCJmdW5jdGlvblwiID8gTW9kZWwub3duZXJPZihtb2RlbCkgOiB1bmRlZmluZWQpO1xuICAgIGNvbnN0IGNvbnN0ciA9IHR5cGVvZiBtb2RlbCA9PT0gXCJmdW5jdGlvblwiID8gbW9kZWwgOiBtb2RlbC5jb25zdHJ1Y3RvcjtcbiAgICBpZiAoIW9yZ05hbWUpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgYE1vZGVsICR7Y29uc3RyLm5hbWV9IGlzIG5vdCBvd25lZCBieSBhbnkgb3JnYW5pemF0aW9uLiBkaWQgeW91IHVzZSBAb3duZWRCeSgpIChvciBwcm92aWRlIHRoZSBuYW1lKT9gXG4gICAgICApO1xuICAgIHJldHVybiBgJHtuYW1lc3BhY2V9JHtvcmdOYW1lID8gdG9QYXNjYWxDYXNlKG9yZ05hbWUpIDogXCJcIn1gO1xuICB9O1xufVxuXG5leHBvcnQgY29uc3QgSW1wbGljaXRQcml2YXRlQ29sbGVjdGlvbjogQ29sbGVjdGlvblJlc29sdmVyID0gPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNIHwgQ29uc3RydWN0b3I8TT4sXG4gIG1zcElkPzogc3RyaW5nXG4pID0+IHtcbiAgY29uc3Qgb3JnTmFtZSA9XG4gICAgbXNwSWQgfHwgKHR5cGVvZiBtb2RlbCAhPT0gXCJmdW5jdGlvblwiID8gTW9kZWwub3duZXJPZihtb2RlbCkgOiB1bmRlZmluZWQpO1xuICBpZiAoIW9yZ05hbWUpXG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICBgTW9kZWwgJHttb2RlbC5jb25zdHJ1Y3Rvci5uYW1lfSBpcyBub3Qgb3duZWQgYnkgYW55IG9yZ2FuaXphdGlvbi4gZGlkIHlvdSB1c2UgQG93bmVkQnkoKSAob3IgcHJvdmlkZSB0aGUgbmFtZSk/YFxuICAgICk7XG4gIHJldHVybiBgX18ke3RvUGFzY2FsQ2FzZShvcmdOYW1lKX1Qcml2YXRlQ29sbGVjdGlvbmA7XG59O1xuXG5leHBvcnQgdHlwZSBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhID0ge1xuICBjb2xsZWN0aW9uczogc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyO1xufTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUHJpb3JpdHkgZm9yIGVhcmx5IGNvbGxlY3Rpb24gZXh0cmFjdGlvbiAoYmVmb3JlIHBrIGdlbmVyYXRpb24gYXQgcHJpb3JpdHkgNjApXG4gKiBAc3VtbWFyeSBUaGlzIHByaW9yaXR5IGVuc3VyZXMgY29sbGVjdGlvbnMgYXJlIHJlZ2lzdGVyZWQgaW4gY29udGV4dCBiZWZvcmUgYW55IHNlcXVlbmNlXG4gKiBvcGVyYXRpb25zIG9jY3VyLCBhbGxvd2luZyBzZXF1ZW5jZXMgdG8gYmUgcmVwbGljYXRlZCB0byBwcml2YXRlL3NoYXJlZCBjb2xsZWN0aW9ucy5cbiAqL1xuZXhwb3J0IGNvbnN0IFNFR1JFR0FURURfQ09MTEVDVElPTl9FWFRSQUNUSU9OX1BSSU9SSVRZID0gMzU7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVhcmx5IGhhbmRsZXIgdG8gZXh0cmFjdCBhbmQgcmVnaXN0ZXIgY29sbGVjdGlvbnMgaW4gY29udGV4dFxuICogQHN1bW1hcnkgUnVucyB3aXRoIHByaW9yaXR5IDwgNDAgdG8gZXh0cmFjdCBjb2xsZWN0aW9uIG5hbWVzIGJlZm9yZSBwayBnZW5lcmF0aW9uIChwcmlvcml0eSA2MCkuXG4gKiBUaGlzIGFsbG93cyBGYWJyaWNDb250cmFjdFNlcXVlbmNlIHRvIGtub3cgd2hpY2ggY29sbGVjdGlvbnMgdG8gcmVwbGljYXRlIHRvLlxuICogQHRlbXBsYXRlIE0gLSBUeXBlIHRoYXQgZXh0ZW5kcyBNb2RlbFxuICogQHBhcmFtIHtDb250ZXh0T2Y8UmVwb3NpdG9yeTxNLCBhbnk+Pn0gY29udGV4dCAtIFRoZSBleGVjdXRpb24gY29udGV4dFxuICogQHBhcmFtIHtTZWdyZWdhdGVkRGF0YU1ldGFkYXRhIHwgU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdfSBkYXRhIC0gVGhlIHNlZ3JlZ2F0ZWQgZGF0YSBtZXRhZGF0YVxuICogQHBhcmFtIHtzdHJpbmcgfCBzdHJpbmdbXX0ga2V5cyAtIFRoZSBwcm9wZXJ0eSBrZXkocykgYmVpbmcgc2VncmVnYXRlZFxuICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZVxuICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RTZWdyZWdhdGVkQ29sbGVjdGlvbnM8TSBleHRlbmRzIE1vZGVsPihcbiAgdGhpczogUmVwb3NpdG9yeTxNLCBhbnk+LFxuICBjb250ZXh0OiBDb250ZXh0T2Y8dHlwZW9mIHRoaXM+LFxuICBkYXRhOiBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhIHwgU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdLFxuICBrZXlzOiBrZXlvZiBNIHwgKGtleW9mIE0pW10sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgZGF0YUFycmF5ID0gKFxuICAgIEFycmF5LmlzQXJyYXkoZGF0YSkgPyBkYXRhIDogW2RhdGFdXG4gICkgYXMgU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdO1xuXG4gIGNvbnN0IG1zcCA9XG4gICAgTW9kZWwub3duZXJPZihtb2RlbCkgfHxcbiAgICBleHRyYWN0TXNwSWQoXG4gICAgICBjb250ZXh0LmdldChcImlkZW50aXR5XCIpIGFzIHN0cmluZyB8IENsaWVudElkZW50aXR5IHwgdW5kZWZpbmVkXG4gICAgKTtcbiAgaWYgKCFtc3ApIHtcbiAgICAvLyBDYW4ndCBleHRyYWN0IGNvbGxlY3Rpb25zIHdpdGhvdXQgTVNQLCB3aWxsIGJlIGNhdWdodCBieSBsYXRlciBoYW5kbGVyc1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGNvbGxlY3Rpb25zOiBzdHJpbmdbXSA9IFtdO1xuICBmb3IgKGNvbnN0IG1ldGFkYXRhIG9mIGRhdGFBcnJheSkge1xuICAgIGNvbnN0IGNvbGxlY3Rpb25SZXNvbHZlciA9IG1ldGFkYXRhLmNvbGxlY3Rpb25zO1xuICAgIGNvbnN0IGNvbGxlY3Rpb24gPVxuICAgICAgdHlwZW9mIGNvbGxlY3Rpb25SZXNvbHZlciA9PT0gXCJzdHJpbmdcIlxuICAgICAgICA/IGNvbGxlY3Rpb25SZXNvbHZlclxuICAgICAgICA6IGNvbGxlY3Rpb25SZXNvbHZlcihtb2RlbCwgbXNwLCBjb250ZXh0KTtcbiAgICBpZiAoY29sbGVjdGlvbiAmJiAhY29sbGVjdGlvbnMuaW5jbHVkZXMoY29sbGVjdGlvbikpIHtcbiAgICAgIGNvbGxlY3Rpb25zLnB1c2goY29sbGVjdGlvbik7XG4gICAgfVxuICB9XG5cbiAgLy8gUmVnaXN0ZXIgY29sbGVjdGlvbnMgZWFybHkgdXNpbmcgcmVhZEZyb20gLSB0aGlzIGFsbG93cyBzZXF1ZW5jZSBjb2RlXG4gIC8vIHRvIGtub3cgd2hpY2ggY29sbGVjdGlvbnMgdG8gcmVwbGljYXRlIHRvIGR1cmluZyBwayBnZW5lcmF0aW9uXG4gIGlmIChjb2xsZWN0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgKGNvbnRleHQgYXMgRmFicmljQ29udHJhY3RDb250ZXh0KS5yZWFkRnJvbShjb2xsZWN0aW9ucyk7XG4gIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlZ3JlZ2F0ZWREYXRhT25DcmVhdGU8TSBleHRlbmRzIE1vZGVsPihcbiAgdGhpczogUmVwb3NpdG9yeTxNLCBhbnk+LFxuICBjb250ZXh0OiBDb250ZXh0T2Y8dHlwZW9mIHRoaXM+LFxuICBkYXRhOiBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhIHwgU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdLFxuICBrZXlzOiBrZXlvZiBNIHwgKGtleW9mIE0pW10sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgZGF0YUFycmF5ID0gKFxuICAgIEFycmF5LmlzQXJyYXkoZGF0YSkgPyBkYXRhIDogW2RhdGFdXG4gICkgYXMgU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdO1xuICBjb25zdCBrZXlBcnJheSA9IChBcnJheS5pc0FycmF5KGtleXMpID8ga2V5cyA6IFtrZXlzXSkgYXMgKGtleW9mIE0pW107XG4gIGlmIChrZXlBcnJheS5sZW5ndGggIT09IGRhdGFBcnJheS5sZW5ndGgpXG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICBgU2VncmVnYXRlZCBkYXRhIGtleXMgYW5kIG1ldGFkYXRhIGxlbmd0aCBtaXNtYXRjaGBcbiAgICApO1xuXG4gIGNvbnN0IG1zcCA9XG4gICAgTW9kZWwub3duZXJPZihtb2RlbCkgfHxcbiAgICBleHRyYWN0TXNwSWQoXG4gICAgICBjb250ZXh0LmdldChcImlkZW50aXR5XCIpIGFzIHN0cmluZyB8IENsaWVudElkZW50aXR5IHwgdW5kZWZpbmVkXG4gICAgKTtcbiAgaWYgKCFtc3ApXG4gICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihcbiAgICAgIGBUaGVyZSdzIG5vIGFzc2lnbmVkIG9yZ2FuaXphdGlvbiBmb3IgbW9kZWwgJHttb2RlbC5jb25zdHJ1Y3Rvci5uYW1lfWBcbiAgICApO1xuXG4gIGNvbnN0IGNvbGxlY3Rpb25SZXNvbHZlciA9IGRhdGFBcnJheVswXS5jb2xsZWN0aW9ucztcbiAgY29uc3QgY29sbGVjdGlvbiA9XG4gICAgdHlwZW9mIGNvbGxlY3Rpb25SZXNvbHZlciA9PT0gXCJzdHJpbmdcIlxuICAgICAgPyBjb2xsZWN0aW9uUmVzb2x2ZXJcbiAgICAgIDogY29sbGVjdGlvblJlc29sdmVyKG1vZGVsLCBtc3AsIGNvbnRleHQpO1xuXG4gIGNvbnN0IHJlYnVpbHQgPSBrZXlBcnJheS5yZWR1Y2UoXG4gICAgKGFjYzogUmVjb3JkPGtleW9mIE0sIGFueT4sIGssIGkpID0+IHtcbiAgICAgIGNvbnN0IGMgPVxuICAgICAgICB0eXBlb2YgZGF0YUFycmF5W2ldLmNvbGxlY3Rpb25zID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgPyBkYXRhQXJyYXlbaV0uY29sbGVjdGlvbnNcbiAgICAgICAgICA6IGRhdGFBcnJheVtpXS5jb2xsZWN0aW9ucyhtb2RlbCwgbXNwLCBjb250ZXh0KTtcbiAgICAgIGlmIChjICE9PSBjb2xsZWN0aW9uKVxuICAgICAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgICAgICBgU2VncmVnYXRlZCBkYXRhIGNvbGxlY3Rpb24gbWlzbWF0Y2g6ICR7Y30gdnMgJHtjb2xsZWN0aW9ufWBcbiAgICAgICAgKTtcbiAgICAgIGFjY1trXSA9IG1vZGVsW2tdO1xuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LFxuICAgIHt9IGFzIFJlY29yZDxrZXlvZiBNLCBhbnk+XG4gICk7XG5cbiAgY29uc3QgdG9DcmVhdGUgPSBuZXcgdGhpcy5jbGFzcyhyZWJ1aWx0KTtcblxuICBjb25zdCBzZWdyZWdhdGVkID0gTW9kZWwuc2VncmVnYXRlKG1vZGVsKTtcbiAgLy8gIHRvIHRoZSBjb250ZXh0IHRoZSBtb2RlbCwgc2VnZ3JlZ2F0ZWQgYnUgY29sZWxjdGlvbiAoYW5kIGluY2x1ZGluZyB0aGUgbm9uIHRyYW5zaWVudCBwYXJ0KVxuICAoY29udGV4dCBhcyBGYWJyaWNDb250cmFjdENvbnRleHQpLndyaXRlVG8oY29sbGVjdGlvbiwgc2VncmVnYXRlZCk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWdyZWdhdGVkRGF0YU9uUmVhZDxNIGV4dGVuZHMgTW9kZWw+KFxuICB0aGlzOiBSZXBvc2l0b3J5PE0sIGFueT4sXG4gIGNvbnRleHQ6IENvbnRleHQ8RmFicmljRmxhZ3M+LFxuICBkYXRhOiBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhIHwgU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdLFxuICBrZXlzOiBrZXlvZiBNIHwgKGtleW9mIE0pW10sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgZGF0YUFycmF5ID0gKFxuICAgIEFycmF5LmlzQXJyYXkoZGF0YSkgPyBkYXRhIDogW2RhdGFdXG4gICkgYXMgU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdO1xuICBjb25zdCBrZXlBcnJheSA9IChBcnJheS5pc0FycmF5KGtleXMpID8ga2V5cyA6IFtrZXlzXSkgYXMgKGtleW9mIE0pW107XG4gIGlmIChrZXlBcnJheS5sZW5ndGggIT09IGRhdGFBcnJheS5sZW5ndGgpXG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICBgU2VncmVnYXRlZCBkYXRhIGtleXMgYW5kIG1ldGFkYXRhIGxlbmd0aCBtaXNtYXRjaGBcbiAgICApO1xuXG4gIGNvbnN0IG1zcCA9IE1vZGVsLm93bmVyT2YobW9kZWwpIHx8IGV4dHJhY3RNc3BJZChjb250ZXh0LmdldChcImlkZW50aXR5XCIpKTtcbiAgaWYgKCFtc3ApXG4gICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihcbiAgICAgIGBUaGVyZSdzIG5vIGFzc2lnbmVkIG9yZ2FuaXphdGlvbiBmb3IgbW9kZWwgJHttb2RlbC5jb25zdHJ1Y3Rvci5uYW1lfWBcbiAgICApO1xuXG4gIGNvbnN0IGNvbGxlY3Rpb25SZXNvbHZlciA9IGRhdGFBcnJheVswXS5jb2xsZWN0aW9ucztcbiAgY29uc3QgY29sbGVjdGlvbiA9XG4gICAgdHlwZW9mIGNvbGxlY3Rpb25SZXNvbHZlciA9PT0gXCJzdHJpbmdcIlxuICAgICAgPyBjb2xsZWN0aW9uUmVzb2x2ZXJcbiAgICAgIDogYXdhaXQgY29sbGVjdGlvblJlc29sdmVyKG1vZGVsLCBtc3AsIGNvbnRleHQpO1xuXG4gIChjb250ZXh0IGFzIEZhYnJpY0NvbnRyYWN0Q29udGV4dCkucmVhZEZyb20oY29sbGVjdGlvbik7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWdyZWdhdGVkRGF0YU9uVXBkYXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIHRoaXM6IFJlcG9zaXRvcnk8TSwgYW55PixcbiAgY29udGV4dDogQ29udGV4dE9mPHR5cGVvZiB0aGlzPixcbiAgZGF0YTogU2VncmVnYXRlZERhdGFNZXRhZGF0YSB8IFNlZ3JlZ2F0ZWREYXRhTWV0YWRhdGFbXSxcbiAga2V5OiBrZXlvZiBNIHwgKGtleW9mIE0pW10sXG4gIG1vZGVsOiBNLFxuICBvbGRNb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGRhdGFBcnJheSA9IChcbiAgICBBcnJheS5pc0FycmF5KGRhdGEpID8gZGF0YSA6IFtkYXRhXVxuICApIGFzIFNlZ3JlZ2F0ZWREYXRhTWV0YWRhdGFbXTtcbiAgY29uc3Qga2V5QXJyYXkgPSAoQXJyYXkuaXNBcnJheShrZXkpID8ga2V5IDogW2tleV0pIGFzIChrZXlvZiBNKVtdO1xuICBpZiAoa2V5QXJyYXkubGVuZ3RoICE9PSBkYXRhQXJyYXkubGVuZ3RoKVxuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgYFNlZ3JlZ2F0ZWQgZGF0YSBrZXlzIGFuZCBtZXRhZGF0YSBsZW5ndGggbWlzbWF0Y2hgXG4gICAgKTtcblxuICBjb25zdCBtc3AgPVxuICAgIE1vZGVsLm93bmVyT2YobW9kZWwpIHx8XG4gICAgZXh0cmFjdE1zcElkKFxuICAgICAgY29udGV4dC5nZXQoXCJpZGVudGl0eVwiKSBhcyBzdHJpbmcgfCBDbGllbnRJZGVudGl0eSB8IHVuZGVmaW5lZFxuICAgICk7XG4gIGlmICghbXNwKVxuICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXG4gICAgICBgVGhlcmUncyBubyBhc3NpZ25lZCBvcmdhbml6YXRpb24gZm9yIG1vZGVsICR7bW9kZWwuY29uc3RydWN0b3IubmFtZX1gXG4gICAgKTtcblxuICBjb25zdCBjb2xsZWN0aW9uUmVzb2x2ZXIgPSBkYXRhQXJyYXlbMF0uY29sbGVjdGlvbnM7XG4gIGNvbnN0IGNvbGxlY3Rpb24gPVxuICAgIHR5cGVvZiBjb2xsZWN0aW9uUmVzb2x2ZXIgPT09IFwic3RyaW5nXCJcbiAgICAgID8gY29sbGVjdGlvblJlc29sdmVyXG4gICAgICA6IGNvbGxlY3Rpb25SZXNvbHZlcihtb2RlbCwgbXNwLCBjb250ZXh0KTtcblxuICBrZXlBcnJheS5mb3JFYWNoKChrLCBpKSA9PiB7XG4gICAgY29uc3QgYyA9XG4gICAgICB0eXBlb2YgZGF0YUFycmF5W2ldLmNvbGxlY3Rpb25zID09PSBcInN0cmluZ1wiXG4gICAgICAgID8gZGF0YUFycmF5W2ldLmNvbGxlY3Rpb25zXG4gICAgICAgIDogZGF0YUFycmF5W2ldLmNvbGxlY3Rpb25zKG1vZGVsLCBtc3AsIGNvbnRleHQpO1xuICAgIGlmIChjICE9PSBjb2xsZWN0aW9uKVxuICAgICAgdGhyb3cgbmV3IFVuc3VwcG9ydGVkRXJyb3IoXG4gICAgICAgIGBTZWdyZWdhdGVkIGRhdGEgY29sbGVjdGlvbiBtaXNtYXRjaDogJHtjfSB2cyAke2NvbGxlY3Rpb259YFxuICAgICAgKTtcbiAgfSk7XG5cbiAgY29uc3Qgc2VncmVnYXRlZCA9IE1vZGVsLnNlZ3JlZ2F0ZShtb2RlbCk7XG4gIChjb250ZXh0IGFzIEZhYnJpY0NvbnRyYWN0Q29udGV4dCkud3JpdGVUbyhjb2xsZWN0aW9uLCBzZWdyZWdhdGVkKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlZ3JlZ2F0ZWREYXRhT25EZWxldGU8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIFJlcG9zaXRvcnk8TSwgYW55PixcbiAgViBleHRlbmRzIFNlZ3JlZ2F0ZWREYXRhTWV0YWRhdGEsXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBDb250ZXh0T2Y8Uj4sXG4gIGRhdGE6IFYgfCBWW10sXG4gIGtleTogKGtleW9mIE0pW10sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgZGF0YUFycmF5ID0gKEFycmF5LmlzQXJyYXkoZGF0YSkgPyBkYXRhIDogW2RhdGFdKSBhcyBWW107XG4gIGNvbnN0IGtleUFycmF5ID0gKEFycmF5LmlzQXJyYXkoa2V5KSA/IGtleSA6IFtrZXldKSBhcyAoa2V5b2YgTSlbXTtcbiAgaWYgKGtleUFycmF5Lmxlbmd0aCAhPT0gZGF0YUFycmF5Lmxlbmd0aClcbiAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgIGBTZWdyZWdhdGVkIGRhdGEga2V5cyBhbmQgbWV0YWRhdGEgbGVuZ3RoIG1pc21hdGNoYFxuICAgICk7XG5cbiAgY29uc3QgbXNwID1cbiAgICBNb2RlbC5vd25lck9mKG1vZGVsKSB8fFxuICAgIGV4dHJhY3RNc3BJZChcbiAgICAgIGNvbnRleHQuZ2V0KFwiaWRlbnRpdHlcIikgYXMgc3RyaW5nIHwgQ2xpZW50SWRlbnRpdHkgfCB1bmRlZmluZWRcbiAgICApO1xuICBpZiAoIW1zcClcbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFxuICAgICAgYFRoZXJlJ3Mgbm8gYXNzaWduZWQgb3JnYW5pemF0aW9uIGZvciBtb2RlbCAke21vZGVsLmNvbnN0cnVjdG9yLm5hbWV9YFxuICAgICk7XG5cbiAgY29uc3QgY29sbGVjdGlvblJlc29sdmVyID0gZGF0YUFycmF5WzBdLmNvbGxlY3Rpb25zO1xuICBjb25zdCBjb2xsZWN0aW9uID1cbiAgICB0eXBlb2YgY29sbGVjdGlvblJlc29sdmVyID09PSBcInN0cmluZ1wiXG4gICAgICA/IGNvbGxlY3Rpb25SZXNvbHZlclxuICAgICAgOiBjb2xsZWN0aW9uUmVzb2x2ZXIobW9kZWwsIG1zcCwgY29udGV4dCk7XG5cbiAgKGNvbnRleHQgYXMgRmFicmljQ29udHJhY3RDb250ZXh0KS5yZWFkRnJvbShjb2xsZWN0aW9uKTtcbn1cblxuZnVuY3Rpb24gc2VncmVnYXRlZChcbiAgY29sbGVjdGlvbjogc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyLFxuICB0eXBlOiBGYWJyaWNNb2RlbEtleXMuUFJJVkFURSB8IEZhYnJpY01vZGVsS2V5cy5TSEFSRUQsXG4gIGZpbHRlcj86IChwcm9wTmFtZTogc3RyaW5nKSA9PiBib29sZWFuXG4pIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIGlubmVyU2VncmVnYXRlZCh0YXJnZXQ6IG9iamVjdCwgcHJvcGVydHlLZXk/OiBhbnkpIHtcbiAgICBmdW5jdGlvbiBzZWdyZWdhdGVkRGVjKHRhcmdldDogb2JqZWN0LCBwcm9wZXJ0eUtleT86IGFueSkge1xuICAgICAgY29uc3Qga2V5ID0gTWV0YWRhdGEua2V5KHR5cGUsIHByb3BlcnR5S2V5KTtcbiAgICAgIGNvbnN0IGNvbnN0cjogQ29uc3RydWN0b3IgPSB0YXJnZXQuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3I7XG5cbiAgICAgIGNvbnN0IG1ldGEgPSBNZXRhZGF0YS5nZXQoY29uc3RyIGFzIENvbnN0cnVjdG9yLCBrZXkpIHx8IHt9O1xuICAgICAgY29uc3QgY29sbGVjdGlvbnMgPSBuZXcgU2V0KG1ldGEuY29sbGVjdGlvbnMgfHwgW10pO1xuICAgICAgY29sbGVjdGlvbnMuYWRkKGNvbGxlY3Rpb24pO1xuICAgICAgbWV0YS5jb2xsZWN0aW9ucyA9IFsuLi5jb2xsZWN0aW9uc107XG4gICAgICBNZXRhZGF0YS5zZXQoY29uc3RyIGFzIENvbnN0cnVjdG9yLCBrZXksIG1ldGEpO1xuXG4gICAgICBjb25zdCBjb25zdHJNZXRhID0gTWV0YWRhdGEuZ2V0KGNvbnN0ciBhcyBDb25zdHJ1Y3RvciwgdHlwZSkgfHwge307XG4gICAgICBjb25zdCBjb25zdHJDb2xsZWN0aW9ucyA9IG5ldyBTZXQoY29uc3RyTWV0YS5jb2xsZWN0aW9ucyB8fCBbXSk7XG4gICAgICBjb25zdHJDb2xsZWN0aW9ucy5hZGQoY29sbGVjdGlvbik7XG4gICAgICBjb25zdHJNZXRhLmNvbGxlY3Rpb25zID0gWy4uLmNvbnN0ckNvbGxlY3Rpb25zXTtcbiAgICAgIE1ldGFkYXRhLnNldChjb25zdHIgYXMgQ29uc3RydWN0b3IsIHR5cGUsIGNvbnN0ck1ldGEpO1xuXG4gICAgICBjb25zdCB0cmFuc2llbnRNZXRhID1cbiAgICAgICAgTWV0YWRhdGEuZ2V0KGNvbnN0ciBhcyBDb25zdHJ1Y3RvciwgREJLZXlzLlRSQU5TSUVOVCkgfHwge307XG4gICAgICBjb25zdCB1cGRhdGVkVHJhbnNpZW50TWV0YSA9IHtcbiAgICAgICAgLi4udHJhbnNpZW50TWV0YSxcbiAgICAgICAgW3Byb3BlcnR5S2V5IGFzIGFueV06IHt9LFxuICAgICAgfTtcbiAgICAgIE1ldGFkYXRhLnNldChcbiAgICAgICAgY29uc3RyIGFzIENvbnN0cnVjdG9yLFxuICAgICAgICBEQktleXMuVFJBTlNJRU5ULFxuICAgICAgICB1cGRhdGVkVHJhbnNpZW50TWV0YVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZWNzOiBhbnlbXSA9IFtdO1xuICAgIGlmICghcHJvcGVydHlLZXkpIHtcbiAgICAgIC8vIGRlY29yYXRlZCBhdCB0aGUgY2xhc3MgbGV2ZWxcbiAgICAgIGNvbnN0IHByb3BlcnRpZXMgPSBNZXRhZGF0YS52YWxpZGF0YWJsZVByb3BlcnRpZXModGFyZ2V0IGFzIENvbnN0cnVjdG9yKTtcbiAgICAgIHByb3BlcnRpZXM/LmZvckVhY2goKHApID0+IHtcbiAgICAgICAgaWYgKCFmaWx0ZXIgfHwgZmlsdGVyKHApKSB7XG4gICAgICAgICAgc2VncmVnYXRlZChjb2xsZWN0aW9uLCB0eXBlKSgodGFyZ2V0IGFzIGFueSkucHJvdG90eXBlLCBwKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGdyb3VwTmFtZSA9XG4gICAgICAgIHR5cGVvZiBjb2xsZWN0aW9uID09PSBcInN0cmluZ1wiID8gY29sbGVjdGlvbiA6IGNvbGxlY3Rpb24udG9TdHJpbmcoKTtcbiAgICAgIGNvbnN0IGVhcmx5RXh0cmFjdGlvbk1ldGEgPSB7IGNvbGxlY3Rpb25zOiBjb2xsZWN0aW9uIH07XG4gICAgICBjb25zdCBlYXJseUV4dHJhY3Rpb25Hcm91cFNvcnQgPSB7XG4gICAgICAgIHByaW9yaXR5OiBTRUdSRUdBVEVEX0NPTExFQ1RJT05fRVhUUkFDVElPTl9QUklPUklUWSxcbiAgICAgICAgZ3JvdXA6IGdyb3VwTmFtZSxcbiAgICAgIH07XG4gICAgICBkZWNzLnB1c2goXG4gICAgICAgIHByb3AoKSxcbiAgICAgICAgdHJhbnNpZW50KCksXG4gICAgICAgIHNlZ3JlZ2F0ZWREZWMsXG4gICAgICAgIC8vIEVhcmx5IGV4dHJhY3Rpb24gaGFuZGxlcnMgLSBydW4gQkVGT1JFIHBrIGdlbmVyYXRpb24gKHByaW9yaXR5IDYwKVxuICAgICAgICAvLyBUaGlzIGVuc3VyZXMgY29sbGVjdGlvbnMgYXJlIHJlZ2lzdGVyZWQgaW4gY29udGV4dCBmb3Igc2VxdWVuY2UgcmVwbGljYXRpb25cbiAgICAgICAgLy8gV2UgcmVnaXN0ZXIgZm9yIGVhY2ggb3BlcmF0aW9uIGV4cGxpY2l0bHkgdG8gZW5zdXJlIHByb3BlciBoYW5kbGVyIGxvb2t1cFxuICAgICAgICBvbihcbiAgICAgICAgICBEQk9wZXJhdGlvbnMuQUxMLFxuICAgICAgICAgIGV4dHJhY3RTZWdyZWdhdGVkQ29sbGVjdGlvbnMgYXMgYW55LFxuICAgICAgICAgIGVhcmx5RXh0cmFjdGlvbk1ldGEsXG4gICAgICAgICAgZWFybHlFeHRyYWN0aW9uR3JvdXBTb3J0XG4gICAgICAgICksXG4gICAgICAgIC8vIE1haW4gaGFuZGxlcnMgZm9yIHNlZ3JlZ2F0ZWQgZGF0YSBvcGVyYXRpb25zIChwcmlvcml0eSA5NSlcbiAgICAgICAgb25DcmVhdGUoXG4gICAgICAgICAgc2VncmVnYXRlZERhdGFPbkNyZWF0ZSxcbiAgICAgICAgICB7IGNvbGxlY3Rpb25zOiBjb2xsZWN0aW9uIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgcHJpb3JpdHk6IDk1LFxuICAgICAgICAgICAgZ3JvdXA6IGdyb3VwTmFtZSxcbiAgICAgICAgICB9XG4gICAgICAgICksXG4gICAgICAgIG9uUmVhZChcbiAgICAgICAgICBzZWdyZWdhdGVkRGF0YU9uUmVhZCBhcyBhbnksXG4gICAgICAgICAgeyBjb2xsZWN0aW9uczogY29sbGVjdGlvbiB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHByaW9yaXR5OiA5NSxcbiAgICAgICAgICAgIGdyb3VwOiBncm91cE5hbWUsXG4gICAgICAgICAgfVxuICAgICAgICApLFxuICAgICAgICBvblVwZGF0ZShcbiAgICAgICAgICBzZWdyZWdhdGVkRGF0YU9uVXBkYXRlIGFzIGFueSxcbiAgICAgICAgICB7IGNvbGxlY3Rpb25zOiBjb2xsZWN0aW9uIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgcHJpb3JpdHk6IDk1LFxuICAgICAgICAgICAgZ3JvdXA6IGdyb3VwTmFtZSxcbiAgICAgICAgICB9XG4gICAgICAgICksXG4gICAgICAgIG9uRGVsZXRlKFxuICAgICAgICAgIHNlZ3JlZ2F0ZWREYXRhT25EZWxldGUgYXMgYW55LFxuICAgICAgICAgIHsgY29sbGVjdGlvbnM6IGNvbGxlY3Rpb24gfSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBwcmlvcml0eTogOTUsXG4gICAgICAgICAgICBncm91cDogZ3JvdXBOYW1lLFxuICAgICAgICAgIH1cbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGFwcGx5KC4uLmRlY3MpKHRhcmdldCwgcHJvcGVydHlLZXkpO1xuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcHJpdmF0ZURhdGEoXG4gIGNvbGxlY3Rpb246IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlciA9IEltcGxpY2l0UHJpdmF0ZUNvbGxlY3Rpb25cbikge1xuICBmdW5jdGlvbiBwcml2YXRlRGF0YShjb2xsZWN0aW9uOiBzdHJpbmcgfCBDb2xsZWN0aW9uUmVzb2x2ZXIpIHtcbiAgICByZXR1cm4gc2VncmVnYXRlZChjb2xsZWN0aW9uLCBGYWJyaWNNb2RlbEtleXMuUFJJVkFURSk7XG4gIH1cblxuICByZXR1cm4gRGVjb3JhdGlvbi5mb3IoRmFicmljTW9kZWxLZXlzLlBSSVZBVEUpXG4gICAgLmRlZmluZSh7XG4gICAgICBkZWNvcmF0b3I6IHByaXZhdGVEYXRhLFxuICAgICAgYXJnczogW2NvbGxlY3Rpb25dLFxuICAgIH0pXG4gICAgLmFwcGx5KCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzaGFyZWREYXRhKGNvbGxlY3Rpb246IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlcikge1xuICBmdW5jdGlvbiBzaGFyZWREYXRhKGNvbGxlY3Rpb246IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlcikge1xuICAgIHJldHVybiBzZWdyZWdhdGVkKGNvbGxlY3Rpb24sIEZhYnJpY01vZGVsS2V5cy5TSEFSRUQpO1xuICB9XG5cbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKEZhYnJpY01vZGVsS2V5cy5TSEFSRUQpXG4gICAgLmRlZmluZSh7XG4gICAgICBkZWNvcmF0b3I6IHNoYXJlZERhdGEsXG4gICAgICBhcmdzOiBbY29sbGVjdGlvbl0sXG4gICAgfSlcbiAgICAuYXBwbHkoKTtcbn1cbiIsIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHMgKi9cbmltcG9ydCB7IENvbnN0cnVjdG9yLCBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHtcbiAgSlNPTlNlcmlhbGl6ZXIsXG4gIE1vZGVsLFxuICBNb2RlbEtleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGV0ZXJtaW5pc3RpYyBKU09OIHNlcmlhbGl6ZXIgZm9yIEZhYnJpYyBtb2RlbHNcbiAqIEBzdW1tYXJ5IEVuc3VyZXMgc3RhYmxlLCBkZXRlcm1pbmlzdGljIEpTT04gb3V0cHV0IGJ5IHNvcnRpbmcgb2JqZWN0IGtleXMgcmVjdXJzaXZlbHkgYmVmb3JlIHN0cmluZ2lmaWNhdGlvbiwgd2hpY2ggaXMgaW1wb3J0YW50IGZvciBGYWJyaWMgZW5kb3JzZW1lbnQgYW5kIGhhc2hpbmcuIEV4dGVuZHMgSlNPTlNlcmlhbGl6ZXIgdG8gcGx1ZyBpbnRvIGV4aXN0aW5nIERlY2FmIG1vZGVsIHNlcmlhbGl6YXRpb24gZmxvdy5cbiAqIEB0ZW1wbGF0ZSBNIC0gVGhlIERlY2FmIE1vZGVsIHN1YnR5cGUgc2VyaWFsaXplZCBieSB0aGlzIGluc3RhbmNlXG4gKiBAcGFyYW0ge3ZvaWR9IFtjb25zdHJ1Y3Rvcl0gTm8gcHVibGljIGNvbnN0cnVjdG9yIGFyZ3VtZW50c1xuICogQGNsYXNzIERldGVybWluaXN0aWNTZXJpYWxpemVyXG4gKiBAZXhhbXBsZVxuICogY29uc3Qgc2VyaWFsaXplciA9IG5ldyBEZXRlcm1pbmlzdGljU2VyaWFsaXplcjxNeU1vZGVsPigpO1xuICogY29uc3QganNvbiA9IHNlcmlhbGl6ZXIuc2VyaWFsaXplKG1vZGVsKTtcbiAqIGNvbnN0IHJlYnVpbHQgPSBzZXJpYWxpemVyLmRlc2VyaWFsaXplKGpzb24pO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgRFMgYXMgRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXJcbiAqICAgQ2FsbGVyLT4+RFM6IHNlcmlhbGl6ZShtb2RlbClcbiAqICAgRFMtPj5EUzogcHJlU2VyaWFsaXplKG1vZGVsKVxuICogICBEUy0+PkRTOiBzb3J0LWtleXMtcmVjdXJzaXZlXG4gKiAgIERTLT4+RFM6IGpzb24tc3RyaW5naWZ5LWRldGVybWluaXN0aWNcbiAqICAgRFMtLT4+Q2FsbGVyOiBzdHJpbmdcbiAqICAgQ2FsbGVyLT4+RFM6IGRlc2VyaWFsaXplKHN0cmluZylcbiAqICAgRFMtLT4+Q2FsbGVyOiBtb2RlbFxuICovXG5leHBvcnQgY2xhc3MgRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbj4gZXh0ZW5kcyBKU09OU2VyaWFsaXplcjxNPiB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHByZVNlcmlhbGl6ZShtb2RlbDogTSkge1xuICAgIC8vIFRPRE86IG5lc3RlZCBwcmVzZXJpYWxpemF0aW9uIChzbyBpbmNyZWFzZSBwZXJmb3JtYW5jZSB3aGVuIGRlc2VyaWFsaXppbmcpXG4gICAgLy8gVE9ETzogVmVyaWZ5IHdoeSB0aGVyZSBpcyBubyBtZXRhZGF0YVxuICAgIGNvbnN0IHRvU2VyaWFsaXplOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gT2JqZWN0LmFzc2lnbih7fSwgbW9kZWwpO1xuICAgIGxldCBtZXRhZGF0YTtcbiAgICB0cnkge1xuICAgICAgbWV0YWRhdGEgPSBNZXRhZGF0YS5tb2RlbE5hbWUobW9kZWwuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICBtZXRhZGF0YSA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgdG9TZXJpYWxpemVbTW9kZWxLZXlzLkFOQ0hPUl0gPSBtZXRhZGF0YSB8fCBtb2RlbC5jb25zdHJ1Y3Rvci5uYW1lO1xuXG4gICAgY29uc3QgcHJlU2VyaWFsaXplID0gZnVuY3Rpb24gcHJlU2VyaWFsaXplKFxuICAgICAgdGhpczogRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8YW55PixcbiAgICAgIG9iajogYW55XG4gICAgKTogYW55IHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdGhpcy1hbGlhc1xuICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICBpZiAodHlwZW9mIG9iaiAhPT0gXCJvYmplY3RcIikgcmV0dXJuIG9iajtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHJldHVybiBvYmoubWFwKChvKSA9PiBwcmVTZXJpYWxpemUuY2FsbChzZWxmLCBvKSk7XG4gICAgICByZXR1cm4gdGhpcy5wcmVTZXJpYWxpemUuY2FsbCh0aGlzLCBvYmopO1xuICAgIH0uYmluZCh0aGlzKTtcblxuICAgIE1vZGVsLnJlbGF0aW9ucyhtb2RlbCkuZm9yRWFjaCgocikgPT4ge1xuICAgICAgdG9TZXJpYWxpemVbcl0gPSBwcmVTZXJpYWxpemUodG9TZXJpYWxpemVbcl0pO1xuICAgIH0pO1xuICAgIHJldHVybiB0b1NlcmlhbGl6ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSBSZWJ1aWxkcyBhIG1vZGVsIGZyb20gYSBzZXJpYWxpemF0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzdHJcbiAgICpcbiAgICogQHRocm93cyB7RXJyb3J9IElmIGl0IGZhaWxzIHRvIHBhcnNlIHRoZSBzdHJpbmcsIG9yIHRvIGJ1aWxkIHRoZSBtb2RlbFxuICAgKi9cbiAgb3ZlcnJpZGUgZGVzZXJpYWxpemUoc3RyOiBzdHJpbmcpOiBNIHtcbiAgICBjb25zdCBkZXNlcmlhbGl6YXRpb24gPSBKU09OLnBhcnNlKHN0cik7XG4gICAgY29uc3QgY2xhc3NOYW1lID0gZGVzZXJpYWxpemF0aW9uW01vZGVsS2V5cy5BTkNIT1JdO1xuICAgIGlmICghY2xhc3NOYW1lKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGQgbm90IGZpbmQgY2xhc3MgcmVmZXJlbmNlIGluIHNlcmlhbGl6ZWQgbW9kZWxcIik7XG4gICAgY29uc3QgbW9kZWw6IE0gPSBNb2RlbC5idWlsZChkZXNlcmlhbGl6YXRpb24sIGNsYXNzTmFtZSkgYXMgdW5rbm93biBhcyBNO1xuICAgIHJldHVybiBtb2RlbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2VyaWFsaXplIGEgbW9kZWwgaW50byBhIGRldGVybWluaXN0aWMgSlNPTiBzdHJpbmdcbiAgICogQHN1bW1hcnkgUHJlcGFyZXMgdGhlIG1vZGVsIHdpdGggcHJlU2VyaWFsaXplLCBzb3J0cyBrZXlzIHJlY3Vyc2l2ZWx5LCBhbmQgc3RyaW5naWZpZXMgZGV0ZXJtaW5pc3RpY2FsbHkgZm9yIHN0YWJsZSBvcmRlcmluZ1xuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHRvIHNlcmlhbGl6ZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IERldGVybWluaXN0aWMgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgbW9kZWxcbiAgICovXG4gIG92ZXJyaWRlIHNlcmlhbGl6ZShtb2RlbDogTSk6IHN0cmluZyB7XG4gICAgY29uc3Qgc3RyaW5naWZ5ID0gcmVxdWlyZShcImpzb24tc3RyaW5naWZ5LWRldGVybWluaXN0aWNcIik7XG4gICAgY29uc3Qgc29ydEtleXNSZWN1cnNpdmUgPSByZXF1aXJlKFwic29ydC1rZXlzLXJlY3Vyc2l2ZVwiKTtcbiAgICByZXR1cm4gc3RyaW5naWZ5KHNvcnRLZXlzUmVjdXJzaXZlKHRoaXMucHJlU2VyaWFsaXplKG1vZGVsKSkpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBCdWxrQ3J1ZE9wZXJhdGlvbktleXMsIE9wZXJhdGlvbktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gR2VuZXJhdGVzIGEgRmFicmljIGV2ZW50IG5hbWUgZnJvbSBjb21wb25lbnRzXG4gKiBAc3VtbWFyeSBDcmVhdGVzIGEgc3RhbmRhcmRpemVkIGV2ZW50IG5hbWUgYnkgam9pbmluZyB0YWJsZSwgZXZlbnQsIGFuZCBvcHRpb25hbCBvd25lciB3aXRoIHVuZGVyc2NvcmVzXG4gKiBAcGFyYW0ge3N0cmluZ30gdGFibGUgLSBUaGUgdGFibGUvY29sbGVjdGlvbiBuYW1lXG4gKiBAcGFyYW0ge09wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmd9IGV2ZW50IC0gVGhlIGV2ZW50IHR5cGVcbiAqIEBwYXJhbSB7c3RyaW5nfSBbb3duZXJdIC0gT3B0aW9uYWwgb3duZXIgaWRlbnRpZmllclxuICogQHJldHVybiB7c3RyaW5nfSBUaGUgZ2VuZXJhdGVkIGV2ZW50IG5hbWUgaW4gZm9ybWF0IFwidGFibGVfZXZlbnRcIiBvciBcInRhYmxlX2V2ZW50X293bmVyXCJcbiAqIEBmdW5jdGlvbiBnZW5lcmF0ZUZhYnJpY0V2ZW50TmFtZVxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVGYWJyaWNFdmVudE5hbWUoXG4gIHRhYmxlOiBzdHJpbmcsXG4gIGV2ZW50OiBPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nLFxuICBvd25lcj86IHN0cmluZ1xuKSB7XG4gIGNvbnN0IHBhcmFtcyA9IFt0YWJsZSwgZXZlbnRdO1xuICBpZiAob3duZXIpIHBhcmFtcy5wdXNoKG93bmVyKTtcbiAgcmV0dXJuIHBhcmFtcy5qb2luKFwiX1wiKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUGFyc2VzIGEgRmFicmljIGV2ZW50IG5hbWUgaW50byBpdHMgY29tcG9uZW50c1xuICogQHN1bW1hcnkgU3BsaXRzIGFuIGV2ZW50IG5hbWUgYnkgdW5kZXJzY29yZXMgYW5kIGV4dHJhY3RzIHRhYmxlLCBldmVudCwgYW5kIG9wdGlvbmFsIG93bmVyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBldmVudCBuYW1lIHRvIHBhcnNlXG4gKiBAcmV0dXJuIHt7dGFibGU6IHN0cmluZywgZXZlbnQ6IE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmcsIG93bmVyOiBzdHJpbmd9fSBUaGUgcGFyc2VkIGNvbXBvbmVudHMgYXMgYSBzdHJ1Y3R1cmVkIG9iamVjdFxuICogQHRocm93cyB7SW50ZXJuYWxFcnJvcn0gSWYgdGhlIGV2ZW50IG5hbWUgZm9ybWF0IGlzIGludmFsaWRcbiAqIEBmdW5jdGlvbiBwYXJzZUV2ZW50TmFtZVxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgUGFyc2VyIGFzIHBhcnNlRXZlbnROYW1lXG4gKiAgIENhbGxlci0+PlBhcnNlcjogcGFyc2VFdmVudE5hbWUobmFtZSlcbiAqICAgUGFyc2VyLT4+UGFyc2VyOiBzcGxpdCBuYW1lIGJ5IFwiX1wiXG4gKiAgIGFsdCBwYXJ0cyBsZW5ndGggaW52YWxpZFxuICogICAgIFBhcnNlci0tPj5DYWxsZXI6IHRocm93IEludGVybmFsRXJyb3JcbiAqICAgZWxzZVxuICogICAgIFBhcnNlci0tPj5DYWxsZXI6IHsgdGFibGUsIGV2ZW50LCBvd25lcj8gfVxuICogICBlbmRcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlRXZlbnROYW1lKG5hbWU6IHN0cmluZyk6IHtcbiAgdGFibGU/OiBzdHJpbmc7XG4gIGV2ZW50OiBPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nO1xuICBvd25lcj86IHN0cmluZztcbn0ge1xuICBjb25zdCBwYXJ0cyA9IG5hbWUuc3BsaXQoXCJfXCIpO1xuICBpZiAocGFydHMubGVuZ3RoIDwgMiB8fCBwYXJ0cy5sZW5ndGggPiAzKVxuICAgIHJldHVybiB7IHRhYmxlOiB1bmRlZmluZWQsIGV2ZW50OiBuYW1lLCBvd25lcjogdW5kZWZpbmVkIH07XG4gIHJldHVybiB7XG4gICAgdGFibGU6IHBhcnRzWzBdLFxuICAgIGV2ZW50OiBwYXJ0c1sxXSxcbiAgICBvd25lcjogcGFydHNbMl0sXG4gIH0gYXMge1xuICAgIHRhYmxlOiBzdHJpbmc7XG4gICAgZXZlbnQ6IE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmc7XG4gICAgb3duZXI/OiBzdHJpbmc7XG4gIH07XG59XG4iLCJpbXBvcnQgeyBzdHJpbmdGb3JtYXQgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBPdmVyZmxvd0Vycm9yIH0gZnJvbSBcIi4vZXJyb3JzXCI7XG5pbXBvcnQgeyBWYWxpZGF0aW9uRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gT3ZlcmZsb3ctc2FmZSBhZGRpdGlvbiBvcGVyYXRpb25cbiAqIEBzdW1tYXJ5IEFkZHMgdHdvIG51bWJlcnMgYW5kIHZlcmlmaWVzIG5vIG92ZXJmbG93IGJ5IHJldmVyc2UtY2hlY2tpbmcgdGhlIG9wZXJhbmRzXG4gKiBAcGFyYW0ge251bWJlcn0gYSAtIEZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7bnVtYmVyfSBiIC0gU2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm4ge251bWJlcn0gVGhlIHN1bSBvZiBhIGFuZCBiXG4gKiBAZnVuY3Rpb24gYWRkXG4gKiBAdGhyb3dzIHtPdmVyZmxvd0Vycm9yfSBvbiBhZGRpdGlvbiBvdmVyZmxvd1xuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gYWRkKGE6IG51bWJlciwgYjogbnVtYmVyKTogbnVtYmVyIHtcbiAgY29uc3QgYyA9IGEgKyBiO1xuICBpZiAoYSAhPT0gYyAtIGIgfHwgYiAhPT0gYyAtIGEpIHtcbiAgICB0aHJvdyBuZXcgT3ZlcmZsb3dFcnJvcihgQWRkaXRpb24gb3ZlcmZsb3c6ICR7YX0gKyAke2J9YCk7XG4gIH1cbiAgcmV0dXJuIGM7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE92ZXJmbG93LXNhZmUgc3VidHJhY3Rpb24gb3BlcmF0aW9uXG4gKiBAc3VtbWFyeSBTdWJ0cmFjdHMgYiBmcm9tIGEgYW5kIHZhbGlkYXRlcyBubyBvdmVyZmxvdyBieSByZXZlcnNlLWNoZWNraW5nIHRoZSBvcGVyYW5kc1xuICogQHBhcmFtIHtudW1iZXJ9IGEgLSBNaW51ZW5kXG4gKiBAcGFyYW0ge251bWJlcn0gYiAtIFN1YnRyYWhlbmRcbiAqIEByZXR1cm4ge251bWJlcn0gVGhlIGRpZmZlcmVuY2UgYSAtIGJcbiAqIEBmdW5jdGlvbiBzdWJcbiAqIEB0aHJvd3Mge092ZXJmbG93RXJyb3J9IG9uIHN1YnRhY3Rpb24gb3ZlcmZsb3dcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN1YihhOiBudW1iZXIsIGI6IG51bWJlcik6IG51bWJlciB7XG4gIGNvbnN0IGMgPSBhIC0gYjtcbiAgaWYgKGEgIT09IGMgKyBiIHx8IGIgIT09IGEgLSBjKSB7XG4gICAgdGhyb3cgbmV3IE92ZXJmbG93RXJyb3IoYFN1YnRyYWN0aW9uIG92ZXJmbG93OiAke2F9IC0gJHtifWApO1xuICB9XG4gIHJldHVybiBjO1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFNhZmUgSW50ZWdlciBQYXJzZVxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdcbiAqXG4gKiBAZnVuY3Rpb24gc2FmZVBhcnNlSW50XG4gKlxuICogQHRocm93cyB7VmFsaWRhdGlvbkVycm9yfSBpZiBwYXJzZUludCByZXR1cm5zIE5hTlxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNhZmVQYXJzZUludChzdHJpbmc6IHN0cmluZyk6IG51bWJlciB7XG4gIC8vIFJlZ3VsYXIgZXhwcmVzc2lvbiB0byBjaGVjayBpZiBzdHJpbmcgb25seSBoYXZlIGRpZ2l0c1xuICBjb25zdCBkaWdpdFJlZ2V4ID0gL15cXGQrJC87XG4gIGlmICghZGlnaXRSZWdleC50ZXN0KHN0cmluZykpIHtcbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFxuICAgICAgc3RyaW5nRm9ybWF0KFwiRmFpbGVkIHRvIHBhcnNlOiB7MH1cIiwgXCJzdHJpbmcgY29udGFpbnMgZGlnaXRzXCIpXG4gICAgKTtcbiAgfVxuICBjb25zdCBwYXJzZWRpbnQgPSBwYXJzZUludChzdHJpbmcpO1xuICBpZiAoaXNOYU4ocGFyc2VkaW50KSkge1xuICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXG4gICAgICBzdHJpbmdGb3JtYXQoXCJGYWlsZWQgdG8gcGFyc2U6IHswfVwiLCBcInN0cmluZyBpcyBub3QgYSBwYXJzYWJsZSBpbnRlZ2VyXCIpXG4gICAgKTtcbiAgfVxuICByZXR1cm4gcGFyc2VkaW50O1xufVxuIiwiaW1wb3J0IHtcbiAgSlNPTlNlcmlhbGl6ZXIsXG4gIE1vZGVsLFxuICBNb2RlbEtleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yLCBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuXG5leHBvcnQgY2xhc3MgU2ltcGxlRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbj4gZXh0ZW5kcyBKU09OU2VyaWFsaXplcjxNPiB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIG92ZXJyaWRlIGRlc2VyaWFsaXplKHN0cjogc3RyaW5nLCB0YWJsZU5hbWU/OiBzdHJpbmcpOiBNIHtcbiAgICBjb25zdCBkZXNlcmlhbGl6YXRpb24gPSBKU09OLnBhcnNlKHN0cik7XG4gICAgLy8gY29uc3QgY2xhc3NOYW1lID0gdGFibGVOYW1lO1xuICAgIC8vIGlmICghY2xhc3NOYW1lKVxuICAgIC8vICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGQgbm90IGZpbmQgY2xhc3MgcmVmZXJlbmNlIGluIHNlcmlhbGl6ZWQgbW9kZWxcIik7XG5cbiAgICAvLyAvLyB0aGlzIHdpbGwgcmV0dXJuIHVuZGVmaW5lZCB2YWx1ZXNcbiAgICAvLyBjb25zdCBtb2RlbDogTSA9IE1vZGVsLmJ1aWxkKGRlc2VyaWFsaXphdGlvbiwgY2xhc3NOYW1lKSBhcyB1bmtub3duIGFzIE07XG5cbiAgICAvLyAvLyBQb3B1bGF0ZSBNb2RlbFxuICAgIC8vIGNvbnN0IHByb2Nlc3NlZERlc2VhbGl6YXRpb24gPSBPYmplY3Qua2V5cyhtb2RlbCkucmVkdWNlKFxuICAgIC8vICAgKGFjY3VtOiBNLCBrZXkpID0+IHtcbiAgICAvLyAgICAgKGFjY3VtIGFzIFJlY29yZDxzdHJpbmcsIGFueT4pW2tleV0gPVxuICAgIC8vICAgICAgIGRlc2VyaWFsaXphdGlvbltSZXBvc2l0b3J5LmNvbHVtbihhY2N1bSwga2V5KV07XG4gICAgLy8gICAgIHJldHVybiBhY2N1bTtcbiAgICAvLyAgIH0sXG4gICAgLy8gICBtb2RlbFxuICAgIC8vICk7XG5cbiAgICAvLyBjb25zdCByZXN1bHQgPSBNb2RlbC5idWlsZChcbiAgICAvLyAgIHByb2Nlc3NlZERlc2VhbGl6YXRpb24sXG4gICAgLy8gICBjbGFzc05hbWVcbiAgICAvLyApIGFzIHVua25vd24gYXMgTTtcblxuICAgIC8vIHJldHVybiByZXN1bHQ7XG4gICAgcmV0dXJuIGRlc2VyaWFsaXphdGlvbjtcbiAgfVxuXG4gIG92ZXJyaWRlIHNlcmlhbGl6ZShtb2RlbDogTSwgcHV0QW5jaG9yID0gdHJ1ZSk6IHN0cmluZyB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCBzdHJpbmdpZnkgPSByZXF1aXJlKFwianNvbi1zdHJpbmdpZnktZGV0ZXJtaW5pc3RpY1wiKTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICAgIGNvbnN0IHNvcnRLZXlzUmVjdXJzaXZlID0gcmVxdWlyZShcInNvcnQta2V5cy1yZWN1cnNpdmVcIik7XG4gICAgY29uc3QgcHJlU2VyaWFsaXphdGlvbiA9IHRoaXMucHJlU2VyaWFsaXplKG1vZGVsLCBwdXRBbmNob3IpO1xuICAgIHJldHVybiBzdHJpbmdpZnkoc29ydEtleXNSZWN1cnNpdmUocHJlU2VyaWFsaXphdGlvbikpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHByZVNlcmlhbGl6ZShtb2RlbDogTSwgcHV0QW5jaG9yOiBib29sZWFuID0gdHJ1ZSkge1xuICAgIC8vIFRPRE86IG5lc3RlZCBwcmVzZXJpYWxpemF0aW9uIChzbyBpbmNyZWFzZSBwZXJmb3JtYW5jZSB3aGVuIGRlc2VyaWFsaXppbmcpXG4gICAgLy8gVE9ETzogVmVyaWZ5IHdoeSB0aGVyZSBpcyBubyBtZXRhZGF0YVxuICAgIGNvbnN0IHRvU2VyaWFsaXplOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gT2JqZWN0LmFzc2lnbih7fSwgbW9kZWwpO1xuICAgIGxldCBtZXRhZGF0YTtcbiAgICB0cnkge1xuICAgICAgbWV0YWRhdGEgPSBNZXRhZGF0YS5tb2RlbE5hbWUobW9kZWwuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICBtZXRhZGF0YSA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgaWYgKHB1dEFuY2hvcilcbiAgICAgIHRvU2VyaWFsaXplW01vZGVsS2V5cy5BTkNIT1JdID0gbWV0YWRhdGEgfHwgbW9kZWwuY29uc3RydWN0b3IubmFtZTtcblxuICAgIGZ1bmN0aW9uIHByZVNlcmlhbGl6ZShcbiAgICAgIHRoaXM6IFNpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyPGFueT4sXG4gICAgICBvYmo6IGFueVxuICAgICk6IGFueSB7XG4gICAgICBpZiAodHlwZW9mIG9iaiAhPT0gXCJvYmplY3RcIikgcmV0dXJuIG9iajtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHJldHVybiBvYmoubWFwKHByZVNlcmlhbGl6ZSk7XG4gICAgICByZXR1cm4gdGhpcy5wcmVTZXJpYWxpemUob2JqKTtcbiAgICB9XG4gICAgTW9kZWwucmVsYXRpb25zKG1vZGVsKS5mb3JFYWNoKChyKSA9PiB7XG4gICAgICB0b1NlcmlhbGl6ZVtyXSA9IHByZVNlcmlhbGl6ZS5jYWxsKHRoaXMsIHRvU2VyaWFsaXplW3JdKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdG9TZXJpYWxpemU7XG4gIH1cbn1cbiIsImltcG9ydCB7XG4gIEF1dGhvcml6YXRpb25FcnJvcixcbiAgQ2xpZW50QmFzZWRTZXJ2aWNlLFxuICBDb250ZXh0LFxuICBNYXliZUNvbnRleHR1YWxBcmcsXG4gIFBlcnNpc3RlbmNlS2V5cyxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgRmFicmljQ0FTZXJ2aWNlcywge1xuICBBZmZpbGlhdGlvblNlcnZpY2UsXG4gIElkZW50aXR5U2VydmljZSxcbiAgSUVucm9sbFJlc3BvbnNlLFxuICBJUmVnaXN0ZXJSZXF1ZXN0LFxuICBJU2VydmljZVJlc3BvbnNlLFxuICBUTFNPcHRpb25zLFxufSBmcm9tIFwiZmFicmljLWNhLWNsaWVudFwiO1xuaW1wb3J0IHsgQ0FDb25maWcsIENyZWRlbnRpYWxzIH0gZnJvbSBcIi4uLy4uL3NoYXJlZC90eXBlc1wiO1xuaW1wb3J0IHtcbiAgQ29uZmxpY3RFcnJvcixcbiAgSW50ZXJuYWxFcnJvcixcbiAgTm90Rm91bmRFcnJvcixcbiAgT3BlcmF0aW9uS2V5cyxcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDb3JlVXRpbHMgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7XG4gIENlcnRpZmljYXRlUmVzcG9uc2UsXG4gIEZhYnJpY0lkZW50aXR5LFxuICBHZXRDZXJ0aWZpY2F0ZXNSZXF1ZXN0LFxuICBJZGVudGl0eVJlc3BvbnNlLFxufSBmcm9tIFwiLi4vLi4vc2hhcmVkL2ZhYnJpYy10eXBlc1wiO1xuaW1wb3J0IHsgVXNlciB9IGZyb20gXCJmYWJyaWMtY29tbW9uXCI7XG5pbXBvcnQgeyBSZWdpc3RyYXRpb25FcnJvciB9IGZyb20gXCIuLi8uLi9zaGFyZWQvZXJyb3JzXCI7XG5pbXBvcnQgeyBDQV9ST0xFIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBJS2V5VmFsdWVBdHRyaWJ1dGUgfSBmcm9tIFwiLi9GYWJyaWNFbnJvbGxtZW50U2VydmljZVwiO1xuaW1wb3J0IHsgSWRlbnRpdHkgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL2luZGV4XCI7XG5pbXBvcnQgeyBDcnlwdG9VdGlscyB9IGZyb20gXCIuLi9jcnlwdG9cIjtcblxuZXhwb3J0IGNsYXNzIEZhYnJpY0lkZW50aXR5U2VydmljZSBleHRlbmRzIENsaWVudEJhc2VkU2VydmljZTxcbiAgRmFicmljQ0FTZXJ2aWNlcyxcbiAgQ0FDb25maWdcbj4ge1xuICBwcm90ZWN0ZWQgX3VzZXIhOiBVc2VyO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IHJvb3RDbGllbnQoKTogeyBuZXdDZXJ0aWZpY2F0ZVNlcnZpY2U6IGFueSB9IHtcbiAgICByZXR1cm4gKHRoaXMuY2xpZW50IGFzIGFueSlbXCJfRmFicmljQ2FTZXJ2aWNlc1wiXSBhcyBhbnk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IHVzZXIoKTogVXNlciB7XG4gICAgaWYgKCF0aGlzLl91c2VyKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIFwiRmFicmljIGlkZW50aXR5IHNlcnZpY2Ugbm90IHByb3Blcmx5IHNldHVwOiBtaXNzaW5nIHVzZXJcIlxuICAgICAgKTtcbiAgICByZXR1cm4gdGhpcy5fdXNlcjtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXQgY2VydGlmaWNhdGVzKCkge1xuICAgIHJldHVybiB0aGlzLnJvb3RDbGllbnQubmV3Q2VydGlmaWNhdGVTZXJ2aWNlKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IGFmZmlsaWF0aW9ucygpOiBBZmZpbGlhdGlvblNlcnZpY2Uge1xuICAgIHJldHVybiB0aGlzLmNsaWVudC5uZXdBZmZpbGlhdGlvblNlcnZpY2UoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXQgaWRlbnRpdGllcygpOiBJZGVudGl0eVNlcnZpY2Uge1xuICAgIHJldHVybiB0aGlzLmNsaWVudC5uZXdJZGVudGl0eVNlcnZpY2UoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBnZXRVc2VyKGNmZzogQ0FDb25maWcsIGN0eDogQ29udGV4dCkge1xuICAgIGNvbnN0IGxvZyA9IGN0eC5sb2dnZXIuZm9yKHRoaXMuZ2V0VXNlcik7XG4gICAgY29uc3QgeyBjYU5hbWUsIGNhQ2VydCwgY2FLZXksIHVybCwgaHNtIH0gPSBjZmc7XG5cbiAgICBsb2cuaW5mbyhgQ3JlYXRpbmcgQ0EgdXNlciBmb3IgJHtjYU5hbWV9IGF0ICR7dXJsfWApO1xuICAgIGxvZy52ZXJib3NlKGBSZXRyaWV2aW5nIENBIGNlcnRpZmljYXRlIGZyb20gJHtjYUNlcnR9YCk7XG4gICAgY29uc3QgY2VydGlmaWNhdGUgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0Rmlyc3REaXJGaWxlTmFtZUNvbnRlbnQoY2FDZXJ0KTtcbiAgICBsZXQga2V5OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgaWYgKCFoc20pIHtcbiAgICAgIGlmICghY2FLZXkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgICAgYE1pc3NpbmcgY2FLZXkgY29uZmlndXJhdGlvbiBmb3IgQ0EgJHtjYU5hbWV9LiBQcm92aWRlIGEga2V5IGRpcmVjdG9yeSBvciBjb25maWd1cmUgSFNNIHN1cHBvcnQuYFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIENBIGtleSBmcm9tICR7Y2FLZXl9YCk7XG4gICAgICBrZXkgPSBhd2FpdCBDb3JlVXRpbHMuZ2V0Rmlyc3REaXJGaWxlTmFtZUNvbnRlbnQoY2FLZXkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBVc2luZyBIU00gY29uZmlndXJhdGlvbiBmb3IgQ0EgJHtjYU5hbWV9IHdpdGggbGlicmFyeSAke2hzbS5saWJyYXJ5fWBcbiAgICAgICk7XG4gICAgfVxuICAgIGxvZy5kZWJ1ZyhgTG9hZGluZyBBZG1pbiB1c2VyIGZvciBjYSAke2NhTmFtZX1gKTtcbiAgICB0aGlzLl91c2VyID0gYXdhaXQgQ29yZVV0aWxzLmdldENBVXNlcihcImFkbWluXCIsIGtleSwgY2VydGlmaWNhdGUsIGNhTmFtZSwge1xuICAgICAgaHNtLFxuICAgIH0pO1xuICAgIHJldHVybiB0aGlzLl91c2VyO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgaW5pdGlhbGl6ZShcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPHsgY29uZmlnOiBDQUNvbmZpZzsgY2xpZW50OiBGYWJyaWNDQVNlcnZpY2VzIH0+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSAoXG4gICAgICBhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBQZXJzaXN0ZW5jZUtleXMuSU5JVElBTElaQVRJT04sIHRydWUpXG4gICAgKS5mb3IodGhpcy5pbml0aWFsaXplKTtcbiAgICBjb25zdCBbY29uZmlnXSA9IGFyZ3M7XG4gICAgaWYgKCFjb25maWcpIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiTWlzc2luZyBGYWJyaWMgQ0EgY29uZmlndXJhdGlvblwiKTtcblxuICAgIGNvbnN0IHsgdXJsLCB0bHMsIGNhTmFtZSB9ID0gY29uZmlnO1xuICAgIGxvZy5pbmZvKGBJbml0aWFsaXppbmcgQ0EgQ2xpZW50IGZvciBDQSAke2NvbmZpZy5jYU5hbWV9IGF0ICR7Y29uZmlnLnVybH1gKTtcbiAgICBjb25zdCB7IHRydXN0ZWRSb290cywgdmVyaWZ5IH0gPSB0bHMgYXMgVExTT3B0aW9ucztcblxuICAgIGNvbnN0IHJvb3QgPSAodHJ1c3RlZFJvb3RzIGFzIHN0cmluZ1tdKVswXSBhcyBzdHJpbmc7XG4gICAgbG9nLmRlYnVnKGBSZXRyaWV2aW5nIENBIGNlcnRpZmljYXRlIGZyb20gJHtyb290fS4gY3dkOiAke3Byb2Nlc3MuY3dkKCl9YCk7XG5cbiAgICBjb25zdCBjZXJ0aWZpY2F0ZSA9IGF3YWl0IENvcmVVdGlscy5nZXRGaWxlQ29udGVudChyb290KTtcblxuICAgIGxvZy5kZWJ1ZyhgQ0EgQ2VydGlmaWNhdGU6ICR7Y2VydGlmaWNhdGUudG9TdHJpbmcoKX1gKTtcblxuICAgIGNvbnN0IGNsaWVudCA9IG5ldyBGYWJyaWNDQVNlcnZpY2VzKFxuICAgICAgdXJsLFxuICAgICAge1xuICAgICAgICB0cnVzdGVkUm9vdHM6IEJ1ZmZlci5mcm9tKGNlcnRpZmljYXRlKSxcbiAgICAgICAgdmVyaWZ5LFxuICAgICAgfSBhcyBUTFNPcHRpb25zLFxuICAgICAgY2FOYW1lXG4gICAgKTtcblxuICAgIGNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLmdldFVzZXIoY29uZmlnLCBjdHgpO1xuICAgIGxvZy5kZWJ1ZyhgQ0EgdXNlciBsb2FkZWQ6ICR7dXNlci5nZXROYW1lKCl9YCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbmZpZyxcbiAgICAgIGNsaWVudCxcbiAgICB9O1xuICB9XG5cbiAgYXN5bmMgZ2V0Q2VydGlmaWNhdGVzKC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxhbnk+KTogUHJvbWlzZTxzdHJpbmdbXT47XG4gIGFzeW5jIGdldENlcnRpZmljYXRlcyhcbiAgICByZXF1ZXN0OiBHZXRDZXJ0aWZpY2F0ZXNSZXF1ZXN0LFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxhbnk+XG4gICk6IFByb21pc2U8c3RyaW5nW10+O1xuICBhc3luYyBnZXRDZXJ0aWZpY2F0ZXM8TUFQIGV4dGVuZHMgYm9vbGVhbj4oXG4gICAgZG9NYXA6IE1BUCxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPE1BUCBleHRlbmRzIGZhbHNlID8gQ2VydGlmaWNhdGVSZXNwb25zZSA6IHN0cmluZ1tdPjtcbiAgYXN5bmMgZ2V0Q2VydGlmaWNhdGVzPE1BUCBleHRlbmRzIGJvb2xlYW4+KFxuICAgIHJlcXVlc3Q6IEdldENlcnRpZmljYXRlc1JlcXVlc3QsXG4gICAgZG9NYXA6IE1BUCxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPE1BUCBleHRlbmRzIGZhbHNlID8gQ2VydGlmaWNhdGVSZXNwb25zZSA6IHN0cmluZ1tdPjtcbiAgYXN5bmMgZ2V0Q2VydGlmaWNhdGVzPE1BUCBleHRlbmRzIGJvb2xlYW4+KFxuICAgIHJlcXVlc3Q/OiBHZXRDZXJ0aWZpY2F0ZXNSZXF1ZXN0IHwgTUFQLFxuICAgIGRvTWFwOiBNQVAgPSB0cnVlIGFzIE1BUCxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPE1BUCBleHRlbmRzIGZhbHNlID8gQ2VydGlmaWNhdGVSZXNwb25zZSA6IHN0cmluZ1tdPiB7XG4gICAgaWYgKHJlcXVlc3QgaW5zdGFuY2VvZiBDb250ZXh0KSB7XG4gICAgICBhcmdzID0gW3JlcXVlc3RdO1xuICAgICAgZG9NYXAgPSB0cnVlIGFzIE1BUDtcbiAgICAgIHJlcXVlc3QgPSB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgcmVxdWVzdCA9PT0gXCJib29sZWFuXCIpIHtcbiAgICAgIGRvTWFwID0gcmVxdWVzdDtcbiAgICAgIHJlcXVlc3QgPSB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgZG9NYXAgIT09IFwiYm9vbGVhblwiKSB7XG4gICAgICBhcmdzID0gW2RvTWFwIGFzIE1heWJlQ29udGV4dHVhbEFyZzxhbnk+LCAuLi5hcmdzXTtcbiAgICAgIGRvTWFwID0gdHJ1ZSBhcyBNQVA7XG4gICAgfVxuXG4gICAgY29uc3QgeyBsb2cgfSA9IChhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBPcGVyYXRpb25LZXlzLlJFQUQsIHRydWUpKS5mb3IoXG4gICAgICB0aGlzLmdldENlcnRpZmljYXRlc1xuICAgICk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYFJldHJpZXZpbmcgY2VydGlmaWNhdGVzJHtyZXF1ZXN0ID8gYCBmb3IgJHtyZXF1ZXN0LmlkfWAgOiBcIlwifSBmb3IgQ0EgJHt0aGlzLmNvbmZpZy5jYU5hbWV9YFxuICAgICk7XG4gICAgY29uc3QgcmVzcG9uc2U6IENlcnRpZmljYXRlUmVzcG9uc2UgPSAoXG4gICAgICBhd2FpdCB0aGlzLmNlcnRpZmljYXRlcy5nZXRDZXJ0aWZpY2F0ZXMocmVxdWVzdCB8fCB7fSwgdGhpcy51c2VyKVxuICAgICkucmVzdWx0O1xuICAgIGxvZy52ZXJib3NlKGBGb3VuZCAke3Jlc3BvbnNlLmNlcnRzLmxlbmd0aH0gY2VydGlmaWNhdGVzYCk7XG4gICAgbG9nLmRlYnVnKHJlc3BvbnNlLmNlcnRzKTtcbiAgICByZXR1cm4gKFxuICAgICAgZG9NYXAgPyByZXNwb25zZS5jZXJ0cy5tYXAoKGMpID0+IGMuUEVNKSA6IHJlc3BvbnNlXG4gICAgKSBhcyBNQVAgZXh0ZW5kcyBmYWxzZSA/IENlcnRpZmljYXRlUmVzcG9uc2UgOiBzdHJpbmdbXTtcbiAgfVxuXG4gIGFzeW5jIGdldElkZW50aXRpZXMoY3R4OiBDb250ZXh0KTogUHJvbWlzZTxGYWJyaWNJZGVudGl0eVtdPiB7XG4gICAgY29uc3QgbG9nID0gY3R4LmxvZ2dlci5mb3IodGhpcy5nZXRJZGVudGl0aWVzKTtcbiAgICBsb2cudmVyYm9zZShgUmV0cmlldmluZyBJZGVudGl0aWVzIHVuZGVyIENBICR7dGhpcy5jb25maWcuY2FOYW1lfWApO1xuICAgIGNvbnN0IHJlc3BvbnNlOiBJZGVudGl0eVJlc3BvbnNlID0gKGF3YWl0IHRoaXMuaWRlbnRpdGllcy5nZXRBbGwodGhpcy51c2VyKSlcbiAgICAgIC5yZXN1bHQ7XG4gICAgbG9nLnZlcmJvc2UoYEZvdW5kICR7cmVzcG9uc2UuaWRlbnRpdGllcy5sZW5ndGh9IElkZW50aXRpZXNgKTtcbiAgICBsb2cuZGVidWcocmVzcG9uc2UuaWRlbnRpdGllcyk7XG4gICAgcmV0dXJuIHJlc3BvbnNlLmlkZW50aXRpZXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJldHJpZXZlIGFmZmlsaWF0aW9ucyBmcm9tIHRoZSBDQS5cbiAgICogQHN1bW1hcnkgUXVlcmllcyB0aGUgQ0EgZm9yIHRoZSBsaXN0IG9mIGFmZmlsaWF0aW9ucyBhdmFpbGFibGUgdW5kZXIgdGhlIGNvbmZpZ3VyZWQgQ0EuXG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGFmZmlsaWF0aW9ucyByZXN1bHQgcGF5bG9hZC5cbiAgICovXG4gIGFzeW5jIGdldEFmZmlsaWF0aW9ucyhjdHg6IENvbnRleHQpIHtcbiAgICBjb25zdCBsb2cgPSBjdHgubG9nZ2VyLmZvcih0aGlzLmdldEFmZmlsaWF0aW9ucyk7XG4gICAgbG9nLnZlcmJvc2UoYFJldHJpZXZpbmcgQWZmaWxpYXRpb25zIHVuZGVyIENBICR7dGhpcy5jb25maWcuY2FOYW1lfWApO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gKGF3YWl0IHRoaXMuYWZmaWxpYXRpb25zLmdldEFsbCh0aGlzLnVzZXIpKS5yZXN1bHQ7XG4gICAgbG9nLnZlcmJvc2UoYEZvdW5kICR7cmVzcG9uc2UuYS5sZW5ndGh9IEFmZmlsaWF0aW9uc2ApO1xuICAgIGxvZy5kZWJ1ZyhKU09OLnN0cmluZ2lmeShyZXNwb25zZSkpO1xuICAgIHJldHVybiByZXNwb25zZTtcbiAgfVxuXG4gIHByb3RlY3RlZCBwYXJzZUVycm9yKGU6IEVycm9yKSB7XG4gICAgY29uc3QgcmVnZXhwID0gLy4qY29kZTpcXHMoXFxkKykuKj9tZXNzYWdlOlxcc1tcIiddKC4rKVtcIiddL2dzO1xuICAgIGNvbnN0IG1hdGNoID0gcmVnZXhwLmV4ZWMoZS5tZXNzYWdlKTtcbiAgICBpZiAoIW1hdGNoKSByZXR1cm4gbmV3IFJlZ2lzdHJhdGlvbkVycm9yKGUpO1xuICAgIGNvbnN0IFssIGNvZGUsIG1lc3NhZ2VdID0gbWF0Y2g7XG4gICAgc3dpdGNoIChjb2RlKSB7XG4gICAgICBjYXNlIFwiNzRcIjpcbiAgICAgIGNhc2UgXCI3MVwiOlxuICAgICAgICByZXR1cm4gbmV3IENvbmZsaWN0RXJyb3IobWVzc2FnZSk7XG4gICAgICBjYXNlIFwiMjBcIjpcbiAgICAgICAgcmV0dXJuIG5ldyBBdXRob3JpemF0aW9uRXJyb3IobWVzc2FnZSk7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gbmV3IFJlZ2lzdHJhdGlvbkVycm9yKG1lc3NhZ2UpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVhZCBpZGVudGl0eSBkZXRhaWxzIGZyb20gdGhlIENBIGJ5IGVucm9sbG1lbnQgSUQuXG4gICAqIEBzdW1tYXJ5IFJldHJpZXZlcyBhbmQgdmFsaWRhdGVzIGEgc2luZ2xlIGlkZW50aXR5LCB0aHJvd2luZyBOb3RGb3VuZEVycm9yIHdoZW4gbWlzc2luZy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGVucm9sbG1lbnRJZCAtIEVucm9sbG1lbnQgSUQgdG8gbG9va3VwLlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPEZhYnJpY0lkZW50aXR5Pn0gVGhlIGlkZW50aXR5IGRldGFpbHMgc3RvcmVkIGluIHRoZSBDQS5cbiAgICovXG4gIGFzeW5jIHJlYWQoXG4gICAgZW5yb2xsbWVudElkOiBzdHJpbmcsXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPGFueT5cbiAgKTogUHJvbWlzZTxGYWJyaWNJZGVudGl0eT4ge1xuICAgIGNvbnN0IHsgbG9nIH0gPSAoYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgT3BlcmF0aW9uS2V5cy5SRUFELCB0cnVlKSkuZm9yKFxuICAgICAgdGhpcy5yZWFkXG4gICAgKTtcbiAgICBsb2cudmVyYm9zZShgUmV0cmlldmluZyBpZGVudGl0eSB3aXRoIGVucm9sbG1lbnQgSUQgJHtlbnJvbGxtZW50SWR9YCk7XG4gICAgbGV0IHJlc3VsdDogSVNlcnZpY2VSZXNwb25zZTtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gYXdhaXQgdGhpcy5pZGVudGl0aWVzLmdldE9uZShlbnJvbGxtZW50SWQsIHRoaXMudXNlcik7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihcbiAgICAgICAgYENvdWxkbid0IGZpbmQgZW5yb2xsbWVudCB3aXRoIGlkICR7ZW5yb2xsbWVudElkfTogJHtlfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKCFyZXN1bHQuc3VjY2VzcylcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEVycm9yKFxuICAgICAgICBgQ291bGRuJ3QgZmluZCBlbnJvbGxtZW50IHdpdGggaWQgJHtlbnJvbGxtZW50SWR9OiAke3Jlc3VsdC5lcnJvcnMuam9pbihcIlxcblwiKX1gXG4gICAgICApO1xuXG4gICAgcmV0dXJuIHJlc3VsdC5yZXN1bHQgYXMgRmFicmljSWRlbnRpdHk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlZ2lzdGVyIGEgbmV3IGlkZW50aXR5IHdpdGggdGhlIENBLlxuICAgKiBAc3VtbWFyeSBTdWJtaXRzIGEgcmVnaXN0cmF0aW9uIHJlcXVlc3QgZm9yIGEgbmV3IGVucm9sbG1lbnQgSUQsIHJldHVybmluZyB0aGUgZW5yb2xsbWVudCBzZWNyZXQgdXBvbiBzdWNjZXNzLlxuICAgKiBAcGFyYW0ge0NyZWRlbnRpYWxzfSBtb2RlbCAtIENyZWRlbnRpYWxzIGNvbnRhaW5pbmcgdXNlck5hbWUgYW5kIHBhc3N3b3JkIGZvciB0aGUgbmV3IGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtpc1N1cGVyVXNlcj1mYWxzZV0gLSBXaGV0aGVyIHRvIHJlZ2lzdGVyIHRoZSBpZGVudGl0eSBhcyBhIHN1cGVyIHVzZXIuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYWZmaWxpYXRpb249XCJcIl0gLSBBZmZpbGlhdGlvbiBzdHJpbmcgKGUuZy4sIG9yZzEuZGVwYXJ0bWVudDEpLlxuICAgKiBAcGFyYW0ge0NBX1JPTEUgfCBzdHJpbmd9IFt1c2VyUm9sZV0gLSBSb2xlIHRvIGFzc2lnbiB0byB0aGUgaWRlbnRpdHkuXG4gICAqIEBwYXJhbSB7SUtleVZhbHVlQXR0cmlidXRlfSBbYXR0cnNdIC0gT3B0aW9uYWwgYXR0cmlidXRlcyB0byBhdHRhY2ggdG8gdGhlIGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge251bWJlcn0gW21heEVucm9sbG1lbnRzXSAtIE1heGltdW0gbnVtYmVyIG9mIGVucm9sbG1lbnRzIGFsbG93ZWQgZm9yIHRoZSBpZGVudGl0eS5cbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZW5yb2xsbWVudCBzZWNyZXQgZm9yIHRoZSByZWdpc3RlcmVkIGlkZW50aXR5LlxuICAgKi9cbiAgYXN5bmMgcmVnaXN0ZXIoXG4gICAgbW9kZWw6IENyZWRlbnRpYWxzLFxuICAgIGlzU3VwZXJVc2VyOiBib29sZWFuID0gZmFsc2UsXG4gICAgYWZmaWxpYXRpb246IHN0cmluZyA9IFwiXCIsXG4gICAgdXNlclJvbGU/OiBDQV9ST0xFIHwgc3RyaW5nLFxuICAgIGF0dHJzPzogSUtleVZhbHVlQXR0cmlidXRlLFxuICAgIG1heEVucm9sbG1lbnRzPzogbnVtYmVyLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxhbnk+XG4gICk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBsb2cgfSA9IChhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBcInJlZ2lzdGVyXCIsIHRydWUpKS5mb3IoXG4gICAgICB0aGlzLnJlZ2lzdGVyXG4gICAgKTtcblxuICAgIGxldCByZWdpc3RyYXRpb246IHN0cmluZztcbiAgICB0cnkge1xuICAgICAgY29uc3QgeyB1c2VyTmFtZSwgcGFzc3dvcmQgfSA9IG1vZGVsO1xuICAgICAgY29uc3QgcHJvcHMgPSB7XG4gICAgICAgIGVucm9sbG1lbnRJRDogdXNlck5hbWUgYXMgc3RyaW5nLFxuICAgICAgICBlbnJvbGxtZW50U2VjcmV0OiBwYXNzd29yZCxcbiAgICAgICAgYWZmaWxpYXRpb246IGFmZmlsaWF0aW9uLFxuICAgICAgICB1c2VyUm9sZTogdXNlclJvbGUsXG4gICAgICAgIGF0dHJzOiBhdHRycyxcbiAgICAgICAgbWF4RW5yb2xsbWVudHM6IG1heEVucm9sbG1lbnRzLFxuICAgICAgfSBhcyBJUmVnaXN0ZXJSZXF1ZXN0O1xuICAgICAgcmVnaXN0cmF0aW9uID0gYXdhaXQgdGhpcy5jbGllbnQucmVnaXN0ZXIocHJvcHMsIHRoaXMudXNlcik7XG4gICAgICBsb2cuaW5mbyhcbiAgICAgICAgYFJlZ2lzdHJhdGlvbiBmb3IgJHt1c2VyTmFtZX0gY3JlYXRlZCB3aXRoIHVzZXIgdHlwZSAke3VzZXJSb2xlID8/IFwiVW5kZWZpbmVkIFJvbGVcIn0gJHtpc1N1cGVyVXNlciA/IFwiYXMgc3VwZXIgdXNlclwiIDogXCJcIn1gXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUpO1xuICAgIH1cbiAgICByZXR1cm4gcmVnaXN0cmF0aW9uO1xuICB9XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBpZGVudGl0eUZyb21FbnJvbGxtZW50KFxuICAgIGVucm9sbG1lbnQ6IElFbnJvbGxSZXNwb25zZSxcbiAgICBtc3BJZDogc3RyaW5nLFxuICAgIGN0eDogQ29udGV4dFxuICApOiBJZGVudGl0eSB7XG4gICAgY29uc3QgbG9nID0gY3R4LmxvZ2dlci5mb3IodGhpcy5pZGVudGl0eUZyb21FbnJvbGxtZW50KTtcbiAgICBjb25zdCB7IGNlcnRpZmljYXRlLCBrZXksIHJvb3RDZXJ0aWZpY2F0ZSB9ID0gZW5yb2xsbWVudDtcbiAgICBsb2cudmVyYm9zZShcbiAgICAgIGBHZW5lcmF0aW5nIElkZW50aXR5IGZyb20gY2VydGlmaWNhdGUgJHtjZXJ0aWZpY2F0ZX0gaW4gbXNwICR7bXNwSWR9YFxuICAgICk7XG4gICAgY29uc3QgY2xpZW50SWQgPSBDcnlwdG9VdGlscy5mYWJyaWNJZEZyb21DZXJ0aWZpY2F0ZShjZXJ0aWZpY2F0ZSk7XG4gICAgY29uc3QgaWQgPSBDcnlwdG9VdGlscy5lbmNvZGUoY2xpZW50SWQpO1xuICAgIGxvZy5kZWJ1ZyhgSWRlbnRpdHkgJHtjbGllbnRJZH0gYW5kIGVuY29kZWRJZCAke2lkfWApO1xuICAgIHJldHVybiBuZXcgSWRlbnRpdHkoe1xuICAgICAgaWQ6IGlkLFxuICAgICAgY3JlZGVudGlhbHM6IHtcbiAgICAgICAgaWQ6IGlkLFxuICAgICAgICBjZXJ0aWZpY2F0ZTogY2VydGlmaWNhdGUsXG4gICAgICAgIHByaXZhdGVLZXk6IGtleS50b0J5dGVzKCksXG4gICAgICAgIHJvb3RDZXJ0aWZpY2F0ZTogcm9vdENlcnRpZmljYXRlLFxuICAgICAgfSxcbiAgICAgIG1zcElkOiBtc3BJZCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRW5yb2xsIGFuIGlkZW50aXR5IHdpdGggdGhlIENBIHVzaW5nIGEgcmVnaXN0cmF0aW9uIHNlY3JldC5cbiAgICogQHN1bW1hcnkgRXhjaGFuZ2VzIHRoZSBlbnJvbGxtZW50IElEIGFuZCBzZWNyZXQgZm9yIGNlcnRpZmljYXRlcywgcmV0dXJuaW5nIGEgY29uc3RydWN0ZWQgSWRlbnRpdHkgbW9kZWwuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBlbnJvbGxtZW50SWQgLSBFbnJvbGxtZW50IElEIHRvIGVucm9sbC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZ2lzdHJhdGlvbiAtIEVucm9sbG1lbnQgc2VjcmV0IHJldHVybmVkIGF0IHJlZ2lzdHJhdGlvbiB0aW1lLlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPElkZW50aXR5Pn0gVGhlIGVucm9sbGVkIGlkZW50aXR5IG9iamVjdCB3aXRoIGNyZWRlbnRpYWxzLlxuICAgKi9cbiAgYXN5bmMgZW5yb2xsKFxuICAgIGVucm9sbG1lbnRJZDogc3RyaW5nLFxuICAgIHJlZ2lzdHJhdGlvbjogc3RyaW5nLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxhbnk+XG4gICk6IFByb21pc2U8SWRlbnRpdHk+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSAoYXdhaXQgdGhpcy5sb2dDdHgoYXJncywgXCJlbnJvbGxcIiwgdHJ1ZSkpLmZvcihcbiAgICAgIHRoaXMuZW5yb2xsXG4gICAgKTtcbiAgICBsZXQgaWRlbnRpdHk6IElkZW50aXR5O1xuICAgIHRyeSB7XG4gICAgICBsb2cuZGVidWcoYEVucm9sbGluZyAke2Vucm9sbG1lbnRJZH1gKTtcbiAgICAgIGNvbnN0IGVucm9sbG1lbnQ6IElFbnJvbGxSZXNwb25zZSA9IGF3YWl0IHRoaXMuY2xpZW50LmVucm9sbCh7XG4gICAgICAgIGVucm9sbG1lbnRJRDogZW5yb2xsbWVudElkLFxuICAgICAgICBlbnJvbGxtZW50U2VjcmV0OiByZWdpc3RyYXRpb24sXG4gICAgICB9KTtcbiAgICAgIGlkZW50aXR5ID0gRmFicmljSWRlbnRpdHlTZXJ2aWNlLmlkZW50aXR5RnJvbUVucm9sbG1lbnQoXG4gICAgICAgIGVucm9sbG1lbnQsXG4gICAgICAgIHRoaXMuY29uZmlnLmNhTmFtZSxcbiAgICAgICAgY3R4XG4gICAgICApO1xuICAgICAgbG9nLmluZm8oXG4gICAgICAgIGBTdWNjZXNzZnVsbHkgZW5yb2xsZWQgJHtlbnJvbGxtZW50SWR9IHVuZGVyICR7dGhpcy5jb25maWcuY2FOYW1lfSBhcyAke2lkZW50aXR5LmlkfWBcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSk7XG4gICAgfVxuICAgIHJldHVybiBpZGVudGl0eTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVnaXN0ZXIgYW5kIGVucm9sbCBhIG5ldyBpZGVudGl0eSBpbiBvbmUgc3RlcC5cbiAgICogQHN1bW1hcnkgUmVnaXN0ZXJzIGEgbmV3IGVucm9sbG1lbnQgSUQgd2l0aCB0aGUgQ0EgYW5kIGltbWVkaWF0ZWx5IGV4Y2hhbmdlcyB0aGUgc2VjcmV0IHRvIGVucm9sbCwgcmV0dXJuaW5nIHRoZSBjcmVhdGVkIElkZW50aXR5LlxuICAgKiBAcGFyYW0ge0NyZWRlbnRpYWxzfSBtb2RlbCAtIENyZWRlbnRpYWxzIGZvciB0aGUgbmV3IGlkZW50aXR5IGNvbnRhaW5pbmcgdXNlck5hbWUgYW5kIHBhc3N3b3JkLlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtpc1N1cGVyVXNlcj1mYWxzZV0gLSBXaGV0aGVyIHRvIHJlZ2lzdGVyIHRoZSBpZGVudGl0eSBhcyBhIHN1cGVyIHVzZXIuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYWZmaWxpYXRpb249XCJcIl0gLSBBZmZpbGlhdGlvbiBzdHJpbmcgKGUuZy4sIG9yZzEuZGVwYXJ0bWVudDEpLlxuICAgKiBAcGFyYW0ge0NBX1JPTEUgfCBzdHJpbmd9IFt1c2VyUm9sZV0gLSBSb2xlIHRvIGFzc2lnbiB0byB0aGUgaWRlbnRpdHkuXG4gICAqIEBwYXJhbSB7SUtleVZhbHVlQXR0cmlidXRlfSBbYXR0cnNdIC0gT3B0aW9uYWwgYXR0cmlidXRlcyB0byBhdHRhY2ggdG8gdGhlIGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge251bWJlcn0gW21heEVucm9sbG1lbnRzXSAtIE1heGltdW0gbnVtYmVyIG9mIGVucm9sbG1lbnRzIGFsbG93ZWQgZm9yIHRoZSBpZGVudGl0eS5cbiAgICogQHJldHVybiB7UHJvbWlzZTxJZGVudGl0eT59IFRoZSBlbnJvbGxlZCBpZGVudGl0eS5cbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyQW5kRW5yb2xsKFxuICAgIG1vZGVsOiBDcmVkZW50aWFscyxcbiAgICBpc1N1cGVyVXNlcjogYm9vbGVhbiA9IGZhbHNlLFxuICAgIGFmZmlsaWF0aW9uOiBzdHJpbmcgPSBcIlwiLFxuICAgIHVzZXJSb2xlPzogQ0FfUk9MRSB8IHN0cmluZyxcbiAgICBhdHRycz86IElLZXlWYWx1ZUF0dHJpYnV0ZSxcbiAgICBtYXhFbnJvbGxtZW50cz86IG51bWJlcixcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8YW55PlxuICApOiBQcm9taXNlPElkZW50aXR5PiB7XG4gICAgY29uc3QgeyBjdHggfSA9IChhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBcInJlZ2lzdGVyLWVucm9sbFwiLCB0cnVlKSkuZm9yKFxuICAgICAgdGhpcy5yZWdpc3RlckFuZEVucm9sbFxuICAgICk7XG4gICAgY29uc3QgcmVnaXN0cmF0aW9uID0gYXdhaXQgdGhpcy5yZWdpc3RlcihcbiAgICAgIG1vZGVsLFxuICAgICAgaXNTdXBlclVzZXIsXG4gICAgICBhZmZpbGlhdGlvbixcbiAgICAgIHVzZXJSb2xlLFxuICAgICAgYXR0cnMsXG4gICAgICBtYXhFbnJvbGxtZW50cyxcbiAgICAgIGN0eFxuICAgICk7XG4gICAgY29uc3QgeyB1c2VyTmFtZSB9ID0gbW9kZWw7XG4gICAgcmV0dXJuIHRoaXMuZW5yb2xsKHVzZXJOYW1lIGFzIHN0cmluZywgcmVnaXN0cmF0aW9uLCBjdHgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldm9rZXMgdGhlIGVucm9sbG1lbnQgb2YgYW4gaWRlbnRpdHkgd2l0aCB0aGUgc3BlY2lmaWVkIGVucm9sbG1lbnQgSUQuXG4gICAqXG4gICAqIEBwYXJhbSBlbnJvbGxtZW50SWQgLSBUaGUgZW5yb2xsbWVudCBJRCBvZiB0aGUgaWRlbnRpdHkgdG8gYmUgcmV2b2tlZC5cbiAgICpcbiAgICogQHJldHVybnMgQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgcmV2b2NhdGlvbiBvcGVyYXRpb24uXG4gICAqXG4gICAqIEB0aHJvd3Mge05vdEZvdW5kRXJyb3J9IElmIHRoZSBlbnJvbGxtZW50IHdpdGggdGhlIHNwZWNpZmllZCBJRCBkb2VzIG5vdCBleGlzdC5cbiAgICogQHRocm93cyB7SW50ZXJuYWxFcnJvcn0gSWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nIHRoZSByZXZvY2F0aW9uIHByb2Nlc3MuXG4gICAqL1xuICBhc3luYyByZXZva2UoXG4gICAgZW5yb2xsbWVudElkOiBzdHJpbmcsXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPGFueT5cbiAgKTogUHJvbWlzZTxJU2VydmljZVJlc3BvbnNlPiB7XG4gICAgY29uc3QgeyBsb2cgfSA9IChhd2FpdCB0aGlzLmxvZ0N0eChhcmdzLCBcInJldm9rZVwiLCB0cnVlKSkuZm9yKHRoaXMucmV2b2tlKTtcbiAgICBsb2cudmVyYm9zZShgUmV2b2tpbmcgaWRlbnRpdHkgd2l0aCBlbnJvbGxtZW50IElEICR7ZW5yb2xsbWVudElkfWApO1xuICAgIGNvbnN0IGlkZW50aXR5ID0gYXdhaXQgdGhpcy5yZWFkKGVucm9sbG1lbnRJZCk7XG4gICAgaWYgKCFpZGVudGl0eSlcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEVycm9yKFxuICAgICAgICBgQ291bGQgbm90IGZpbmQgZW5yb2xsbWVudCB3aXRoIGlkICR7ZW5yb2xsbWVudElkfWBcbiAgICAgICk7XG4gICAgbGV0IHJlc3VsdDogSVNlcnZpY2VSZXNwb25zZTtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gYXdhaXQgdGhpcy5jbGllbnQucmV2b2tlKFxuICAgICAgICB7IGVucm9sbG1lbnRJRDogaWRlbnRpdHkuaWQsIHJlYXNvbjogXCJVc2VyIERlbGV0aW9uXCIgfSxcbiAgICAgICAgdGhpcy51c2VyXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBgQ291bGQgbm90IHJldm9rZSBlbnJvbGxtZW50IHdpdGggaWQgJHtlbnJvbGxtZW50SWR9OiAke2V9YFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCFyZXN1bHQuc3VjY2VzcylcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBgQ291bGQgbm90IHJldm9rZSBlbnJvbGxtZW50IHdpdGggaWQgJHtlbnJvbGxtZW50SWR9OiAke3Jlc3VsdC5lcnJvcnMuam9pbihcIlxcblwiKX1gXG4gICAgICApO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbn1cbiIsImltcG9ydCB7IEZhYnJpY0NsaWVudEZsYWdzIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuZXhwb3J0IGNvbnN0IERlZmF1bHRGYWJyaWNDbGllbnRGbGFnczogRmFicmljQ2xpZW50RmxhZ3MgPSBPYmplY3QuYXNzaWduKHtcbiAgZXZhbHVhdGVUaW1lb3V0OiA1LFxuICBlbmRvcnNlVGltZW91dDogMTUsXG4gIHN1Ym1pdFRpbWVvdXQ6IDUsXG4gIGNvbW1pdFRpbWVvdXQ6IDYwLFxufSkgYXMgYW55O1xuIiwiaW1wb3J0IHsgaXNCcm93c2VyLCBNaW5pTG9nZ2VyIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQgeyBVc2VyIH0gZnJvbSBcImZhYnJpYy1jb21tb25cIjtcbmltcG9ydCB7IElkZW50aXR5LCBTaWduZXIsIHNpZ25lcnMgfSBmcm9tIFwiQGh5cGVybGVkZ2VyL2ZhYnJpYy1nYXRld2F5XCI7XG5pbXBvcnQgeyBJbnRlcm5hbEVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBub3JtYWxpemVJbXBvcnQgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcblxuY29uc3QgbG9nID0gbmV3IE1pbmlMb2dnZXIoXCJmYWJyaWMtZnNcIik7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIExvYWRzIGNvbnRlbnQgZnJvbSBhIGZpbGUgb3IgcmV0dXJucyB0aGUgY29udGVudCBpZiBhbHJlYWR5IGxvYWRlZFxuICogQHN1bW1hcnkgRGV0ZXJtaW5lcyBpZiB0aGUgaW5wdXQgaXMgYWxyZWFkeSBjb250ZW50IG9yIGEgcGF0aCB0byBhIGZpbGUsIGFuZCBsb2FkcyB0aGUgZmlsZSBpZiBuZWVkZWRcbiAqIEBwYXJhbSB7c3RyaW5nIHwgVWludDhBcnJheX0gY29udGVudE9yUGF0aCAtIFRoZSBjb250ZW50IG9yIHBhdGggdG8gbG9hZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gZmlsZVJlYWRlciAtIEZ1bmN0aW9uIHRvIHJlYWQgdGhlIGZpbGUgaWYgY29udGVudE9yUGF0aCBpcyBhIHBhdGhcbiAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nIHwgVWludDhBcnJheSB8IEJ1ZmZlcj59IFRoZSBjb250ZW50XG4gKiBAZnVuY3Rpb24gY29udGVudE9mTG9hZEZpbGVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvbnRlbnRPZkxvYWRGaWxlKFxuICBjb250ZW50T3JQYXRoOiBzdHJpbmcgfCBVaW50OEFycmF5LFxuICBmaWxlUmVhZGVyOiAocGF0aDogc3RyaW5nKSA9PiBQcm9taXNlPHN0cmluZyB8IFVpbnQ4QXJyYXkgfCBCdWZmZXI+XG4pIHtcbiAgaWYgKGNvbnRlbnRPclBhdGggaW5zdGFuY2VvZiBVaW50OEFycmF5KSByZXR1cm4gY29udGVudE9yUGF0aDtcbiAgaWYgKFxuICAgIGNvbnRlbnRPclBhdGgubWF0Y2goXG4gICAgICAvLS0tLS1CRUdJTiAoQ0VSVElGSUNBVEV8S0VZfFBSSVZBVEUgS0VZKS0tLS0tLis/LS0tLS1FTkQgXFwxLS0tLS0kL2dtc1xuICAgIClcbiAgKVxuICAgIHJldHVybiBjb250ZW50T3JQYXRoO1xuICByZXR1cm4gYXdhaXQgZmlsZVJlYWRlcihjb250ZW50T3JQYXRoKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmVhZHMgYSBmaWxlIGZyb20gdGhlIGZpbGUgc3lzdGVtXG4gKiBAc3VtbWFyeSBMb2FkcyBhIGZpbGUgdXNpbmcgdGhlIE5vZGUuanMgZmlsZSBzeXN0ZW0gbW9kdWxlXG4gKiBAcGFyYW0ge3N0cmluZyB8IEJ1ZmZlcn0gY29udGVudE9yUGF0aCAtIFRoZSBjb250ZW50IG9yIHBhdGggdG8gbG9hZFxuICogQHJldHVybiB7UHJvbWlzZTxCdWZmZXI+fSBUaGUgZmlsZSBjb250ZW50IGFzIGEgQnVmZmVyXG4gKiBAZnVuY3Rpb24gcmVhZEZpbGVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRGaWxlKGNvbnRlbnRPclBhdGg6IHN0cmluZyB8IEJ1ZmZlcikge1xuICBpZiAodHlwZW9mIGNvbnRlbnRPclBhdGggIT09IFwic3RyaW5nXCIpIHJldHVybiBjb250ZW50T3JQYXRoO1xuXG4gIGNvbnN0IGZpbGVSZWFkZXIgPSBhc3luYyAocGF0aDogc3RyaW5nKSA9PiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICByZXR1cm4gYXdhaXQgcHJvbWlzZXMucmVhZEZpbGUocGF0aCk7XG4gIH07XG5cbiAgcmV0dXJuIGF3YWl0IGZpbGVSZWFkZXIoY29udGVudE9yUGF0aCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgdXNlclxuICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYSB1c2VyIHdpdGggdGhlIGdpdmVuIGNyZWRlbnRpYWxzIGZvciBpbnRlcmFjdGluZyB3aXRoIGEgRmFicmljIENBXG4gKiBAcGFyYW0ge3N0cmluZ30gdXNlck5hbWUgLSBUaGUgdXNlciBuYW1lXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJpdmF0ZUtleSAtIFRoZSBwcml2YXRlIGtleSBhcyBhIHN0cmluZ1xuICogQHBhcmFtIHtzdHJpbmd9IGNlcnRpZmljYXRlIC0gVGhlIGNlcnRpZmljYXRlIGFzIGEgc3RyaW5nXG4gKiBAcGFyYW0ge3N0cmluZ30gbXNwSWQgLSBUaGUgTWVtYmVyc2hpcCBTZXJ2aWNlIFByb3ZpZGVyIElEXG4gKiBAcmV0dXJuIHtQcm9taXNlPFVzZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgY3JlYXRlZCB1c2VyXG4gKiBAZnVuY3Rpb24gZ2V0Q0FVc2VyXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuY2xpZW50XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRDQVVzZXIoXG4gIHVzZXJOYW1lOiBzdHJpbmcsXG4gIHByaXZhdGVLZXk6IHN0cmluZyxcbiAgY2VydGlmaWNhdGU6IHN0cmluZyxcbiAgbXNwSWQ6IHN0cmluZ1xuKTogUHJvbWlzZTxVc2VyPiB7XG4gIGxvZy5kZWJ1ZyhcbiAgICBgQ3JlYXRpbmcgYSBDQSAke21zcElkfSB1c2VyICR7dXNlck5hbWV9IHdpdGggY2VydGlmaWNhdGUgJHtjZXJ0aWZpY2F0ZX1gXG4gICk7XG4gIGNvbnN0IHVzZXIgPSBuZXcgVXNlcih1c2VyTmFtZSk7XG4gIGNvbnN0IGNyeXB0b1N1aXRlID0gVXNlci5uZXdDcnlwdG9TdWl0ZSgpO1xuICB1c2VyLnNldENyeXB0b1N1aXRlKGNyeXB0b1N1aXRlKTtcbiAgY29uc3QgaW1wb3J0ZWRLZXkgPSBjcnlwdG9TdWl0ZS5jcmVhdGVLZXlGcm9tUmF3KHByaXZhdGVLZXkpO1xuICBhd2FpdCB1c2VyLnNldEVucm9sbG1lbnQoaW1wb3J0ZWRLZXksIGNlcnRpZmljYXRlLCBtc3BJZCk7XG4gIHJldHVybiB1c2VyO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBHZXRzIGFuIGlkZW50aXR5IGZyb20gYSBjZXJ0aWZpY2F0ZSBkaXJlY3RvcnlcbiAqIEBzdW1tYXJ5IExvYWRzIGEgY2VydGlmaWNhdGUgZnJvbSBhIGRpcmVjdG9yeSBhbmQgY3JlYXRlcyBhbiBJZGVudGl0eSBvYmplY3RcbiAqIEBwYXJhbSB7c3RyaW5nfSBtc3BJZCAtIFRoZSBNZW1iZXJzaGlwIFNlcnZpY2UgUHJvdmlkZXIgSURcbiAqIEBwYXJhbSB7c3RyaW5nfSBjZXJ0RGlyZWN0b3J5UGF0aCAtIFBhdGggdG8gdGhlIGRpcmVjdG9yeSBjb250YWluaW5nIHRoZSBjZXJ0aWZpY2F0ZVxuICogQHJldHVybiB7UHJvbWlzZTxJZGVudGl0eT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpZGVudGl0eVxuICogQGZ1bmN0aW9uIGdldElkZW50aXR5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuY2xpZW50XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRJZGVudGl0eShcbiAgbXNwSWQ6IHN0cmluZyxcbiAgY2VydERpcmVjdG9yeVBhdGg6IHN0cmluZ1xuKTogUHJvbWlzZTxJZGVudGl0eT4ge1xuICBjb25zdCBpZGVudGl0eUZpbGVSZWFkZXIgPSBhc3luYyAocGF0aDogc3RyaW5nKSA9PiB7XG4gICAgY29uc3QgeyBwcm9taXNlcyB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcImZzXCIpKTtcbiAgICBjb25zdCBjZXJ0UGF0aCA9IGF3YWl0IGdldEZpcnN0RGlyRmlsZU5hbWUocGF0aCk7XG4gICAgY29uc3QgY3JlZGVudGlhbHMgPSBhd2FpdCBwcm9taXNlcy5yZWFkRmlsZShjZXJ0UGF0aCk7XG4gICAgcmV0dXJuIGNyZWRlbnRpYWxzO1xuICB9O1xuXG4gIGNvbnN0IGNyZWRlbnRpYWxzOiBVaW50OEFycmF5ID0gKGF3YWl0IGNvbnRlbnRPZkxvYWRGaWxlKFxuICAgIGNlcnREaXJlY3RvcnlQYXRoLFxuICAgIGlkZW50aXR5RmlsZVJlYWRlclxuICApKSBhcyBVaW50OEFycmF5O1xuXG4gIHJldHVybiB7IG1zcElkLCBjcmVkZW50aWFscyB9O1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBHZXRzIHRoZSBmdWxsIHBhdGggb2YgdGhlIGZpcnN0IGZpbGUgaW4gYSBkaXJlY3RvcnlcbiAqIEBzdW1tYXJ5IFJlYWRzIGEgZGlyZWN0b3J5IGFuZCByZXR1cm5zIHRoZSBwYXRoIHRvIHRoZSBmaXJzdCBmaWxlIGZvdW5kXG4gKiBAcGFyYW0ge3N0cmluZ30gZGlyUGF0aCAtIFBhdGggdG8gdGhlIGRpcmVjdG9yeVxuICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZnVsbCBwYXRoIG9mIHRoZSBmaXJzdCBmaWxlXG4gKiBAZnVuY3Rpb24gZ2V0Rmlyc3REaXJGaWxlTmFtZVxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLmNsaWVudFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0Rmlyc3REaXJGaWxlTmFtZShkaXJQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCB7IHByb21pc2VzIH0gPSBhd2FpdCBub3JtYWxpemVJbXBvcnQoaW1wb3J0KFwiZnNcIikpO1xuICBjb25zdCB7IGpvaW4gfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJwYXRoXCIpKTtcbiAgY29uc3QgZmlsZXMgPSBhd2FpdCBwcm9taXNlcy5yZWFkZGlyKGRpclBhdGgpO1xuICByZXR1cm4gam9pbihkaXJQYXRoLCBmaWxlc1swXSk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEdldHMgdGhlIGNvbnRlbnQgb2YgdGhlIGZpcnN0IGZpbGUgaW4gYSBkaXJlY3RvcnlcbiAqIEBzdW1tYXJ5IFJlYWRzIGEgZGlyZWN0b3J5LCBmaW5kcyB0aGUgZmlyc3QgZmlsZSwgYW5kIHJldHVybnMgaXRzIGNvbnRlbnQgYXMgYSBzdHJpbmdcbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXJQYXRoIC0gUGF0aCB0byB0aGUgZGlyZWN0b3J5XG4gKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBjb250ZW50IG9mIHRoZSBmaXJzdCBmaWxlXG4gKiBAZnVuY3Rpb24gZ2V0Rmlyc3REaXJGaWxlTmFtZUNvbnRlbnRcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldEZpcnN0RGlyRmlsZU5hbWVDb250ZW50KFxuICBkaXJQYXRoOiBzdHJpbmdcbik6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHsgcHJvbWlzZXMgfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJmc1wiKSk7XG4gIGNvbnN0IHsgam9pbiB9ID0gYXdhaXQgbm9ybWFsaXplSW1wb3J0KGltcG9ydChcInBhdGhcIikpO1xuICBjb25zdCBmaWxlcyA9IGF3YWl0IHByb21pc2VzLnJlYWRkaXIoZGlyUGF0aCk7XG4gIHJldHVybiAoYXdhaXQgcHJvbWlzZXMucmVhZEZpbGUoam9pbihkaXJQYXRoLCBmaWxlc1swXSkpKS50b1N0cmluZygpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBHZXRzIGEgc2lnbmVyIGZyb20gYSBrZXkgZGlyZWN0b3J5XG4gKiBAc3VtbWFyeSBMb2FkcyBhIHByaXZhdGUga2V5IGZyb20gYSBkaXJlY3RvcnkgYW5kIGNyZWF0ZXMgYSBTaWduZXIgZm9yIEZhYnJpYyB0cmFuc2FjdGlvbnNcbiAqIEBwYXJhbSB7c3RyaW5nfSBrZXlEaXJlY3RvcnlQYXRoIC0gUGF0aCB0byB0aGUgZGlyZWN0b3J5IGNvbnRhaW5pbmcgdGhlIHByaXZhdGUga2V5XG4gKiBAcmV0dXJuIHtQcm9taXNlPFNpZ25lcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBzaWduZXJcbiAqIEBmdW5jdGlvbiBnZXRTaWduZXJcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jbGllbnRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldFNpZ25lcihrZXlEaXJlY3RvcnlQYXRoOiBzdHJpbmcpOiBQcm9taXNlPFNpZ25lcj4ge1xuICBjb25zdCBzaWduZXJGaWxlUmVhZGVyID0gYXN5bmMgKHBhdGg6IHN0cmluZykgPT4ge1xuICAgIGNvbnN0IHsgcHJvbWlzZXMgfSA9IGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQoXCJmc1wiKSk7XG4gICAgY29uc3Qga2V5UGF0aCA9IGF3YWl0IGdldEZpcnN0RGlyRmlsZU5hbWUocGF0aCk7XG4gICAgcmV0dXJuIGF3YWl0IHByb21pc2VzLnJlYWRGaWxlKGtleVBhdGgpO1xuICB9O1xuXG4gIGNvbnN0IHByaXZhdGVLZXlQZW0gPSAoYXdhaXQgY29udGVudE9mTG9hZEZpbGUoXG4gICAga2V5RGlyZWN0b3J5UGF0aCxcbiAgICBzaWduZXJGaWxlUmVhZGVyXG4gICkpIGFzIEJ1ZmZlcjtcbiAgLy8gTm9kZSBiYXNlZCBpbXBsZW1lbnRhdGlvblxuICAvLyBwcml2YXRlS2V5ID0gY3JlYXRlUHJpdmF0ZUtleShwcml2YXRlS2V5UGVtKTtcbiAgLy8gLS1cblxuICAvLyB3ZWIgYmFzZWQgaW1wbGVtZW50YXRpb25cbiAgY29uc3QgcHJpdmF0ZUtleSA9IGF3YWl0IGV4dHJhY3RQcml2YXRlS2V5KHByaXZhdGVLZXlQZW0pO1xuICBjb25zdCBrZXlzID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhwcml2YXRlS2V5KTtcbiAgY29uc3QgayA9IChwcml2YXRlS2V5IGFzIGFueSlba2V5c1swXV07XG4gIC8vIC0tXG5cbiAgcmV0dXJuIHNpZ25lcnMubmV3UHJpdmF0ZUtleVNpZ25lcihrIGFzIGFueSk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEV4dHJhY3RzIGEgcHJpdmF0ZSBrZXkgZnJvbSBhIFBFTSBidWZmZXJcbiAqIEBzdW1tYXJ5IENvbnZlcnRzIGEgUEVNLWVuY29kZWQgcHJpdmF0ZSBrZXkgdG8gYSBDcnlwdG9LZXkgb2JqZWN0XG4gKiBAcGFyYW0ge0J1ZmZlcn0gcGVtIC0gVGhlIFBFTS1lbmNvZGVkIHByaXZhdGUga2V5XG4gKiBAcmV0dXJuIHtQcm9taXNlPENyeXB0b0tleT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBDcnlwdG9LZXlcbiAqIEBmdW5jdGlvbiBleHRyYWN0UHJpdmF0ZUtleVxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLmNsaWVudFxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgRXh0cmFjdFByaXZhdGVLZXlcbiAqICAgcGFydGljaXBhbnQgU3VidGxlQ3J5cHRvXG4gKlxuICogICBDYWxsZXItPj5FeHRyYWN0UHJpdmF0ZUtleTogZXh0cmFjdFByaXZhdGVLZXkocGVtKVxuICogICBFeHRyYWN0UHJpdmF0ZUtleS0+PkV4dHJhY3RQcml2YXRlS2V5OiBHZXQgU3VidGxlQ3J5cHRvIGltcGxlbWVudGF0aW9uXG4gKiAgIEV4dHJhY3RQcml2YXRlS2V5LT4+RXh0cmFjdFByaXZhdGVLZXk6IFBhcnNlIFBFTSBmb3JtYXRcbiAqICAgRXh0cmFjdFByaXZhdGVLZXktPj5FeHRyYWN0UHJpdmF0ZUtleTogQ29udmVydCB0byBiaW5hcnkgREVSXG4gKiAgIEV4dHJhY3RQcml2YXRlS2V5LT4+U3VidGxlQ3J5cHRvOiBpbXBvcnRLZXkocGtjczgsIGJpbmFyeURlciwgb3B0aW9ucylcbiAqICAgU3VidGxlQ3J5cHRvLS0+PkV4dHJhY3RQcml2YXRlS2V5OiBDcnlwdG9LZXlcbiAqICAgRXh0cmFjdFByaXZhdGVLZXktLT4+Q2FsbGVyOiBDcnlwdG9LZXlcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RQcml2YXRlS2V5KHBlbTogQnVmZmVyKSB7XG4gIGNvbnN0IGxpYk5hbWUgPSBcImNyeXB0b1wiO1xuICBsZXQgc3VidGxlO1xuICBpZiAoaXNCcm93c2VyKCkpIHtcbiAgICBzdWJ0bGUgPSAoZ2xvYmFsVGhpcyBhcyBhbnkpLmNyeXB0by5zdWJ0bGU7XG4gIH0gZWxzZSB7XG4gICAgY29uc3QgbGliID0gKGF3YWl0IG5vcm1hbGl6ZUltcG9ydChpbXBvcnQobGliTmFtZSkpKSBhcyBhbnk7XG4gICAgc3VidGxlID0gbGliLnN1YnRsZSB8fCBsaWIud2ViY3J5cHRvLnN1YnRsZTtcbiAgfVxuXG4gIGlmICghc3VidGxlKSB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgbG9hZCBTdWJ0bGVDcnlwdG8gbW9kdWxlXCIpO1xuXG4gIGZ1bmN0aW9uIHN0cjJhYihzdHI6IHN0cmluZykge1xuICAgIGNvbnN0IGJ1ZiA9IG5ldyBBcnJheUJ1ZmZlcihzdHIubGVuZ3RoKTtcbiAgICBjb25zdCBidWZWaWV3ID0gbmV3IFVpbnQ4QXJyYXkoYnVmKTtcbiAgICBmb3IgKGxldCBpID0gMCwgc3RyTGVuID0gc3RyLmxlbmd0aDsgaSA8IHN0ckxlbjsgaSsrKSB7XG4gICAgICBidWZWaWV3W2ldID0gc3RyLmNoYXJDb2RlQXQoaSk7XG4gICAgfVxuICAgIHJldHVybiBidWY7XG4gIH1cblxuICBjb25zdCBzdHIgPSBwZW1cbiAgICAudG9TdHJpbmcoXCJ1dGY4XCIpXG4gICAgLnJlcGxhY2UoXCItLS0tLUJFR0lOIFBSSVZBVEUgS0VZLS0tLS1cIiwgXCJcIilcbiAgICAucmVwbGFjZUFsbChcIlxcblwiLCBcIlwiKVxuICAgIC5yZXBsYWNlKFwiLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLVwiLCBcIlwiKTtcbiAgY29uc3QgZGVjb2RlZCA9IEJ1ZmZlci5mcm9tKHN0ciwgXCJiYXNlNjRcIikudG9TdHJpbmcoXCJiaW5hcnlcIik7XG4gIGNvbnN0IGJpbmFyeURlciA9IHN0cjJhYihkZWNvZGVkKTtcblxuICB0cnkge1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IHN1YnRsZS5pbXBvcnRLZXkoXG4gICAgICBcInBrY3M4XCIsXG4gICAgICBiaW5hcnlEZXIsXG4gICAgICB7XG4gICAgICAgIG5hbWU6IFwiRUNEU0FcIixcbiAgICAgICAgbmFtZWRDdXJ2ZTogXCJQLTI1NlwiLFxuICAgICAgfSxcbiAgICAgIHRydWUsXG4gICAgICBbXCJzaWduXCJdXG4gICAgKTtcblxuICAgIHJldHVybiBrZXk7XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGUpO1xuICB9XG59XG4iLCJpbXBvcnQgcGtjczExIGZyb20gXCJwa2NzMTFqc1wiO1xuaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IE1pc3NpbmdQS0NTUzExTGliIH0gZnJvbSBcIi4uL3NoYXJlZC9lcnJvcnNcIjtcbmltcG9ydCBjcnlwdG8gZnJvbSBcImNyeXB0b1wiO1xuaW1wb3J0IHsgcDI1NiB9IGZyb20gXCJAbm9ibGUvY3VydmVzL25pc3RcIjtcblxuZXhwb3J0IGNsYXNzIEhTTVNpZ25lckZhY3RvcnlDdXN0b20ge1xuICBzdGF0aWMgI3BrY3MxMTogcGtjczExLlBLQ1MxMSB8IG51bGwgPSBudWxsO1xuICBzdGF0aWMgI2luaXRpYWxpemVkID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IobGlicmFyeTogc3RyaW5nKSB7XG4gICAgaWYgKCFIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEpIHtcbiAgICAgIEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSA9IG5ldyBwa2NzMTEuUEtDUzExKCk7XG4gICAgICBIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEubG9hZCh0aGlzLmZpbmRIU01QS0NTMTFMaWIobGlicmFyeSkpO1xuICAgIH1cblxuICAgIGlmICghSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jaW5pdGlhbGl6ZWQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMS5DX0luaXRpYWxpemUoKTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgLy8gaWdub3JlIFwiYWxyZWFkeSBpbml0aWFsaXplZFwiIGlmIHRlc3RzIC8gaG90IHJlbG9hZHMgY2F1c2UgcmV1c2VcbiAgICAgICAgaWYgKChlIGFzIGFueSkuY29kZSAhPT0gcGtjczExLkNLUl9DUllQVE9LSV9BTFJFQURZX0lOSVRJQUxJWkVEKSB7XG4gICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jaW5pdGlhbGl6ZWQgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmluZEhTTVBLQ1MxMUxpYihsaWI/OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvbW1vblNvZnRIU01QYXRoTmFtZXMgPSBbXG4gICAgICBcIi91c3IvbGliL3NvZnRoc20vbGlic29mdGhzbTIuc29cIixcbiAgICAgIFwiL3Vzci9saWIveDg2XzY0LWxpbnV4LWdudS9zb2Z0aHNtL2xpYnNvZnRoc20yLnNvXCIsXG4gICAgICBcIi91c3IvbG9jYWwvbGliL3NvZnRoc20vbGlic29mdGhzbTIuc29cIixcbiAgICAgIFwiL3Vzci9saWIvbGliYWNzcC1wa2NzMTEuc29cIixcbiAgICAgIFwiL29wdC9ob21lYnJldy9saWIvc29mdGhzbS9saWJzb2Z0aHNtMi5zb1wiLFxuICAgIF07XG5cbiAgICBpZiAobGliKSBjb21tb25Tb2Z0SFNNUGF0aE5hbWVzLnB1c2gobGliKTtcblxuICAgIGZvciAoY29uc3QgcGF0aG5hbWVUb1RyeSBvZiBjb21tb25Tb2Z0SFNNUGF0aE5hbWVzKSB7XG4gICAgICBpZiAoZnMuZXhpc3RzU3luYyhwYXRobmFtZVRvVHJ5KSkge1xuICAgICAgICByZXR1cm4gcGF0aG5hbWVUb1RyeTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgTWlzc2luZ1BLQ1NTMTFMaWIoXCJVbmFibGUgdG8gZmluZCBQS0NTMTEgbGlicmFyeVwiKTtcbiAgfVxuXG4gIGRpc3Bvc2UoKSB7XG4gICAgSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jcGtjczExIS5DX0ZpbmFsaXplKCk7XG4gIH1cblxuICBwcml2YXRlIHNhbml0aXplT3B0aW9ucyhoc21TaWduZXJPcHRpb25zOiBIU01Db25maWcpIHtcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcbiAgICAgIHtcbiAgICAgICAgdXNlclR5cGU6IHBrY3MxMS5DS1VfVVNFUixcbiAgICAgIH0sXG4gICAgICBoc21TaWduZXJPcHRpb25zXG4gICAgKTtcbiAgICB0aGlzLmFzc2VydE5vdEVtcHR5KG9wdGlvbnMubGFiZWwsIFwibGFiZWxcIik7XG4gICAgdGhpcy5hc3NlcnROb3RFbXB0eShvcHRpb25zLnBpbiwgXCJwaW5cIik7XG4gICAgdGhpcy5hc3NlcnROb3RFbXB0eShvcHRpb25zLmlkZW50aWZpZXIgYXMgdW5rbm93biBhcyBzdHJpbmcsIFwiaWRlbnRpZmllclwiKTtcbiAgICByZXR1cm4gb3B0aW9ucztcbiAgfVxuXG4gIHByaXZhdGUgYXNzZXJ0Tm90RW1wdHkocHJvcGVydHk6IHN0cmluZywgbmFtZTogc3RyaW5nKSB7XG4gICAgaWYgKCFwcm9wZXJ0eSB8fCBwcm9wZXJ0eS50b1N0cmluZygpLnRyaW0oKS5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtuYW1lfSBwcm9wZXJ0eSBtdXN0IGJlIHByb3ZpZGVkYCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBmaW5kU2xvdEZvckxhYmVsKHBrY3MxMUxhYmVsOiBzdHJpbmcpIHtcbiAgICBjb25zdCBzbG90cyA9IChcbiAgICAgIEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExXG4gICAgKS5DX0dldFNsb3RMaXN0KHRydWUpO1xuICAgIGlmIChzbG90cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIHBrY3MxMSBzbG90cyBjYW4gYmUgZm91bmRcIik7XG4gICAgfVxuICAgIGNvbnN0IHNsb3QgPSBzbG90cy5maW5kKChzbG90VG9DaGVjaykgPT4ge1xuICAgICAgY29uc3QgdG9rZW5JbmZvID0gKFxuICAgICAgICBIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEgYXMgcGtjczExLlBLQ1MxMVxuICAgICAgKS5DX0dldFRva2VuSW5mbyhzbG90VG9DaGVjayk7XG4gICAgICByZXR1cm4gdG9rZW5JbmZvLmxhYmVsLnRyaW0oKSA9PT0gcGtjczExTGFiZWw7XG4gICAgfSk7XG4gICAgaWYgKCFzbG90KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBsYWJlbCAke3BrY3MxMUxhYmVsfSBjYW5ub3QgYmUgZm91bmQgaW4gdGhlIHBrY3MxMSBzbG90IGxpc3RgXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gc2xvdDtcbiAgfVxuXG4gIHByaXZhdGUgbG9naW4oc2Vzc2lvbjogcGtjczExLkhhbmRsZSwgdXNlclR5cGU6IG51bWJlciwgcGluOiBzdHJpbmcpIHtcbiAgICB0cnkge1xuICAgICAgKEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExKS5DX0xvZ2luKFxuICAgICAgICBzZXNzaW9uLFxuICAgICAgICB1c2VyVHlwZSxcbiAgICAgICAgcGluXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycjogdW5rbm93bikge1xuICAgICAgY29uc3QgcGtjczExZXJyID0gZXJyIGFzIHsgY29kZTogbnVtYmVyIH07XG4gICAgICBpZiAocGtjczExZXJyLmNvZGUgIT09IHBrY3MxMS5DS1JfVVNFUl9BTFJFQURZX0xPR0dFRF9JTikge1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBmaW5kT2JqZWN0SW5IU00oXG4gICAgc2Vzc2lvbjogcGtjczExLkhhbmRsZSxcbiAgICBrZXl0eXBlOiBudW1iZXIsXG4gICAgaWRlbnRpZmllcjogYW55XG4gICkge1xuICAgIGNvbnN0IHBrY3MxMVRlbXBsYXRlID0gW1xuICAgICAgeyB0eXBlOiBwa2NzMTEuQ0tBX0lELCB2YWx1ZTogaWRlbnRpZmllciB9LFxuICAgICAgeyB0eXBlOiBwa2NzMTEuQ0tBX0NMQVNTLCB2YWx1ZToga2V5dHlwZSB9LFxuICAgICAgeyB0eXBlOiBwa2NzMTEuQ0tBX0tFWV9UWVBFLCB2YWx1ZTogcGtjczExLkNLS19FQyB9LFxuICAgIF07XG5cbiAgICAoSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jcGtjczExIGFzIHBrY3MxMS5QS0NTMTEpLkNfRmluZE9iamVjdHNJbml0KFxuICAgICAgc2Vzc2lvbixcbiAgICAgIHBrY3MxMVRlbXBsYXRlXG4gICAgKTtcbiAgICBjb25zdCBoc21PYmplY3QgPSAoXG4gICAgICBIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEgYXMgcGtjczExLlBLQ1MxMVxuICAgICkuQ19GaW5kT2JqZWN0cyhzZXNzaW9uLCAxKVswXTtcbiAgICBpZiAoIWhzbU9iamVjdCkge1xuICAgICAgKEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExKS5DX0ZpbmRPYmplY3RzRmluYWwoXG4gICAgICAgIHNlc3Npb25cbiAgICAgICk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBVbmFibGUgdG8gZmluZCBvYmplY3QgaW4gSFNNIHdpdGggSUQgJHtpZGVudGlmaWVyLnRvU3RyaW5nKCl9YFxuICAgICAgKTtcbiAgICB9XG4gICAgKEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExKS5DX0ZpbmRPYmplY3RzRmluYWwoXG4gICAgICBzZXNzaW9uXG4gICAgKTtcbiAgICByZXR1cm4gaHNtT2JqZWN0O1xuICB9XG5cbiAgbmV3U2lnbmVyKGhzbVNpZ25lck9wdGlvbnM6IEhTTUNvbmZpZykge1xuICAgIGNvbnN0IG9wdGlvbnMgPSB0aGlzLnNhbml0aXplT3B0aW9ucyhoc21TaWduZXJPcHRpb25zKTtcbiAgICBjb25zdCBwa2NzID0gSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jcGtjczExIGFzIHBrY3MxMS5QS0NTMTE7XG4gICAgY29uc3Qgc2xvdCA9IHRoaXMuZmluZFNsb3RGb3JMYWJlbChvcHRpb25zLmxhYmVsKTtcbiAgICBjb25zdCBzZXNzaW9uID0gcGtjcy5DX09wZW5TZXNzaW9uKHNsb3QsIHBrY3MxMS5DS0ZfU0VSSUFMX1NFU1NJT04pO1xuICAgIGxldCBwcml2YXRlS2V5SGFuZGxlO1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmxvZ2luKHNlc3Npb24sIG9wdGlvbnMudXNlclR5cGUsIG9wdGlvbnMucGluKTtcbiAgICAgIHByaXZhdGVLZXlIYW5kbGUgPSB0aGlzLmZpbmRPYmplY3RJbkhTTShcbiAgICAgICAgc2Vzc2lvbixcbiAgICAgICAgcGtjczExLkNLT19QUklWQVRFX0tFWSxcbiAgICAgICAgb3B0aW9ucy5pZGVudGlmaWVyXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgKEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExKS5DX0Nsb3NlU2Vzc2lvbihzZXNzaW9uKTtcbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIHNpZ25lcjogYXN5bmMgKGRpZ2VzdDogYW55KSA9PiB7XG4gICAgICAgIChIU01TaWduZXJGYWN0b3J5Q3VzdG9tLiNwa2NzMTEgYXMgcGtjczExLlBLQ1MxMSkuQ19TaWduSW5pdChcbiAgICAgICAgICBzZXNzaW9uLFxuICAgICAgICAgIHsgbWVjaGFuaXNtOiBwa2NzMTEuQ0tNX0VDRFNBIH0sXG4gICAgICAgICAgcHJpdmF0ZUtleUhhbmRsZVxuICAgICAgICApO1xuICAgICAgICBjb25zdCBjb21wYWN0U2lnbmF0dXJlID0gYXdhaXQgKFxuICAgICAgICAgIEhTTVNpZ25lckZhY3RvcnlDdXN0b20uI3BrY3MxMSBhcyBwa2NzMTEuUEtDUzExXG4gICAgICAgICkuQ19TaWduQXN5bmMoXG4gICAgICAgICAgc2Vzc2lvbixcbiAgICAgICAgICBCdWZmZXIuZnJvbShkaWdlc3QpLFxuICAgICAgICAgIC8vIEVDIHNpZ25hdHVyZXMgaGF2ZSBsZW5ndGggb2YgMm4gYWNjb3JkaW5nIHRvIHRoZSBQS0NTMTEgc3BlYzpcbiAgICAgICAgICAvLyBodHRwczovL2RvY3Mub2FzaXMtb3Blbi5vcmcvcGtjczExL3BrY3MxMS1zcGVjL3YzLjEvcGtjczExLXNwZWMtdjMuMS5odG1sXG4gICAgICAgICAgQnVmZmVyLmFsbG9jKHAyNTYuUG9pbnQuRm4uQllURVMgKiAyKVxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gcDI1Ni5TaWduYXR1cmUuZnJvbUJ5dGVzKGNvbXBhY3RTaWduYXR1cmUsIFwiY29tcGFjdFwiKVxuICAgICAgICAgIC5ub3JtYWxpemVTKClcbiAgICAgICAgICAudG9CeXRlcyhcImRlclwiKTtcbiAgICAgIH0sXG4gICAgICBjbG9zZTogKCkgPT4ge1xuICAgICAgICAoSFNNU2lnbmVyRmFjdG9yeUN1c3RvbS4jcGtjczExIGFzIHBrY3MxMS5QS0NTMTEpLkNfQ2xvc2VTZXNzaW9uKFxuICAgICAgICAgIHNlc3Npb25cbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXNzZXJ0RGVmaW5lZDxUPih2YWx1ZTogVCB8IHVuZGVmaW5lZCk6IFQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJyZXF1aXJlZCB2YWx1ZSB3YXMgdW5kZWZpbmVkXCIpO1xuICAgIH1cblxuICAgIHJldHVybiB2YWx1ZTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0VW5jb21wcmVzc2VkUG9pbnRPbkN1cnZlKGtleTogY3J5cHRvLktleU9iamVjdCk6IEJ1ZmZlciB7XG4gICAgY29uc3QgandrID0ga2V5LmV4cG9ydCh7IGZvcm1hdDogXCJqd2tcIiB9KTtcbiAgICBjb25zdCB4ID0gQnVmZmVyLmZyb20odGhpcy5hc3NlcnREZWZpbmVkKGp3ay54KSwgXCJiYXNlNjR1cmxcIik7XG4gICAgY29uc3QgeSA9IEJ1ZmZlci5mcm9tKHRoaXMuYXNzZXJ0RGVmaW5lZChqd2sueSksIFwiYmFzZTY0dXJsXCIpO1xuICAgIGNvbnN0IHByZWZpeCA9IEJ1ZmZlci5mcm9tKFwiMDRcIiwgXCJoZXhcIik7XG4gICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoW3ByZWZpeCwgeCwgeV0pO1xuICB9XG5cbiAgZ2V0U0tJRnJvbUNlcnRpZmljYXRlUGF0aChjZXJ0UGF0aDogc3RyaW5nKSB7XG4gICAgY29uc3QgcCA9IGNlcnRQYXRoLmVuZHNXaXRoKFwiLnBlbVwiKVxuICAgICAgPyBjZXJ0UGF0aFxuICAgICAgOiBwYXRoLmpvaW4oY2VydFBhdGgsIFwiY2VydC5wZW1cIik7XG4gICAgY29uc3QgY3JlZGVudGlhbHMgPSBmcy5yZWFkRmlsZVN5bmMocCk7XG5cbiAgICByZXR1cm4gdGhpcy5nZXRTS0lGcm9tQ2VydGlmaWNhdGUoY3JlZGVudGlhbHMpO1xuICB9XG5cbiAgZ2V0U0tJRnJvbUNlcnRpZmljYXRlKGNlcnQ6IHN0cmluZyB8IE5vblNoYXJlZEJ1ZmZlcik6IEJ1ZmZlciB7XG4gICAgY29uc3QgY2VydGlmaWNhdGUgPSBuZXcgY3J5cHRvLlg1MDlDZXJ0aWZpY2F0ZShjZXJ0KTtcbiAgICBjb25zdCB1bmNvbXByZXNzZWRQb2ludCA9IHRoaXMuZ2V0VW5jb21wcmVzc2VkUG9pbnRPbkN1cnZlKFxuICAgICAgY2VydGlmaWNhdGUucHVibGljS2V5XG4gICAgKTtcblxuICAgIHJldHVybiBjcnlwdG8uY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUodW5jb21wcmVzc2VkUG9pbnQpLmRpZ2VzdCgpO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSFNNQ29uZmlnIHtcbiAgbGFiZWw6IHN0cmluZztcbiAgaWRlbnRpZmllcjogQnVmZmVyPEFycmF5QnVmZmVyTGlrZT47XG4gIHBpbjogc3RyaW5nO1xufVxuIiwiaW1wb3J0IHtcbiAgQWRhcHRlckZsYWdzLFxuICBDb25kaXRpb24sXG4gIENvbnRleHQsXG4gIEdyb3VwT3BlcmF0b3IsXG4gIE1heWJlQ29udGV4dHVhbEFyZyxcbiAgT3BlcmF0b3IsXG4gIE9yZGVyRGlyZWN0aW9uLFxuICBQZXJzaXN0ZW5jZUtleXMsXG4gIFByZXBhcmVkU3RhdGVtZW50LFxuICBQcmVwYXJlZFN0YXRlbWVudEtleXMsXG4gIFF1ZXJ5Q2xhdXNlLFxuICBRdWVyeUVycm9yLFxuICBSZXBvc2l0b3J5LFxuICBTZWxlY3RTZWxlY3RvcixcbiAgU2VxdWVuY2UsXG4gIFN0YXRlbWVudCxcbiAgU3RhdGVtZW50RXhlY3V0b3IsXG4gIFZpZXdLaW5kLFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljQ2xpZW50QWRhcHRlciB9IGZyb20gXCIuL0ZhYnJpY0NsaWVudEFkYXB0ZXJcIjtcbmltcG9ydCB7XG4gIENvdWNoREJLZXlzLFxuICBDb3VjaERCT3BlcmF0b3IsXG4gIENvdWNoREJHcm91cE9wZXJhdG9yLFxuICBDb3VjaERCUXVlcnlMaW1pdCxcbiAgTWFuZ29RdWVyeSxcbiAgTWFuZ29PcGVyYXRvcixcbiAgTWFuZ29TZWxlY3RvcixcbiAgdHJhbnNsYXRlT3BlcmF0b3JzLFxuICBnZW5lcmF0ZURlc2lnbkRvY05hbWUsXG4gIGdlbmVyYXRlVmlld05hbWUsXG4gIGZpbmRWaWV3TWV0YWRhdGEsXG4gIENvdWNoREJWaWV3TWV0YWRhdGEsXG4gIFZpZXdSZXNwb25zZSxcbn0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuaW1wb3J0IHsgRmFicmljQ2xpZW50RmxhZ3MgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgdG9DYW1lbENhc2UgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7IERCS2V5cywgSW50ZXJuYWxFcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcblxudHlwZSBGYWJyaWNWaWV3RGVzY3JpcHRvciA9IHtcbiAgZGRvYzogc3RyaW5nO1xuICB2aWV3OiBzdHJpbmc7XG4gIG9wdGlvbnM6IFJlY29yZDxzdHJpbmcsIGFueT47XG59O1xuXG50eXBlIEZhYnJpY0FnZ3JlZ2F0ZUluZm8gPVxuICB8IHtcbiAgICAgIGtpbmQ6IFZpZXdLaW5kO1xuICAgICAgbWV0YTogQ291Y2hEQlZpZXdNZXRhZGF0YTtcbiAgICAgIGRlc2NyaXB0b3I6IEZhYnJpY1ZpZXdEZXNjcmlwdG9yO1xuICAgICAgY291bnREaXN0aW5jdD86IGJvb2xlYW47XG4gICAgfVxuICB8IHtcbiAgICAgIGtpbmQ6IFwiYXZnXCI7XG4gICAgICBhdHRyaWJ1dGU6IHN0cmluZztcbiAgICAgIHN1bURlc2NyaXB0b3I6IEZhYnJpY1ZpZXdEZXNjcmlwdG9yO1xuICAgICAgY291bnREZXNjcmlwdG9yOiBGYWJyaWNWaWV3RGVzY3JpcHRvcjtcbiAgICB9O1xuXG5leHBvcnQgY2xhc3MgRmFicmljQ2xpZW50U3RhdGVtZW50PE0gZXh0ZW5kcyBNb2RlbCwgUj4gZXh0ZW5kcyBTdGF0ZW1lbnQ8XG4gIE0sXG4gIEZhYnJpY0NsaWVudEFkYXB0ZXIsXG4gIFIsXG4gIE1hbmdvUXVlcnlcbj4ge1xuICBjb25zdHJ1Y3RvcihhZGFwdGVyOiBGYWJyaWNDbGllbnRBZGFwdGVyLCBvdmVycmlkZXM/OiBQYXJ0aWFsPEFkYXB0ZXJGbGFncz4pIHtcbiAgICBzdXBlcihhZGFwdGVyLCBvdmVycmlkZXMpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHNxdWFzaChcbiAgICBjdHg6IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+XG4gICk6IFByZXBhcmVkU3RhdGVtZW50PGFueT4gfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHNxdWFzaGVkOiBQcmVwYXJlZFN0YXRlbWVudDxNPiB8IHVuZGVmaW5lZCA9IHN1cGVyLnNxdWFzaChcbiAgICAgIGN0eCBhcyBuZXZlclxuICAgICk7XG4gICAgaWYgKCFzcXVhc2hlZCkgcmV0dXJuIHNxdWFzaGVkO1xuXG4gICAgY29uc3QgeyBtZXRob2QsIHBhcmFtcywgYXJncyB9ID0gc3F1YXNoZWQ7XG4gICAgY29uc3QgeyBkaXJlY3Rpb24sIGxpbWl0IH0gPSBwYXJhbXM7XG4gICAgc3dpdGNoIChtZXRob2QpIHtcbiAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkRfQlk6XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuTElTVF9CWTpcbiAgICAgICAgYXJncy5wdXNoKGRpcmVjdGlvbik7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuUEFHRV9CWTpcbiAgICAgICAgYXJncy5wdXNoKGRpcmVjdGlvbiwgbGltaXQpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkRfT05FX0JZOlxuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBVbnN1cHBvcnRlZCBtZXRob2QgJHttZXRob2R9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNxdWFzaGVkO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIGV4ZWN1dGVQcmVwYXJlZChcbiAgICAuLi5hcmd6OiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8Uj4ge1xuICAgIGNvbnN0IHJlcG8gPSBSZXBvc2l0b3J5LmZvck1vZGVsKHRoaXMuZnJvbVNlbGVjdG9yLCB0aGlzLmFkYXB0ZXIuYWxpYXMpO1xuICAgIGNvbnN0IHsgbWV0aG9kLCBhcmdzIH0gPSB0aGlzLnByZXBhcmVkIGFzIFByZXBhcmVkU3RhdGVtZW50PGFueT47XG4gICAgcmV0dXJuIHJlcG8uc3RhdGVtZW50KG1ldGhvZCwgLi4uYXJncywgLi4uYXJneik7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBwcmVwYXJlKFxuICAgIGN0eD86IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+XG4gICk6IFByb21pc2U8U3RhdGVtZW50RXhlY3V0b3I8TSwgUj4+IHtcbiAgICBjdHggPVxuICAgICAgY3R4IHx8XG4gICAgICAoYXdhaXQgdGhpcy5hZGFwdGVyLmNvbnRleHQoXG4gICAgICAgIFBlcnNpc3RlbmNlS2V5cy5RVUVSWSxcbiAgICAgICAgdGhpcy5vdmVycmlkZXMgfHwge30sXG4gICAgICAgIHRoaXMuZnJvbVNlbGVjdG9yXG4gICAgICApKTtcblxuICAgIGlmIChcbiAgICAgIHRoaXMuaXNTaW1wbGVRdWVyeSgpICYmXG4gICAgICAoY3R4IGFzIENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+KS5nZXQoXCJmb3JjZVByZXBhcmVTaW1wbGVRdWVyaWVzXCIpXG4gICAgKSB7XG4gICAgICBjb25zdCBzcXVhc2hlZCA9IHRoaXMuc3F1YXNoKGN0eCBhcyBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPik7XG4gICAgICBpZiAoc3F1YXNoZWQpIHtcbiAgICAgICAgdGhpcy5wcmVwYXJlZCA9IHNxdWFzaGVkO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgYXJnczogKHN0cmluZyB8IG51bWJlcilbXSA9IFtdO1xuICAgIGNvbnN0IHBhcmFtczogYW55ID0ge30gYXMgYW55O1xuXG4gICAgY29uc3QgcHJlcGFyZWQ6IFByZXBhcmVkU3RhdGVtZW50PGFueT4gPSB7XG4gICAgICBjbGFzczogdGhpcy5mcm9tU2VsZWN0b3IsXG4gICAgICBhcmdzLFxuICAgICAgcGFyYW1zLFxuICAgIH0gYXMgYW55O1xuXG4gICAgY29uc3QgbWV0aG9kOiBzdHJpbmdbXSA9IFtRdWVyeUNsYXVzZS5GSU5EX0JZXTtcblxuICAgIGlmICh0aGlzLndoZXJlQ29uZGl0aW9uKSB7XG4gICAgICBjb25zdCBwYXJzZWQgPSB0aGlzLnByZXBhcmVDb25kaXRpb24odGhpcy53aGVyZUNvbmRpdGlvbiwgY3R4IGFzIG5ldmVyKTtcbiAgICAgIG1ldGhvZC5wdXNoKHBhcnNlZC5tZXRob2QpO1xuICAgICAgaWYgKHBhcnNlZC5hcmdzICYmIHBhcnNlZC5hcmdzLmxlbmd0aClcbiAgICAgICAgYXJncy5wdXNoKC4uLihwYXJzZWQuYXJncyBhcyAoc3RyaW5nIHwgbnVtYmVyKVtdKSk7XG4gICAgfVxuICAgIGlmICh0aGlzLnNlbGVjdFNlbGVjdG9yKVxuICAgICAgbWV0aG9kLnB1c2goXG4gICAgICAgIFF1ZXJ5Q2xhdXNlLlNFTEVDVCxcbiAgICAgICAgdGhpcy5zZWxlY3RTZWxlY3Rvci5qb2luKGAgJHtRdWVyeUNsYXVzZS5BTkQudG9Mb3dlckNhc2UoKX0gYClcbiAgICAgICk7XG4gICAgaWYgKHRoaXMub3JkZXJCeVNlbGVjdG9ycz8ubGVuZ3RoKSB7XG4gICAgICBtZXRob2QucHVzaChRdWVyeUNsYXVzZS5PUkRFUl9CWSwgdGhpcy5vcmRlckJ5U2VsZWN0b3JzWzBdWzBdIGFzIHN0cmluZyk7XG4gICAgICBhcmdzLnB1c2godGhpcy5vcmRlckJ5U2VsZWN0b3JzWzBdWzFdIGFzIGFueSk7XG4gICAgfVxuICAgIHByZXBhcmVkLm1ldGhvZCA9IHRvQ2FtZWxDYXNlKG1ldGhvZC5qb2luKFwiIFwiKSk7XG4gICAgcHJlcGFyZWQucGFyYW1zID0gcGFyYW1zO1xuICAgIHRoaXMucHJlcGFyZWQgPSBwcmVwYXJlZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJvY2Vzc2VzIGEgcmVjb3JkIGZyb20gQ291Y2hEQi9GYWJyaWNcbiAgICogQHN1bW1hcnkgRXh0cmFjdHMgdGhlIElEIGZyb20gYSBDb3VjaERCIGRvY3VtZW50IGFuZCByZXZlcnRzIGl0IHRvIGEgbW9kZWwgaW5zdGFuY2VcbiAgICovXG4gIHByb3RlY3RlZCBwcm9jZXNzUmVjb3JkKFxuICAgIHI6IGFueSxcbiAgICBwa0F0dHI6IGtleW9mIE0sXG4gICAgc2VxdWVuY2VUeXBlOiBcIk51bWJlclwiIHwgXCJCaWdJbnRcIiB8IHVuZGVmaW5lZCxcbiAgICBjdHg6IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+XG4gICkge1xuICAgIGlmIChyW0NvdWNoREJLZXlzLklEXSkge1xuICAgICAgY29uc3QgWywgLi4ua2V5QXJnc10gPSByW0NvdWNoREJLZXlzLklEXS5zcGxpdChDb3VjaERCS2V5cy5TRVBBUkFUT1IpO1xuICAgICAgY29uc3QgaWQgPSBrZXlBcmdzLmpvaW4oXCJfXCIpO1xuICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci5yZXZlcnQoXG4gICAgICAgIHIsXG4gICAgICAgIHRoaXMuZnJvbVNlbGVjdG9yLFxuICAgICAgICBTZXF1ZW5jZS5wYXJzZVZhbHVlKHNlcXVlbmNlVHlwZSwgaWQpLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIGN0eFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHI7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgcmF3IE1hbmdvIHF1ZXJ5XG4gICAqIEBzdW1tYXJ5IFNlbmRzIGEgcmF3IE1hbmdvIHF1ZXJ5IHRvIEZhYnJpYyBhbmQgcHJvY2Vzc2VzIHRoZSByZXN1bHRzXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyByYXc8Uj4ocmF3SW5wdXQ6IE1hbmdvUXVlcnksIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxSPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmF3KTtcbiAgICBjb25zdCBhZ2dyZWdhdG9yID0gKHJhd0lucHV0IGFzIGFueSk/LmFnZ3JlZ2F0ZUluZm87XG4gICAgaWYgKChyYXdJbnB1dCBhcyBhbnkpPy5hZ2dyZWdhdGUgJiYgYWdncmVnYXRvcikge1xuICAgICAgcmV0dXJuIHRoaXMuZXhlY3V0ZUFnZ3JlZ2F0ZTxSPihhZ2dyZWdhdG9yLCBjdHgpO1xuICAgIH1cbiAgICBjb25zdCByZXN1bHRzOiBhbnlbXSA9IGF3YWl0IHRoaXMuYWRhcHRlci5yYXcoXG4gICAgICByYXdJbnB1dCxcbiAgICAgIHRydWUsXG4gICAgICB0aGlzLmZyb21TZWxlY3RvcixcbiAgICAgIGN0eFxuICAgICk7XG5cbiAgICBjb25zdCBwa0F0dHIgPSBNb2RlbC5wayh0aGlzLmZyb21TZWxlY3Rvcik7XG4gICAgY29uc3QgdHlwZSA9IE1ldGFkYXRhLmdldChcbiAgICAgIHRoaXMuZnJvbVNlbGVjdG9yLFxuICAgICAgTWV0YWRhdGEua2V5KERCS2V5cy5JRCwgcGtBdHRyIGFzIHN0cmluZylcbiAgICApPy50eXBlO1xuXG4gICAgaWYgKCF0aGlzLnNlbGVjdFNlbGVjdG9yKVxuICAgICAgcmV0dXJuIHJlc3VsdHMubWFwKChyKSA9PiB0aGlzLnByb2Nlc3NSZWNvcmQociwgcGtBdHRyLCB0eXBlLCBjdHgpKSBhcyBSO1xuICAgIHJldHVybiByZXN1bHRzIGFzIFI7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEJ1aWxkcyBhIENvdWNoREIgTWFuZ28gcXVlcnkgZnJvbSB0aGUgc3RhdGVtZW50XG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIHRoZSBzdGF0ZW1lbnQncyBjb25kaXRpb25zLCBzZWxlY3RvcnMsIGFuZCBvcHRpb25zIGludG8gYSBDb3VjaERCIE1hbmdvIHF1ZXJ5XG4gICAqL1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYnVpbGQoKTogTWFuZ29RdWVyeSB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuYnVpbGQpO1xuICAgIGNvbnN0IGFnZ3JlZ2F0ZVF1ZXJ5ID0gdGhpcy5idWlsZEFnZ3JlZ2F0ZVF1ZXJ5KCk7XG4gICAgaWYgKGFnZ3JlZ2F0ZVF1ZXJ5KSByZXR1cm4gYWdncmVnYXRlUXVlcnk7XG4gICAgY29uc3Qgc2VsZWN0b3JzOiBNYW5nb1NlbGVjdG9yID0ge307XG4gICAgc2VsZWN0b3JzW0NvdWNoREJLZXlzLlRBQkxFXSA9IHt9O1xuICAgIHNlbGVjdG9yc1tDb3VjaERCS2V5cy5UQUJMRV0gPSBNb2RlbC50YWJsZU5hbWUodGhpcy5mcm9tU2VsZWN0b3IpO1xuICAgIGNvbnN0IHF1ZXJ5OiBNYW5nb1F1ZXJ5ID0geyBzZWxlY3Rvcjogc2VsZWN0b3JzIH07XG4gICAgaWYgKHRoaXMuc2VsZWN0U2VsZWN0b3IpIHF1ZXJ5LmZpZWxkcyA9IHRoaXMuc2VsZWN0U2VsZWN0b3IgYXMgc3RyaW5nW107XG5cbiAgICBpZiAodGhpcy53aGVyZUNvbmRpdGlvbikge1xuICAgICAgY29uc3QgY29uZGl0aW9uOiBNYW5nb1NlbGVjdG9yID0gdGhpcy5wYXJzZUNvbmRpdGlvbihcbiAgICAgICAgQ29uZGl0aW9uLmFuZChcbiAgICAgICAgICB0aGlzLndoZXJlQ29uZGl0aW9uLFxuICAgICAgICAgIENvbmRpdGlvbi5hdHRyaWJ1dGU8TT4oQ291Y2hEQktleXMuVEFCTEUgYXMga2V5b2YgTSkuZXEoXG4gICAgICAgICAgICBxdWVyeS5zZWxlY3RvcltDb3VjaERCS2V5cy5UQUJMRV1cbiAgICAgICAgICApXG4gICAgICAgIClcbiAgICAgICkuc2VsZWN0b3I7XG4gICAgICBjb25zdCBzZWxlY3RvcktleXMgPSBPYmplY3Qua2V5cyhjb25kaXRpb24pIGFzIE1hbmdvT3BlcmF0b3JbXTtcbiAgICAgIGlmIChcbiAgICAgICAgc2VsZWN0b3JLZXlzLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICBPYmplY3QudmFsdWVzKENvdWNoREJHcm91cE9wZXJhdG9yKS5pbmRleE9mKHNlbGVjdG9yS2V5c1swXSkgIT09IC0xXG4gICAgICApXG4gICAgICAgIHN3aXRjaCAoc2VsZWN0b3JLZXlzWzBdKSB7XG4gICAgICAgICAgY2FzZSBDb3VjaERCR3JvdXBPcGVyYXRvci5BTkQ6XG4gICAgICAgICAgICBjb25kaXRpb25bQ291Y2hEQkdyb3VwT3BlcmF0b3IuQU5EXSA9IFtcbiAgICAgICAgICAgICAgLi4uT2JqZWN0LnZhbHVlcyhcbiAgICAgICAgICAgICAgICBjb25kaXRpb25bQ291Y2hEQkdyb3VwT3BlcmF0b3IuQU5EXSBhcyBNYW5nb1NlbGVjdG9yXG4gICAgICAgICAgICAgICkucmVkdWNlKChhY2N1bTogTWFuZ29TZWxlY3RvcltdLCB2YWw6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyh2YWwpO1xuICAgICAgICAgICAgICAgIGlmIChrZXlzLmxlbmd0aCAhPT0gMSlcbiAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgXCJUb28gbWFueSBrZXlzIGluIHF1ZXJ5IHNlbGVjdG9yLiBzaG91bGQgYmUgb25lXCJcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgY29uc3QgayA9IGtleXNbMF07XG4gICAgICAgICAgICAgICAgaWYgKGsgPT09IENvdWNoREJHcm91cE9wZXJhdG9yLkFORClcbiAgICAgICAgICAgICAgICAgIGFjY3VtLnB1c2goLi4uKHZhbFtrXSBhcyBhbnlbXSkpO1xuICAgICAgICAgICAgICAgIGVsc2UgYWNjdW0ucHVzaCh2YWwpO1xuICAgICAgICAgICAgICAgIHJldHVybiBhY2N1bTtcbiAgICAgICAgICAgICAgfSwgW10pLFxuICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIHF1ZXJ5LnNlbGVjdG9yID0gY29uZGl0aW9uO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgY2FzZSBDb3VjaERCR3JvdXBPcGVyYXRvci5PUjoge1xuICAgICAgICAgICAgY29uc3QgczogUmVjb3JkPGFueSwgYW55PiA9IHt9O1xuICAgICAgICAgICAgc1tDb3VjaERCR3JvdXBPcGVyYXRvci5BTkRdID0gW1xuICAgICAgICAgICAgICBjb25kaXRpb24sXG4gICAgICAgICAgICAgIC4uLk9iamVjdC5lbnRyaWVzKHF1ZXJ5LnNlbGVjdG9yKS5tYXAoKFtrZXksIHZhbF0pID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQ6IFJlY29yZDxhbnksIGFueT4gPSB7fTtcbiAgICAgICAgICAgICAgICByZXN1bHRba2V5XSA9IHZhbDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIF07XG4gICAgICAgICAgICBxdWVyeS5zZWxlY3RvciA9IHM7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoaXMgc2hvdWxkIGJlIGltcG9zc2libGVcIik7XG4gICAgICAgIH1cbiAgICAgIGVsc2Uge1xuICAgICAgICBPYmplY3QuZW50cmllcyhjb25kaXRpb24pLmZvckVhY2goKFtrZXksIHZhbF0pID0+IHtcbiAgICAgICAgICBpZiAocXVlcnkuc2VsZWN0b3Jba2V5XSlcbiAgICAgICAgICAgIGxvZy53YXJuKFxuICAgICAgICAgICAgICBgQSAke2tleX0gcXVlcnkgcGFyYW0gaXMgYWJvdXQgdG8gYmUgb3ZlcnJpZGRlbjogJHtxdWVyeS5zZWxlY3RvcltrZXldfSBieSAke3ZhbH1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgIHF1ZXJ5LnNlbGVjdG9yW2tleV0gPSB2YWw7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh0aGlzLm9yZGVyQnlTZWxlY3RvcnM/Lmxlbmd0aCkge1xuICAgICAgcXVlcnkuc29ydCA9IHF1ZXJ5LnNvcnQgfHwgW107XG4gICAgICBxdWVyeS5zZWxlY3RvciA9IHF1ZXJ5LnNlbGVjdG9yIHx8ICh7fSBhcyBNYW5nb1NlbGVjdG9yKTtcbiAgICAgIGZvciAoY29uc3QgW3NlbGVjdG9yS2V5LCBkaXJlY3Rpb25dIG9mIHRoaXMub3JkZXJCeVNlbGVjdG9ycykge1xuICAgICAgICBjb25zdCBzZWxlY3RvciA9IHNlbGVjdG9yS2V5IGFzIHN0cmluZztcbiAgICAgICAgY29uc3QgcmVjOiBSZWNvcmQ8c3RyaW5nLCBPcmRlckRpcmVjdGlvbj4gPSB7fTtcbiAgICAgICAgcmVjW3NlbGVjdG9yXSA9IGRpcmVjdGlvbiBhcyBPcmRlckRpcmVjdGlvbjtcbiAgICAgICAgKHF1ZXJ5LnNvcnQgYXMgUmVjb3JkPHN0cmluZywgT3JkZXJEaXJlY3Rpb24+W10pLnB1c2gocmVjKTtcbiAgICAgICAgaWYgKCFxdWVyeS5zZWxlY3RvcltzZWxlY3Rvcl0pIHtcbiAgICAgICAgICBxdWVyeS5zZWxlY3RvcltzZWxlY3Rvcl0gPSB7fSBhcyBNYW5nb1NlbGVjdG9yO1xuICAgICAgICAgIChxdWVyeS5zZWxlY3RvcltzZWxlY3Rvcl0gYXMgTWFuZ29TZWxlY3RvcilbQ291Y2hEQk9wZXJhdG9yLkJJR0dFUl0gPVxuICAgICAgICAgICAgbnVsbDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh0aGlzLmxpbWl0U2VsZWN0b3IpIHtcbiAgICAgIHF1ZXJ5LmxpbWl0ID0gdGhpcy5saW1pdFNlbGVjdG9yO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cud2FybihcbiAgICAgICAgYE5vIGxpbWl0IHNlbGVjdG9yIGRlZmluZWQuIFVzaW5nIGRlZmF1bHQgY291Y2hkYiBsaW1pdCBvZiAke0NvdWNoREJRdWVyeUxpbWl0fWBcbiAgICAgICk7XG4gICAgICBxdWVyeS5saW1pdCA9IENvdWNoREJRdWVyeUxpbWl0O1xuICAgIH1cblxuICAgIGlmICh0aGlzLm9mZnNldFNlbGVjdG9yKSBxdWVyeS5za2lwID0gdGhpcy5vZmZzZXRTZWxlY3RvcjtcblxuICAgIHJldHVybiBxdWVyeTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUGFyc2VzIGEgY29uZGl0aW9uIGludG8gYSBDb3VjaERCIE1hbmdvIHF1ZXJ5IHNlbGVjdG9yXG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIGEgQ29uZGl0aW9uIG9iamVjdCBpbnRvIGEgQ291Y2hEQiBNYW5nbyBxdWVyeSBzZWxlY3RvciBzdHJ1Y3R1cmVcbiAgICovXG4gIHByb3RlY3RlZCBvdmVycmlkZSBwYXJzZUNvbmRpdGlvbihjb25kaXRpb246IENvbmRpdGlvbjxNPik6IE1hbmdvUXVlcnkge1xuICAgIGZ1bmN0aW9uIG1lcmdlKFxuICAgICAgb3A6IE1hbmdvT3BlcmF0b3IsXG4gICAgICBvYmoxOiBNYW5nb1NlbGVjdG9yLFxuICAgICAgb2JqMjogTWFuZ29TZWxlY3RvclxuICAgICk6IE1hbmdvUXVlcnkge1xuICAgICAgY29uc3QgcmVzdWx0OiBNYW5nb1F1ZXJ5ID0geyBzZWxlY3Rvcjoge30gYXMgTWFuZ29TZWxlY3RvciB9O1xuICAgICAgcmVzdWx0LnNlbGVjdG9yW29wXSA9IFtvYmoxLCBvYmoyXTtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgY29uc3QgeyBhdHRyMSwgb3BlcmF0b3IsIGNvbXBhcmlzb24gfSA9IGNvbmRpdGlvbiBhcyB1bmtub3duIGFzIHtcbiAgICAgIGF0dHIxOiBzdHJpbmcgfCBDb25kaXRpb248TT47XG4gICAgICBvcGVyYXRvcjogT3BlcmF0b3IgfCBHcm91cE9wZXJhdG9yO1xuICAgICAgY29tcGFyaXNvbjogYW55O1xuICAgIH07XG5cbiAgICBpZiAob3BlcmF0b3IgPT09IE9wZXJhdG9yLkJFVFdFRU4pIHtcbiAgICAgIGNvbnN0IGF0dHIgPSBhdHRyMSBhcyBzdHJpbmc7XG4gICAgICBpZiAoIUFycmF5LmlzQXJyYXkoY29tcGFyaXNvbikgfHwgY29tcGFyaXNvbi5sZW5ndGggIT09IDIpXG4gICAgICAgIHRocm93IG5ldyBRdWVyeUVycm9yKFwiQkVUV0VFTiBvcGVyYXRvciByZXF1aXJlcyBbbWluLCBtYXhdIGNvbXBhcmlzb25cIik7XG4gICAgICBjb25zdCBbbWluLCBtYXhdID0gY29tcGFyaXNvbjtcbiAgICAgIGNvbnN0IG9wQmV0d2VlbjogTWFuZ29TZWxlY3RvciA9IHt9IGFzIE1hbmdvU2VsZWN0b3I7XG4gICAgICBvcEJldHdlZW5bYXR0cl0gPSB7fSBhcyBNYW5nb1NlbGVjdG9yO1xuICAgICAgKG9wQmV0d2VlblthdHRyXSBhcyBNYW5nb1NlbGVjdG9yKVtcbiAgICAgICAgdHJhbnNsYXRlT3BlcmF0b3JzKE9wZXJhdG9yLkJJR0dFUl9FUSlcbiAgICAgIF0gPSBtaW47XG4gICAgICAob3BCZXR3ZWVuW2F0dHJdIGFzIE1hbmdvU2VsZWN0b3IpW1xuICAgICAgICB0cmFuc2xhdGVPcGVyYXRvcnMoT3BlcmF0b3IuU01BTExFUl9FUSlcbiAgICAgIF0gPSBtYXg7XG4gICAgICByZXR1cm4geyBzZWxlY3Rvcjogb3BCZXR3ZWVuIH07XG4gICAgfVxuXG4gICAgbGV0IG9wOiBNYW5nb1NlbGVjdG9yID0ge30gYXMgTWFuZ29TZWxlY3RvcjtcbiAgICBpZiAoXG4gICAgICBbR3JvdXBPcGVyYXRvci5BTkQsIEdyb3VwT3BlcmF0b3IuT1IsIE9wZXJhdG9yLk5PVF0uaW5kZXhPZihcbiAgICAgICAgb3BlcmF0b3IgYXMgR3JvdXBPcGVyYXRvclxuICAgICAgKSA9PT0gLTFcbiAgICApIHtcbiAgICAgIG9wW2F0dHIxIGFzIHN0cmluZ10gPSB7fSBhcyBNYW5nb1NlbGVjdG9yO1xuICAgICAgKG9wW2F0dHIxIGFzIHN0cmluZ10gYXMgTWFuZ29TZWxlY3RvcilbdHJhbnNsYXRlT3BlcmF0b3JzKG9wZXJhdG9yKV0gPVxuICAgICAgICBjb21wYXJpc29uO1xuICAgIH0gZWxzZSBpZiAob3BlcmF0b3IgPT09IE9wZXJhdG9yLk5PVCkge1xuICAgICAgb3AgPSB0aGlzLnBhcnNlQ29uZGl0aW9uKGF0dHIxIGFzIENvbmRpdGlvbjxNPikuc2VsZWN0b3IgYXMgTWFuZ29TZWxlY3RvcjtcbiAgICAgIG9wW3RyYW5zbGF0ZU9wZXJhdG9ycyhPcGVyYXRvci5OT1QpXSA9IHt9IGFzIE1hbmdvU2VsZWN0b3I7XG4gICAgICAob3BbdHJhbnNsYXRlT3BlcmF0b3JzKE9wZXJhdG9yLk5PVCldIGFzIE1hbmdvU2VsZWN0b3IpW1xuICAgICAgICAoYXR0cjEgYXMgdW5rbm93biBhcyB7IGF0dHIxOiBzdHJpbmcgfSkuYXR0cjFcbiAgICAgIF0gPSBjb21wYXJpc29uO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBvcDE6IGFueSA9IHRoaXMucGFyc2VDb25kaXRpb24oYXR0cjEgYXMgQ29uZGl0aW9uPE0+KS5zZWxlY3RvcjtcbiAgICAgIGNvbnN0IG9wMjogYW55ID0gdGhpcy5wYXJzZUNvbmRpdGlvbihjb21wYXJpc29uIGFzIENvbmRpdGlvbjxNPikuc2VsZWN0b3I7XG4gICAgICBvcCA9IG1lcmdlKHRyYW5zbGF0ZU9wZXJhdG9ycyhvcGVyYXRvciksIG9wMSwgb3AyKS5zZWxlY3RvcjtcbiAgICB9XG5cbiAgICByZXR1cm4geyBzZWxlY3Rvcjogb3AgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQnVpbGRzIGFuIGFnZ3JlZ2F0ZSBxdWVyeSBpZiBhZ2dyZWdhdGlvbiBpcyByZXF1ZXN0ZWRcbiAgICogQHN1bW1hcnkgQ2hlY2tzIGZvciBhZ2dyZWdhdGUgb3BlcmF0aW9ucyBhbmQgcmV0dXJucyBhIHNwZWNpYWwgTWFuZ29RdWVyeSBmb3IgdGhlbVxuICAgKi9cbiAgcHJpdmF0ZSBidWlsZEFnZ3JlZ2F0ZVF1ZXJ5KCk6IE1hbmdvUXVlcnkgfCB1bmRlZmluZWQge1xuICAgIGlmICghdGhpcy5mcm9tU2VsZWN0b3IpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgaWYgKHRoaXMuYXZnU2VsZWN0b3IpIHtcbiAgICAgIGNvbnN0IGF0dHJpYnV0ZSA9IFN0cmluZyh0aGlzLmF2Z1NlbGVjdG9yKTtcbiAgICAgIGNvbnN0IHN1bUluZm8gPSB0aGlzLmNyZWF0ZUFnZ3JlZ2F0ZURlc2NyaXB0b3IoXCJzdW1cIiwgYXR0cmlidXRlKTtcbiAgICAgIGNvbnN0IGNvdW50SW5mbyA9IHRoaXMuY3JlYXRlQWdncmVnYXRlRGVzY3JpcHRvcihcImNvdW50XCIsIGF0dHJpYnV0ZSk7XG4gICAgICBpZiAoIXN1bUluZm8gfHwgIWNvdW50SW5mbylcbiAgICAgICAgdGhyb3cgbmV3IFF1ZXJ5RXJyb3IoXG4gICAgICAgICAgYEF2ZyBvcGVyYXRpb24gcmVxdWlyZXMgc3VtIGFuZCBjb3VudCB2aWV3cyBmb3IgYXR0cmlidXRlICR7YXR0cmlidXRlfWBcbiAgICAgICAgKTtcbiAgICAgIHJldHVybiB0aGlzLmNyZWF0ZUFnZ3JlZ2F0ZVF1ZXJ5KHtcbiAgICAgICAga2luZDogXCJhdmdcIixcbiAgICAgICAgYXR0cmlidXRlLFxuICAgICAgICBzdW1EZXNjcmlwdG9yOiBzdW1JbmZvLmRlc2NyaXB0b3IsXG4gICAgICAgIGNvdW50RGVzY3JpcHRvcjogY291bnRJbmZvLmRlc2NyaXB0b3IsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHRoaXMuY291bnREaXN0aW5jdFNlbGVjdG9yICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICBjb25zdCBhdHRyaWJ1dGUgPVxuICAgICAgICB0aGlzLmNvdW50RGlzdGluY3RTZWxlY3RvciA9PSBudWxsXG4gICAgICAgICAgPyB1bmRlZmluZWRcbiAgICAgICAgICA6IFN0cmluZyh0aGlzLmNvdW50RGlzdGluY3RTZWxlY3Rvcik7XG4gICAgICBjb25zdCBpbmZvID0gdGhpcy5jcmVhdGVBZ2dyZWdhdGVEZXNjcmlwdG9yKFwiZGlzdGluY3RcIiwgYXR0cmlidXRlKTtcbiAgICAgIGlmIChpbmZvKSB7XG4gICAgICAgIGluZm8uY291bnREaXN0aW5jdCA9IHRydWU7XG4gICAgICAgIHJldHVybiB0aGlzLmNyZWF0ZUFnZ3JlZ2F0ZVF1ZXJ5KGluZm8pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGFnZ3JlZ2F0b3JVc2VkID1cbiAgICAgIHR5cGVvZiB0aGlzLmNvdW50U2VsZWN0b3IgIT09IFwidW5kZWZpbmVkXCIgfHxcbiAgICAgIHR5cGVvZiB0aGlzLmNvdW50RGlzdGluY3RTZWxlY3RvciAhPT0gXCJ1bmRlZmluZWRcIiB8fFxuICAgICAgISF0aGlzLm1pblNlbGVjdG9yIHx8XG4gICAgICAhIXRoaXMubWF4U2VsZWN0b3IgfHxcbiAgICAgICEhdGhpcy5zdW1TZWxlY3RvciB8fFxuICAgICAgISF0aGlzLmRpc3RpbmN0U2VsZWN0b3I7XG5cbiAgICBjb25zdCBhZ2dyZWdhdG9yQ2hlY2tzOiBBcnJheTxbVmlld0tpbmQsIFNlbGVjdFNlbGVjdG9yPE0+IHwgdW5kZWZpbmVkXT4gPSBbXG4gICAgICBbXG4gICAgICAgIFwiY291bnRcIixcbiAgICAgICAgKHRoaXMuY291bnRTZWxlY3RvciA/PyB1bmRlZmluZWQpIGFzIFNlbGVjdFNlbGVjdG9yPE0+IHwgdW5kZWZpbmVkLFxuICAgICAgXSxcbiAgICAgIFtcIm1heFwiLCB0aGlzLm1heFNlbGVjdG9yXSxcbiAgICAgIFtcIm1pblwiLCB0aGlzLm1pblNlbGVjdG9yXSxcbiAgICAgIFtcInN1bVwiLCB0aGlzLnN1bVNlbGVjdG9yXSxcbiAgICAgIFtcImRpc3RpbmN0XCIsIHRoaXMuZGlzdGluY3RTZWxlY3Rvcl0sXG4gICAgXTtcblxuICAgIGZvciAoY29uc3QgW2tpbmQsIHNlbGVjdG9yXSBvZiBhZ2dyZWdhdG9yQ2hlY2tzKSB7XG4gICAgICBjb25zdCBhdHRyaWJ1dGUgPSBzZWxlY3RvciA/IFN0cmluZyhzZWxlY3RvcikgOiB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBpbmZvID0gdGhpcy5jcmVhdGVBZ2dyZWdhdGVEZXNjcmlwdG9yKGtpbmQsIGF0dHJpYnV0ZSk7XG4gICAgICBpZiAoaW5mbykgcmV0dXJuIHRoaXMuY3JlYXRlQWdncmVnYXRlUXVlcnkoaW5mbyk7XG4gICAgfVxuXG4gICAgaWYgKGFnZ3JlZ2F0b3JVc2VkKSB7XG4gICAgICB0aHJvdyBuZXcgUXVlcnlFcnJvcihcbiAgICAgICAgYE5vIENvdWNoREIgdmlldyBtZXRhZGF0YSBmb3VuZCBmb3IgdGFibGUgJHtNb2RlbC50YWJsZU5hbWUoXG4gICAgICAgICAgdGhpcy5mcm9tU2VsZWN0b3JcbiAgICAgICAgKX0gYWdncmVnYXRvcmBcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYW4gYWdncmVnYXRlIGRlc2NyaXB0b3IgZm9yIGEgdmlldy1iYXNlZCBhZ2dyZWdhdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVBZ2dyZWdhdGVEZXNjcmlwdG9yKFxuICAgIGtpbmQ6IFZpZXdLaW5kLFxuICAgIGF0dHJpYnV0ZT86IHN0cmluZ1xuICApOiBFeHRyYWN0PEZhYnJpY0FnZ3JlZ2F0ZUluZm8sIHsga2luZDogVmlld0tpbmQgfT4gfCB1bmRlZmluZWQge1xuICAgIGlmICghdGhpcy5mcm9tU2VsZWN0b3IpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgY29uc3QgbWV0YXMgPSBmaW5kVmlld01ldGFkYXRhKHRoaXMuZnJvbVNlbGVjdG9yLCBraW5kLCBhdHRyaWJ1dGUpO1xuICAgIGlmICghbWV0YXMubGVuZ3RoKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGNvbnN0IG1ldGEgPSBtZXRhc1swXTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUodGhpcy5mcm9tU2VsZWN0b3IpO1xuICAgIGNvbnN0IHZpZXdOYW1lID0gZ2VuZXJhdGVWaWV3TmFtZSh0YWJsZU5hbWUsIG1ldGEuYXR0cmlidXRlLCBraW5kLCBtZXRhKTtcbiAgICBjb25zdCBkZG9jID0gbWV0YS5kZG9jIHx8IGdlbmVyYXRlRGVzaWduRG9jTmFtZSh0YWJsZU5hbWUsIHZpZXdOYW1lKTtcbiAgICBjb25zdCBvcHRpb25zOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge1xuICAgICAgcmVkdWNlOiBtZXRhLnJlZHVjZSAhPT0gdW5kZWZpbmVkID8gdHJ1ZSA6ICFtZXRhLnJldHVybkRvY3MsXG4gICAgfTtcbiAgICBpZiAoa2luZCA9PT0gXCJkaXN0aW5jdFwiIHx8IGtpbmQgPT09IFwiZ3JvdXBCeVwiKSBvcHRpb25zLmdyb3VwID0gdHJ1ZTtcbiAgICByZXR1cm4ge1xuICAgICAga2luZCxcbiAgICAgIG1ldGEsXG4gICAgICBkZXNjcmlwdG9yOiB7XG4gICAgICAgIGRkb2MsXG4gICAgICAgIHZpZXc6IHZpZXdOYW1lLFxuICAgICAgICBvcHRpb25zLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIHRoZSBzcGVjaWFsIGFnZ3JlZ2F0ZSBNYW5nb1F1ZXJ5IG1hcmtlclxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVBZ2dyZWdhdGVRdWVyeShcbiAgICBpbmZvOiBGYWJyaWNBZ2dyZWdhdGVJbmZvXG4gICk6IE1hbmdvUXVlcnkgJiB7IGFnZ3JlZ2F0ZTogdHJ1ZTsgYWdncmVnYXRlSW5mbzogRmFicmljQWdncmVnYXRlSW5mbyB9IHtcbiAgICByZXR1cm4ge1xuICAgICAgc2VsZWN0b3I6IHt9LFxuICAgICAgYWdncmVnYXRlOiB0cnVlLFxuICAgICAgYWdncmVnYXRlSW5mbzogaW5mbyxcbiAgICB9IGFzIE1hbmdvUXVlcnkgJiB7IGFnZ3JlZ2F0ZTogdHJ1ZTsgYWdncmVnYXRlSW5mbzogRmFicmljQWdncmVnYXRlSW5mbyB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIHRoZSBhZGFwdGVyIGNhc3QgdG8gRmFicmljQ2xpZW50QWRhcHRlciBmb3IgdmlldyBhY2Nlc3NcbiAgICovXG4gIHByaXZhdGUgZ2V0RmFicmljQWRhcHRlcigpOiBGYWJyaWNDbGllbnRBZGFwdGVyIHtcbiAgICByZXR1cm4gdGhpcy5hZGFwdGVyIGFzIEZhYnJpY0NsaWVudEFkYXB0ZXI7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGFuIGFnZ3JlZ2F0ZSBxdWVyeSB2aWEgYWRhcHRlcidzIHZpZXcgbWV0aG9kXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGV4ZWN1dGVBZ2dyZWdhdGU8Uj4oXG4gICAgaW5mbzogRmFicmljQWdncmVnYXRlSW5mbyxcbiAgICBjdHg6IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+XG4gICk6IFByb21pc2U8Uj4ge1xuICAgIGlmICghdGhpcy5pc1ZpZXdBZ2dyZWdhdGUoaW5mbykpIHtcbiAgICAgIHJldHVybiB0aGlzLmhhbmRsZUF2ZXJhZ2U8Uj4oaW5mbywgY3R4KTtcbiAgICB9XG4gICAgY29uc3QgZmFicmljQWRhcHRlciA9IHRoaXMuZ2V0RmFicmljQWRhcHRlcigpO1xuICAgIGNvbnN0IHZpZXdJbmZvID0gaW5mbyBhcyBFeHRyYWN0PEZhYnJpY0FnZ3JlZ2F0ZUluZm8sIHsga2luZDogVmlld0tpbmQgfT47XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmYWJyaWNBZGFwdGVyLnZpZXc8Vmlld1Jlc3BvbnNlPihcbiAgICAgIHZpZXdJbmZvLmRlc2NyaXB0b3IuZGRvYyxcbiAgICAgIHZpZXdJbmZvLmRlc2NyaXB0b3IudmlldyxcbiAgICAgIHZpZXdJbmZvLmRlc2NyaXB0b3Iub3B0aW9ucyxcbiAgICAgIGN0eFxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMucHJvY2Vzc1ZpZXdSZXNwb25zZTxSPihpbmZvLCByZXNwb25zZSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEhhbmRsZXMgYXZlcmFnZSBjYWxjdWxhdGlvbiBmcm9tIHN1bSBhbmQgY291bnQgdmlld3NcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgaGFuZGxlQXZlcmFnZTxSPihcbiAgICBpbmZvOiBGYWJyaWNBZ2dyZWdhdGVJbmZvLFxuICAgIGN0eDogQ29udGV4dDxGYWJyaWNDbGllbnRGbGFncz5cbiAgKTogUHJvbWlzZTxSPiB7XG4gICAgaWYgKGluZm8ua2luZCAhPT0gXCJhdmdcIilcbiAgICAgIHRocm93IG5ldyBRdWVyeUVycm9yKFwiQXZlcmFnZSBkZXNjcmlwdG9yIGlzIG5vdCB2YWxpZFwiKTtcbiAgICBjb25zdCBmYWJyaWNBZGFwdGVyID0gdGhpcy5nZXRGYWJyaWNBZGFwdGVyKCk7XG4gICAgY29uc3QgW3N1bURlc2MsIGNvdW50RGVzY10gPSBbaW5mby5zdW1EZXNjcmlwdG9yLCBpbmZvLmNvdW50RGVzY3JpcHRvcl07XG4gICAgY29uc3QgW3N1bVJlc3BvbnNlLCBjb3VudFJlc3BvbnNlXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIGZhYnJpY0FkYXB0ZXIudmlldzxWaWV3UmVzcG9uc2U+KFxuICAgICAgICBzdW1EZXNjLmRkb2MsXG4gICAgICAgIHN1bURlc2MudmlldyxcbiAgICAgICAgc3VtRGVzYy5vcHRpb25zLFxuICAgICAgICBjdHhcbiAgICAgICksXG4gICAgICBmYWJyaWNBZGFwdGVyLnZpZXc8Vmlld1Jlc3BvbnNlPihcbiAgICAgICAgY291bnREZXNjLmRkb2MsXG4gICAgICAgIGNvdW50RGVzYy52aWV3LFxuICAgICAgICBjb3VudERlc2Mub3B0aW9ucyxcbiAgICAgICAgY3R4XG4gICAgICApLFxuICAgIF0pO1xuICAgIGNvbnN0IHN1bSA9IHN1bVJlc3BvbnNlLnJvd3M/LlswXT8udmFsdWUgPz8gMDtcbiAgICBjb25zdCBjb3VudCA9IGNvdW50UmVzcG9uc2Uucm93cz8uWzBdPy52YWx1ZSA/PyAwO1xuICAgIGlmICghY291bnQpIHJldHVybiAwIGFzIHVua25vd24gYXMgUjtcbiAgICByZXR1cm4gKHN1bSAvIGNvdW50KSBhcyB1bmtub3duIGFzIFI7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByb2Nlc3NlcyB0aGUgdmlldyByZXNwb25zZSBiYXNlZCBvbiBhZ2dyZWdhdGUga2luZFxuICAgKi9cbiAgcHJpdmF0ZSBwcm9jZXNzVmlld1Jlc3BvbnNlPFI+KFxuICAgIGluZm86IEZhYnJpY0FnZ3JlZ2F0ZUluZm8sXG4gICAgcmVzcG9uc2U6IFZpZXdSZXNwb25zZVxuICApOiBSIHtcbiAgICBpZiAoaW5mby5raW5kID09PSBcImF2Z1wiKVxuICAgICAgdGhyb3cgbmV3IFF1ZXJ5RXJyb3IoXG4gICAgICAgIFwiQXZlcmFnZSByZXN1bHRzIHNob3VsZCBiZSBoYW5kbGVkIGJlZm9yZSBwcm9jZXNzaW5nIHJvd3NcIlxuICAgICAgKTtcbiAgICBjb25zdCByb3dzID0gcmVzcG9uc2Uucm93cyB8fCBbXTtcbiAgICBjb25zdCB2aWV3SW5mbyA9IGluZm8gYXMgRXh0cmFjdDxGYWJyaWNBZ2dyZWdhdGVJbmZvLCB7IGtpbmQ6IFZpZXdLaW5kIH0+O1xuICAgIGNvbnN0IG1ldGEgPSB2aWV3SW5mby5tZXRhO1xuICAgIGlmICh2aWV3SW5mby5jb3VudERpc3RpbmN0KSB7XG4gICAgICByZXR1cm4gKHJvd3MubGVuZ3RoIHx8IDApIGFzIHVua25vd24gYXMgUjtcbiAgICB9XG4gICAgaWYgKHZpZXdJbmZvLmtpbmQgPT09IFwiZGlzdGluY3RcIiB8fCB2aWV3SW5mby5raW5kID09PSBcImdyb3VwQnlcIikge1xuICAgICAgcmV0dXJuIHJvd3MubWFwKChyb3cpID0+IHJvdy5rZXkgPz8gcm93LnZhbHVlKSBhcyB1bmtub3duIGFzIFI7XG4gICAgfVxuICAgIGlmIChtZXRhLnJldHVybkRvY3MpIHtcbiAgICAgIHJldHVybiByb3dzLm1hcCgocm93KSA9PiByb3cudmFsdWUgPz8gcm93LmRvYyA/PyByb3cpIGFzIHVua25vd24gYXMgUjtcbiAgICB9XG4gICAgaWYgKCFyb3dzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuICh2aWV3SW5mby5raW5kID09PSBcImNvdW50XCIgPyAwIDogbnVsbCkgYXMgdW5rbm93biBhcyBSO1xuICAgIH1cbiAgICByZXR1cm4gKHJvd3NbMF0udmFsdWUgPz8gcm93c1swXS5rZXkgPz8gbnVsbCkgYXMgdW5rbm93biBhcyBSO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUeXBlIGd1YXJkIHRvIGNoZWNrIGlmIGluZm8gaXMgYSB2aWV3LWJhc2VkIGFnZ3JlZ2F0ZVxuICAgKi9cbiAgcHJpdmF0ZSBpc1ZpZXdBZ2dyZWdhdGUoXG4gICAgaW5mbzogRmFicmljQWdncmVnYXRlSW5mb1xuICApOiBpbmZvIGlzIEV4dHJhY3Q8RmFicmljQWdncmVnYXRlSW5mbywgeyBraW5kOiBWaWV3S2luZCB9PiB7XG4gICAgcmV0dXJuIGluZm8ua2luZCAhPT0gXCJhdmdcIjtcbiAgfVxufVxuIiwiaW1wb3J0IHtcbiAgTWF5YmVDb250ZXh0dWFsQXJnLFxuICBQYWdpbmF0b3IsXG4gIFByZXBhcmVkU3RhdGVtZW50LFxuICBVbnN1cHBvcnRlZEVycm9yLFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudEFkYXB0ZXIgfSBmcm9tIFwiLi9GYWJyaWNDbGllbnRBZGFwdGVyXCI7XG5pbXBvcnQgeyBNYW5nb1F1ZXJ5IH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuXG5leHBvcnQgY2xhc3MgRmFicmljQ2xpZW50UGFnaW5hdG9yPE0gZXh0ZW5kcyBNb2RlbD4gZXh0ZW5kcyBQYWdpbmF0b3I8XG4gIE0sXG4gIE1bXSxcbiAgTWFuZ29RdWVyeVxuPiB7XG4gIGJvb2ttYXJrPzogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIGFkYXB0ZXI6IEZhYnJpY0NsaWVudEFkYXB0ZXIsXG4gICAgcXVlcnk6IE1hbmdvUXVlcnkgfCBQcmVwYXJlZFN0YXRlbWVudDxhbnk+LFxuICAgIHNpemU6IG51bWJlcixcbiAgICBjbGF6ejogQ29uc3RydWN0b3I8TT5cbiAgKSB7XG4gICAgc3VwZXIoYWRhcHRlciwgcXVlcnksIHNpemUsIGNsYXp6KTtcbiAgfVxuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgcHJvdGVjdGVkIHByZXBhcmUocmF3U3RhdGVtZW50OiBNYW5nb1F1ZXJ5KTogTWFuZ29RdWVyeSB7XG4gICAgdGhyb3cgbmV3IFVuc3VwcG9ydGVkRXJyb3IoXG4gICAgICBgUmF3IHF1ZXJ5IGFjY2VzcyBtdXN0IGJlIGltcGxlbWVudGVkIGJ5IGEgc3ViY2xhc3MuIG9ubHkgcHJlcGFyZWQgc3RhdGVtZW50cyBhcmUgbmF0aXZlbHkgYXZhaWxhYmxlYFxuICAgICk7XG4gIH1cblxuICBvdmVycmlkZSBwYWdlKFxuICAgIHBhZ2U6IG51bWJlciA9IDEsXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPGFueT5cbiAgKTogUHJvbWlzZTxNW10+IHtcbiAgICByZXR1cm4gc3VwZXIucGFnZShwYWdlLCAuLi5hcmdzKTsgLy8gdGhpcyB3aWxsIGZhaWwgZm9yIG5vbi1wcmVwYXJlZCBzdGF0ZW1lbnRzXG4gIH1cbn1cbiIsImltcG9ydCBcIi4uL3NoYXJlZC9vdmVycmlkZXNcIjtcbmltcG9ydCB7XG4gIENvdWNoREJLZXlzLFxuICB0eXBlIE1hbmdvUXVlcnksXG4gIHR5cGUgVmlld1Jlc3BvbnNlLFxufSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1jb3VjaGRiXCI7XG5pbXBvcnQgeyBDbGllbnQgfSBmcm9tIFwiQGdycGMvZ3JwYy1qc1wiO1xuaW1wb3J0ICogYXMgZ3JwYyBmcm9tIFwiQGdycGMvZ3JwYy1qc1wiO1xuaW1wb3J0IHtcbiAgTW9kZWwsXG4gIHR5cGUgTW9kZWxDb25zdHJ1Y3RvcixcbiAgdHlwZSBTZXJpYWxpemVyLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBkZWJ1ZywgZmluYWwsIExvZ2dpbmcgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7IHR5cGUgUGVlckNvbmZpZywgdHlwZSBTZWdyZWdhdGVkTW9kZWwgfSBmcm9tIFwiLi4vc2hhcmVkL3R5cGVzXCI7XG5pbXBvcnQge1xuICBjb25uZWN0LFxuICB0eXBlIENvbm5lY3RPcHRpb25zLFxuICBHYXRld2F5LFxuICBOZXR3b3JrLFxuICBQcm9wb3NhbE9wdGlvbnMsXG4gIENvbnRyYWN0IGFzIENvbnRyYWt0LFxuICB0eXBlIFNpZ25lcixcbn0gZnJvbSBcIkBoeXBlcmxlZGdlci9mYWJyaWMtZ2F0ZXdheVwiO1xuaW1wb3J0IHsgZ2V0SWRlbnRpdHksIGdldFNpZ25lciB9IGZyb20gXCIuL2ZhYnJpYy1mc1wiO1xuaW1wb3J0IHtcbiAgQmFzZUVycm9yLFxuICBJbnRlcm5hbEVycm9yLFxuICBPcGVyYXRpb25LZXlzLFxuICBTZXJpYWxpemF0aW9uRXJyb3IsXG4gIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyxcbiAgTm90Rm91bmRFcnJvcixcbiAgQ29uZmxpY3RFcnJvcixcbiAgQmFkUmVxdWVzdEVycm9yLFxuICB0eXBlIFByaW1hcnlLZXlUeXBlLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7XG4gIENvbnRleHQsXG4gIEFkYXB0ZXIsXG4gIHR5cGUgQWRhcHRlckZsYWdzLFxuICBBdXRob3JpemF0aW9uRXJyb3IsXG4gIENvbm5lY3Rpb25FcnJvcixcbiAgRm9yYmlkZGVuRXJyb3IsXG4gIE1pZ3JhdGlvbkVycm9yLFxuICBPYnNlcnZlckVycm9yLFxuICBQYWdpbmdFcnJvcixcbiAgUGVyc2lzdGVuY2VLZXlzLFxuICBRdWVyeUVycm9yLFxuICBSZXBvc2l0b3J5LFxuICBVbnN1cHBvcnRlZEVycm9yLFxuICBTdGF0ZW1lbnQsXG4gIHR5cGUgUHJlcGFyZWRTdGF0ZW1lbnQsXG4gIFBhZ2luYXRvcixcbiAgTWF5YmVDb250ZXh0dWFsQXJnLFxuICBDb250ZXh0dWFsQXJncyxcbiAgdHlwZSBQcmVwYXJlZE1vZGVsLFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IEZhYnJpY0ZsYXZvdXIgfSBmcm9tIFwiLi4vc2hhcmVkL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgQ2xpZW50U2VyaWFsaXplciB9IGZyb20gXCIuLi9zaGFyZWQvQ2xpZW50U2VyaWFsaXplclwiO1xuaW1wb3J0IHsgRmFicmljQ2xpZW50RGlzcGF0Y2ggfSBmcm9tIFwiLi9GYWJyaWNDbGllbnREaXNwYXRjaFwiO1xuaW1wb3J0IHsgSFNNU2lnbmVyRmFjdG9yeUN1c3RvbSB9IGZyb20gXCIuL2ZhYnJpYy1oc21cIjtcbmltcG9ydCB7IHR5cGUgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudFN0YXRlbWVudCB9IGZyb20gXCIuL0ZhYnJpY0NsaWVudFN0YXRlbWVudFwiO1xuaW1wb3J0IHsgRmFicmljQ2xpZW50UGFnaW5hdG9yIH0gZnJvbSBcIi4vRmFicmljQ2xpZW50UGFnaW5hdG9yXCI7XG5pbXBvcnQgeyBGYWJyaWNDbGllbnRSZXBvc2l0b3J5IH0gZnJvbSBcIi4vRmFicmljQ2xpZW50UmVwb3NpdG9yeVwiO1xuaW1wb3J0IHtcbiAgRW5kb3JzZW1lbnRFcnJvcixcbiAgRW5kb3JzZW1lbnRQb2xpY3lFcnJvcixcbiAgTXZjY1JlYWRDb25mbGljdEVycm9yLFxuICBQaGFudG9tUmVhZENvbmZsaWN0RXJyb3IsXG59IGZyb20gXCIuLi9zaGFyZWQvZXJyb3JzXCI7XG5pbXBvcnQgeyBGYWJyaWNDbGllbnRGbGFncyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBEZWZhdWx0RmFicmljQ2xpZW50RmxhZ3MgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCBmcyBmcm9tIFwiZnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQWRhcHRlciBmb3IgaW50ZXJhY3Rpbmcgd2l0aCBIeXBlcmxlZGdlciBGYWJyaWMgbmV0d29ya3NcbiAqIEBzdW1tYXJ5IFRoZSBGYWJyaWNBZGFwdGVyIGV4dGVuZHMgQ291Y2hEQkFkYXB0ZXIgdG8gcHJvdmlkZSBhIHNlYW1sZXNzIGludGVyZmFjZSBmb3IgaW50ZXJhY3Rpbmcgd2l0aCBIeXBlcmxlZGdlciBGYWJyaWMgbmV0d29ya3MuXG4gKiBJdCBoYW5kbGVzIGNvbm5lY3Rpb24gbWFuYWdlbWVudCwgdHJhbnNhY3Rpb24gc3VibWlzc2lvbiwgYW5kIENSVUQgb3BlcmF0aW9ucyBhZ2FpbnN0IEZhYnJpYyBjaGFpbmNvZGUuXG4gKiBAdGVtcGxhdGUgUGVlckNvbmZpZyAtIENvbmZpZ3VyYXRpb24gdHlwZSBmb3IgY29ubmVjdGluZyB0byBhIEZhYnJpYyBwZWVyXG4gKiBAdGVtcGxhdGUgRmFicmljRmxhZ3MgLSBGbGFncyBzcGVjaWZpYyB0byBGYWJyaWMgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIENvbnRleHQ8RmFicmljRmxhZ3M+IC0gQ29udGV4dCB0eXBlIGNvbnRhaW5pbmcgRmFicmljLXNwZWNpZmljIGZsYWdzXG4gKiBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBmb3IgY29ubmVjdGluZyB0byBhIEZhYnJpYyBwZWVyXG4gKiBAcGFyYW0gYWxpYXMgLSBPcHRpb25hbCBhbGlhcyBmb3IgdGhlIGFkYXB0ZXIgaW5zdGFuY2VcbiAqIEBjbGFzcyBGYWJyaWNDbGllbnRBZGFwdGVyXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gQ3JlYXRlIGEgbmV3IEZhYnJpY0FkYXB0ZXIgaW5zdGFuY2VcbiAqIGNvbnN0IGNvbmZpZzogUGVlckNvbmZpZyA9IHtcbiAqICAgbXNwSWQ6ICdPcmcxTVNQJyxcbiAqICAgcGVlckVuZHBvaW50OiAnbG9jYWxob3N0OjcwNTEnLFxuICogICBjaGFubmVsTmFtZTogJ215Y2hhbm5lbCcsXG4gKiAgIGNoYWluY29kZU5hbWU6ICdteWNjJyxcbiAqICAgY29udHJhY3ROYW1lOiAnbXljb250cmFjdCcsXG4gKiAgIHRsc0NlcnRQYXRoOiAnL3BhdGgvdG8vdGxzL2NlcnQnLFxuICogICBjZXJ0RGlyZWN0b3J5UGF0aDogJy9wYXRoL3RvL2NlcnQvZGlyJyxcbiAqICAga2V5RGlyZWN0b3J5UGF0aDogJy9wYXRoL3RvL2tleS9kaXInXG4gKiB9O1xuICpcbiAqIGNvbnN0IGFkYXB0ZXIgPSBuZXcgRmFicmljQWRhcHRlcihjb25maWcsICdvcmcxLWFkYXB0ZXInKTtcbiAqXG4gKiAvLyBVc2UgdGhlIGFkYXB0ZXIgdG8gaW50ZXJhY3Qgd2l0aCB0aGUgRmFicmljIG5ldHdvcmtcbiAqIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGFkYXB0ZXIucmVhZCgndXNlcnMnLCAndXNlcjEnLCBteVNlcmlhbGl6ZXIpO1xuICogYGBgXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENsaWVudFxuICogICBwYXJ0aWNpcGFudCBGYWJyaWNBZGFwdGVyXG4gKiAgIHBhcnRpY2lwYW50IEdhdGV3YXlcbiAqICAgcGFydGljaXBhbnQgTmV0d29ya1xuICogICBwYXJ0aWNpcGFudCBDb250cmFjdFxuICogICBwYXJ0aWNpcGFudCBDaGFpbmNvZGVcbiAqXG4gKiAgIENsaWVudC0+PkZhYnJpY0FkYXB0ZXI6IGNyZWF0ZSh0YWJsZU5hbWUsIGlkLCBtb2RlbCwgdHJhbnNpZW50LCBzZXJpYWxpemVyKVxuICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogc3VibWl0VHJhbnNhY3Rpb24oT3BlcmF0aW9uS2V5cy5DUkVBVEUsIFtzZXJpYWxpemVkTW9kZWxdLCB0cmFuc2llbnQpXG4gKiAgIEZhYnJpY0FkYXB0ZXItPj5HYXRld2F5OiBjb25uZWN0KClcbiAqICAgR2F0ZXdheS0+Pk5ldHdvcms6IGdldE5ldHdvcmsoY2hhbm5lbE5hbWUpXG4gKiAgIE5ldHdvcmstPj5Db250cmFjdDogZ2V0Q29udHJhY3QoY2hhaW5jb2RlTmFtZSwgY29udHJhY3ROYW1lKVxuICogICBGYWJyaWNBZGFwdGVyLT4+Q29udHJhY3Q6IHN1Ym1pdChhcGksIHByb3Bvc2FsT3B0aW9ucylcbiAqICAgQ29udHJhY3QtPj5DaGFpbmNvZGU6IGludm9rZVxuICogICBDaGFpbmNvZGUtLT4+Q29udHJhY3Q6IHJlc3BvbnNlXG4gKiAgIENvbnRyYWN0LS0+PkZhYnJpY0FkYXB0ZXI6IHJlc3VsdFxuICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogZGVjb2RlKHJlc3VsdClcbiAqICAgRmFicmljQWRhcHRlci0+PkZhYnJpY0FkYXB0ZXI6IHNlcmlhbGl6ZXIuZGVzZXJpYWxpemUoZGVjb2RlZFJlc3VsdClcbiAqICAgRmFicmljQWRhcHRlci0tPj5DbGllbnQ6IGRlc2VyaWFsaXplZFJlc3VsdFxuICovXG5leHBvcnQgY2xhc3MgRmFicmljQ2xpZW50QWRhcHRlciBleHRlbmRzIEFkYXB0ZXI8XG4gIFBlZXJDb25maWcsXG4gIENsaWVudCxcbiAgTWFuZ29RdWVyeSxcbiAgQ29udGV4dDxGYWJyaWNDbGllbnRGbGFncz5cbj4ge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFN0YXRpYyB0ZXh0IGRlY29kZXIgZm9yIGNvbnZlcnRpbmcgVWludDhBcnJheSB0byBzdHJpbmdcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGRlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoXCJ1dGY4XCIpO1xuXG4gIHByaXZhdGUgc3RhdGljIHNlcmlhbGl6ZXIgPSBuZXcgQ2xpZW50U2VyaWFsaXplcigpO1xuXG4gIHByb3RlY3RlZCBzdGF0aWMgbG9nID0gTG9nZ2luZy5mb3IoRmFicmljQ2xpZW50QWRhcHRlcik7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHNlcmlhbGl6ZXI6IFNlcmlhbGl6ZXI8YW55PiA9XG4gICAgRmFicmljQ2xpZW50QWRhcHRlci5zZXJpYWxpemVyO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIG5ldyBGYWJyaWNBZGFwdGVyIGluc3RhbmNlXG4gICAqIEBzdW1tYXJ5IEluaXRpYWxpemVzIGEgbmV3IGFkYXB0ZXIgZm9yIGludGVyYWN0aW5nIHdpdGggYSBIeXBlcmxlZGdlciBGYWJyaWMgbmV0d29ya1xuICAgKiBAcGFyYW0ge1BlZXJDb25maWd9IGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gZm9yIGNvbm5lY3RpbmcgdG8gYSBGYWJyaWMgcGVlclxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FsaWFzXSAtIE9wdGlvbmFsIGFsaWFzIGZvciB0aGUgYWRhcHRlciBpbnN0YW5jZVxuICAgKi9cbiAgY29uc3RydWN0b3IoY29uZmlnOiBQZWVyQ29uZmlnLCBhbGlhcz86IHN0cmluZykge1xuICAgIHN1cGVyKFxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnLCB7XG4gICAgICAgIGV2YWx1YXRlVGltZW91dDogNSxcbiAgICAgICAgZW5kb3JzZVRpbWVvdXQ6IDE1LFxuICAgICAgICBzdWJtaXRUaW1lb3V0OiA1LFxuICAgICAgICBjb21taXRUaW1lb3V0OiA2MCxcbiAgICAgIH0pLFxuICAgICAgRmFicmljRmxhdm91cixcbiAgICAgIGFsaWFzXG4gICAgKTtcbiAgfVxuXG4gIG92ZXJyaWRlIFN0YXRlbWVudDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIG92ZXJyaWRlcz86IFBhcnRpYWw8QWRhcHRlckZsYWdzPlxuICApOiBTdGF0ZW1lbnQ8TSwgRmFicmljQ2xpZW50QWRhcHRlciwgYW55LCBNYW5nb1F1ZXJ5PiB7XG4gICAgcmV0dXJuIG5ldyBGYWJyaWNDbGllbnRTdGF0ZW1lbnQodGhpcywgb3ZlcnJpZGVzKTtcbiAgfVxuXG4gIFBhZ2luYXRvcjxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIHF1ZXJ5OiBQcmVwYXJlZFN0YXRlbWVudDxhbnk+IHwgTWFuZ29RdWVyeSxcbiAgICBzaXplOiBudW1iZXIsXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+XG4gICk6IFBhZ2luYXRvcjxNLCBhbnksIE1hbmdvUXVlcnk+IHtcbiAgICByZXR1cm4gbmV3IEZhYnJpY0NsaWVudFBhZ2luYXRvcih0aGlzLCBxdWVyeSwgc2l6ZSwgY2xhenopO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIGZsYWdzPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgb3BlcmF0aW9uOiBPcGVyYXRpb25LZXlzIHwgc3RyaW5nLFxuICAgIG1vZGVsOiBDb25zdHJ1Y3RvcjxNPiB8IENvbnN0cnVjdG9yPE0+W10gfCB1bmRlZmluZWQsXG4gICAgZmxhZ3M6IFBhcnRpYWw8RmFicmljQ2xpZW50RmxhZ3M+LFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8RmFicmljQ2xpZW50RmxhZ3M+IHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihcbiAgICAgIGF3YWl0IHN1cGVyLmZsYWdzKFxuICAgICAgICBvcGVyYXRpb24sXG4gICAgICAgIG1vZGVsLFxuICAgICAgICBPYmplY3QuYXNzaWduKHt9LCB0aGlzLmNvbmZpZywgZmxhZ3MpLFxuICAgICAgICAuLi5hcmdzXG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVjb2RlcyBhIFVpbnQ4QXJyYXkgdG8gYSBzdHJpbmdcbiAgICogQHN1bW1hcnkgQ29udmVydHMgYmluYXJ5IGRhdGEgcmVjZWl2ZWQgZnJvbSBGYWJyaWMgdG8gYSBzdHJpbmcgdXNpbmcgVVRGLTggZW5jb2RpbmdcbiAgICogQHBhcmFtIHtVaW50OEFycmF5fSBkYXRhIC0gVGhlIGJpbmFyeSBkYXRhIHRvIGRlY29kZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBkZWNvZGVkIHN0cmluZ1xuICAgKi9cbiAgZGVjb2RlKGRhdGE6IFVpbnQ4QXJyYXkpOiBzdHJpbmcge1xuICAgIHJldHVybiBGYWJyaWNDbGllbnRBZGFwdGVyLmRlY29kZXIuZGVjb2RlKGRhdGEpO1xuICB9XG5cbiAgb3ZlcnJpZGUgcmVwb3NpdG9yeTxcbiAgICBSIGV4dGVuZHMgUmVwb3NpdG9yeTxcbiAgICAgIGFueSxcbiAgICAgIEFkYXB0ZXI8UGVlckNvbmZpZywgQ2xpZW50LCBNYW5nb1F1ZXJ5LCBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj5cbiAgICA+LFxuICA+KCk6IENvbnN0cnVjdG9yPFI+IHtcbiAgICByZXR1cm4gRmFicmljQ2xpZW50UmVwb3NpdG9yeSBhcyB1bmtub3duIGFzIENvbnN0cnVjdG9yPFI+O1xuICB9XG5cbiAgcHJvdGVjdGVkIGNyZWF0ZVByZWZpeDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBbQ29uc3RydWN0b3I8TT4sIFByaW1hcnlLZXlUeXBlLCBSZWNvcmQ8c3RyaW5nLCBhbnk+LCAuLi5hbnlbXSwgQ29udGV4dF0ge1xuICAgIGNvbnN0IHsgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5jcmVhdGVQcmVmaXgpO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IHRhYmxlTmFtZTtcbiAgICBPYmplY3QuYXNzaWduKHJlY29yZCwgbW9kZWwpO1xuICAgIHJldHVybiBbY2xhenosIGlkLCByZWNvcmQsIC4uLmN0eEFyZ3NdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcmVwYXJlcyBtdWx0aXBsZSByZWNvcmRzIGZvciBjcmVhdGlvblxuICAgKiBAc3VtbWFyeSBBZGRzIG5lY2Vzc2FyeSBDb3VjaERCIGZpZWxkcyB0byBtdWx0aXBsZSByZWNvcmRzIGJlZm9yZSBjcmVhdGlvblxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlXG4gICAqIEBwYXJhbSB7c3RyaW5nW118bnVtYmVyW119IGlkcyAtIFRoZSBJRHMgb2YgdGhlIHJlY29yZHNcbiAgICogQHBhcmFtIG1vZGVscyAtIFRoZSBtb2RlbHMgdG8gcHJlcGFyZVxuICAgKiBAcmV0dXJuIEEgdHVwbGUgY29udGFpbmluZyB0aGUgdGFibGVOYW1lLCBpZHMsIGFuZCBwcmVwYXJlZCByZWNvcmRzXG4gICAqIEB0aHJvd3Mge0ludGVybmFsRXJyb3J9IElmIGlkcyBhbmQgbW9kZWxzIGFycmF5cyBoYXZlIGRpZmZlcmVudCBsZW5ndGhzXG4gICAqL1xuICBwcm90ZWN0ZWQgY3JlYXRlQWxsUHJlZml4PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkczogc3RyaW5nW10gfCBudW1iZXJbXSxcbiAgICBtb2RlbHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICkge1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgaWYgKGlkcy5sZW5ndGggIT09IG1vZGVscy5sZW5ndGgpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIklkcyBhbmQgbW9kZWxzIG11c3QgaGF2ZSB0aGUgc2FtZSBsZW5ndGhcIik7XG4gICAgY29uc3QgeyBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLmNyZWF0ZUFsbFByZWZpeCk7XG4gICAgY29uc3QgcmVjb3JkcyA9IGlkcy5tYXAoKGlkLCBjb3VudCkgPT4ge1xuICAgICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgICByZWNvcmRbQ291Y2hEQktleXMuVEFCTEVdID0gdGFibGVOYW1lO1xuICAgICAgT2JqZWN0LmFzc2lnbihyZWNvcmQsIG1vZGVsc1tjb3VudF0pO1xuICAgICAgcmV0dXJuIHJlY29yZDtcbiAgICB9KTtcbiAgICByZXR1cm4gW2NsYXp6LCBpZHMsIHJlY29yZHMsIC4uLmN0eEFyZ3NdO1xuICB9XG5cbiAgcHJvdGVjdGVkIHVwZGF0ZUFsbFByZWZpeDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZHM6IFByaW1hcnlLZXlUeXBlW10sXG4gICAgbW9kZWxzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+W10sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApIHtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIGlmIChpZHMubGVuZ3RoICE9PSBtb2RlbHMubGVuZ3RoKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJJZHMgYW5kIG1vZGVscyBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoXCIpO1xuICAgIGNvbnN0IHsgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy51cGRhdGVBbGxQcmVmaXgpO1xuICAgIGNvbnN0IHJlY29yZHMgPSBpZHMubWFwKCgpID0+IHtcbiAgICAgIGNvbnN0IHJlY29yZDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IHRhYmxlTmFtZTtcbiAgICAgIHJldHVybiByZWNvcmQ7XG4gICAgfSk7XG4gICAgcmV0dXJuIFtjbGF6eiwgaWRzLCByZWNvcmRzLCAuLi5jdHhBcmdzXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBtdWx0aXBsZSByZWNvcmRzIGluIGEgc2luZ2xlIHRyYW5zYWN0aW9uXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgYSB0cmFuc2FjdGlvbiB0byBjcmVhdGUgbXVsdGlwbGUgcmVjb3JkcyBpbiB0aGUgRmFicmljIGxlZGdlclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlL2NvbGxlY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmdbXSB8IG51bWJlcltdfSBpZHMgLSBBcnJheSBvZiByZWNvcmQgaWRlbnRpZmllcnNcbiAgICogQHBhcmFtIHtBcnJheTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pn0gbW9kZWxzIC0gQXJyYXkgb2YgcmVjb3JkIGRhdGFcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSB0cmFuc2llbnQgLSBUcmFuc2llbnQgZGF0YSBmb3IgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8QXJyYXk8UmVjb3JkPHN0cmluZywgYW55Pj4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgY3JlYXRlZCByZWNvcmRzXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyBjcmVhdGVBbGw8TSBleHRlbmRzIE1vZGVsPihcbiAgICBjbGF6ejogQ29uc3RydWN0b3I8TT4sXG4gICAgaWRzOiBQcmltYXJ5S2V5VHlwZVtdLFxuICAgIG1vZGVsczogUmVjb3JkPHN0cmluZywgYW55PltdLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT5bXT4ge1xuICAgIGlmIChpZHMubGVuZ3RoICE9PSBtb2RlbHMubGVuZ3RoKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJJZHMgYW5kIG1vZGVscyBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoXCIpO1xuICAgIC8vSEVSRSFcbiAgICBjb25zdCBjdHhBcmdzID0gWy4uLihhcmdzIGFzIHVua25vd24gYXMgYW55W10pXTtcbiAgICBjb25zdCB0cmFuc2llbnQgPSBjdHhBcmdzLnNoaWZ0KCkgYXMgUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSB0aGlzLmxvZ0N0eChcbiAgICAgIGN0eEFyZ3MgYXMgQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+LFxuICAgICAgdGhpcy5jcmVhdGVBbGxcbiAgICApO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG5cbiAgICBsb2cuaW5mbyhgYWRkaW5nICR7aWRzLmxlbmd0aH0gZW50cmllcyB0byAke3RhYmxlTmFtZX0gdGFibGVgKTtcbiAgICBsb2cudmVyYm9zZShgcGtzOiAke2lkc31gKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnN1Ym1pdFRyYW5zYWN0aW9uKFxuICAgICAgY3R4LFxuICAgICAgQnVsa0NydWRPcGVyYXRpb25LZXlzLkNSRUFURV9BTEwsXG4gICAgICBbXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KFxuICAgICAgICAgIG1vZGVscy5tYXAoKG0pID0+IHRoaXMuc2VyaWFsaXplci5zZXJpYWxpemUobSwgY2xhenoubmFtZSkpXG4gICAgICAgICksXG4gICAgICBdLFxuICAgICAgdHJhbnNpZW50LFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgY2xhenoubmFtZVxuICAgICk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBKU09OLnBhcnNlKHRoaXMuZGVjb2RlKHJlc3VsdCkpLm1hcCgocjogYW55KSA9PiBKU09OLnBhcnNlKHIpKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgU2VyaWFsaXphdGlvbkVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVhZHMgbXVsdGlwbGUgcmVjb3JkcyBpbiBhIHNpbmdsZSB0cmFuc2FjdGlvblxuICAgKiBAc3VtbWFyeSBTdWJtaXRzIGEgdHJhbnNhY3Rpb24gdG8gcmVhZCBtdWx0aXBsZSByZWNvcmRzIGZyb20gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nW10gfCBudW1iZXJbXX0gaWRzIC0gQXJyYXkgb2YgcmVjb3JkIGlkZW50aWZpZXJzIHRvIHJlYWRcbiAgICogQHJldHVybiB7UHJvbWlzZTxBcnJheTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSByZXRyaWV2ZWQgcmVjb3Jkc1xuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgcmVhZEFsbDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZHM6IFByaW1hcnlLZXlUeXBlW10sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55PltdPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5yZWFkQWxsKTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIGxvZy5pbmZvKGByZWFkaW5nICR7aWRzLmxlbmd0aH0gZW50cmllcyB0byAke3RhYmxlTmFtZX0gdGFibGVgKTtcbiAgICBsb2cudmVyYm9zZShgcGtzOiAke2lkc31gKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmV2YWx1YXRlVHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuUkVBRF9BTEwsXG4gICAgICBbSlNPTi5zdHJpbmdpZnkoaWRzKV0sXG4gICAgICB1bmRlZmluZWQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBjbGF6ei5uYW1lXG4gICAgKTtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEpTT04ucGFyc2UodGhpcy5kZWNvZGUocmVzdWx0KSkubWFwKChyOiBhbnkpID0+IEpTT04ucGFyc2UocikpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIG11bHRpcGxlIHJlY29yZHMgaW4gYSBzaW5nbGUgdHJhbnNhY3Rpb25cbiAgICogQHN1bW1hcnkgU3VibWl0cyBhIHRyYW5zYWN0aW9uIHRvIHVwZGF0ZSBtdWx0aXBsZSByZWNvcmRzIGluIHRoZSBGYWJyaWMgbGVkZ2VyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGFibGUvY29sbGVjdGlvblxuICAgKiBAcGFyYW0ge3N0cmluZ1tdIHwgbnVtYmVyW119IGlkcyAtIEFycmF5IG9mIHJlY29yZCBpZGVudGlmaWVyc1xuICAgKiBAcGFyYW0ge0FycmF5PFJlY29yZDxzdHJpbmcsIGFueT4+fSBtb2RlbHMgLSBBcnJheSBvZiB1cGRhdGVkIHJlY29yZCBkYXRhXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gdHJhbnNpZW50IC0gVHJhbnNpZW50IGRhdGEgZm9yIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPEFycmF5PFJlY29yZDxzdHJpbmcsIGFueT4+Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWQgcmVjb3Jkc1xuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgdXBkYXRlQWxsPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkczogUHJpbWFyeUtleVR5cGVbXSxcbiAgICBtb2RlbHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXSxcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj5cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+W10+IHtcbiAgICBpZiAoaWRzLmxlbmd0aCAhPT0gbW9kZWxzLmxlbmd0aClcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiSWRzIGFuZCBtb2RlbHMgbXVzdCBoYXZlIHRoZSBzYW1lIGxlbmd0aFwiKTtcbiAgICBjb25zdCBjdHhBcmdzID0gWy4uLihhcmdzIGFzIHVua25vd24gYXMgYW55W10pXTtcbiAgICBjb25zdCB0cmFuc2llbnQgPSBjdHhBcmdzLnNoaWZ0KCkgYXMgUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSB0aGlzLmxvZ0N0eChcbiAgICAgIGN0eEFyZ3MgYXMgQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+LFxuICAgICAgdGhpcy51cGRhdGVBbGxcbiAgICApO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgbG9nLmluZm8oYHVwZGF0aW5nICR7aWRzLmxlbmd0aH0gZW50cmllcyB0byAke3RhYmxlTmFtZX0gdGFibGVgKTtcbiAgICBsb2cudmVyYm9zZShgcGtzOiAke2lkc31gKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuc3VibWl0VHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuVVBEQVRFX0FMTCxcbiAgICAgIFtcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgbW9kZWxzLm1hcCgobSkgPT4gdGhpcy5zZXJpYWxpemVyLnNlcmlhbGl6ZShtLCBjbGF6ei5uYW1lKSlcbiAgICAgICAgKSxcbiAgICAgIF0sXG4gICAgICB0cmFuc2llbnQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBjbGF6ei5uYW1lXG4gICAgKTtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEpTT04ucGFyc2UodGhpcy5kZWNvZGUocmVzdWx0KSkubWFwKChyOiBhbnkpID0+IEpTT04ucGFyc2UocikpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBEZWxldGVzIG11bHRpcGxlIHJlY29yZHMgaW4gYSBzaW5nbGUgdHJhbnNhY3Rpb25cbiAgICogQHN1bW1hcnkgU3VibWl0cyBhIHRyYW5zYWN0aW9uIHRvIGRlbGV0ZSBtdWx0aXBsZSByZWNvcmRzIGZyb20gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50Pn0gaWRzIC0gQXJyYXkgb2YgcmVjb3JkIGlkZW50aWZpZXJzIHRvIGRlbGV0ZVxuICAgKiBAcGFyYW0ge1NlcmlhbGl6ZXI8YW55Pn0gc2VyaWFsaXplciAtIFNlcmlhbGl6ZXIgZm9yIHRoZSBtb2RlbCBkYXRhXG4gICAqIEByZXR1cm4ge1Byb21pc2U8QXJyYXk8UmVjb3JkPHN0cmluZywgYW55Pj4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZGVsZXRlZCByZWNvcmRzXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyBkZWxldGVBbGw8TSBleHRlbmRzIE1vZGVsPihcbiAgICBjbGF6ejogQ29uc3RydWN0b3I8TT4sXG4gICAgaWRzOiBQcmltYXJ5S2V5VHlwZVtdLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT5bXT4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuZGVsZXRlQWxsKTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIGxvZy5pbmZvKGBkZWxldGluZyAke2lkcy5sZW5ndGh9IGVudHJpZXMgdG8gJHt0YWJsZU5hbWV9IHRhYmxlYCk7XG4gICAgbG9nLnZlcmJvc2UoYHBrczogJHtpZHN9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cy5ERUxFVEVfQUxMLFxuICAgICAgW0pTT04uc3RyaW5naWZ5KGlkcyldLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgY2xhenoubmFtZVxuICAgICk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBKU09OLnBhcnNlKHRoaXMuZGVjb2RlKHJlc3VsdCkpLm1hcCgocjogYW55KSA9PiBKU09OLnBhcnNlKHIpKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgU2VyaWFsaXphdGlvbkVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJlcGFyZXMgYSBtb2RlbCBmb3IgcGVyc2lzdGVuY2VcbiAgICogQHN1bW1hcnkgQ29udmVydHMgYSBtb2RlbCBpbnN0YW5jZSBpbnRvIGEgZm9ybWF0IHN1aXRhYmxlIGZvciBkYXRhYmFzZSBzdG9yYWdlLFxuICAgKiBoYW5kbGluZyBjb2x1bW4gbWFwcGluZyBhbmQgc2VwYXJhdGluZyB0cmFuc2llbnQgcHJvcGVydGllc1xuICAgKiBAdGVtcGxhdGUgTSAtIFRoZSBtb2RlbCB0eXBlXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgdG8gcHJlcGFyZVxuICAgKiBAcGFyYW0gcGsgLSBUaGUgcHJpbWFyeSBrZXkgcHJvcGVydHkgbmFtZVxuICAgKiBAcmV0dXJuIFRoZSBwcmVwYXJlZCBkYXRhXG4gICAqL1xuICBvdmVycmlkZSBwcmVwYXJlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgbW9kZWw6IE0sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFNlZ3JlZ2F0ZWRNb2RlbDxNPiAmIFByZXBhcmVkTW9kZWwge1xuICAgIGNvbnN0IHsgbG9nIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnByZXBhcmUpO1xuICAgIGNvbnN0IHNwbGl0ID0gTW9kZWwuc2VncmVnYXRlKG1vZGVsKTtcbiAgICBpZiAoKG1vZGVsIGFzIGFueSlbUGVyc2lzdGVuY2VLZXlzLk1FVEFEQVRBXSkge1xuICAgICAgbG9nLnNpbGx5KFxuICAgICAgICBgUGFzc2luZyBhbG9uZyBwZXJzaXN0ZW5jZSBtZXRhZGF0YSBmb3IgJHsobW9kZWwgYXMgYW55KVtQZXJzaXN0ZW5jZUtleXMuTUVUQURBVEFdfWBcbiAgICAgICk7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoc3BsaXQubW9kZWwsIFBlcnNpc3RlbmNlS2V5cy5NRVRBREFUQSwge1xuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgIHZhbHVlOiAobW9kZWwgYXMgYW55KVtQZXJzaXN0ZW5jZUtleXMuTUVUQURBVEFdLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHJlY29yZDogc3BsaXQubW9kZWwsXG4gICAgICBtb2RlbDogc3BsaXQubW9kZWwsXG4gICAgICBpZDogbW9kZWxbTW9kZWwucGsobW9kZWwuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3I8TT4pXSBhcyBzdHJpbmcsXG4gICAgICB0cmFuc2llbnQ6IHNwbGl0LnRyYW5zaWVudCxcbiAgICAgIHByaXZhdGVzOiBzcGxpdC5wcml2YXRlcyxcbiAgICAgIHNoYXJlZDogc3BsaXQuc2hhcmVkLFxuICAgIH07XG4gIH1cblxuICBvdmVycmlkZSByZXZlcnQ8TSBleHRlbmRzIE1vZGVsPihcbiAgICBvYmo6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkOiBQcmltYXJ5S2V5VHlwZSxcbiAgICB0cmFuc2llbnQ/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBNIHtcbiAgICBjb25zdCB7IGxvZyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5yZXZlcnQpO1xuICAgIGlmICh0cmFuc2llbnQpIHtcbiAgICAgIGxvZy52ZXJib3NlKFxuICAgICAgICBgcmUtYWRkaW5nIHRyYW5zaWVudCBwcm9wZXJ0aWVzOiAke09iamVjdC5rZXlzKHRyYW5zaWVudCkuam9pbihcIiwgXCIpfWBcbiAgICAgICk7XG4gICAgICBPYmplY3QuZW50cmllcyh0cmFuc2llbnQgYXMgUmVjb3JkPHN0cmluZywgYW55PikuZm9yRWFjaCgoW2tleSwgdmFsXSkgPT4ge1xuICAgICAgICBpZiAoa2V5IGluIG9iaiAmJiB0eXBlb2Ygb2JqW2tleV0gIT09IFwidW5kZWZpbmVkXCIpXG4gICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgICAgICBgVHJhbnNpZW50IHByb3BlcnR5ICR7a2V5fSBhbHJlYWR5IGV4aXN0cyBvbiBtb2RlbCAke3R5cGVvZiBjbGF6eiA9PT0gXCJzdHJpbmdcIiA/IGNsYXp6IDogY2xhenoubmFtZX0uIHNob3VsZCBiZSBpbXBvc3NpYmxlYFxuICAgICAgICAgICk7XG4gICAgICAgIChvYmogYXMgTSlba2V5IGFzIGtleW9mIE1dID0gdmFsO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyAoY2xhenogYXMgQ29uc3RydWN0b3I8TT4pKG9iaik7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBzaW5nbGUgcmVjb3JkXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgYSB0cmFuc2FjdGlvbiB0byBjcmVhdGUgYSByZWNvcmQgaW4gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIFRoZSByZWNvcmQgaWRlbnRpZmllclxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IG1vZGVsIC0gVGhlIHJlY29yZCBkYXRhXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gdHJhbnNpZW50IC0gVHJhbnNpZW50IGRhdGEgZm9yIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgY3JlYXRlZCByZWNvcmRcbiAgICovXG4gIEBkZWJ1ZygpXG4gIEBmaW5hbCgpXG4gIG92ZXJyaWRlIGFzeW5jIGNyZWF0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgdHJhbnNpZW50OiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge30sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IGN0eEFyZ3MgPSBbLi4uKGFyZ3MgYXMgdW5rbm93biBhcyBhbnlbXSldO1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KFxuICAgICAgY3R4QXJncyBhcyBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj4sXG4gICAgICB0aGlzLmNyZWF0ZVxuICAgICk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKGNsYXp6KTtcbiAgICBsb2cudmVyYm9zZShgYWRkaW5nIGVudHJ5IHRvICR7dGFibGVOYW1lfSB0YWJsZWApO1xuICAgIGxvZy5kZWJ1ZyhgcGs6ICR7aWR9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICAgICAgW3RoaXMuc2VyaWFsaXplci5zZXJpYWxpemUobW9kZWwsIGNsYXp6Lm5hbWUpXSxcbiAgICAgIHRyYW5zaWVudCxcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIGNsYXp6Lm5hbWVcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZXIuZGVzZXJpYWxpemUodGhpcy5kZWNvZGUocmVzdWx0KSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlYWRzIGEgc2luZ2xlIHJlY29yZFxuICAgKiBAc3VtbWFyeSBFdmFsdWF0ZXMgYSB0cmFuc2FjdGlvbiB0byByZWFkIGEgcmVjb3JkIGZyb20gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIFRoZSByZWNvcmQgaWRlbnRpZmllclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgcmV0cmlldmVkIHJlY29yZFxuICAgKi9cbiAgQGRlYnVnKClcbiAgQGZpbmFsKClcbiAgYXN5bmMgcmVhZDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmVhZEFsbCk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKGNsYXp6KTtcblxuICAgIGxvZy52ZXJib3NlKGByZWFkaW5nIGVudHJ5IGZyb20gJHt0YWJsZU5hbWV9IHRhYmxlYCk7XG4gICAgbG9nLmRlYnVnKGBwazogJHtpZH1gKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmV2YWx1YXRlVHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBPcGVyYXRpb25LZXlzLlJFQUQsXG4gICAgICBbaWQudG9TdHJpbmcoKV0sXG4gICAgICB1bmRlZmluZWQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBjbGF6ei5uYW1lXG4gICAgKTtcbiAgICByZXR1cm4gdGhpcy5zZXJpYWxpemVyLmRlc2VyaWFsaXplKHRoaXMuZGVjb2RlKHJlc3VsdCkpO1xuICB9XG5cbiAgdXBkYXRlUHJlZml4PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkOiBQcmltYXJ5S2V5VHlwZSxcbiAgICBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICkge1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgY29uc3QgeyBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnVwZGF0ZVByZWZpeCk7XG4gICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IHRhYmxlTmFtZTtcbiAgICAvLyByZWNvcmRbQ291Y2hEQktleXMuSURdID0gdGhpcy5nZW5lcmF0ZUlkKHRhYmxlTmFtZSwgaWQpO1xuICAgIE9iamVjdC5hc3NpZ24ocmVjb3JkLCBtb2RlbCk7XG4gICAgcmV0dXJuIFtjbGF6eiwgaWQsIHJlY29yZCwgLi4uY3R4QXJnc107XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVwZGF0ZXMgYSBzaW5nbGUgcmVjb3JkXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgYSB0cmFuc2FjdGlvbiB0byB1cGRhdGUgYSByZWNvcmQgaW4gdGhlIEZhYnJpYyBsZWRnZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIFRoZSByZWNvcmQgaWRlbnRpZmllclxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IG1vZGVsIC0gVGhlIHVwZGF0ZWQgcmVjb3JkIGRhdGFcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSB0cmFuc2llbnQgLSBUcmFuc2llbnQgZGF0YSBmb3IgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIHJlY29yZFxuICAgKi9cbiAgQGRlYnVnKClcbiAgQGZpbmFsKClcbiAgYXN5bmMgdXBkYXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkOiBQcmltYXJ5S2V5VHlwZSxcbiAgICBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICB0cmFuc2llbnQ6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fSxcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj5cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+PiB7XG4gICAgY29uc3QgY3R4QXJncyA9IFsuLi4oYXJncyBhcyB1bmtub3duIGFzIGFueVtdKV07XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gdGhpcy5sb2dDdHgoXG4gICAgICBjdHhBcmdzIGFzIENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PixcbiAgICAgIHRoaXMudXBkYXRlQWxsXG4gICAgKTtcbiAgICBsb2cuaW5mbyhgQ0xJRU5UIFVQREFURSBjbGFzcyA6ICR7dHlwZW9mIGNsYXp6fWApO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG4gICAgbG9nLnZlcmJvc2UoYHVwZGF0aW5nIGVudHJ5IHRvICR7dGFibGVOYW1lfSB0YWJsZWApO1xuICAgIGxvZy5kZWJ1ZyhgcGs6ICR7aWR9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIE9wZXJhdGlvbktleXMuVVBEQVRFLFxuICAgICAgW3RoaXMuc2VyaWFsaXplci5zZXJpYWxpemUobW9kZWwsIGNsYXp6Lm5hbWUgfHwgY2xhenopXSwgLy8gVE9ETyBzaG91bGQgYmUgcmVjZXZpbmcgY2xhc3MgYnV0IGlzIHJlY2VpdmluZyBzdHJpbmdcbiAgICAgIHRyYW5zaWVudCxcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIGNsYXp6Lm5hbWVcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZXIuZGVzZXJpYWxpemUodGhpcy5kZWNvZGUocmVzdWx0KSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIERlbGV0ZXMgYSBzaW5nbGUgcmVjb3JkXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgYSB0cmFuc2FjdGlvbiB0byBkZWxldGUgYSByZWNvcmQgZnJvbSB0aGUgRmFicmljIGxlZGdlclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlL2NvbGxlY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXJ9IGlkIC0gVGhlIHJlY29yZCBpZGVudGlmaWVyIHRvIGRlbGV0ZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZGVsZXRlZCByZWNvcmRcbiAgICovXG4gIEBkZWJ1ZygpXG4gIEBmaW5hbCgpXG4gIG92ZXJyaWRlIGFzeW5jIGRlbGV0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuZGVsZXRlKTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIGxvZy52ZXJib3NlKGBkZWxldGluZyBlbnRyeSBmcm9tICR7dGFibGVOYW1lfSB0YWJsZWApO1xuICAgIGxvZy5kZWJ1ZyhgcGs6ICR7aWR9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdWJtaXRUcmFuc2FjdGlvbihcbiAgICAgIGN0eCxcbiAgICAgIE9wZXJhdGlvbktleXMuREVMRVRFLFxuICAgICAgW2lkLnRvU3RyaW5nKCldLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgY2xhenoubmFtZVxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuc2VyaWFsaXplci5kZXNlcmlhbGl6ZSh0aGlzLmRlY29kZShyZXN1bHQpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRXhlY3V0ZXMgYSByYXcgcXVlcnkgYWdhaW5zdCB0aGUgRmFicmljIGxlZGdlclxuICAgKiBAc3VtbWFyeSBFdmFsdWF0ZXMgYSB0cmFuc2FjdGlvbiB0byBwZXJmb3JtIGEgcXVlcnkgdXNpbmcgTWFuZ28gUXVlcnkgc3ludGF4XG4gICAqIEB0ZW1wbGF0ZSBWIC0gVGhlIHJldHVybiB0eXBlXG4gICAqIEBwYXJhbSB7TWFuZ29RdWVyeX0gcmF3SW5wdXQgLSBUaGUgTWFuZ28gUXVlcnkgdG8gZXhlY3V0ZVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHByb2Nlc3MgLSBXaGV0aGVyIHRvIHByb2Nlc3MgdGhlIHJlc3VsdFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFY+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgcXVlcnkgcmVzdWx0XG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IENsaWVudFxuICAgKiAgIHBhcnRpY2lwYW50IEZhYnJpY0FkYXB0ZXJcbiAgICogICBwYXJ0aWNpcGFudCBDb250cmFjdFxuICAgKiAgIHBhcnRpY2lwYW50IENoYWluY29kZVxuICAgKlxuICAgKiAgIENsaWVudC0+PkZhYnJpY0FkYXB0ZXI6IHJhdyhyYXdJbnB1dCwgcHJvY2VzcylcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogSlNPTi5zdHJpbmdpZnkocmF3SW5wdXQpXG4gICAqICAgRmFicmljQWRhcHRlci0+PkZhYnJpY0FkYXB0ZXI6IGV2YWx1YXRlVHJhbnNhY3Rpb24oXCJxdWVyeVwiLCBbaW5wdXRdKVxuICAgKiAgIEZhYnJpY0FkYXB0ZXItPj5Db250cmFjdDogZXZhbHVhdGUoXCJxdWVyeVwiLCBwcm9wb3NhbE9wdGlvbnMpXG4gICAqICAgQ29udHJhY3QtPj5DaGFpbmNvZGU6IGludm9rZVxuICAgKiAgIENoYWluY29kZS0tPj5Db250cmFjdDogcmVzcG9uc2VcbiAgICogICBDb250cmFjdC0tPj5GYWJyaWNBZGFwdGVyOiByZXN1bHRcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogSlNPTi5wYXJzZShkZWNvZGUocmVzdWx0KSlcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogUHJvY2VzcyByZXN1bHQgYmFzZWQgb24gdHlwZVxuICAgKiAgIEZhYnJpY0FkYXB0ZXItLT4+Q2xpZW50OiBwcm9jZXNzZWQgcmVzdWx0XG4gICAqL1xuICBAZGVidWcoKVxuICBhc3luYyByYXc8ViwgRCBleHRlbmRzIGJvb2xlYW4+KFxuICAgIHJhd0lucHV0OiBNYW5nb1F1ZXJ5LFxuICAgIGRvY3NPbmx5OiBEID0gdHJ1ZSBhcyBELFxuICAgIGNsYXp6OiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+XG4gICk6IFByb21pc2U8Vj4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmF3KTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBjbGF6ei5uYW1lO1xuICAgIGxvZy5pbmZvKGBQZXJmb3JtaW5nIHJhdyBzdGF0ZW1lbnQgb24gdGFibGUgJHtNb2RlbC50YWJsZU5hbWUoY2xhenopfWApO1xuICAgIGxldCB0cmFuc2FjdGlvblJlc3VsdDogYW55O1xuICAgIHRyeSB7XG4gICAgICB0cmFuc2FjdGlvblJlc3VsdCA9IGF3YWl0IHRoaXMuZXZhbHVhdGVUcmFuc2FjdGlvbihcbiAgICAgICAgY3R4LFxuICAgICAgICBcInJhd1wiLFxuICAgICAgICBbSlNPTi5zdHJpbmdpZnkocmF3SW5wdXQpLCBkb2NzT25seV0sXG4gICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICB0YWJsZU5hbWVcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgICBsZXQgcmVzdWx0OiBhbnk7XG4gICAgdHJ5IHtcbiAgICAgIHJlc3VsdCA9IEpTT04ucGFyc2UodGhpcy5kZWNvZGUodHJhbnNhY3Rpb25SZXN1bHQpKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoYEZhaWxlZCB0byBwcm9jZXNzIHJlc3VsdDogJHtlfWApO1xuICAgIH1cblxuICAgIGNvbnN0IHBhcnNlUmVjb3JkID0gKHJlY29yZDogUmVjb3JkPGFueSwgYW55PikgPT4ge1xuICAgICAgaWYgKE1vZGVsLmlzTW9kZWwocmVjb3JkKSkgcmV0dXJuIE1vZGVsLmJ1aWxkKHJlY29yZCk7XG4gICAgICByZXR1cm4gcmVjb3JkO1xuICAgIH07XG5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShyZXN1bHQpKSB7XG4gICAgICBpZiAoIXJlc3VsdC5sZW5ndGgpIHJldHVybiByZXN1bHQgYXMgVjtcbiAgICAgIGNvbnN0IGVsID0gcmVzdWx0WzBdO1xuICAgICAgaWYgKE1vZGVsLmlzTW9kZWwoZWwpKVxuICAgICAgICAvLyBpZiB0aGUgZmlyc3Qgb25lIGlzIGEgbW9kZWwsIGFsbCBhcmUgbW9kZWxzXG4gICAgICAgIHJldHVybiByZXN1bHQubWFwKChlbCkgPT4gTW9kZWwuYnVpbGQoZWwpKSBhcyBWO1xuICAgICAgcmV0dXJuIHJlc3VsdCBhcyBWO1xuICAgIH1cblxuICAgIHJldHVybiBwYXJzZVJlY29yZChyZXN1bHQgYXMgYW55KSBhcyBWO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFeGVjdXRlcyBhIENvdWNoREIgdmlldyBxdWVyeSBhZ2FpbnN0IHRoZSBGYWJyaWMgY2hhaW5jb2RlXG4gICAqIEBzdW1tYXJ5IEV2YWx1YXRlcyBhIHRyYW5zYWN0aW9uIHRvIHF1ZXJ5IGEgZGVzaWduIGRvY3VtZW50IHZpZXdcbiAgICogQHRlbXBsYXRlIFIgLSBUaGUgdmlldyByZXNwb25zZSB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBkZG9jIC0gRGVzaWduIGRvY3VtZW50IG5hbWVcbiAgICogQHBhcmFtIHtzdHJpbmd9IHZpZXdOYW1lIC0gVmlldyBuYW1lXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gb3B0aW9ucyAtIFZpZXcgcXVlcnkgb3B0aW9uc1xuICAgKiBAcGFyYW0gey4uLkNvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+Pn0gYXJncyAtIE9wdGlvbmFsIGNvbnRleHR1YWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Vmlld1Jlc3BvbnNlPFI+Pn0gVGhlIHZpZXcgcmVzcG9uc2VcbiAgICovXG4gIEBkZWJ1ZygpXG4gIGFzeW5jIHZpZXc8Uj4oXG4gICAgZGRvYzogc3RyaW5nLFxuICAgIHZpZXdOYW1lOiBzdHJpbmcsXG4gICAgb3B0aW9uczogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPj5cbiAgKTogUHJvbWlzZTxWaWV3UmVzcG9uc2U8Uj4+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnZpZXcpO1xuICAgIGxvZy5pbmZvKGBRdWVyeWluZyB2aWV3ICR7ZGRvY30vJHt2aWV3TmFtZX1gKTtcbiAgICBsZXQgdHJhbnNhY3Rpb25SZXN1bHQ6IGFueTtcbiAgICB0cnkge1xuICAgICAgdHJhbnNhY3Rpb25SZXN1bHQgPSBhd2FpdCB0aGlzLmV2YWx1YXRlVHJhbnNhY3Rpb24oXG4gICAgICAgIGN0eCxcbiAgICAgICAgXCJ2aWV3XCIsXG4gICAgICAgIFtkZG9jLCB2aWV3TmFtZSwgSlNPTi5zdHJpbmdpZnkob3B0aW9ucyldLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgdW5kZWZpbmVkXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gICAgbGV0IHJlc3VsdDogVmlld1Jlc3BvbnNlPFI+O1xuICAgIHRyeSB7XG4gICAgICByZXN1bHQgPSBKU09OLnBhcnNlKHRoaXMuZGVjb2RlKHRyYW5zYWN0aW9uUmVzdWx0KSk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aHJvdyBuZXcgU2VyaWFsaXphdGlvbkVycm9yKGBGYWlsZWQgdG8gcHJvY2VzcyB2aWV3IHJlc3VsdDogJHtlfWApO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIG9yIGNyZWF0ZXMgYSBnUlBDIGNsaWVudCBmb3IgdGhlIEZhYnJpYyBwZWVyXG4gICAqIEBzdW1tYXJ5IFJldHVybnMgYSBjYWNoZWQgY2xpZW50IG9yIGNyZWF0ZXMgYSBuZXcgb25lIGlmIG5vbmUgZXhpc3RzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Q2xpZW50Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGdSUEMgY2xpZW50XG4gICAqL1xuICBvdmVycmlkZSBnZXRDbGllbnQoKTogQ2xpZW50IHtcbiAgICBpZiAoIXRoaXMuX2NsaWVudClcbiAgICAgIHRoaXMuX2NsaWVudCA9IEZhYnJpY0NsaWVudEFkYXB0ZXIuZ2V0Q2xpZW50KHRoaXMuY29uZmlnKTtcbiAgICByZXR1cm4gdGhpcy5fY2xpZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIGEgR2F0ZXdheSBpbnN0YW5jZSBmb3IgdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBuZXcgR2F0ZXdheSBpbnN0YW5jZSB1c2luZyB0aGUgY3VycmVudCBjbGllbnRcbiAgICogQHJldHVybiB7UHJvbWlzZTxHYXRld2F5Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEdhdGV3YXkgaW5zdGFuY2VcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBHYXRld2F5KGN0eDogQ29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4pOiBQcm9taXNlPEdhdGV3YXk+IHtcbiAgICByZXR1cm4gRmFicmljQ2xpZW50QWRhcHRlci5nZXRHYXRld2F5KGN0eCwgdGhpcy5jb25maWcsIHRoaXMuY2xpZW50KTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0Q29udHJhY3ROYW1lKGNsYXNzTmFtZT86IHN0cmluZykge1xuICAgIGlmICghY2xhc3NOYW1lKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIHJldHVybiBgJHtjbGFzc05hbWV9Q29udHJhY3RgO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIGEgQ29udHJhY3QgaW5zdGFuY2UgZm9yIHRoZSBGYWJyaWMgY2hhaW5jb2RlXG4gICAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBuZXcgQ29udHJhY3QgaW5zdGFuY2UgdXNpbmcgdGhlIGN1cnJlbnQgR2F0ZXdheVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPENvbnRyYWt0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIENvbnRyYWN0IGluc3RhbmNlXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgQ29udHJhY3QoXG4gICAgY3R4OiBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPixcbiAgICBjb250cmFjdE5hbWU/OiBzdHJpbmdcbiAgKTogUHJvbWlzZTxDb250cmFrdD4ge1xuICAgIHJldHVybiBGYWJyaWNDbGllbnRBZGFwdGVyLmdldENvbnRyYWN0KFxuICAgICAgYXdhaXQgdGhpcy5HYXRld2F5KGN0eCksXG4gICAgICB0aGlzLmNvbmZpZyxcbiAgICAgIGNvbnRyYWN0TmFtZVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgdHJhbnNhY3Rpb24gb24gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IFN1Ym1pdHMgb3IgZXZhbHVhdGVzIGEgdHJhbnNhY3Rpb24gb24gdGhlIEZhYnJpYyBjaGFpbmNvZGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFwaSAtIFRoZSBjaGFpbmNvZGUgZnVuY3Rpb24gdG8gY2FsbFxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN1Ym1pdCAtIFdoZXRoZXIgdG8gc3VibWl0ICh0cnVlKSBvciBldmFsdWF0ZSAoZmFsc2UpIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge2FueVtdfSBbYXJnc10gLSBBcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgY2hhaW5jb2RlIGZ1bmN0aW9uXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgc3RyaW5nPn0gW3RyYW5zaWVudERhdGFdIC0gVHJhbnNpZW50IGRhdGEgZm9yIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IFtlbmRvcnNpbmdPcmdhbml6YXRpb25zXSAtIE9yZ2FuaXphdGlvbnMgdGhhdCBtdXN0IGVuZG9yc2UgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8VWludDhBcnJheT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB0cmFuc2FjdGlvbiByZXN1bHRcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgRmFicmljQWRhcHRlclxuICAgKiAgIHBhcnRpY2lwYW50IEdhdGV3YXlcbiAgICogICBwYXJ0aWNpcGFudCBDb250cmFjdFxuICAgKiAgIHBhcnRpY2lwYW50IENoYWluY29kZVxuICAgKlxuICAgKiAgIEZhYnJpY0FkYXB0ZXItPj5HYXRld2F5OiBjb25uZWN0KClcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+Q29udHJhY3Q6IGdldENvbnRyYWN0KClcbiAgICogICBhbHQgc3VibWl0IHRyYW5zYWN0aW9uXG4gICAqICAgICBGYWJyaWNBZGFwdGVyLT4+Q29udHJhY3Q6IHN1Ym1pdChhcGksIHByb3Bvc2FsT3B0aW9ucylcbiAgICogICBlbHNlIGV2YWx1YXRlIHRyYW5zYWN0aW9uXG4gICAqICAgICBGYWJyaWNBZGFwdGVyLT4+Q29udHJhY3Q6IGV2YWx1YXRlKGFwaSwgcHJvcG9zYWxPcHRpb25zKVxuICAgKiAgIGVuZFxuICAgKiAgIENvbnRyYWN0LT4+Q2hhaW5jb2RlOiBpbnZva2VcbiAgICogICBDaGFpbmNvZGUtLT4+Q29udHJhY3Q6IHJlc3BvbnNlXG4gICAqICAgQ29udHJhY3QtLT4+RmFicmljQWRhcHRlcjogcmVzdWx0XG4gICAqICAgRmFicmljQWRhcHRlci0+PkdhdGV3YXk6IGNsb3NlKClcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyB0cmFuc2FjdGlvbihcbiAgICBjdHg6IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+LFxuICAgIGFwaTogc3RyaW5nLFxuICAgIHN1Ym1pdCA9IHRydWUsXG4gICAgYXJncz86IGFueVtdLFxuICAgIHRyYW5zaWVudERhdGE/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICAgIGVuZG9yc2luZ09yZ2FuaXphdGlvbnM/OiBBcnJheTxzdHJpbmc+LFxuICAgIGNsYXNzTmFtZT86IHN0cmluZ1xuICApOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy50cmFuc2FjdGlvbik7XG4gICAgY29uc3QgZ2F0ZXdheSA9IGF3YWl0IHRoaXMuR2F0ZXdheShjdHgpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb250cmFjdCA9IGF3YWl0IHRoaXMuQ29udHJhY3QoXG4gICAgICAgIGN0eCxcbiAgICAgICAgdGhpcy5nZXRDb250cmFjdE5hbWUoY2xhc3NOYW1lKVxuICAgICAgKTtcbiAgICAgIGxvZy52ZXJib3NlKFxuICAgICAgICBgJHtzdWJtaXQgPyBcIlN1Ym1pdFwiIDogXCJFdmFsdWF0ZVwifXRpbmcgdHJhbnNhY3Rpb24gJHt0aGlzLmdldENvbnRyYWN0TmFtZShjbGFzc05hbWUpIHx8IHRoaXMuY29uZmlnLmNvbnRyYWN0TmFtZX0uJHthcGl9YFxuICAgICAgKTtcbiAgICAgIGxvZy5kZWJ1ZyhgYXJnczogJHthcmdzPy5tYXAoKGEpID0+IGEudG9TdHJpbmcoKSkuam9pbihcIlxcblwiKSB8fCBcIm5vbmVcIn1gKTtcbiAgICAgIGNvbnN0IG1ldGhvZCA9IHN1Ym1pdCA/IGNvbnRyYWN0LnN1Ym1pdCA6IGNvbnRyYWN0LmV2YWx1YXRlO1xuXG4gICAgICBlbmRvcnNpbmdPcmdhbml6YXRpb25zID0gZW5kb3JzaW5nT3JnYW5pemF0aW9ucz8ubGVuZ3RoXG4gICAgICAgID8gZW5kb3JzaW5nT3JnYW5pemF0aW9uc1xuICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IHByb3Bvc2FsT3B0aW9uczogUHJvcG9zYWxPcHRpb25zID0ge1xuICAgICAgICBhcmd1bWVudHM6IGFyZ3MgfHwgW10sXG4gICAgICAgIHRyYW5zaWVudERhdGE6IHRyYW5zaWVudERhdGEsXG4gICAgICAgIC8vIC4uLihlbmRvcnNpbmdPcmdhbml6YXRpb25zICYmIHsgZW5kb3JzaW5nT3JnYW5pemF0aW9ucyB9KSAvLyBtc3BJZCBsaXN0XG4gICAgICB9O1xuXG4gICAgICByZXR1cm4gYXdhaXQgbWV0aG9kLmNhbGwoY29udHJhY3QsIGFwaSwgcHJvcG9zYWxPcHRpb25zKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGlmIChlLmNvZGUgPT09IDEwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtlLmRldGFpbHNbMF0ubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5sb2cuZGVidWcoYENsb3NpbmcgJHt0aGlzLmNvbmZpZy5tc3BJZH0gZ2F0ZXdheSBjb25uZWN0aW9uYCk7XG4gICAgICBnYXRld2F5LmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQYXJzZXMgYW4gZXJyb3IgaW50byBhIEJhc2VFcnJvclxuICAgKiBAc3VtbWFyeSBDb252ZXJ0cyBhbnkgZXJyb3IgaW50byBhIHN0YW5kYXJkaXplZCBCYXNlRXJyb3JcbiAgICogQHBhcmFtIHtFcnJvciB8IHN0cmluZ30gZXJyIC0gVGhlIGVycm9yIHRvIHBhcnNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcmVhc29uXSAtIE9wdGlvbmFsIHJlYXNvbiBmb3IgdGhlIGVycm9yXG4gICAqIEByZXR1cm4ge0Jhc2VFcnJvcn0gVGhlIHBhcnNlZCBlcnJvclxuICAgKi9cbiAgb3ZlcnJpZGUgcGFyc2VFcnJvcjxFIGV4dGVuZHMgQmFzZUVycm9yPihlcnI6IEVycm9yIHwgc3RyaW5nKTogRSB7XG4gICAgcmV0dXJuIEZhYnJpY0NsaWVudEFkYXB0ZXIucGFyc2VFcnJvcjxFPihlcnIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTdWJtaXRzIGEgdHJhbnNhY3Rpb24gdG8gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IEV4ZWN1dGVzIGEgdHJhbnNhY3Rpb24gdGhhdCBtb2RpZmllcyB0aGUgbGVkZ2VyIHN0YXRlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcGkgLSBUaGUgY2hhaW5jb2RlIGZ1bmN0aW9uIHRvIGNhbGxcbiAgICogQHBhcmFtIHthbnlbXX0gW2FyZ3NdIC0gQXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIGNoYWluY29kZSBmdW5jdGlvblxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHN0cmluZz59IFt0cmFuc2llbnREYXRhXSAtIFRyYW5zaWVudCBkYXRhIGZvciB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBbZW5kb3JzaW5nT3JnYW5pemF0aW9uc10gLSBPcmdhbml6YXRpb25zIHRoYXQgbXVzdCBlbmRvcnNlIHRoZSB0cmFuc2FjdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFVpbnQ4QXJyYXk+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdHJhbnNhY3Rpb24gcmVzdWx0XG4gICAqL1xuICBhc3luYyBzdWJtaXRUcmFuc2FjdGlvbihcbiAgICBjdHg6IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+LFxuICAgIGFwaTogc3RyaW5nLFxuICAgIGFyZ3M/OiBhbnlbXSxcbiAgICB0cmFuc2llbnREYXRhPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcbiAgICBlbmRvcnNpbmdPcmdhbml6YXRpb25zPzogQXJyYXk8c3RyaW5nPixcbiAgICBjbGFzc05hbWU/OiBzdHJpbmdcbiAgKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBhcGksXG4gICAgICB0cnVlLFxuICAgICAgYXJncyxcbiAgICAgIHRyYW5zaWVudERhdGEsXG4gICAgICBlbmRvcnNpbmdPcmdhbml6YXRpb25zLFxuICAgICAgY2xhc3NOYW1lXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRXZhbHVhdGVzIGEgdHJhbnNhY3Rpb24gb24gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IEV4ZWN1dGVzIGEgdHJhbnNhY3Rpb24gdGhhdCBkb2VzIG5vdCBtb2RpZnkgdGhlIGxlZGdlciBzdGF0ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXBpIC0gVGhlIGNoYWluY29kZSBmdW5jdGlvbiB0byBjYWxsXG4gICAqIEBwYXJhbSB7YW55W119IFthcmdzXSAtIEFyZ3VtZW50cyB0byBwYXNzIHRvIHRoZSBjaGFpbmNvZGUgZnVuY3Rpb25cbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+fSBbdHJhbnNpZW50RGF0YV0gLSBUcmFuc2llbnQgZGF0YSBmb3IgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nPn0gW2VuZG9yc2luZ09yZ2FuaXphdGlvbnNdIC0gT3JnYW5pemF0aW9ucyB0aGF0IG11c3QgZW5kb3JzZSB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxVaW50OEFycmF5Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRyYW5zYWN0aW9uIHJlc3VsdFxuICAgKi9cbiAgYXN5bmMgZXZhbHVhdGVUcmFuc2FjdGlvbihcbiAgICBjdHg6IENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+LFxuICAgIGFwaTogc3RyaW5nLFxuICAgIGFyZ3M/OiBhbnlbXSxcbiAgICB0cmFuc2llbnREYXRhPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcbiAgICBlbmRvcnNpbmdPcmdhbml6YXRpb25zPzogQXJyYXk8c3RyaW5nPixcbiAgICBjbGFzc05hbWU/OiBzdHJpbmdcbiAgKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNhY3Rpb24oXG4gICAgICBjdHgsXG4gICAgICBhcGksXG4gICAgICBmYWxzZSxcbiAgICAgIGFyZ3MsXG4gICAgICB0cmFuc2llbnREYXRhLFxuICAgICAgZW5kb3JzaW5nT3JnYW5pemF0aW9ucyxcbiAgICAgIGNsYXNzTmFtZVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENsb3NlcyB0aGUgY29ubmVjdGlvbiB0byB0aGUgRmFicmljIG5ldHdvcmtcbiAgICogQHN1bW1hcnkgQ2xvc2VzIHRoZSBnUlBDIGNsaWVudCBpZiBpdCBleGlzdHNcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGNsaWVudCBpcyBjbG9zZWRcbiAgICovXG4gIGFzeW5jIGNsb3NlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNsaWVudCkge1xuICAgICAgdGhpcy5sb2cudmVyYm9zZShgQ2xvc2luZyAke3RoaXMuY29uZmlnLm1zcElkfSBnYXRld2F5IGNsaWVudGApO1xuICAgICAgdGhpcy5jbGllbnQuY2xvc2UoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEdldHMgYSBDb250cmFjdCBpbnN0YW5jZSBmcm9tIGEgR2F0ZXdheVxuICAgKiBAc3VtbWFyeSBSZXRyaWV2ZXMgYSBjaGFpbmNvZGUgY29udHJhY3QgZnJvbSB0aGUgc3BlY2lmaWVkIG5ldHdvcmtcbiAgICogQHBhcmFtIHtHYXRld2F5fSBnYXRld2F5IC0gVGhlIEdhdGV3YXkgaW5zdGFuY2VcbiAgICogQHBhcmFtIHtQZWVyQ29uZmlnfSBjb25maWcgLSBUaGUgcGVlciBjb25maWd1cmF0aW9uXG4gICAqIEByZXR1cm4ge0NvbnRyYWt0fSBUaGUgQ29udHJhY3QgaW5zdGFuY2VcbiAgICovXG4gIHN0YXRpYyBnZXRDb250cmFjdChcbiAgICBnYXRld2F5OiBHYXRld2F5LFxuICAgIGNvbmZpZzogUGVlckNvbmZpZyxcbiAgICBjb250cmFjdE5hbWU/OiBzdHJpbmdcbiAgKTogQ29udHJha3Qge1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmdldENvbnRyYWN0KTtcbiAgICBjb25zdCBuZXR3b3JrID0gdGhpcy5nZXROZXR3b3JrKGdhdGV3YXksIGNvbmZpZy5jaGFubmVsKTtcbiAgICBsZXQgY29udHJhY3Q6IENvbnRyYWt0O1xuICAgIHRyeSB7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBSZXRyaWV2aW5nIGNoYWluY29kZSAke2NvbmZpZy5jaGFpbmNvZGVOYW1lfSBjb250cmFjdCAke2NvbnRyYWN0TmFtZSB8fCBjb25maWcuY29udHJhY3ROYW1lfSBmcm9tIG5ldHdvcmsgJHtjb25maWcuY2hhbm5lbH1gXG4gICAgICApO1xuICAgICAgY29udHJhY3ROYW1lID0gY29udHJhY3ROYW1lID8gY29udHJhY3ROYW1lIDogY29uZmlnLmNvbnRyYWN0TmFtZTtcbiAgICAgIGNvbnRyYWN0ID0gbmV0d29yay5nZXRDb250cmFjdChjb25maWcuY2hhaW5jb2RlTmFtZSwgY29udHJhY3ROYW1lKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlKTtcbiAgICB9XG4gICAgcmV0dXJuIGNvbnRyYWN0O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIGEgTmV0d29yayBpbnN0YW5jZSBmcm9tIGEgR2F0ZXdheVxuICAgKiBAc3VtbWFyeSBDb25uZWN0cyB0byBhIHNwZWNpZmljIGNoYW5uZWwgb24gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBwYXJhbSB7R2F0ZXdheX0gZ2F0ZXdheSAtIFRoZSBHYXRld2F5IGluc3RhbmNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjaGFubmVsTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjaGFubmVsIHRvIGNvbm5lY3QgdG9cbiAgICogQHJldHVybiB7TmV0d29ya30gVGhlIE5ldHdvcmsgaW5zdGFuY2VcbiAgICovXG4gIHN0YXRpYyBnZXROZXR3b3JrKGdhdGV3YXk6IEdhdGV3YXksIGNoYW5uZWxOYW1lOiBzdHJpbmcpOiBOZXR3b3JrIHtcbiAgICBjb25zdCBsb2cgPSBMb2dnaW5nLmZvcih0aGlzLmdldE5ldHdvcmspO1xuICAgIGxldCBuZXR3b3JrOiBOZXR3b3JrO1xuICAgIHRyeSB7XG4gICAgICBsb2cuZGVidWcoYENvbm5lY3RpbmcgdG8gY2hhbm5lbCAke2NoYW5uZWxOYW1lfWApO1xuICAgICAgbmV0d29yayA9IGdhdGV3YXkuZ2V0TmV0d29yayhjaGFubmVsTmFtZSk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldHdvcms7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEdldHMgYSBHYXRld2F5IGluc3RhbmNlIGZvciBjb25uZWN0aW5nIHRvIHRoZSBGYWJyaWMgbmV0d29ya1xuICAgKiBAc3VtbWFyeSBDcmVhdGVzIGEgR2F0ZXdheSB1c2luZyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgY2xpZW50XG4gICAqIEBwYXJhbSB7UGVlckNvbmZpZ30gY29uZmlnIC0gVGhlIHBlZXIgY29uZmlndXJhdGlvblxuICAgKiBAcGFyYW0ge0NsaWVudH0gW2NsaWVudF0gLSBPcHRpb25hbCBnUlBDIGNsaWVudCwgd2lsbCBiZSBjcmVhdGVkIGlmIG5vdCBwcm92aWRlZFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPEdhdGV3YXk+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgR2F0ZXdheSBpbnN0YW5jZVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGdldEdhdGV3YXkoXG4gICAgY3R4OiBDb250ZXh0PEZhYnJpY0NsaWVudEZsYWdzPixcbiAgICBjb25maWc6IFBlZXJDb25maWcsXG4gICAgY2xpZW50PzogQ2xpZW50XG4gICkge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5nZXRDb25uZWN0aW9uKFxuICAgICAgY2xpZW50IHx8IChhd2FpdCB0aGlzLmdldENsaWVudChjb25maWcpKSxcbiAgICAgIGNvbmZpZyxcbiAgICAgIGN0eFxuICAgICkpIGFzIEdhdGV3YXk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBnUlBDIGNsaWVudCBmb3IgY29ubmVjdGluZyB0byBhIEZhYnJpYyBwZWVyXG4gICAqIEBzdW1tYXJ5IEluaXRpYWxpemVzIGEgY2xpZW50IHdpdGggVExTIGNyZWRlbnRpYWxzIGZvciBzZWN1cmUgY29tbXVuaWNhdGlvblxuICAgKiBAcGFyYW0ge1BlZXJDb25maWd9IGNvbmZpZyAtIFRoZSBwZWVyIGNvbmZpZ3VyYXRpb25cbiAgICogQHJldHVybiB7Q2xpZW50fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZ1JQQyBjbGllbnRcbiAgICovXG4gIHN0YXRpYyBnZXRDbGllbnQoY29uZmlnOiBQZWVyQ29uZmlnKTogQ2xpZW50IHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5nZXRDbGllbnQpO1xuICAgIGxvZy5kZWJ1ZyhgZ2VuZXJhdGluZyBUTFMgY3JlZGVudGlhbHMgZm9yIG1zcCAke2NvbmZpZy5tc3BJZH1gKTtcbiAgICBsZXQgcGF0aE9yQ2VydDogc3RyaW5nIHwgQnVmZmVyID0gY29uZmlnLnRsc0NlcnQgYXMgc3RyaW5nIHwgQnVmZmVyO1xuXG4gICAgaWYgKHR5cGVvZiBwYXRoT3JDZXJ0ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBpZiAoXG4gICAgICAgIHBhdGhPckNlcnQubWF0Y2goXG4gICAgICAgICAgLy0tLS0tQkVHSU4gKENFUlRJRklDQVRFfEtFWXxQUklWQVRFIEtFWSktLS0tLS4rPy0tLS0tRU5EIFxcMS0tLS0tJC9nbXNcbiAgICAgICAgKVxuICAgICAgKSB7XG4gICAgICAgIHBhdGhPckNlcnQgPSBCdWZmZXIuZnJvbShwYXRoT3JDZXJ0LCBcInV0ZjhcIik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHBhdGhPckNlcnQgPSBCdWZmZXIuZnJvbShmcy5yZWFkRmlsZVN5bmMocGF0aE9yQ2VydCwgXCJ1dGY4XCIpKTtcbiAgICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgYEZhaWxlZCB0byByZWFkIHRoZSB0bHMgY2VydGlmaWNhdGUgZnJvbSAke3BhdGhPckNlcnR9OiAke2V9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCB0bHNDcmVkZW50aWFscyA9IGdycGMuY3JlZGVudGlhbHMuY3JlYXRlU3NsKHBhdGhPckNlcnQpO1xuICAgIGxvZy5kZWJ1ZyhgZ2VuZXJhdGluZyBHYXRld2F5IENsaWVudCBmb3IgdXJsICR7Y29uZmlnLnBlZXJFbmRwb2ludH1gKTtcbiAgICByZXR1cm4gbmV3IENsaWVudChjb25maWcucGVlckVuZHBvaW50LCB0bHNDcmVkZW50aWFscywge1xuICAgICAgXCJncnBjLm1heF9yZWNlaXZlX21lc3NhZ2VfbGVuZ3RoXCI6IChjb25maWcuc2l6ZUxpbWl0IHx8IDE1KSAqIDEwMjQgKiAxMDI0LFxuICAgICAgXCJncnBjLm1heF9zZW5kX21lc3NhZ2VfbGVuZ3RoXCI6IChjb25maWcuc2l6ZUxpbWl0IHx8IDE1KSAqIDEwMjQgKiAxMDI0LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFc3RhYmxpc2hlcyBhIGNvbm5lY3Rpb24gdG8gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBHYXRld2F5IGNvbm5lY3Rpb24gd2l0aCBpZGVudGl0eSBhbmQgc2lnbmVyXG4gICAqIEBwYXJhbSB7Q2xpZW50fSBjbGllbnQgLSBUaGUgZ1JQQyBjbGllbnRcbiAgICogQHBhcmFtIHtQZWVyQ29uZmlnfSBjb25maWcgLSBUaGUgcGVlciBjb25maWd1cmF0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8R2F0ZXdheT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBjb25uZWN0ZWQgR2F0ZXdheVxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAgICogICBwYXJ0aWNpcGFudCBGYWJyaWNBZGFwdGVyXG4gICAqICAgcGFydGljaXBhbnQgSWRlbnRpdHlcbiAgICogICBwYXJ0aWNpcGFudCBTaWduZXJcbiAgICogICBwYXJ0aWNpcGFudCBHYXRld2F5XG4gICAqXG4gICAqICAgQ2FsbGVyLT4+RmFicmljQWRhcHRlcjogZ2V0Q29ubmVjdGlvbihjbGllbnQsIGNvbmZpZylcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+SWRlbnRpdHk6IGdldElkZW50aXR5KG1zcElkLCBjZXJ0RGlyZWN0b3J5UGF0aClcbiAgICogICBJZGVudGl0eS0tPj5GYWJyaWNBZGFwdGVyOiBpZGVudGl0eVxuICAgKiAgIEZhYnJpY0FkYXB0ZXItPj5TaWduZXI6IGdldFNpZ25lcihrZXlEaXJlY3RvcnlQYXRoKVxuICAgKiAgIFNpZ25lci0tPj5GYWJyaWNBZGFwdGVyOiBzaWduZXJcbiAgICogICBGYWJyaWNBZGFwdGVyLT4+RmFicmljQWRhcHRlcjogQ3JlYXRlIENvbm5lY3RPcHRpb25zXG4gICAqICAgRmFicmljQWRhcHRlci0+PkdhdGV3YXk6IGNvbm5lY3Qob3B0aW9ucylcbiAgICogICBHYXRld2F5LS0+PkZhYnJpY0FkYXB0ZXI6IGdhdGV3YXlcbiAgICogICBGYWJyaWNBZGFwdGVyLS0+PkNhbGxlcjogZ2F0ZXdheVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGdldENvbm5lY3Rpb24oXG4gICAgY2xpZW50OiBDbGllbnQsXG4gICAgY29uZmlnOiBQZWVyQ29uZmlnLFxuICAgIGN0eDogQ29udGV4dDxGYWJyaWNDbGllbnRGbGFncz5cbiAgKSB7XG4gICAgY29uc3QgbG9nID0gTG9nZ2luZy5mb3IodGhpcy5nZXRDb25uZWN0aW9uKTtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgUmV0cmlldmluZyBQZWVyIElkZW50aXR5IGZvciAke2NvbmZpZy5tc3BJZH0gdW5kZXIgJHtjb25maWcuY2VydENlcnRPckRpcmVjdG9yeVBhdGh9YFxuICAgICk7XG4gICAgY29uc3QgaWRlbnRpdHkgPSBhd2FpdCBnZXRJZGVudGl0eShcbiAgICAgIGNvbmZpZy5tc3BJZCxcbiAgICAgIGNvbmZpZy5jZXJ0Q2VydE9yRGlyZWN0b3J5UGF0aCBhcyBhbnlcbiAgICApO1xuICAgIGxvZy5kZWJ1ZyhgUmV0cmlldmluZyBzaWduZXIga2V5IGZyb20gJHtjb25maWcua2V5Q2VydE9yRGlyZWN0b3J5UGF0aH1gKTtcblxuICAgIGxldCBzaWduZXI6IFNpZ25lcixcbiAgICAgIGNsb3NlID0gKCkgPT4ge307XG4gICAgaWYgKCFjb25maWcuaHNtKSB7XG4gICAgICBzaWduZXIgPSBhd2FpdCBnZXRTaWduZXIoY29uZmlnLmtleUNlcnRPckRpcmVjdG9yeVBhdGggYXMgYW55KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgaHNtID0gbmV3IEhTTVNpZ25lckZhY3RvcnlDdXN0b20oY29uZmlnLmhzbS5saWJyYXJ5KTtcbiAgICAgIGNvbnN0IGlkZW50aWZpZXIgPSBoc20uZ2V0U0tJRnJvbUNlcnRpZmljYXRlUGF0aChcbiAgICAgICAgY29uZmlnLmNlcnRDZXJ0T3JEaXJlY3RvcnlQYXRoIGFzIGFueVxuICAgICAgKTtcbiAgICAgIGNvbnN0IHBrY3MxMVNpZ25lciA9IGhzbS5uZXdTaWduZXIoe1xuICAgICAgICBsYWJlbDogY29uZmlnLmhzbS50b2tlbkxhYmVsIGFzIHN0cmluZyxcbiAgICAgICAgcGluOiBTdHJpbmcoY29uZmlnLmhzbS5waW4pIGFzIHN0cmluZyxcbiAgICAgICAgaWRlbnRpZmllcjogaWRlbnRpZmllcixcbiAgICAgICAgLy8gdXNlclR5cGU6IDEgLypDS1VfVVNFUiAqLyxcbiAgICAgIH0pO1xuICAgICAgc2lnbmVyID0gcGtjczExU2lnbmVyLnNpZ25lcjtcblxuICAgICAgY2xvc2UgPSBwa2NzMTFTaWduZXIuY2xvc2U7XG4gICAgfVxuXG4gICAgY29uc3Qgb3B0aW9ucyA9IHtcbiAgICAgIGNsaWVudCxcbiAgICAgIGlkZW50aXR5OiBpZGVudGl0eSxcbiAgICAgIHNpZ25lcjogc2lnbmVyLFxuICAgICAgLy8gRGVmYXVsdCB0aW1lb3V0cyBmb3IgZGlmZmVyZW50IGdSUEMgY2FsbHNcbiAgICAgIGV2YWx1YXRlT3B0aW9uczogKCkgPT4ge1xuICAgICAgICByZXR1cm4geyBkZWFkbGluZTogRGF0ZS5ub3coKSArIDEwMDAgKiBjdHguZ2V0KFwiZXZhbHVhdGVUaW1lb3V0XCIpIH07IC8vIGRlZmF1bHRzIHRvIDUgc2Vjb25kc1xuICAgICAgfSxcbiAgICAgIGVuZG9yc2VPcHRpb25zOiAoKSA9PiB7XG4gICAgICAgIHJldHVybiB7IGRlYWRsaW5lOiBEYXRlLm5vdygpICsgMTAwMCAqIGN0eC5nZXQoXCJlbmRvcnNlVGltZW91dFwiKSB9OyAvLyBkZWZhdWx0cyB0byAxNSBzZWNvbmRzXG4gICAgICB9LFxuICAgICAgc3VibWl0T3B0aW9uczogKCkgPT4ge1xuICAgICAgICByZXR1cm4geyBkZWFkbGluZTogRGF0ZS5ub3coKSArIDEwMDAgKiBjdHguZ2V0KFwic3VibWl0VGltZW91dFwiKSB9OyAvLyBkZWZhdWx0cyB0byA1IHNlY29uZHNcbiAgICAgIH0sXG4gICAgICBjb21taXRTdGF0dXNPcHRpb25zOiAoKSA9PiB7XG4gICAgICAgIHJldHVybiB7IGRlYWRsaW5lOiBEYXRlLm5vdygpICsgMTAwMCAqIGN0eC5nZXQoXCJjb21taXRUaW1lb3V0XCIpIH07IC8vIGRlZmF1bHRzIHRvIDEgbWludXRlXG4gICAgICB9LFxuICAgIH0gYXMgQ29ubmVjdE9wdGlvbnM7XG5cbiAgICBsb2cuZGVidWcoYENvbm5lY3RpbmcgdG8gJHtjb25maWcubXNwSWR9YCk7XG4gICAgY29uc3QgZ2F0ZXdheSA9IGNvbm5lY3Qob3B0aW9ucyk7XG5cbiAgICAvLyBUT0RPOiByZXBsYWNlP1xuICAgIGlmIChjb25maWcuaHNtKSB7XG4gICAgICBnYXRld2F5LmNsb3NlID0gbmV3IFByb3h5KGdhdGV3YXkuY2xvc2UsIHtcbiAgICAgICAgYXBwbHkodGFyZ2V0OiAoKSA9PiB2b2lkLCB0aGlzQXJnOiBhbnksIGFyZ0FycmF5OiBhbnlbXSk6IGFueSB7XG4gICAgICAgICAgUmVmbGVjdC5hcHBseSh0YXJnZXQsIHRoaXNBcmcsIGFyZ0FycmF5KTtcbiAgICAgICAgICBjbG9zZSgpO1xuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGdhdGV3YXk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgRGlzcGF0Y2ggaW5zdGFuY2UgZm9yIHRoZSBGYWJyaWMgY2xpZW50LlxuICAgKiBAc3VtbWFyeSBUaGlzIGZ1bmN0aW9uIGlzIHJlc3BvbnNpYmxlIGZvciBjcmVhdGluZyBhIG5ldyBGYWJyaWNDbGllbnREaXNwYXRjaCBpbnN0YW5jZSB0aGF0IGNhbiBiZSB1c2VkIHRvIGludGVyYWN0IHdpdGggdGhlIEZhYnJpYyBuZXR3b3JrLlxuICAgKiBAcmV0dXJucyB7RGlzcGF0Y2h9IEEgbmV3IERpc3BhdGNoIGluc3RhbmNlIGNvbmZpZ3VyZWQgZm9yIHRoZSBGYWJyaWMgY2xpZW50LlxuICAgKiBAcmVtYXJrcyBUaGUgRGlzcGF0Y2ggaW5zdGFuY2UgaXMgdXNlZCB0byBlbmNhcHN1bGF0ZSB0aGUgbG9naWMgZm9yIGludGVyYWN0aW5nIHdpdGggdGhlIEZhYnJpYyBuZXR3b3JrLCBzdWNoIGFzIHN1Ym1pdHRpbmcgdHJhbnNhY3Rpb25zIG9yIHF1ZXJ5aW5nIGRhdGEuXG4gICAqIEBleGFtcGxlXG4gICAqIGNvbnN0IGZhYnJpY0Rpc3BhdGNoID0gZmFicmljQ2xpZW50QWRhcHRlci5EaXNwYXRjaCgpO1xuICAgKiBmYWJyaWNEaXNwYXRjaC5zdWJtaXRUcmFuc2FjdGlvbignY3JlYXRlUHJvZHVjdCcsIHsgbmFtZTogJ1Byb2R1Y3QgQScsIHByaWNlOiAxMDAgfSk7XG4gICAqL1xuICBvdmVycmlkZSBEaXNwYXRjaCgpOiBGYWJyaWNDbGllbnREaXNwYXRjaCB7XG4gICAgcmV0dXJuIG5ldyBGYWJyaWNDbGllbnRBZGFwdGVyW1wiX2Jhc2VEaXNwYXRjaFwiXSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQYXJzZXMgYW4gZXJyb3IgaW50byBhIEJhc2VFcnJvclxuICAgKiBAc3VtbWFyeSBDb252ZXJ0cyBhbnkgZXJyb3IgaW50byBhIHN0YW5kYXJkaXplZCBCYXNlRXJyb3IgdXNpbmcgdGhlIHBhcmVudCBjbGFzcyBpbXBsZW1lbnRhdGlvblxuICAgKiBAcGFyYW0ge0Vycm9yIHwgc3RyaW5nfSBlcnIgLSBUaGUgZXJyb3IgdG8gcGFyc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtyZWFzb25dIC0gT3B0aW9uYWwgcmVhc29uIGZvciB0aGUgZXJyb3JcbiAgICogQHJldHVybiB7QmFzZUVycm9yfSBUaGUgcGFyc2VkIGVycm9yXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIHBhcnNlRXJyb3I8RSBleHRlbmRzIEJhc2VFcnJvcj4oZXJyOiBFcnJvciB8IHN0cmluZyk6IEUge1xuICAgIC8vIGlmIChcbiAgICAvLyAgIE1JU1NJTkdfUFJJVkFURV9EQVRBX1JFR0VYLnRlc3QoXG4gICAgLy8gICAgIHR5cGVvZiBlcnIgPT09IFwic3RyaW5nXCIgPyBlcnIgOiBlcnIubWVzc2FnZVxuICAgIC8vICAgKVxuICAgIC8vIClcbiAgICAvLyAgIHJldHVybiBuZXcgVW5hdXRob3JpemVkUHJpdmF0ZURhdGFBY2Nlc3MoZXJyKSBhcyBFO1xuICAgIGNvbnN0IG1zZyA9IHR5cGVvZiBlcnIgPT09IFwic3RyaW5nXCIgPyBlcnIgOiBlcnIubWVzc2FnZTtcblxuICAgIGlmIChtc2cuaW5jbHVkZXMoXCJNVkNDX1JFQURfQ09ORkxJQ1RcIikpXG4gICAgICByZXR1cm4gbmV3IE12Y2NSZWFkQ29uZmxpY3RFcnJvcihlcnIpIGFzIEU7XG5cbiAgICBpZiAobXNnLmluY2x1ZGVzKFwiRU5ET1JTRU1FTlRfUE9MSUNZX0ZBSUxVUkVcIikpXG4gICAgICByZXR1cm4gbmV3IEVuZG9yc2VtZW50UG9saWN5RXJyb3IoZXJyKSBhcyBFO1xuXG4gICAgaWYgKG1zZy5pbmNsdWRlcyhcIlBIQU5UT01fUkVBRF9DT05GTElDVFwiKSlcbiAgICAgIHJldHVybiBuZXcgUGhhbnRvbVJlYWRDb25mbGljdEVycm9yKGVycikgYXMgRTtcblxuICAgIGlmIChlcnIgaW5zdGFuY2VvZiBFcnJvciAmJiAoZXJyIGFzIGFueSkuY29kZSkge1xuICAgICAgc3dpdGNoICgoZXJyIGFzIGFueSkuY29kZSkge1xuICAgICAgICBjYXNlIDk6XG4gICAgICAgICAgcmV0dXJuIG5ldyBFbmRvcnNlbWVudEVycm9yKGVycikgYXMgRTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAobXNnLmluY2x1ZGVzKE5vdEZvdW5kRXJyb3IubmFtZSkpIHJldHVybiBuZXcgTm90Rm91bmRFcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhDb25mbGljdEVycm9yLm5hbWUpKSByZXR1cm4gbmV3IENvbmZsaWN0RXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoQmFkUmVxdWVzdEVycm9yLm5hbWUpKVxuICAgICAgcmV0dXJuIG5ldyBCYWRSZXF1ZXN0RXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoUXVlcnlFcnJvci5uYW1lKSkgcmV0dXJuIG5ldyBRdWVyeUVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKFBhZ2luZ0Vycm9yLm5hbWUpKSByZXR1cm4gbmV3IFBhZ2luZ0Vycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKFVuc3VwcG9ydGVkRXJyb3IubmFtZSkpXG4gICAgICByZXR1cm4gbmV3IFVuc3VwcG9ydGVkRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoTWlncmF0aW9uRXJyb3IubmFtZSkpIHJldHVybiBuZXcgTWlncmF0aW9uRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoT2JzZXJ2ZXJFcnJvci5uYW1lKSkgcmV0dXJuIG5ldyBPYnNlcnZlckVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKEF1dGhvcml6YXRpb25FcnJvci5uYW1lKSlcbiAgICAgIHJldHVybiBuZXcgQXV0aG9yaXphdGlvbkVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKEZvcmJpZGRlbkVycm9yLm5hbWUpKSByZXR1cm4gbmV3IEZvcmJpZGRlbkVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKENvbm5lY3Rpb25FcnJvci5uYW1lKSlcbiAgICAgIHJldHVybiBuZXcgQ29ubmVjdGlvbkVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKFNlcmlhbGl6YXRpb25FcnJvci5uYW1lKSlcbiAgICAgIHJldHVybiBuZXcgU2VyaWFsaXphdGlvbkVycm9yKGVycikgYXMgRTtcbiAgICByZXR1cm4gbmV3IEludGVybmFsRXJyb3IoZXJyKSBhcyBFO1xuICB9XG59XG5cbkZhYnJpY0NsaWVudEFkYXB0ZXIuZGVjb3JhdGlvbigpO1xuQWRhcHRlci5zZXRDdXJyZW50KEZhYnJpY0ZsYXZvdXIpO1xuIiwiaW1wb3J0IHtcbiAgQWRhcHRlcixcbiAgQ29udGV4dHVhbEFyZ3MsXG4gIERpc3BhdGNoLFxuICBFdmVudElkcyxcbiAgVW5zdXBwb3J0ZWRFcnJvcixcbiAgQ29udGV4dCxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBQZWVyQ29uZmlnIH0gZnJvbSBcIi4uL3NoYXJlZC90eXBlc1wiO1xuaW1wb3J0IHsgQ2xpZW50IH0gZnJvbSBcIkBncnBjL2dycGMtanNcIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudEFkYXB0ZXIgfSBmcm9tIFwiLi9GYWJyaWNDbGllbnRBZGFwdGVyXCI7XG5pbXBvcnQge1xuICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMsXG4gIEludGVybmFsRXJyb3IsXG4gIE9wZXJhdGlvbktleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHtcbiAgQ2hhaW5jb2RlRXZlbnQsXG4gIENsb3NlYWJsZUFzeW5jSXRlcmFibGUsXG59IGZyb20gXCJAaHlwZXJsZWRnZXIvZmFicmljLWdhdGV3YXlcIjtcbmltcG9ydCB7IHBhcnNlRXZlbnROYW1lIH0gZnJvbSBcIi4uL3NoYXJlZC9ldmVudHNcIjtcbmltcG9ydCB7IE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0NsaWVudEZsYWdzIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRXZlbnQgZGlzcGF0Y2hlciBmb3IgSHlwZXJsZWRnZXIgRmFicmljIGNoYWluY29kZSBldmVudHNcbiAqIEBzdW1tYXJ5IExpc3RlbnMgZm9yIGFuZCBwcm9jZXNzZXMgZXZlbnRzIGVtaXR0ZWQgYnkgRmFicmljIGNoYWluY29kZSwgZGlzcGF0Y2hpbmcgdGhlbSB0byByZWdpc3RlcmVkIG9ic2VydmVyc1xuICogQHRlbXBsYXRlIFBlZXJDb25maWcgLSBDb25maWd1cmF0aW9uIHR5cGUgZm9yIGNvbm5lY3RpbmcgdG8gYSBGYWJyaWMgcGVlclxuICogQHBhcmFtIGNsaWVudCAtIGdSUEMgY2xpZW50IGZvciBjb25uZWN0aW5nIHRvIHRoZSBGYWJyaWMgbmV0d29ya1xuICogQGNsYXNzIEZhYnJpY0NsaWVudERpc3BhdGNoXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gQ3JlYXRlIGEgbmV3IEZhYnJpY0Rpc3BhdGNoIGluc3RhbmNlXG4gKiBjb25zdCBjbGllbnQgPSBhd2FpdCBGYWJyaWNBZGFwdGVyLmdldENsaWVudChwZWVyQ29uZmlnKTtcbiAqIGNvbnN0IGRpc3BhdGNoID0gbmV3IEZhYnJpY0Rpc3BhdGNoKGNsaWVudCk7XG4gKlxuICogLy8gQ29uZmlndXJlIHRoZSBkaXNwYXRjaCB3aXRoIHBlZXIgY29uZmlndXJhdGlvblxuICogZGlzcGF0Y2guY29uZmlndXJlKHBlZXJDb25maWcpO1xuICpcbiAqIC8vIFJlZ2lzdGVyIGFuIG9ic2VydmVyIGZvciBhIHNwZWNpZmljIHRhYmxlIGFuZCBldmVudFxuICogZGlzcGF0Y2gub2JzZXJ2ZSgndXNlcnMnLCAnY3JlYXRlJywgKGlkKSA9PiB7XG4gKiAgIGNvbnNvbGUubG9nKGBVc2VyIGNyZWF0ZWQ6ICR7aWR9YCk7XG4gKiB9KTtcbiAqXG4gKiAvLyBTdGFydCBsaXN0ZW5pbmcgZm9yIGV2ZW50c1xuICogYXdhaXQgZGlzcGF0Y2guc3RhcnQoKTtcbiAqIGBgYFxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgRmFicmljRGlzcGF0Y2hcbiAqICAgcGFydGljaXBhbnQgR2F0ZXdheVxuICogICBwYXJ0aWNpcGFudCBOZXR3b3JrXG4gKiAgIHBhcnRpY2lwYW50IENoYWluY29kZVxuICpcbiAqICAgQ2xpZW50LT4+RmFicmljRGlzcGF0Y2g6IG5ldyBGYWJyaWNEaXNwYXRjaChjbGllbnQpXG4gKiAgIENsaWVudC0+PkZhYnJpY0Rpc3BhdGNoOiBjb25maWd1cmUocGVlckNvbmZpZylcbiAqICAgQ2xpZW50LT4+RmFicmljRGlzcGF0Y2g6IG9ic2VydmUodGFibGUsIGV2ZW50LCBjYWxsYmFjaylcbiAqICAgQ2xpZW50LT4+RmFicmljRGlzcGF0Y2g6IHN0YXJ0KClcbiAqICAgRmFicmljRGlzcGF0Y2gtPj5GYWJyaWNEaXNwYXRjaDogaW5pdGlhbGl6ZSgpXG4gKiAgIEZhYnJpY0Rpc3BhdGNoLT4+R2F0ZXdheTogZ2V0R2F0ZXdheShjb25maWcsIGNsaWVudClcbiAqICAgR2F0ZXdheS0+Pk5ldHdvcms6IGdldE5ldHdvcmsoY2hhbm5lbClcbiAqICAgTmV0d29yay0+Pk5ldHdvcms6IGdldENoYWluY29kZUV2ZW50cyhjaGFpbmNvZGVOYW1lKVxuICogICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiBoYW5kbGVFdmVudHMoKVxuICogICBsb29wIEZvciBlYWNoIGV2ZW50XG4gKiAgICAgQ2hhaW5jb2RlLS0+PkZhYnJpY0Rpc3BhdGNoOiBDaGFpbmNvZGVFdmVudFxuICogICAgIEZhYnJpY0Rpc3BhdGNoLT4+RmFicmljRGlzcGF0Y2g6IHBhcnNlRXZlbnROYW1lKGV2ZW50TmFtZSlcbiAqICAgICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiBwYXJzZVBheWxvYWQocGF5bG9hZClcbiAqICAgICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiB1cGRhdGVPYnNlcnZlcnModGFibGUsIGV2ZW50LCBpZClcbiAqICAgICBGYWJyaWNEaXNwYXRjaC0tPj5DbGllbnQ6IGNhbGxiYWNrKGlkKVxuICogICBlbmRcbiAqL1xuZXhwb3J0IGNsYXNzIEZhYnJpY0NsaWVudERpc3BhdGNoIGV4dGVuZHMgRGlzcGF0Y2g8RmFicmljQ2xpZW50QWRhcHRlcj4ge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV2ZW50IGxpc3RlbmluZyBzdGFjayBmb3IgY2hhaW5jb2RlIGV2ZW50c1xuICAgKi9cbiAgcHJpdmF0ZSBsaXN0ZW5pbmdTdGFjaz86IENsb3NlYWJsZUFzeW5jSXRlcmFibGU8Q2hhaW5jb2RlRXZlbnQ+O1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGV4dCBkZWNvZGVyIGZvciBjb252ZXJ0aW5nIGV2ZW50IHBheWxvYWRzIGZyb20gYnl0ZXMgdG8gc3RyaW5nc1xuICAgKi9cbiAgcHJpdmF0ZSBkZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKFwidXRmOFwiKTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgRmFicmljRGlzcGF0Y2ggaW5zdGFuY2VcbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYSBkaXNwYXRjaGVyIGZvciBGYWJyaWMgY2hhaW5jb2RlIGV2ZW50c1xuICAgKiBAcGFyYW0ge0NsaWVudH0gY2xpZW50IC0gZ1JQQyBjbGllbnQgZm9yIGNvbm5lY3RpbmcgdG8gdGhlIEZhYnJpYyBuZXR3b3JrXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgY2xpZW50OiBDbGllbnQpIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDbG9zZXMgdGhlIGV2ZW50IGxpc3RlbmluZyBjb25uZWN0aW9uXG4gICAqIEBzdW1tYXJ5IFN0b3BzIGxpc3RlbmluZyBmb3IgY2hhaW5jb2RlIGV2ZW50cyBhbmQgcmVsZWFzZXMgcmVzb3VyY2VzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZFxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgY2xvc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMubGlzdGVuaW5nU3RhY2spIHRoaXMubGlzdGVuaW5nU3RhY2suY2xvc2UoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUGFyc2VzIGV2ZW50IHBheWxvYWQgZnJvbSBiaW5hcnkgZm9ybWF0XG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIGEgVWludDhBcnJheSBjb250YWluaW5nIEpTT04gdG8gYW4gb2JqZWN0IHdpdGggYW4gaWQgcHJvcGVydHlcbiAgICogQHBhcmFtIHtVaW50OEFycmF5fSBqc29uQnl0ZXMgLSBUaGUgYmluYXJ5IHBheWxvYWQgZnJvbSB0aGUgY2hhaW5jb2RlIGV2ZW50XG4gICAqIEByZXR1cm4ge3sgaWQ6IHN0cmluZyB9fSBUaGUgcGFyc2VkIHBheWxvYWQgY29udGFpbmluZyB0aGUgcmVjb3JkIElEXG4gICAqL1xuICBwcml2YXRlIHBhcnNlUGF5bG9hZChqc29uQnl0ZXM6IFVpbnQ4QXJyYXkpOiB7IGlkOiBzdHJpbmcgfSB7XG4gICAgY29uc3QganNvbiA9IHRoaXMuZGVjb2Rlci5kZWNvZGUoanNvbkJ5dGVzKTtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShqc29uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU3RhcnRzIG9ic2VydmluZyBhbiBhZGFwdGVyXG4gICAqIEBzdW1tYXJ5IENvbm5lY3RzIHRoaXMgZGlzcGF0Y2ggdG8gYW4gYWRhcHRlciB0byBtb25pdG9yIGl0cyBvcGVyYXRpb25zXG4gICAqIEBwYXJhbSB7QWRhcHRlcjxhbnksIGFueSwgYW55LCBhbnk+fSBvYnNlcnZlciAtIFRoZSBhZGFwdGVyIHRvIG9ic2VydmVcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICovXG4gIG92ZXJyaWRlIG9ic2VydmUob2JzZXJ2ZXI6IEFkYXB0ZXI8YW55LCBhbnksIGFueSwgYW55Pik6ICgpID0+IHZvaWQge1xuICAgIGlmICghKG9ic2VydmVyIGluc3RhbmNlb2YgRmFicmljQ2xpZW50QWRhcHRlcikpXG4gICAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgICAgXCJPbmx5IEZhYnJpY0NsaWVudEFkYXB0ZXIgY2FuIGJlIG9ic2VydmVkIGJ5IGRpc3BhdGNoXCJcbiAgICAgICk7XG4gICAgc3VwZXIub2JzZXJ2ZShvYnNlcnZlciBhcyBGYWJyaWNDbGllbnRBZGFwdGVyKTtcbiAgICByZXR1cm4gKCkgPT4gdGhpcy51bk9ic2VydmUob2JzZXJ2ZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIG9ic2VydmVycyBhYm91dCBhIGRhdGFiYXNlIGV2ZW50XG4gICAqIEBzdW1tYXJ5IE5vdGlmaWVzIG9ic2VydmVycyBhYm91dCBhIGNoYW5nZSBpbiB0aGUgZGF0YWJhc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlIHdoZXJlIHRoZSBjaGFuZ2Ugb2NjdXJyZWRcbiAgICogQHBhcmFtIHtPcGVyYXRpb25LZXlzfEJ1bGtDcnVkT3BlcmF0aW9uS2V5c3xzdHJpbmd9IGV2ZW50IC0gVGhlIHR5cGUgb2Ygb3BlcmF0aW9uIHRoYXQgb2NjdXJyZWRcbiAgICogQHBhcmFtIHthbnl9IHBheWxvYWQgLSBUaGUgZXZlbnQgcGF5bG9hZFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBvYnNlcnZlcnMgaGF2ZSBiZWVuIG5vdGlmaWVkXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyB1cGRhdGVPYnNlcnZlcnMoXG4gICAgbW9kZWw6IENvbnN0cnVjdG9yPGFueT4gfCBzdHJpbmcsXG4gICAgZXZlbnQ6IE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmcsXG4gICAgaWQ6IEV2ZW50SWRzLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ2xpZW50RmxhZ3M+PlxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gQWRhcHRlci5sb2dDdHg8Q29udGV4dDxGYWJyaWNDbGllbnRGbGFncz4+KFxuICAgICAgdGhpcy51cGRhdGVPYnNlcnZlcnMsXG4gICAgICBldmVudCxcbiAgICAgIGZhbHNlLFxuICAgICAgLi4uYXJnc1xuICAgICk7XG4gICAgaWYgKCF0aGlzLmFkYXB0ZXIpIHtcbiAgICAgIGxvZy52ZXJib3NlKFxuICAgICAgICBgTm8gYWRhcHRlciBvYnNlcnZlZCBmb3IgZGlzcGF0Y2g7IHNraXBwaW5nIG9ic2VydmVyIHVwZGF0ZSBmb3IgJHt0eXBlb2YgbW9kZWwgPT09IFwic3RyaW5nXCIgPyBtb2RlbCA6IE1vZGVsLnRhYmxlTmFtZShtb2RlbCl9OiR7ZXZlbnR9YFxuICAgICAgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuYWRhcHRlci5yZWZyZXNoKG1vZGVsLCBldmVudCwgaWQsIC4uLmN0eEFyZ3MpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBGYWlsZWQgdG8gcmVmcmVzaCBkaXNwYXRjaDogJHtlfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJvY2Vzc2VzIGluY29taW5nIGNoYWluY29kZSBldmVudHNcbiAgICogQHN1bW1hcnkgTGlzdGVucyBmb3IgZXZlbnRzIGZyb20gdGhlIGNoYWluY29kZSBhbmQgZGlzcGF0Y2hlcyB0aGVtIHRvIHJlZ2lzdGVyZWQgb2JzZXJ2ZXJzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGV2ZW50IGhhbmRsaW5nIHN0b3BzXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEZhYnJpY0Rpc3BhdGNoXG4gICAqICAgcGFydGljaXBhbnQgRXZlbnRTdGFja1xuICAgKiAgIHBhcnRpY2lwYW50IEV2ZW50UGFyc2VyXG4gICAqICAgcGFydGljaXBhbnQgT2JzZXJ2ZXJzXG4gICAqXG4gICAqICAgRmFicmljRGlzcGF0Y2gtPj5GYWJyaWNEaXNwYXRjaDogaGFuZGxlRXZlbnRzKClcbiAgICogICBGYWJyaWNEaXNwYXRjaC0+PkV2ZW50U3RhY2s6IGZvciBhd2FpdCAoY29uc3QgZXZ0IG9mIGxpc3RlbmluZ1N0YWNrKVxuICAgKiAgIEV2ZW50U3RhY2stLT4+RmFicmljRGlzcGF0Y2g6IENoYWluY29kZUV2ZW50XG4gICAqICAgRmFicmljRGlzcGF0Y2gtPj5FdmVudFBhcnNlcjogcGFyc2VFdmVudE5hbWUoZXZ0LmV2ZW50TmFtZSlcbiAgICogICBFdmVudFBhcnNlci0tPj5GYWJyaWNEaXNwYXRjaDogeyB0YWJsZSwgZXZlbnQsIG93bmVyIH1cbiAgICogICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiBDaGVjayBpZiBldmVudCBpcyBmb3IgdGhpcyBNU1BcbiAgICogICBGYWJyaWNEaXNwYXRjaC0+PkZhYnJpY0Rpc3BhdGNoOiBwYXJzZVBheWxvYWQoZXZ0LnBheWxvYWQpXG4gICAqICAgRmFicmljRGlzcGF0Y2gtPj5PYnNlcnZlcnM6IHVwZGF0ZU9ic2VydmVycyh0YWJsZSwgZXZlbnQsIHBheWxvYWQuaWQpXG4gICAqICAgT2JzZXJ2ZXJzLS0+PkZhYnJpY0Rpc3BhdGNoOiBDYWxsYmFja3MgZXhlY3V0ZWRcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBoYW5kbGVFdmVudHMoXG4gICAgY3R4QXJnPzogQ29udGV4dDxGYWJyaWNDbGllbnRGbGFncz5cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmxpc3RlbmluZ1N0YWNrKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBFdmVudCBzdGFjayBub3QgaW5pdGlhbGl6ZWQuIEVuc3VyZSB0aGF0IFwic3RhcnRMaXN0ZW5pbmdcIiBpcyBjYWxsZWQgYmVmb3JlIGF0dGVtcHRpbmcgdGhpcyBvcGVyYXRpb24uYFxuICAgICAgKTtcblxuICAgIGlmICghdGhpcy5hZGFwdGVyIHx8ICF0aGlzLmFkYXB0ZXIuY29uZmlnKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYE5vIGFkYXB0ZXIgZm91bmQuIHNob3VsZCBiZSBpbXBvc3NpYmxlYCk7XG5cbiAgICBjb25zdCBjdHggPVxuICAgICAgY3R4QXJnIHx8XG4gICAgICAoYXdhaXQgdGhpcy5hZGFwdGVyLmNvbnRleHQoXG4gICAgICAgIE9wZXJhdGlvbktleXMuUkVBRCxcbiAgICAgICAge1xuICAgICAgICAgIGNvcnJlbGF0aW9uSWQ6IHRoaXMuYWRhcHRlci5jb25maWcuY2hhaW5jb2RlTmFtZSxcbiAgICAgICAgfSxcbiAgICAgICAgKHRoaXMubW9kZWxzICYmIHRoaXMubW9kZWxzWzBdKSB8fCAoTW9kZWwgYXMgdW5rbm93biBhcyBDb25zdHJ1Y3RvcilcbiAgICAgICkpO1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmhhbmRsZUV2ZW50cyk7XG5cbiAgICBsb2cuaW5mbyhcbiAgICAgIGBMaXN0ZW5pbmcgZm9yIGluY29taW5nIGV2ZW50cyBvbiBjaGFpbmNvZGUgXCIke3RoaXMuYWRhcHRlci5jb25maWcuY2hhaW5jb2RlTmFtZX1cIiBvbiBjaGFubmVsIFwiJHt0aGlzLmFkYXB0ZXIuY29uZmlnLmNoYW5uZWx9XCIuLi5gXG4gICAgKTtcblxuICAgIHRyeSB7XG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IGV2dCBvZiB0aGlzLmxpc3RlbmluZ1N0YWNrKSB7XG4gICAgICAgIGNvbnN0IHsgdGFibGUsIGV2ZW50LCBvd25lciB9ID0gcGFyc2VFdmVudE5hbWUoZXZ0LmV2ZW50TmFtZSk7XG4gICAgICAgIGlmIChvd25lciAmJiBvd25lciAhPT0gdGhpcy5hZGFwdGVyLmNvbmZpZz8ubXNwSWQpIGNvbnRpbnVlO1xuICAgICAgICBjb25zdCBwYXlsb2FkOiB7IGlkOiBzdHJpbmcgfSA9IHRoaXMucGFyc2VQYXlsb2FkKGV2dC5wYXlsb2FkKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCB0YXJnZXRNb2RlbCA9IHRhYmxlXG4gICAgICAgICAgICA/IE1vZGVsLmdldCh0YWJsZSlcbiAgICAgICAgICAgIDogTW9kZWwuZ2V0KHRoaXMubW9kZWxzWzBdLm5hbWUpO1xuICAgICAgICAgIGNvbnN0IG1vZGVsUmVmID0gdGFyZ2V0TW9kZWwgPz8gKHRhYmxlIHx8IHRoaXMubW9kZWxzWzBdPy5uYW1lKTtcbiAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZU9ic2VydmVycyhcbiAgICAgICAgICAgIG1vZGVsUmVmIGFzIENvbnN0cnVjdG9yIHwgc3RyaW5nLFxuICAgICAgICAgICAgZXZlbnQsXG4gICAgICAgICAgICBwYXlsb2FkLmlkIGFzIHN0cmluZyxcbiAgICAgICAgICAgIGN0eFxuICAgICAgICAgICk7XG4gICAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgICBsb2cuZXJyb3IoXG4gICAgICAgICAgICBgRmFpbGVkIHVwZGF0ZSBvYnNlcnZhYmxlcyBmb3IgdGFibGUgJHt0YWJsZX0gZXZlbnQgJHtldmVudH0gaWQ6ICR7cGF5bG9hZC5pZH06ICR7ZX1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgbG9nLmVycm9yKFxuICAgICAgICBgRmFpbGVkIHRvIHJlYWQgZXZlbnQgZm9yIGNoYWluY29kZSBcIiR7dGhpcy5hZGFwdGVyLmNvbmZpZy5jaGFpbmNvZGVOYW1lfVwiIG9uIGNoYW5uZWwgXCIke3RoaXMuYWRhcHRlci5jb25maWcuY2hhbm5lbH1cIjogJHtlfWBcbiAgICAgICk7XG4gICAgICBhd2FpdCB0aGlzLmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBJbml0aWFsaXplcyB0aGUgZXZlbnQgbGlzdGVuZXJcbiAgICogQHN1bW1hcnkgU2V0cyB1cCB0aGUgY29ubmVjdGlvbiB0byB0aGUgRmFicmljIG5ldHdvcmsgYW5kIHN0YXJ0cyBsaXN0ZW5pbmcgZm9yIGNoYWluY29kZSBldmVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gaW5pdGlhbGl6YXRpb24gaXMgY29tcGxldGVcbiAgICovXG4gIHByb3RlY3RlZCBvdmVycmlkZSBhc3luYyBpbml0aWFsaXplKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5hZGFwdGVyKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYE5vIGFkYXB0ZXIgb3IgY29uZmlnIG9ic2VydmVkIGZvciBkaXNwYXRjaGApO1xuICAgIGNvbnN0IGNvbnRleHQgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuY29udGV4dChcbiAgICAgIFwiZGlzcGF0Y2hcIixcbiAgICAgIHtcbiAgICAgICAgY29ycmVsYXRpb25JZDogdGhpcy5hZGFwdGVyLmNvbmZpZy5jaGFpbmNvZGVOYW1lLFxuICAgICAgfSxcbiAgICAgIE1vZGVsIGFzIGFueVxuICAgICk7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5pbml0aWFsaXplKTtcbiAgICBjb25zdCBnYXRld2F5ID0gYXdhaXQgRmFicmljQ2xpZW50QWRhcHRlci5nZXRHYXRld2F5KFxuICAgICAgY3R4LFxuICAgICAgdGhpcy5hZGFwdGVyLmNvbmZpZyBhcyBQZWVyQ29uZmlnLFxuICAgICAgdGhpcy5jbGllbnRcbiAgICApO1xuICAgIGNvbnN0IG5ldHdvcmsgPSBnYXRld2F5LmdldE5ldHdvcmsodGhpcy5hZGFwdGVyLmNvbmZpZy5jaGFubmVsKTtcbiAgICBpZiAoIXRoaXMuYWRhcHRlcilcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBObyBhZGFwdGVyIG9ic2VydmVkIGZvciBkaXNwYXRjaGApO1xuICAgIHRoaXMubGlzdGVuaW5nU3RhY2sgPSBhd2FpdCBuZXR3b3JrLmdldENoYWluY29kZUV2ZW50cyhcbiAgICAgIHRoaXMuYWRhcHRlci5jb25maWcuY2hhaW5jb2RlTmFtZVxuICAgICk7XG4gICAgdGhpcy5oYW5kbGVFdmVudHMoY3R4KTtcbiAgfVxufVxuXG5pZiAoRmFicmljQ2xpZW50QWRhcHRlcilcbiAgRmFicmljQ2xpZW50QWRhcHRlcltcIl9iYXNlRGlzcGF0Y2hcIl0gPSBGYWJyaWNDbGllbnREaXNwYXRjaDtcbiIsImltcG9ydCB7IE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gXCIjI1ZFUlNJT04jI1wiO1xuZXhwb3J0IGNvbnN0IFBBQ0tBR0VfTkFNRSA9IFwiIyNQQUNLQUdFIyNcIjtcblxuTWV0YWRhdGEucmVnaXN0ZXJMaWJyYXJ5KFBBQ0tBR0VfTkFNRSwgVkVSU0lPTik7XG4iXSwibmFtZXMiOlsiRmFicmljQ2xpZW50UmVwb3NpdG9yeSIsIlJlcG9zaXRvcnkiLCJjb25zdHJ1Y3RvciIsImFkYXB0ZXIiLCJjbGF6eiIsInN1cGVyIiwidGhpcyIsIl9vdmVycmlkZXMiLCJPYmplY3QiLCJhc3NpZ24iLCJpZ25vcmVWYWxpZGF0aW9uIiwiaWdub3JlSGFuZGxlcnMiLCJhbGxvd1Jhd1N0YXRlbWVudHMiLCJmb3JjZVByZXBhcmVTaW1wbGVRdWVyaWVzIiwiZm9yY2VQcmVwYXJlQ29tcGxleFF1ZXJpZXMiLCJhbGxvd0dlbmVyYXRpb25PdmVycmlkZSIsIm92ZXJyaWRlIiwiZmxhZ3MiLCJmb3IiLCJPYnNlcnZlckhhbmRsZXIiLCJwYWdpbmF0ZUJ5Iiwia2V5Iiwib3JkZXIiLCJyZWYiLCJvZmZzZXQiLCJsaW1pdCIsImFyZ3MiLCJsb2ciLCJjdHhBcmdzIiwibG9nQ3R4IiwiUHJlcGFyZWRTdGF0ZW1lbnRLZXlzIiwiUEFHRV9CWSIsInZlcmJvc2UiLCJNb2RlbCIsInRhYmxlTmFtZSIsImNsYXNzIiwic3RhdGVtZW50IiwibmFtZSIsImJvb2ttYXJrIiwibGlzdEJ5IiwiTElTVF9CWSIsImZpbmRCeSIsInZhbHVlIiwiRklORF9CWSIsImZpbmRPbmVCeSIsIkZJTkRfT05FX0JZIiwiY3R4IiwiUGVyc2lzdGVuY2VLZXlzIiwiU1RBVEVNRU5UIiwiY2FsbEFyZ3MiLCJzbGljZSIsInJlc3VsdCIsIkpTT04iLCJwYXJzZSIsImRlY29kZSIsImV2YWx1YXRlVHJhbnNhY3Rpb24iLCJzdHJpbmdpZnkiLCJ1bmRlZmluZWQiLCJBcnJheSIsImlzQXJyYXkiLCJtYXAiLCJyIiwiQ291Y2hEQktleXMiLCJUQUJMRSIsIlBhZ2luYXRvciIsImlzU2VyaWFsaXplZFBhZ2UiLCJkYXRhIiwiZCIsImNvdW50T2YiLCJDT1VOVF9PRiIsInN0bXRBcmdzIiwibWF4T2YiLCJNQVhfT0YiLCJtaW5PZiIsIk1JTl9PRiIsImF2Z09mIiwiQVZHX09GIiwic3VtT2YiLCJTVU1fT0YiLCJkaXN0aW5jdE9mIiwiRElTVElOQ1RfT0YiLCJncm91cE9mIiwiR1JPVVBfT0YiLCJjcmVhdGUiLCJtb2RlbCIsImRlYnVnIiwicmVjb3JkIiwiaWQiLCJ0cmFuc2llbnQiLCJwcmVwYXJlIiwicmV2ZXJ0IiwidXBkYXRlIiwiY3JlYXRlQWxsUHJlZml4IiwibW9kZWxzIiwiT3BlcmF0aW9uS2V5cyIsIkNSRUFURSIsImdldCIsImlnbm9yZVZhbGlkYXRlIiwibGVuZ3RoIiwiUHJvbWlzZSIsImFsbCIsImFzeW5jIiwibSIsImVuZm9yY2VEQkRlY29yYXRvcnMiLCJPTiIsImlnbm9yZWRQcm9wcyIsImVycm9ycyIsInJlc29sdmUiLCJoYXNFcnJvcnMiLCJlcnJvck1lc3NhZ2VzIiwicmVkdWNlRXJyb3JzVG9QcmludCIsIlZhbGlkYXRpb25FcnJvciIsImNyZWF0ZUFsbCIsInByZXBhcmVkIiwiaWRzIiwicCIsInJlY29yZHMiLCJpIiwidXBkYXRlQWxsIiwidXBkYXRlZCIsInUiLCJFUkMyMFRva2VuIiwiQmFzZU1vZGVsIiwiX19kZWNvcmF0ZSIsInBrIiwidHlwZSIsIlN0cmluZyIsInByb3RvdHlwZSIsImNvbHVtbiIsInJlcXVpcmVkIiwidGFibGUiLCJFUkMyMFdhbGxldCIsIkFsbG93YW5jZSIsIkNsaWVudFNlcmlhbGl6ZXIiLCJKU09OU2VyaWFsaXplciIsInByZVNlcmlhbGl6ZSIsIm1vZGVsTmFtZSIsInRvU2VyaWFsaXplIiwibWV0YWRhdGEiLCJNZXRhZGF0YSIsIlNlcmlhbGl6YXRpb25FcnJvciIsIk1vZGVsS2V5cyIsIkFOQ0hPUiIsImRlc2VyaWFsaXplIiwic3RyIiwiZGVzZXJpYWxpemF0aW9uIiwiY2xhc3NOYW1lIiwiRXJyb3IiLCJidWlsZCIsInNlcmlhbGl6ZSIsIkZhYnJpY0VSQzIwQ2xpZW50UmVwb3NpdG9yeSIsInNlcmlhbGl6ZXIiLCJkZWNvZGVyIiwiVGV4dERlY29kZXIiLCJ1cGRhdGVPYnNlcnZlcnMiLCJldmVudCIsIm9ic2VydmVySGFuZGxlciIsIkludGVybmFsRXJyb3IiLCJjb3VudCIsInBhcnNlZElkIiwiU2VxdWVuY2UiLCJwYXJzZVZhbHVlIiwic2VxdWVuY2VGb3IiLCJ0b2tlbk5hbWUiLCJzeW1ib2wiLCJkZWNpbWFscyIsIk51bWJlciIsInRvdGFsU3VwcGx5IiwidG90YWwiLCJiYWxhbmNlT2YiLCJvd25lciIsImJhbGFuY2UiLCJ0cmFuc2ZlciIsInRvIiwidHJhbnNmZXJyZWQiLCJzdWJtaXRUcmFuc2FjdGlvbiIsInRvU3RyaW5nIiwidHJhbnNmZXJGcm9tIiwiZnJvbSIsImNvbnRleHRBcmdzIiwiQ29udGV4dCIsImFwcHJvdmUiLCJzcGVuZGVyIiwiYXBwcm92ZWQiLCJhbGxvd2FuY2UiLCJpbml0aWFsaXplIiwidG9rZW4iLCJpbml0aWxpYXplZCIsImNoZWNrSW5pdGlhbGl6ZWQiLCJtaW50IiwiYW1vdW50IiwiYnVybiIsImJ1cm5Gcm9tIiwiYWNjb3VudCIsImNsaWVudEFjY291bnRCYWxhbmNlIiwic2VyaWFsaXplZEFjY291bnRCYWxhbmNlIiwiY2xpZW50QWNjb3VudElEIiwiZW5zdXJlRGlyZWN0b3J5RXhpc3RlbmNlIiwiZmlsZVBhdGgiLCJmcyIsInJlcXVpcmUiLCJwYXRoIiwiZGlybmFtZSIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJnZW5lcmF0ZU1vZGVsSW5kZXhlcyIsImdlbmVyYXRlSW5kZXhlcyIsImdlbmVyYXRlTW9kZWxEZXNpZ25Eb2NzIiwiYWNjdW0iLCJ2aWV3cyIsImdlbmVyYXRlVmlld3MiLCJzdG9yYWdlIiwiZm9yRWFjaCIsImRvYyIsIl9pZCIsInJlYWRNb2RlbEZpbGUiLCJmaWxlIiwiZXhwb3J0cyIsImpvaW4iLCJwcm9jZXNzIiwiY3dkIiwicGFyZW50UGF0aCIsInZhbHVlcyIsImZpbHRlciIsImUiLCJyZWFkTW9kZWxGb2xkZXJzIiwiZm9sZGVycyIsImZvbGRlciIsImZpbGVzIiwicmVhZGRpclN5bmMiLCJ3aXRoRmlsZVR5cGVzIiwicmVjdXJzaXZlIiwiZiIsImlzRmlsZSIsImVuZHNXaXRoIiwicHVzaCIsIndyaXRlSW5kZXhlcyIsImluZGV4ZXMiLCJjb2xsZWN0aW9uIiwiaW5kZXgiLCJ3cml0ZUZpbGVTeW5jIiwid3JpdGVEZXNpZ25Eb2NzIiwiZGVzaWduRG9jcyIsImRvY0lkIiwicmVwbGFjZSIsInBheWxvYWQiLCJfcmV2IiwiSWRlbnRpdHlDcmVkZW50aWFscyIsImFyZyIsImRlc2NyaXB0aW9uIiwiRmFicmljTW9kZWxLZXlzIiwiSWRlbnRpdHlUeXBlIiwiRmFicmljRmxhdm91ciIsIklkZW50aXR5IiwiWDUwOSIsIm9uZVRvT25lIiwiQ2FzY2FkZSIsIkNBU0NBREUiLCJkZWxldGUiLCJDb3JlVXRpbHMiLCJsb2dnZXIiLCJNaW5pTG9nZ2VyIiwiY29udGVudE9mTG9hZEZpbGUiLCJjb250ZW50T3JQYXRoIiwiZmlsZVJlYWRlciIsIlVpbnQ4QXJyYXkiLCJtYXRjaCIsInJlYWRGaWxlIiwicHJvbWlzZXMiLCJub3JtYWxpemVJbXBvcnQiLCJpbXBvcnQiLCJnZXRDQVVzZXIiLCJ1c2VyTmFtZSIsInByaXZhdGVLZXkiLCJjZXJ0aWZpY2F0ZSIsIm1zcElkIiwib3B0aW9ucyIsInN0cmluZ0Zvcm1hdCIsInVzZXIiLCJVc2VyIiwiY29uZmlnIiwiaHNtIiwic29mdHdhcmUiLCJsaWIiLCJsaWJyYXJ5Iiwic2xvdCIsImxhYmVsIiwidG9rZW5MYWJlbCIsInBpbiIsImNyeXB0b1N1aXRlIiwiZ2V0Q3J5cHRvU3VpdGUiLCJzZXRDcnlwdG9TdWl0ZSIsImVucm9sbG1lbnRLZXkiLCJnZXRIU01FbnJvbGxtZW50S2V5IiwiZ2V0U29mdHdhcmVFbnJvbGxtZW50S2V5Iiwic2V0RW5yb2xsbWVudCIsIm5ld0NyeXB0b1N1aXRlIiwiY3JlYXRlS2V5RnJvbVJhdyIsInNraSIsImtleUlkSGV4IiwidHJpbSIsIkJ1ZmZlciIsImdldENlcnRpZmljYXRlU0tJIiwiZ2V0S2V5IiwiaXNQcml2YXRlIiwieDUwOSIsIlg1MDlDZXJ0aWZpY2F0ZSIsImp3ayIsInB1YmxpY0tleSIsImV4cG9ydCIsImZvcm1hdCIsInByZWZpeCIsIngiLCJ5IiwiY3J5cHRvIiwiY3JlYXRlSGFzaCIsImNvbmNhdCIsImRpZ2VzdCIsImdldElkZW50aXR5IiwiY2VydERpcmVjdG9yeVBhdGgiLCJpZGVudGl0eUZpbGVSZWFkZXIiLCJjZXJ0UGF0aCIsImdldEZpcnN0RGlyRmlsZU5hbWUiLCJjcmVkZW50aWFscyIsImRpclBhdGgiLCJyZWFkZGlyIiwiZ2V0Rmlyc3REaXJGaWxlTmFtZUNvbnRlbnQiLCJnZXRGaWxlQ29udGVudCIsImdldFNpZ25lciIsImtleURpcmVjdG9yeVBhdGgiLCJzaWduZXJGaWxlUmVhZGVyIiwia2V5UGF0aCIsInByaXZhdGVLZXlQZW0iLCJleHRyYWN0UHJpdmF0ZUtleSIsImtleXMiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJrIiwic2lnbmVycyIsIm5ld1ByaXZhdGVLZXlTaWduZXIiLCJwZW0iLCJsaWJOYW1lIiwic3VidGxlIiwiZ2xvYmFsVGhpcyIsIndpbmRvdyIsIkNyeXB0byIsIndlYmNyeXB0byIsInN0cjJhYiIsImJ1ZiIsIkFycmF5QnVmZmVyIiwiYnVmVmlldyIsInN0ckxlbiIsImNoYXJDb2RlQXQiLCJyZXBsYWNlQWxsIiwiZGVjb2RlZCIsImJpbmFyeURlciIsImltcG9ydEtleSIsIm5hbWVkQ3VydmUiLCJjcnlwdG9Qcm92aWRlciIsInNldCIsIkJBU0VfQUxQSEFCRVQiLCJDUllQVE8iLCJCYXNlRW5jb2RlciIsImFscGhhYmV0IiwiYmFzZU1hcCIsImoiLCJjaGFyQXQiLCJ4YyIsImJhc2UiLCJsZWFkZXIiLCJmYWN0b3IiLCJNYXRoIiwiaUZhY3RvciIsImVuY29kZSIsInNvdXJjZSIsImlzVmlldyIsImJ1ZmZlciIsImJ5dGVPZmZzZXQiLCJieXRlTGVuZ3RoIiwiemVyb2VzIiwicGJlZ2luIiwicGVuZCIsInNpemUiLCJiNTgiLCJjYXJyeSIsIml0MSIsIml0MiIsInJlcGVhdCIsImRlY29kZVVuc2FmZSIsInBzeiIsImIyNTYiLCJpdDMiLCJpdDQiLCJ2Y2giLCJDcnlwdG9VdGlscyIsImI1OGVuY29kZXIiLCJCQVNFNTgiLCJmYWJyaWNJZEZyb21DZXJ0aWZpY2F0ZSIsImNlcnQiLCJzdWJqZWN0IiwiaXNzdWVyIiwic3RyaW5nVG9BcnJheUJ1ZmZlciIsImV4dHJhY3RLZXkiLCJ1c2FnZXMiLCJSZWdFeHAiLCJ0b1VwcGVyQ2FzZSIsImV4dHJhY3RQdWJsaWNLZXkiLCJzaWduIiwiYnVmZiIsImhhc2giLCJiIiwicGFkU3RhcnQiLCJ2ZXJpZnkiLCJzaWduYXR1cmUiLCJlbmNyeXB0IiwiZ2V0U3VidGxlQ3J5cHRvIiwiaXNCcm93c2VyIiwiZGVjcnlwdCIsImdldE1hc3RlciIsInRleHRFbmNvZGVyIiwiVGV4dEVuY29kZXIiLCJnZW5HZW5lc2lzIiwicmFuZG9tVVVJRCIsImltcG9ydGVkS2V5IiwiS0VZX0FMR09SWVRITSIsIml2IiwiZ2V0RGVyaXZhdGlvbktleSIsInNhbHQiLCJzYWx0QnVmZmVyIiwic2FsdEhhc2hlZCIsInBhcmFtcyIsIkhBU0giLCJpdGVyYXRpb25zIiwiSVRFUkFUSU9OUyIsImRlcml2YXRpb24iLCJkZXJpdmVCaXRzIiwiS0VZTEVOR1RIIiwiaXZsZW4iLCJrZXlsZW4iLCJkZXJpdmVkS2V5IiwiaW1wb3J0ZWRFbmNyeXB0aW9uS2V5IiwiQUxHT1JZVEhNIiwiZW5jcnlwdFBpbiIsInRleHQiLCJrZXlPYmplY3QiLCJ0ZXh0QnVmZmVyIiwiZW5jcnlwdGVkVGV4dCIsImRlY3J5cHRQaW4iLCJ0ZXh0RGVjb2RlciIsImRlY3J5cHRlZFRleHQiLCJPdmVyZmxvd0Vycm9yIiwibXNnIiwiQmFsYW5jZUVycm9yIiwiQWxsb3dhbmNlRXJyb3IiLCJSZWdpc3RyYXRpb25FcnJvciIsIkF1dGhvcml6YXRpb25FcnJvciIsIk1pc3NpbmdDb250ZXh0RXJyb3IiLCJVbmF1dGhvcml6ZWRQcml2YXRlRGF0YUFjY2VzcyIsIkJhc2VFcnJvciIsIk5vdEluaXRpYWxpemVkRXJyb3IiLCJNaXNzaW5nUEtDU1MxMUxpYiIsIkVuZG9yc2VtZW50RXJyb3IiLCJtZXNzYWdlIiwiTXZjY1JlYWRDb25mbGljdEVycm9yIiwiUGhhbnRvbVJlYWRDb25mbGljdEVycm9yIiwiRW5kb3JzZW1lbnRQb2xpY3lFcnJvciIsIkhGQ0FJZGVudGl0eVR5cGUiLCJIRkNBSWRlbnRpdHlBdHRyaWJ1dGVzIiwiRmFicmljRW5yb2xsbWVudFNlcnZpY2UiLCJMb2dnZWRDbGFzcyIsImNhQ29uZmlnIiwiY2FOYW1lIiwiY2FDZXJ0IiwiY2FLZXkiLCJ1cmwiLCJDQSIsImNhIiwidGxzIiwidHJ1c3RlZFJvb3RzIiwicm9vdCIsIkZhYnJpY0NBU2VydmljZXMiLCJDbGllbnQiLCJjbGllbnQiLCJDZXJ0aWZpY2F0ZSIsImNlcnRpZmljYXRlU2VydmljZSIsIm5ld0NlcnRpZmljYXRlU2VydmljZSIsIkFmZmlsaWF0aW9ucyIsImFmZmlsaWF0aW9uU2VydmljZSIsIm5ld0FmZmlsaWF0aW9uU2VydmljZSIsIklkZW50aXRpZXMiLCJpZGVudGl0eVNlcnZpY2UiLCJuZXdJZGVudGl0eVNlcnZpY2UiLCJnZXRDZXJ0aWZpY2F0ZXMiLCJyZXF1ZXN0IiwiZG9NYXAiLCJyZXNwb25zZSIsImNlcnRzIiwiYyIsIlBFTSIsImdldElkZW50aXRpZXMiLCJpZGVudGl0aWVzU2VydmljZSIsImdldEFsbCIsImlkZW50aXRpZXMiLCJwYXJzZUVycm9yIiwicmVnZXhwIiwiZXhlYyIsImNvZGUiLCJDb25mbGljdEVycm9yIiwiZ2V0QWZmaWxpYXRpb25zIiwiYSIsInJlYWQiLCJlbnJvbGxtZW50SWQiLCJnZXRPbmUiLCJOb3RGb3VuZEVycm9yIiwic3VjY2VzcyIsInJlZ2lzdGVyIiwiaXNTdXBlclVzZXIiLCJhZmZpbGlhdGlvbiIsInVzZXJSb2xlIiwiYXR0cnMiLCJtYXhFbnJvbGxtZW50cyIsInJlZ2lzdHJhdGlvbiIsInBhc3N3b3JkIiwicHJvcHMiLCJlbnJvbGxtZW50SUQiLCJlbnJvbGxtZW50U2VjcmV0IiwiaW5mbyIsImlkZW50aXR5RnJvbUVucm9sbG1lbnQiLCJlbnJvbGxtZW50Iiwicm9vdENlcnRpZmljYXRlIiwiTG9nZ2luZyIsImNsaWVudElkIiwibm93IiwiRGF0ZSIsInRvQnl0ZXMiLCJjcmVhdGVkT24iLCJ1cGRhdGVkT24iLCJlbnJvbGwiLCJpZGVudGl0eSIsInJlZ2lzdGVyQW5kRW5yb2xsIiwicmV2b2tlIiwicmVhc29uIiwiUmVnaXN0cmF0aW9uUmVxdWVzdEJ1aWxkZXIiLCJlcnJzIiwicm9sZSIsInNldEFmZmlsaWF0aW9uIiwiYWRkQXR0ciIsImF0dHIiLCJzZXRBdHRycyIsInNldEVucm9sbG1lbnRJRCIsInNldEVucm9sbG1lbnRTZWNyZXQiLCJzZXRNYXhFbnJvbGxtZW50cyIsInNldFJvbGUiLCJtaW5sZW5ndGgiLCJtaW4iLCJFUkMyMEV2ZW50cyIsIkZhYnJpY0Jhc2VNb2RlbCIsImNyZWF0ZWRBdCIsInVwZGF0ZWRBdCIsInZlcnNpb24iLCJ1c2VzIiwiRmFicmljSWRlbnRpZmllZEJhc2VNb2RlbCIsImNyZWF0ZWRCeSIsInVwZGF0ZWRCeSIsImlzU2hhcmVkIiwic2VncmVnYXRlIiwiaXNUcmFuc2llbnQiLCJkZWNvcmF0ZWRQcm9wZXJ0aWVzIiwidmFsaWRhdGFibGVQcm9wZXJ0aWVzIiwidHJhbnNpZW50UHJvcHMiLCJEQktleXMiLCJUUkFOU0lFTlQiLCJwcml2YXRlUHJvcGVydGllcyIsIlBSSVZBVEUiLCJzaGFyZWRQcm9wZXJ0aWVzIiwiU0hBUkVEIiwicHJpdmF0ZXMiLCJzaGFyZWQiLCJ0cmFuc2llbnRLZXlzIiwicHJpdmF0ZUtleXMiLCJzaGFyZWRLZXlzIiwicGtLZXkiLCJpbmNsdWRlcyIsImlzUHJpbWFyeUtleSIsImRlY29yYXRlZFZhbHVlIiwic2hvdWxkSW5jbHVkZUluTW9kZWwiLCJiaW5kIiwibWlycm9yZWQiLCJGQUJSSUMiLCJNSVJST1IiLCJvd25lck9mIiwibWV0YSIsIk9XTkVEX0JZIiwibWlycm9yZWRBdCIsImNvbGxlY3Rpb25zRm9yIiwic2hhcmVkS2V5IiwiY29uc3RyIiwicHJpdmF0ZU1ldGEiLCJzaGFyZWRNZXRhIiwicHJpdmF0ZUNvbHMiLCJjb2xsZWN0aW9ucyIsInNoYXJlZENvbHMiLCJleHRyYWN0TXNwSWQiLCJnZXRNU1BJRCIsIk93bmVyIiwidGFyZ2V0IiwicHJvcGVydHlLZXkiLCJkZXNjcmlwdG9yIiwib3JpZ2luYWxNZXRob2QiLCJhY291bnRJZCIsImNsaWVudElkZW50aXR5IiwiZ2V0SUQiLCJzZWxlY3QiLCJ0b2tlbnMiLCJleGVjdXRlIiwiYXBwbHkiLCJvd25lZEJ5T25DcmVhdGUiLCJjb250ZXh0Iiwic3R1YiIsImNyZWF0b3IiLCJnZXRDcmVhdG9yIiwibXNwaWQiLCJzZXRPd25lZEJ5S2V5VmFsdWUiLCJkZWZpbmVQcm9wZXJ0eSIsImVudW1lcmFibGUiLCJ3cml0YWJsZSIsImNvbmZpZ3VyYWJsZSIsIm93bmVkQnkiLCJvYmoiLCJhdHRyaWJ1dGUiLCJnZW5lcmF0ZWQiLCJyZWFkb25seSIsIm9uQ3JlYXRlIiwicHJvcE1ldGFkYXRhIiwiRGVjb3JhdGlvbiIsImRlZmluZSIsImRlY29yYXRvciIsInRyYW5zYWN0aW9uSWRPbkNyZWF0ZSIsImdldFR4SUQiLCJ0cmFuc2FjdGlvbklkIiwib25VcGRhdGUiLCJUUkFOU0FDVElPTl9JRCIsImV2YWxNaXJyb3JNZXRhZGF0YSIsInJlc29sdmVyIiwiY3JlYXRlTWlycm9ySGFuZGxlciIsInJlcG8iLCJtaXJyb3IiLCJ1cGRhdGVNaXJyb3JIYW5kbGVyIiwiZGVsZXRlTWlycm9ySGFuZGxlciIsImNvbmRpdGlvbiIsInByaXZhdGVEYXRhIiwiYWZ0ZXJDcmVhdGUiLCJwcmlvcml0eSIsImFmdGVyVXBkYXRlIiwiYWZ0ZXJEZWxldGUiLCJNb2RlbENvbGxlY3Rpb24iLCJvcmdOYW1lIiwidG9QYXNjYWxDYXNlIiwiTmFtZXNwYWNlQ29sbGVjdGlvbiIsIm5hbWVzcGFjZSIsIkltcGxpY2l0UHJpdmF0ZUNvbGxlY3Rpb24iLCJTRUdSRUdBVEVEX0NPTExFQ1RJT05fRVhUUkFDVElPTl9QUklPUklUWSIsImV4dHJhY3RTZWdyZWdhdGVkQ29sbGVjdGlvbnMiLCJkYXRhQXJyYXkiLCJtc3AiLCJjb2xsZWN0aW9uUmVzb2x2ZXIiLCJyZWFkRnJvbSIsInNlZ3JlZ2F0ZWREYXRhT25DcmVhdGUiLCJrZXlBcnJheSIsInJlYnVpbHQiLCJyZWR1Y2UiLCJhY2MiLCJVbnN1cHBvcnRlZEVycm9yIiwidG9DcmVhdGUiLCJzZWdyZWdhdGVkIiwid3JpdGVUbyIsInNlZ3JlZ2F0ZWREYXRhT25SZWFkIiwic2VncmVnYXRlZERhdGFPblVwZGF0ZSIsIm9sZE1vZGVsIiwic2VncmVnYXRlZERhdGFPbkRlbGV0ZSIsImlubmVyU2VncmVnYXRlZCIsInNlZ3JlZ2F0ZWREZWMiLCJTZXQiLCJhZGQiLCJjb25zdHJNZXRhIiwiY29uc3RyQ29sbGVjdGlvbnMiLCJ0cmFuc2llbnRNZXRhIiwidXBkYXRlZFRyYW5zaWVudE1ldGEiLCJkZWNzIiwicHJvcGVydGllcyIsImdyb3VwTmFtZSIsImVhcmx5RXh0cmFjdGlvbk1ldGEiLCJlYXJseUV4dHJhY3Rpb25Hcm91cFNvcnQiLCJncm91cCIsInByb3AiLCJvbiIsIkRCT3BlcmF0aW9ucyIsIkFMTCIsIm9uUmVhZCIsIm9uRGVsZXRlIiwic2hhcmVkRGF0YSIsIkRldGVybWluaXN0aWNTZXJpYWxpemVyIiwiZXJyb3IiLCJzZWxmIiwibyIsImNhbGwiLCJyZWxhdGlvbnMiLCJzb3J0S2V5c1JlY3Vyc2l2ZSIsImdlbmVyYXRlRmFicmljRXZlbnROYW1lIiwicGFyc2VFdmVudE5hbWUiLCJwYXJ0cyIsInNwbGl0Iiwic3ViIiwic2FmZVBhcnNlSW50Iiwic3RyaW5nIiwiZGlnaXRSZWdleCIsInRlc3QiLCJwYXJzZWRpbnQiLCJwYXJzZUludCIsImlzTmFOIiwiU2ltcGxlRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXIiLCJwdXRBbmNob3IiLCJwcmVTZXJpYWxpemF0aW9uIiwiRmFicmljSWRlbnRpdHlTZXJ2aWNlIiwiQ2xpZW50QmFzZWRTZXJ2aWNlIiwicm9vdENsaWVudCIsIl91c2VyIiwiY2VydGlmaWNhdGVzIiwiYWZmaWxpYXRpb25zIiwiZ2V0VXNlciIsImNmZyIsIklOSVRJQUxJWkFUSU9OIiwiZ2V0TmFtZSIsIlJFQUQiLCJEZWZhdWx0RmFicmljQ2xpZW50RmxhZ3MiLCJldmFsdWF0ZVRpbWVvdXQiLCJlbmRvcnNlVGltZW91dCIsInN1Ym1pdFRpbWVvdXQiLCJjb21taXRUaW1lb3V0IiwiSFNNU2lnbmVyRmFjdG9yeUN1c3RvbSIsInN0YXRpYyIsInBrY3MxMSIsIlBLQ1MxMSIsImxvYWQiLCJmaW5kSFNNUEtDUzExTGliIiwiaW5pdGlhbGl6ZWQiLCJDX0luaXRpYWxpemUiLCJDS1JfQ1JZUFRPS0lfQUxSRUFEWV9JTklUSUFMSVpFRCIsImNvbW1vblNvZnRIU01QYXRoTmFtZXMiLCJwYXRobmFtZVRvVHJ5IiwiZGlzcG9zZSIsIkNfRmluYWxpemUiLCJzYW5pdGl6ZU9wdGlvbnMiLCJoc21TaWduZXJPcHRpb25zIiwidXNlclR5cGUiLCJDS1VfVVNFUiIsImFzc2VydE5vdEVtcHR5IiwiaWRlbnRpZmllciIsInByb3BlcnR5IiwiZmluZFNsb3RGb3JMYWJlbCIsInBrY3MxMUxhYmVsIiwic2xvdHMiLCJDX0dldFNsb3RMaXN0IiwiZmluZCIsInNsb3RUb0NoZWNrIiwidG9rZW5JbmZvIiwiQ19HZXRUb2tlbkluZm8iLCJsb2dpbiIsInNlc3Npb24iLCJDX0xvZ2luIiwiZXJyIiwicGtjczExZXJyIiwiQ0tSX1VTRVJfQUxSRUFEWV9MT0dHRURfSU4iLCJmaW5kT2JqZWN0SW5IU00iLCJrZXl0eXBlIiwicGtjczExVGVtcGxhdGUiLCJDS0FfSUQiLCJDS0FfQ0xBU1MiLCJDS0FfS0VZX1RZUEUiLCJDS0tfRUMiLCJDX0ZpbmRPYmplY3RzSW5pdCIsImhzbU9iamVjdCIsIkNfRmluZE9iamVjdHMiLCJDX0ZpbmRPYmplY3RzRmluYWwiLCJuZXdTaWduZXIiLCJwa2NzIiwiQ19PcGVuU2Vzc2lvbiIsIkNLRl9TRVJJQUxfU0VTU0lPTiIsInByaXZhdGVLZXlIYW5kbGUiLCJDS09fUFJJVkFURV9LRVkiLCJDX0Nsb3NlU2Vzc2lvbiIsInNpZ25lciIsIkNfU2lnbkluaXQiLCJtZWNoYW5pc20iLCJDS01fRUNEU0EiLCJjb21wYWN0U2lnbmF0dXJlIiwiQ19TaWduQXN5bmMiLCJhbGxvYyIsInAyNTYiLCJQb2ludCIsIkZuIiwiQllURVMiLCJTaWduYXR1cmUiLCJmcm9tQnl0ZXMiLCJub3JtYWxpemVTIiwiY2xvc2UiLCJhc3NlcnREZWZpbmVkIiwiZ2V0VW5jb21wcmVzc2VkUG9pbnRPbkN1cnZlIiwiZ2V0U0tJRnJvbUNlcnRpZmljYXRlUGF0aCIsInJlYWRGaWxlU3luYyIsImdldFNLSUZyb21DZXJ0aWZpY2F0ZSIsInVuY29tcHJlc3NlZFBvaW50IiwiRmFicmljQ2xpZW50U3RhdGVtZW50IiwiU3RhdGVtZW50Iiwib3ZlcnJpZGVzIiwic3F1YXNoIiwic3F1YXNoZWQiLCJtZXRob2QiLCJkaXJlY3Rpb24iLCJleGVjdXRlUHJlcGFyZWQiLCJhcmd6IiwiZm9yTW9kZWwiLCJmcm9tU2VsZWN0b3IiLCJhbGlhcyIsIlFVRVJZIiwiaXNTaW1wbGVRdWVyeSIsIlF1ZXJ5Q2xhdXNlIiwid2hlcmVDb25kaXRpb24iLCJwYXJzZWQiLCJwcmVwYXJlQ29uZGl0aW9uIiwic2VsZWN0U2VsZWN0b3IiLCJTRUxFQ1QiLCJBTkQiLCJ0b0xvd2VyQ2FzZSIsIm9yZGVyQnlTZWxlY3RvcnMiLCJPUkRFUl9CWSIsInRvQ2FtZWxDYXNlIiwicHJvY2Vzc1JlY29yZCIsInBrQXR0ciIsInNlcXVlbmNlVHlwZSIsIklEIiwia2V5QXJncyIsIlNFUEFSQVRPUiIsInJhdyIsInJhd0lucHV0IiwiYWdncmVnYXRvciIsImFnZ3JlZ2F0ZUluZm8iLCJhZ2dyZWdhdGUiLCJleGVjdXRlQWdncmVnYXRlIiwicmVzdWx0cyIsImFnZ3JlZ2F0ZVF1ZXJ5IiwiYnVpbGRBZ2dyZWdhdGVRdWVyeSIsInNlbGVjdG9ycyIsInF1ZXJ5Iiwic2VsZWN0b3IiLCJmaWVsZHMiLCJwYXJzZUNvbmRpdGlvbiIsIkNvbmRpdGlvbiIsImFuZCIsImVxIiwic2VsZWN0b3JLZXlzIiwiQ291Y2hEQkdyb3VwT3BlcmF0b3IiLCJpbmRleE9mIiwidmFsIiwiT1IiLCJzIiwiZW50cmllcyIsIndhcm4iLCJzb3J0Iiwic2VsZWN0b3JLZXkiLCJyZWMiLCJDb3VjaERCT3BlcmF0b3IiLCJCSUdHRVIiLCJsaW1pdFNlbGVjdG9yIiwiQ291Y2hEQlF1ZXJ5TGltaXQiLCJvZmZzZXRTZWxlY3RvciIsInNraXAiLCJtZXJnZSIsIm9wIiwib2JqMSIsIm9iajIiLCJhdHRyMSIsIm9wZXJhdG9yIiwiY29tcGFyaXNvbiIsIk9wZXJhdG9yIiwiQkVUV0VFTiIsIlF1ZXJ5RXJyb3IiLCJtYXgiLCJvcEJldHdlZW4iLCJ0cmFuc2xhdGVPcGVyYXRvcnMiLCJCSUdHRVJfRVEiLCJTTUFMTEVSX0VRIiwiR3JvdXBPcGVyYXRvciIsIk5PVCIsIm9wMSIsIm9wMiIsImF2Z1NlbGVjdG9yIiwic3VtSW5mbyIsImNyZWF0ZUFnZ3JlZ2F0ZURlc2NyaXB0b3IiLCJjb3VudEluZm8iLCJjcmVhdGVBZ2dyZWdhdGVRdWVyeSIsImtpbmQiLCJzdW1EZXNjcmlwdG9yIiwiY291bnREZXNjcmlwdG9yIiwiY291bnREaXN0aW5jdFNlbGVjdG9yIiwiY291bnREaXN0aW5jdCIsImFnZ3JlZ2F0b3JVc2VkIiwiY291bnRTZWxlY3RvciIsIm1pblNlbGVjdG9yIiwibWF4U2VsZWN0b3IiLCJzdW1TZWxlY3RvciIsImRpc3RpbmN0U2VsZWN0b3IiLCJhZ2dyZWdhdG9yQ2hlY2tzIiwibWV0YXMiLCJmaW5kVmlld01ldGFkYXRhIiwidmlld05hbWUiLCJnZW5lcmF0ZVZpZXdOYW1lIiwiZGRvYyIsImdlbmVyYXRlRGVzaWduRG9jTmFtZSIsInJldHVybkRvY3MiLCJ2aWV3IiwiZ2V0RmFicmljQWRhcHRlciIsImlzVmlld0FnZ3JlZ2F0ZSIsImhhbmRsZUF2ZXJhZ2UiLCJmYWJyaWNBZGFwdGVyIiwidmlld0luZm8iLCJwcm9jZXNzVmlld1Jlc3BvbnNlIiwic3VtRGVzYyIsImNvdW50RGVzYyIsInN1bVJlc3BvbnNlIiwiY291bnRSZXNwb25zZSIsInN1bSIsInJvd3MiLCJyb3ciLCJGYWJyaWNDbGllbnRQYWdpbmF0b3IiLCJyYXdTdGF0ZW1lbnQiLCJwYWdlIiwiRmFicmljQ2xpZW50QWRhcHRlciIsIkFkYXB0ZXIiLCJvcGVyYXRpb24iLCJyZXBvc2l0b3J5IiwiY3JlYXRlUHJlZml4IiwidXBkYXRlQWxsUHJlZml4Iiwic2hpZnQiLCJCdWxrQ3J1ZE9wZXJhdGlvbktleXMiLCJDUkVBVEVfQUxMIiwicmVhZEFsbCIsIlJFQURfQUxMIiwiVVBEQVRFX0FMTCIsImRlbGV0ZUFsbCIsIkRFTEVURV9BTEwiLCJNRVRBREFUQSIsInNpbGx5IiwidXBkYXRlUHJlZml4IiwiVVBEQVRFIiwiREVMRVRFIiwiZG9jc09ubHkiLCJ0cmFuc2FjdGlvblJlc3VsdCIsInBhcnNlUmVjb3JkIiwiaXNNb2RlbCIsImVsIiwiZ2V0Q2xpZW50IiwiX2NsaWVudCIsIkdhdGV3YXkiLCJnZXRHYXRld2F5IiwiZ2V0Q29udHJhY3ROYW1lIiwiQ29udHJhY3QiLCJjb250cmFjdE5hbWUiLCJnZXRDb250cmFjdCIsInRyYW5zYWN0aW9uIiwiYXBpIiwic3VibWl0IiwidHJhbnNpZW50RGF0YSIsImVuZG9yc2luZ09yZ2FuaXphdGlvbnMiLCJnYXRld2F5IiwiY29udHJhY3QiLCJldmFsdWF0ZSIsInByb3Bvc2FsT3B0aW9ucyIsImFyZ3VtZW50cyIsImRldGFpbHMiLCJuZXR3b3JrIiwiZ2V0TmV0d29yayIsImNoYW5uZWwiLCJjaGFpbmNvZGVOYW1lIiwiY2hhbm5lbE5hbWUiLCJnZXRDb25uZWN0aW9uIiwicGF0aE9yQ2VydCIsInRsc0NlcnQiLCJ0bHNDcmVkZW50aWFscyIsImdycGMiLCJjcmVhdGVTc2wiLCJwZWVyRW5kcG9pbnQiLCJzaXplTGltaXQiLCJjZXJ0Q2VydE9yRGlyZWN0b3J5UGF0aCIsImtleUNlcnRPckRpcmVjdG9yeVBhdGgiLCJwa2NzMTFTaWduZXIiLCJldmFsdWF0ZU9wdGlvbnMiLCJkZWFkbGluZSIsImVuZG9yc2VPcHRpb25zIiwic3VibWl0T3B0aW9ucyIsImNvbW1pdFN0YXR1c09wdGlvbnMiLCJjb25uZWN0IiwiUHJveHkiLCJ0aGlzQXJnIiwiYXJnQXJyYXkiLCJSZWZsZWN0IiwiRGlzcGF0Y2giLCJCYWRSZXF1ZXN0RXJyb3IiLCJQYWdpbmdFcnJvciIsIk1pZ3JhdGlvbkVycm9yIiwiT2JzZXJ2ZXJFcnJvciIsIkZvcmJpZGRlbkVycm9yIiwiQ29ubmVjdGlvbkVycm9yIiwiZmluYWwiLCJEIiwiX2EiLCJkZWNvcmF0aW9uIiwic2V0Q3VycmVudCIsIkZhYnJpY0NsaWVudERpc3BhdGNoIiwibGlzdGVuaW5nU3RhY2siLCJwYXJzZVBheWxvYWQiLCJqc29uQnl0ZXMiLCJqc29uIiwib2JzZXJ2ZSIsIm9ic2VydmVyIiwidW5PYnNlcnZlIiwicmVmcmVzaCIsImhhbmRsZUV2ZW50cyIsImN0eEFyZyIsImNvcnJlbGF0aW9uSWQiLCJldnQiLCJldmVudE5hbWUiLCJ0YXJnZXRNb2RlbCIsIm1vZGVsUmVmIiwiZ2V0Q2hhaW5jb2RlRXZlbnRzIiwiVkVSU0lPTiIsIlBBQ0tBR0VfTkFNRSIsInJlZ2lzdGVyTGlicmFyeSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFxRE0sTUFBT0EsK0JBR0hDO0lBVVIsV0FBQUMsQ0FBWUMsU0FBYUM7UUFDdkJDLE1BQU1GLFNBQVNDO1FBVkVFLEtBQVVDLGFBQUdDLE9BQU9DLE9BQU8sQ0FBQSxHQUFJSixNQUFNLGVBQWU7WUFDckVLLGtCQUFrQjtZQUNsQkMsZ0JBQWdCO1lBQ2hCQyxvQkFBb0I7WUFDcEJDLDJCQUEyQjtZQUMzQkMsNEJBQTRCO1lBQzVCQyx5QkFBeUI7O0FBSzFCO0lBRVEsUUFBQUMsQ0FBU0M7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
|