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