summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mod/bpgenerator/TestCases/imports/imports.yaml2
-rw-r--r--mod/bpgenerator/TestCases/imports/importsWithBlanks.yaml3
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/core/TestComponentSpec.java148
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Appconfig.java15
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Blueprint.java122
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Imports.java46
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Interfaces.java4
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Properties.java17
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/ResourceConfig.java19
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Start.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/StartInputs.java13
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapInfo.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapObj.java16
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Artifacts.java9
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Auxilary.java15
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/CallsObj.java5
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ConstraintsObj.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Container.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/EntrySchemaObj.java6
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/HealthCheck.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Host.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Parameters.java11
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Policy.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/PolicySchemaObj.java6
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ProvidesObj.java6
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Publishes.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ReconfigsObj.java9
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/RequestResponseObj.java5
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Self.java10
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Services.java6
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Streams.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Subscribes.java8
-rw-r--r--mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Volumes.java10
-rw-r--r--mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/core/BlueprintGeneratorTest.java244
-rw-r--r--mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/models/blueprint/ImportsTest.java52
-rw-r--r--mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/models/blueprint/tls/ExternalCertificateParametersFactoryTest.java2
-rw-r--r--mod/runtimeapi/pom.xml2
-rw-r--r--mod/runtimeapi/runtime-core/pom.xml6
-rw-r--r--mod/runtimeapi/runtime-web/pom.xml6
-rw-r--r--mod2/auth-service/Dockerfile11
-rw-r--r--mod2/auth-service/pom.xml171
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/AuthServiceApplication.java40
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/DataLoader.java97
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/AuthController.java171
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/RoleController.java58
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/UserController.java96
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/AppExceptionHandler.java52
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/IllegalUserOperationException.java34
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/RoleNotExistsException.java34
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserAlreadyExistsException.java34
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserNotFoundException.java34
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/GenericResponse.java40
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/JwtResponse.java50
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/LoginRequest.java43
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/ModUser.java75
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/Role.java50
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/SignupRequest.java53
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/UpdateUserRequest.java47
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/RoleRepository.java37
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/UserRepository.java40
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/WebSecurityConfigurer.java92
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthEntryPointJwt.java51
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthTokenFilter.java81
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/JwtUtils.java90
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsImpl.java127
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsServiceImpl.java100
-rw-r--r--mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/services/MODUserDetailService.java56
-rw-r--r--mod2/auth-service/src/main/resources/application.properties32
-rw-r--r--mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/AuthObjectMother.java85
-rw-r--r--mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/RoleObjectMother.java56
-rw-r--r--mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/UserObjectMother.java100
-rw-r--r--mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java60
-rw-r--r--mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/AuthControllerTest.java149
-rw-r--r--mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/RoleControllerTest.java109
-rw-r--r--mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/UserControllerTest.java168
-rw-r--r--mod2/auth-service/src/test/resources/application.properties1
-rw-r--r--mod2/auth-service/src/test/resources/http/requests/AuthLoginRequest.json4
-rw-r--r--mod2/auth-service/src/test/resources/http/requests/AuthSignupRequest.json6
-rw-r--r--mod2/auth-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json149
-rw-r--r--mod2/auth-service/src/test/resources/specification/policy_json_sample_3.json28
-rw-r--r--mod2/catalog-service/Dockerfile14
-rw-r--r--mod2/catalog-service/lombok.config1
-rw-r--r--mod2/catalog-service/pom.xml200
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/ModCatalogApplication.java68
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mock/MockDeploymentArtifactGenerator.java45
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mock/MockSpecificationValidationStratergy.java42
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMicroservice.java65
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsLocation.java29
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsStatus.java28
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsType.java32
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/common/AuditFields.java51
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifact.java51
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactFilter.java40
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactSearch.java38
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactStatus.java30
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/MsInstanceInfo.java33
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ErrorMessages.java33
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/MissingRequestBodyException.java24
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/OperationNotAllowedException.java27
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ReleaseNotSupportedException.java24
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ResourceConflictException.java27
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceNotFoundException.java27
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceTagAlreadyExists.java24
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceTagInvalid.java24
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMsServiceNameAlreadyExists.java24
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMsServiceNameInvalid.java24
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/common/UserNotPassedException.java27
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/BlueprintFileNameCreateException.java27
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/DeploymentArtifactNotFound.java27
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/StatusChangeNotValidException.java28
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/msinstance/MsInstanceAlreadyExistsException.java24
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/msinstance/MsInstanceNotFoundException.java27
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/specification/SpecificationInvalid.java38
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/specification/SpecificationNotFoundException.java24
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/DeploymentArtifactsRef.java36
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/MsInstance.java56
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/MsInstanceStatus.java28
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/DeploymentArtifactPatchRequest.java40
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/ErrorResponse.java35
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/GenericErrorResponse.java54
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MicroserviceCreateRequest.java59
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MicroserviceUpdateRequest.java52
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MsInstanceRequest.java52
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MsInstanceUpdateRequest.java42
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/SpecificationRequest.java45
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/SuccessResponse.java34
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/DeploymentType.java28
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/Specification.java52
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/SpecificationStatus.java28
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/basemicroservice/BaseMicroserviceMongoGateway.java71
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/basemicroservice/BaseMicroserviceMongoRepo.java40
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/deploymentartifact/DeploymentArtifactMongoGateway.java86
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/deploymentartifact/DeploymentArtifactMongoRepo.java37
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/microserviceinstance/MsInstanceMongoGateway.java61
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/microserviceinstance/MsInstanceMongoRepo.java38
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/specification/SpecificationMongoGateway.java48
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/specification/SpecificationMongoRepo.java38
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/AppExceptionHandler.java149
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/BaseMicroserviceController.java70
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/DeploymentArtifactController.java115
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/MicroserviceInstanceController.java75
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/SpecificationController.java62
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/BaseMicroserviceGateway.java45
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/MsService.java47
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/MsServiceImpl.java257
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/ArtifactFileNameCreator.java59
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactGateway.java45
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactGeneratorStrategy.java32
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactService.java51
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactServiceImpl.java205
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactStatusChangeHandler.java77
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceGateway.java40
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceService.java51
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceServiceImpl.java213
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceStatusChangeHandler.java75
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationGateway.java37
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationService.java40
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationServiceImpl.java138
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationValidationStratergy.java30
-rw-r--r--mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationValidatorService.java61
-rw-r--r--mod2/catalog-service/src/main/resources/application.properties24
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/BaseMsObjectMother.java131
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/DeploymentArtifactObjectMother.java222
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/MsInstanceObjectMother.java112
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/SpecificationObjectMother.java41
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/persistence/DeploymentArtifactGatewayTest.java147
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java53
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/BaseMicroserviceControllerTest.java165
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/DeploymentArtifactControllerTest.java170
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/MicroserviceInstanceControllerTest.java145
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/MsRequestValidationTest.java87
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/SpecificationControllerTest.java79
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsInstanceServiceImplTest.java209
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsInstanceStatusChangeHandlerTest.java92
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsServiceImplTest.java217
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/SpecificationServiceTest.java103
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/ArtifactFileNameCreatorTest.java89
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactServiceImplTest.java250
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactStatusChangeHandlerTest.java106
-rw-r--r--mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/SearchDeploymentArtifactsTest.java90
-rw-r--r--mod2/catalog-service/src/test/resources/application.properties1
-rw-r--r--mod2/catalog-service/src/test/resources/http/requests/CreateSpecificationRequest.json180
-rw-r--r--mod2/catalog-service/src/test/resources/http/requests/CreateSpecificationResponse.json188
-rw-r--r--mod2/catalog-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json149
-rw-r--r--mod2/catalog-service/src/test/resources/specification/policy_json_sample_3.json28
-rw-r--r--mod2/ui/.editorconfig13
-rw-r--r--mod2/ui/.gitignore46
-rw-r--r--mod2/ui/Dockerfile26
-rw-r--r--mod2/ui/Jenkinsfile3
-rw-r--r--mod2/ui/README.md27
-rw-r--r--mod2/ui/angular.json128
-rw-r--r--mod2/ui/browserslist12
-rw-r--r--mod2/ui/dependenciesFile0
-rw-r--r--mod2/ui/e2e/protractor.conf.js50
-rw-r--r--mod2/ui/e2e/src/app.e2e-spec.ts41
-rw-r--r--mod2/ui/e2e/src/app.po.ts29
-rw-r--r--mod2/ui/e2e/tsconfig.json13
-rw-r--r--mod2/ui/extra-webpack.config.js29
-rw-r--r--mod2/ui/healthcheck.sh20
-rw-r--r--mod2/ui/karma.conf.js50
-rw-r--r--mod2/ui/package-lock.json10747
-rw-r--r--mod2/ui/package.json64
-rw-r--r--mod2/ui/pipelineConfig.json21
-rw-r--r--mod2/ui/pom.xml72
-rw-r--r--mod2/ui/proxy.conf.json11
-rw-r--r--mod2/ui/src/app/app-routing.module.ts55
-rw-r--r--mod2/ui/src/app/app.component.css173
-rw-r--r--mod2/ui/src/app/app.component.html136
-rw-r--r--mod2/ui/src/app/app.component.spec.ts90
-rw-r--r--mod2/ui/src/app/app.component.ts218
-rw-r--r--mod2/ui/src/app/app.module.ts172
-rw-r--r--mod2/ui/src/app/blueprints/blueprints.component.css142
-rw-r--r--mod2/ui/src/app/blueprints/blueprints.component.html283
-rw-r--r--mod2/ui/src/app/blueprints/blueprints.component.spec.ts153
-rw-r--r--mod2/ui/src/app/blueprints/blueprints.component.ts602
-rw-r--r--mod2/ui/src/app/comp-spec-add/comp-spec-add.component.css43
-rw-r--r--mod2/ui/src/app/comp-spec-add/comp-spec-add.component.html64
-rw-r--r--mod2/ui/src/app/comp-spec-add/comp-spec-add.component.spec.ts77
-rw-r--r--mod2/ui/src/app/comp-spec-add/comp-spec-add.component.ts180
-rw-r--r--mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.css73
-rw-r--r--mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.html108
-rw-r--r--mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.spec.ts132
-rw-r--r--mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.ts145
-rw-r--r--mod2/ui/src/app/comp-specs/comp-specs.component.css121
-rw-r--r--mod2/ui/src/app/comp-specs/comp-specs.component.html189
-rw-r--r--mod2/ui/src/app/comp-specs/comp-specs.component.spec.ts133
-rw-r--r--mod2/ui/src/app/comp-specs/comp-specs.component.ts211
-rw-r--r--mod2/ui/src/app/guards/auth.guard.spec.ts44
-rw-r--r--mod2/ui/src/app/guards/auth.guard.ts62
-rw-r--r--mod2/ui/src/app/guards/login.guard.spec.ts41
-rw-r--r--mod2/ui/src/app/guards/login.guard.ts52
-rw-r--r--mod2/ui/src/app/guards/role.guard.spec.ts44
-rw-r--r--mod2/ui/src/app/guards/role.guard.ts61
-rw-r--r--mod2/ui/src/app/home/home.component.css50
-rw-r--r--mod2/ui/src/app/home/home.component.html93
-rw-r--r--mod2/ui/src/app/home/home.component.ts64
-rw-r--r--mod2/ui/src/app/login/login.component.css25
-rw-r--r--mod2/ui/src/app/login/login.component.html58
-rw-r--r--mod2/ui/src/app/login/login.component.spec.ts59
-rw-r--r--mod2/ui/src/app/login/login.component.ts65
-rw-r--r--mod2/ui/src/app/material-elevation.directive.ts64
-rw-r--r--mod2/ui/src/app/microservices/microservices.component.css121
-rw-r--r--mod2/ui/src/app/microservices/microservices.component.html185
-rw-r--r--mod2/ui/src/app/microservices/microservices.component.spec.ts134
-rw-r--r--mod2/ui/src/app/microservices/microservices.component.ts311
-rw-r--r--mod2/ui/src/app/models/AuthResponse.ts28
-rw-r--r--mod2/ui/src/app/models/Authority.enum.ts22
-rw-r--r--mod2/ui/src/app/models/User.ts25
-rw-r--r--mod2/ui/src/app/ms-add-change/ms-add-change.component.css57
-rw-r--r--mod2/ui/src/app/ms-add-change/ms-add-change.component.html109
-rw-r--r--mod2/ui/src/app/ms-add-change/ms-add-change.component.spec.ts67
-rw-r--r--mod2/ui/src/app/ms-add-change/ms-add-change.component.ts180
-rw-r--r--mod2/ui/src/app/ms-instance-add/ms-instance-add.component.css48
-rw-r--r--mod2/ui/src/app/ms-instance-add/ms-instance-add.component.html93
-rw-r--r--mod2/ui/src/app/ms-instance-add/ms-instance-add.component.spec.ts71
-rw-r--r--mod2/ui/src/app/ms-instance-add/ms-instance-add.component.ts189
-rw-r--r--mod2/ui/src/app/msInstances/msInstances.component.css148
-rw-r--r--mod2/ui/src/app/msInstances/msInstances.component.html221
-rw-r--r--mod2/ui/src/app/msInstances/msInstances.component.spec.ts127
-rw-r--r--mod2/ui/src/app/msInstances/msInstances.component.ts511
-rw-r--r--mod2/ui/src/app/onboarding-tools/onboarding-tools.component.css27
-rw-r--r--mod2/ui/src/app/onboarding-tools/onboarding-tools.component.html23
-rw-r--r--mod2/ui/src/app/onboarding-tools/onboarding-tools.component.spec.ts48
-rw-r--r--mod2/ui/src/app/onboarding-tools/onboarding-tools.component.ts52
-rw-r--r--mod2/ui/src/app/register/register.component.css18
-rw-r--r--mod2/ui/src/app/register/register.component.html62
-rw-r--r--mod2/ui/src/app/register/register.component.spec.ts61
-rw-r--r--mod2/ui/src/app/register/register.component.ts99
-rw-r--r--mod2/ui/src/app/reset-password/reset-password.component.css18
-rw-r--r--mod2/ui/src/app/reset-password/reset-password.component.html64
-rw-r--r--mod2/ui/src/app/reset-password/reset-password.component.spec.ts58
-rw-r--r--mod2/ui/src/app/reset-password/reset-password.component.ts78
-rw-r--r--mod2/ui/src/app/services/auth.service.spec.ts43
-rw-r--r--mod2/ui/src/app/services/auth.service.ts95
-rw-r--r--mod2/ui/src/app/services/base-microservice.service.spec.ts42
-rw-r--r--mod2/ui/src/app/services/base-microservice.service.ts35
-rw-r--r--mod2/ui/src/app/services/breadcrumb.service.ts73
-rw-r--r--mod2/ui/src/app/services/comp-spec-add.service.spec.ts42
-rw-r--r--mod2/ui/src/app/services/comp-spec-add.service.ts45
-rw-r--r--mod2/ui/src/app/services/comp-specs-service.service.spec.ts43
-rw-r--r--mod2/ui/src/app/services/comp-specs-service.service.ts43
-rw-r--r--mod2/ui/src/app/services/deployment-artifact.service.spec.ts43
-rw-r--r--mod2/ui/src/app/services/deployment-artifact.service.ts71
-rw-r--r--mod2/ui/src/app/services/download.service.spec.ts41
-rw-r--r--mod2/ui/src/app/services/download.service.ts85
-rw-r--r--mod2/ui/src/app/services/global-filters.service.spec.ts30
-rw-r--r--mod2/ui/src/app/services/global-filters.service.ts55
-rw-r--r--mod2/ui/src/app/services/jwt-interceptor.service.spec.ts30
-rw-r--r--mod2/ui/src/app/services/jwt-interceptor.service.ts40
-rw-r--r--mod2/ui/src/app/services/microservice-instance.service.spec.ts41
-rw-r--r--mod2/ui/src/app/services/microservice-instance.service.ts46
-rw-r--r--mod2/ui/src/app/services/ms-add.service.spec.ts42
-rw-r--r--mod2/ui/src/app/services/ms-add.service.ts52
-rw-r--r--mod2/ui/src/app/services/spec-validation.service.spec.ts41
-rw-r--r--mod2/ui/src/app/services/spec-validation.service.ts53
-rw-r--r--mod2/ui/src/app/services/user.service.spec.ts44
-rw-r--r--mod2/ui/src/app/services/user.service.ts53
-rw-r--r--mod2/ui/src/app/shared/shared-module.ts61
-rw-r--r--mod2/ui/src/app/user-management/user-management.component.css54
-rw-r--r--mod2/ui/src/app/user-management/user-management.component.html89
-rw-r--r--mod2/ui/src/app/user-management/user-management.component.spec.ts63
-rw-r--r--mod2/ui/src/app/user-management/user-management.component.ts149
-rw-r--r--mod2/ui/src/assets/.gitkeep0
-rw-r--r--mod2/ui/src/assets/env.js17
-rw-r--r--mod2/ui/src/environments/environment.prod.ts22
-rw-r--r--mod2/ui/src/environments/environment.ts35
-rw-r--r--mod2/ui/src/favicon.icobin0 -> 5430 bytes
-rw-r--r--mod2/ui/src/index.html36
-rw-r--r--mod2/ui/src/main.ts31
-rw-r--r--mod2/ui/src/polyfills.ts81
-rw-r--r--mod2/ui/src/styles.css33
-rw-r--r--mod2/ui/src/test.ts38
-rw-r--r--mod2/ui/tsconfig.app.json14
-rw-r--r--mod2/ui/tsconfig.json33
-rw-r--r--mod2/ui/tsconfig.spec.json18
-rw-r--r--mod2/ui/tslint.json92
-rw-r--r--mod2/ui/typings.d.ts32
-rw-r--r--releases/1.5.1-blueprint-generator.yaml4
318 files changed, 31639 insertions, 495 deletions
diff --git a/mod/bpgenerator/TestCases/imports/imports.yaml b/mod/bpgenerator/TestCases/imports/imports.yaml
new file mode 100644
index 0000000..4b52b8a
--- /dev/null
+++ b/mod/bpgenerator/TestCases/imports/imports.yaml
@@ -0,0 +1,2 @@
+imports: ['https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml', 'plugin:k8splugin?version=3.4.1',
+ 'plugin:pgaas?version=1.3.0', 'plugin:clamppolicyplugin?version=1.1.0', 'plugin:dmaap?version=1.5.0']
diff --git a/mod/bpgenerator/TestCases/imports/importsWithBlanks.yaml b/mod/bpgenerator/TestCases/imports/importsWithBlanks.yaml
new file mode 100644
index 0000000..242c2a9
--- /dev/null
+++ b/mod/bpgenerator/TestCases/imports/importsWithBlanks.yaml
@@ -0,0 +1,3 @@
+imports: ['https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml', 'plugin:k8splugin?version=3.4.1',
+ '', ' ', ' ', 'plugin:pgaas?version=1.3.0', 'plugin:clamppolicyplugin?version=1.1.0',
+ 'plugin:dmaap?version=1.5.0']
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/core/TestComponentSpec.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/core/TestComponentSpec.java
index 5d4131b..f9fa2cb 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/core/TestComponentSpec.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/core/TestComponentSpec.java
@@ -18,18 +18,32 @@
*/
-
package org.onap.blueprintgenerator.core;
-
-
-
+import java.util.ArrayList;
+import java.util.TreeMap;
import lombok.Getter;
import lombok.Setter;
+import org.onap.blueprintgenerator.models.componentspec.Artifacts;
+import org.onap.blueprintgenerator.models.componentspec.Auxilary;
+import org.onap.blueprintgenerator.models.componentspec.CallsObj;
+import org.onap.blueprintgenerator.models.componentspec.ComponentSpec;
+import org.onap.blueprintgenerator.models.componentspec.Container;
+import org.onap.blueprintgenerator.models.componentspec.HealthCheck;
+import org.onap.blueprintgenerator.models.componentspec.Host;
+import org.onap.blueprintgenerator.models.componentspec.Parameters;
+import org.onap.blueprintgenerator.models.componentspec.Policy;
+import org.onap.blueprintgenerator.models.componentspec.ProvidesObj;
+import org.onap.blueprintgenerator.models.componentspec.Publishes;
+import org.onap.blueprintgenerator.models.componentspec.Self;
+import org.onap.blueprintgenerator.models.componentspec.Services;
+import org.onap.blueprintgenerator.models.componentspec.Streams;
+import org.onap.blueprintgenerator.models.componentspec.Subscribes;
+import org.onap.blueprintgenerator.models.componentspec.Volumes;
@Getter @Setter
public class TestComponentSpec {
- private String cs = "{\r\n" +
+ private String componentSpecAsString = "{\r\n" +
" \"self\": {\r\n" +
" \"component_type\": \"docker\",\r\n" +
" \"description\": \"Test component spec\",\r\n" +
@@ -129,4 +143,128 @@ public class TestComponentSpec {
" }] \r\n" +
"\r\n" +
"}";
+ private ComponentSpec componentSpec;
+
+ public TestComponentSpec() {
+ this.componentSpec = createComponentSpec();
+ }
+
+ private ComponentSpec createComponentSpec(){
+ //Manually fill a component spec object with the values from the file itself
+ ComponentSpec manualSpec = new ComponentSpec();
+
+ Self self = new Self();
+ self.setComponent_type("docker");
+ self.setDescription("Test component spec");
+ self.setName("test.component.spec");
+ self.setVersion("1.0.1");
+ manualSpec.setSelf(self);
+
+ Services services = new Services();
+ CallsObj[] calls = new CallsObj[0];
+ ProvidesObj[] provides = new ProvidesObj[0];
+ services.setCalls(calls);
+ services.setProvides(provides);
+ manualSpec.setServices(null);
+
+ Streams streams = new Streams();
+ Publishes[] publishes = new Publishes[2];
+ Publishes pub1 = new Publishes();
+ pub1.setConfig_key("TEST-PUB-DR");
+ pub1.setFormat("dataformat_Hello_World_PM");
+ pub1.setType("data_router");
+ pub1.setVersion("1.0.0");
+
+ Publishes pub2 = new Publishes();
+ pub2.setConfig_key("TEST-PUB-MR");
+ pub2.setFormat("dataformat_Hello_World_PM");
+ pub2.setType("message_router");
+ pub2.setVersion("1.0.0");
+ publishes[0] = pub1;
+ publishes[1] = pub2;
+ streams.setPublishes(publishes);
+
+ Subscribes[] subscribes = new Subscribes[2];
+ Subscribes sub1 = new Subscribes();
+ sub1.setConfig_key("TEST-SUB-MR");
+ sub1.setFormat("dataformat_Hello_World_PM");
+ sub1.setRoute("/TEST_HELLO_WORLD_SUB_MR");
+ sub1.setType("message_router");
+ sub1.setVersion("1.0.0");
+
+ Subscribes sub2 = new Subscribes();
+ sub2.setConfig_key("TEST-SUB-DR");
+ sub2.setFormat("dataformat_Hello_World_PM");
+ sub2.setRoute("/TEST-HELLO-WORLD-SUB-DR");
+ sub2.setType("data_router");
+ sub2.setVersion("1.0.0");
+ subscribes[0] = sub1;
+ subscribes[1] = sub2;
+ streams.setSubscribes(subscribes);
+
+ manualSpec.setStreams(streams);
+
+ Parameters[] parameters = new Parameters[1];
+ Parameters par1 = new Parameters();
+ par1.setName("testParam1");
+ par1.setValue("test-param-1");
+ par1.setDescription("test parameter 1");
+ par1.setSourced_at_deployment(true);
+ par1.setDesigner_editable(true);
+ par1.setPolicy_editable(true);
+ par1.setPolicy_group("Test_Parameters");
+ par1.setRequired(true);
+ par1.setType("string");
+ parameters[0] = par1;
+
+ manualSpec.setParameters(parameters);
+
+ Auxilary auxilary = new Auxilary();
+ HealthCheck healthcheck = new HealthCheck();
+ healthcheck.setInterval("300s");
+ healthcheck.setTimeout("120s");
+ healthcheck.setScript("/etc/init.d/nagios status");
+ healthcheck.setType("docker");
+ auxilary.setHealthcheck(healthcheck);
+
+ Volumes[] volumes = new Volumes[1];
+ Volumes vol1 = new Volumes();
+ Container con1 = new Container();
+ con1.setBind("/opt/app/manager/config/hostname");
+ Host host1 = new Host();
+ host1.setPath("/etc/hostname");
+ host1.setMode("ro");
+ vol1.setContainer(con1);
+ vol1.setHost(host1);
+
+ volumes[0] = vol1;
+
+ auxilary.setVolumes(volumes);
+
+ ArrayList<Object> ports = new ArrayList();
+ ports.add("80:80");
+
+ TreeMap<String, String> dataBases = new TreeMap<>();
+ dataBases.put("TestDB1", "PGaaS");
+ dataBases.put("TestDB2", "PGaaS");
+ auxilary.setDatabases(dataBases);
+
+ Policy pol = new Policy();
+ pol.setTrigger_type("docker");
+ pol.setScript_path("/opt/app/manager/bin/reconfigure.sh");
+ auxilary.setPolicy(pol);
+
+ auxilary.setPorts(ports);
+
+ manualSpec.setAuxilary(auxilary);
+
+ Artifacts[] artifacts = new Artifacts[1];
+ Artifacts art = new Artifacts();
+ art.setType("docker image");
+ art.setUri("test.tester");
+
+ artifacts[0] = art;
+ manualSpec.setArtifacts(artifacts);
+ return manualSpec;
+ }
}
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Appconfig.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Appconfig.java
index b39a8ec..75864be 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Appconfig.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Appconfig.java
@@ -52,8 +52,7 @@ public class Appconfig {
public TreeMap<String, LinkedHashMap<String, Object>> createAppconfig(TreeMap<String, LinkedHashMap<String, Object>> inps, ComponentSpec cs, String override,
boolean isDmaap) {
- TreeMap<String, LinkedHashMap<String, Object>> retInputs = new TreeMap<String, LinkedHashMap<String, Object>>();
- retInputs = inps;
+ TreeMap<String, LinkedHashMap<String, Object>> retInputs = inps;
//set service calls
CallsObj[] call = new CallsObj[0];
@@ -83,7 +82,7 @@ public class Appconfig {
}
//set the stream publishes
- TreeMap<String, DmaapObj> streamSubscribes = new TreeMap<String, DmaapObj>();
+ TreeMap<String, DmaapObj> streamSubscribes = new TreeMap<>();
if(cs.getStreams().getSubscribes().length != 0) {
for(Subscribes s: cs.getStreams().getSubscribes()) {
@@ -110,7 +109,7 @@ public class Appconfig {
this.setStreams_subscribes(streamSubscribes);
//set the parameters into the appconfig
- TreeMap<String, Object> parameters = new TreeMap<String, Object>();
+ TreeMap<String, Object> parameters = new TreeMap<>();
for(Parameters p: cs.getParameters()) {
String pName = p.getName();
if(p.isSourced_at_deployment()) {
@@ -119,17 +118,17 @@ public class Appconfig {
parameters.put(pName, paramInput);
if(!p.getValue().equals("")) {
- LinkedHashMap<String, Object> inputs = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> inputs = new LinkedHashMap<>();
inputs.put("type", "string");
inputs.put("default", p.getValue());
retInputs.put(pName, inputs);
} else {
- LinkedHashMap<String, Object> inputs = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> inputs = new LinkedHashMap<>();
inputs.put("type", "string");
retInputs.put(pName, inputs);
}
} else {
- if(p.getType() == "string") {
+ if("string".equals(p.getType())) {
String val =(String) p.getValue();
val = '"' + val + '"';
parameters.put(pName, val);
@@ -143,7 +142,7 @@ public class Appconfig {
GetInput ov = new GetInput();
ov.setBpInputName("service_component_name_override");
parameters.put("service_component_name_override", ov);
- LinkedHashMap<String, Object> over = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> over = new LinkedHashMap<>();
over.put("type", "string");
over.put("default", override);
retInputs.put("service_component_name_override", over);
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Blueprint.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Blueprint.java
index c043a9e..f2ef7aa 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Blueprint.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Blueprint.java
@@ -20,35 +20,27 @@
package org.onap.blueprintgenerator.models.blueprint;
-import java.io.*;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.TreeMap;
import java.util.regex.Pattern;
-
+import lombok.Getter;
+import lombok.Setter;
import org.onap.blueprintgenerator.core.Fixes;
import org.onap.blueprintgenerator.models.componentspec.ComponentSpec;
-import org.onap.blueprintgenerator.models.componentspec.Parameters;
-import org.onap.blueprintgenerator.models.componentspec.Publishes;
-import org.onap.blueprintgenerator.models.componentspec.Subscribes;
import org.onap.blueprintgenerator.models.dmaapbp.DmaapBlueprint;
import org.onap.blueprintgenerator.models.onapbp.OnapBlueprint;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.core.JsonProcessingException;
-//import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
-import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import org.yaml.snakeyaml.Yaml;
-
-
@Getter @Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
@@ -100,93 +92,43 @@ public class Blueprint {
public void blueprintToYaml(String outputPath, String bluePrintName, ComponentSpec cs) {
File outputFile;
-
- if(bluePrintName.equals("")) {
- String name = cs.getSelf().getName();
- if(name.contains(".")) {
- name = name.replaceAll(Pattern.quote("."), "_");
- }
- if(name.contains(" ")) {
- name = name.replaceAll(" ", "");
- }
- String file = name + ".yaml";
-
-
- outputFile = new File(outputPath, file);
- outputFile.getParentFile().mkdirs();
- try {
- outputFile.createNewFile();
- } catch (IOException e) {
-
- throw new RuntimeException(e);
- }
- } else {
- if(bluePrintName.contains(" ") || bluePrintName.contains(".")) {
- bluePrintName = bluePrintName.replaceAll(Pattern.quote("."), "_");
- bluePrintName = bluePrintName.replaceAll(" ", "");
- }
- String file = bluePrintName + ".yaml";
- outputFile = new File(outputPath, file);
- outputFile.getParentFile().mkdirs();
- try {
- outputFile.createNewFile();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ String name = bluePrintName.equals("") ? cs.getSelf().getName() : bluePrintName;
+ if(name.contains(".")) {
+ name = name.replaceAll(Pattern.quote("."), "_");
+ }
+ if(name.contains(" ")) {
+ name = name.replaceAll(" ", "");
+ }
+ String file = name + ".yaml";
+ outputFile = new File(outputPath, file);
+ outputFile.getParentFile().mkdirs();
+ try {
+ outputFile.createNewFile();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
String version = "#blueprint_version: " + cs.getSelf().getVersion() + '\n';
String description = "#description: " + cs.getSelf().getDescription() + '\n';
- BufferedWriter writer = null;
- try {
- writer = new BufferedWriter(new FileWriter(outputFile, false));
+ try(BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile, false))) {
+ writer.write(description);
+ writer.write(version);
} catch (IOException e1) {
throw new RuntimeException(e1);
}
- if(writer != null) {
- try {
- writer.write(description);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- try {
- writer.write(version);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- try {
- writer.close();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
//read the translated blueprint into the file
ObjectMapper blueprintMapper = new ObjectMapper(new YAMLFactory().configure(YAMLGenerator.Feature.MINIMIZE_QUOTES, true));
- PrintWriter out = null;
- try {
- out = new PrintWriter(new BufferedWriter(new FileWriter(outputFile, true)));
+ try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(outputFile, true)))) {
+ blueprintMapper.writeValue(out, this);
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
- if(out != null) {
- blueprintMapper.writeValue(out, this);
- out.close();
- }
- } catch (IOException e) {
-
- throw new RuntimeException(e);
- }
-
-
- Fixes fix = new Fixes();
- try {
- fix.fixSingleQuotes(outputFile);
+ Fixes.fixSingleQuotes(outputFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Imports.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Imports.java
index b17b045..7b55e17 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Imports.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Imports.java
@@ -20,24 +20,16 @@
package org.onap.blueprintgenerator.models.blueprint;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-
-
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
-import lombok.AllArgsConstructor;
-import lombok.Getter; import lombok.Setter;
-import lombok.NoArgsConstructor;
-
-
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import lombok.Getter;
+import lombok.Setter;
@Getter @Setter
@JsonInclude(value=Include.NON_NULL)
@@ -46,32 +38,30 @@ public class Imports {
private ArrayList<String> imports;
public static ArrayList<String> createOnapImports() {
- ArrayList<String> imps = new ArrayList<String>();
- imps.add("http://www.getcloudify.org/spec/cloudify/3.4/types.yaml");
- imps.add("https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R6/k8splugin/1.7.2/k8splugin_types.yaml");
- imps.add("https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R6/dcaepolicyplugin/2.4.0/dcaepolicyplugin_types.yaml");
+ ArrayList<String> imps = new ArrayList<>();
+ imps.add("https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml");
+ imps.add("plugin:k8splugin?version=3.4.2");
+ imps.add("plugin:dcaepolicyplugin?version=2.4.0");
return imps;
}
+
public static ArrayList<String> createDmaapImports(){
- ArrayList<String> imps = new ArrayList<String>();
- imps.add("http://www.getcloudify.org/spec/cloudify/3.4/types.yaml");
- imps.add("https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R5/k8splugin/1.6.0/k8splugin_types.yaml");
- imps.add("https://nexus.onap.org/service/local/repositories/raw/content/org.onap.ccsdk.platform.plugins/type_files/dmaap/dmaap.yaml");
+ ArrayList<String> imps = new ArrayList<>();
+ imps.add("https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml");
+ imps.add("plugin:k8splugin?version=3.4.2");
+ imps.add("plugin:dmaap?version=1.5.0");
return imps;
}
+
public static ArrayList<String> createImportsFromFile(String path) {
- Imports imports = new Imports();
ObjectMapper importMapper = new ObjectMapper(new YAMLFactory().configure(YAMLGenerator.Feature.MINIMIZE_QUOTES, true));
File importPath = new File(path);
try {
- imports = importMapper.readValue(importPath, Imports.class);
+ Imports imports = importMapper.readValue(importPath, Imports.class);
+ imports.getImports().removeIf(String::isBlank);
+ return imports.getImports();
} catch (IOException e) {
throw new RuntimeException(e);
}
- ArrayList<String> imps = new ArrayList<String>();
- for(String s: imports.getImports()) {
- imps.add(s);
- }
- return imps;
}
}
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Interfaces.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Interfaces.java
index a3404f6..435059e 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Interfaces.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Interfaces.java
@@ -31,11 +31,9 @@ import lombok.Getter; import lombok.Setter;
public class Interfaces {
private Start start;
public TreeMap<String, LinkedHashMap<String, Object>> createInterface(TreeMap<String, LinkedHashMap<String, Object>> inps, ComponentSpec cs){
- TreeMap<String, LinkedHashMap<String, Object>> retInputs = new TreeMap<String, LinkedHashMap<String, Object>>();
- retInputs = inps;
//create the start object
Start start = new Start();
- retInputs = start.createOnapStart(retInputs, cs);
+ TreeMap<String, LinkedHashMap<String, Object>> retInputs = start.createOnapStart(inps, cs);
this.setStart(start);
return retInputs;
}
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Properties.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Properties.java
index 5693f86..4140ea3 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Properties.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Properties.java
@@ -51,6 +51,8 @@ import org.onap.blueprintgenerator.models.dmaapbp.DmaapStreams;
@JsonInclude(value = Include.NON_NULL)
public class Properties {
+ ArrayList<DmaapStreams> streams_publishes;
+ ArrayList<DmaapStreams> streams_subscribes;
private Appconfig application_config;
private Auxilary docker_config;
private Object image;
@@ -62,8 +64,6 @@ public class Properties {
private String name;
private GetInput topic_name;
private GetInput feed_name;
- ArrayList<DmaapStreams> streams_publishes;
- ArrayList<DmaapStreams> streams_subscribes;
private TlsInfo tls_info;
private ExternalTlsInfo external_cert;
private ResourceConfig resource_config;
@@ -159,8 +159,7 @@ public class Properties {
public TreeMap<String, LinkedHashMap<String, Object>> createDmaapProperties(
TreeMap<String, LinkedHashMap<String, Object>> inps, ComponentSpec cs, String override) {
- TreeMap<String, LinkedHashMap<String, Object>> retInputs = new TreeMap<String, LinkedHashMap<String, Object>>();
- retInputs = inps;
+ TreeMap<String, LinkedHashMap<String, Object>> retInputs = inps;
//set the image
GetInput image = new GetInput();
@@ -175,7 +174,7 @@ public class Properties {
GetInput location = new GetInput();
location.setBpInputName("location_id");
this.setLocation_id(location);
- LinkedHashMap<String, Object> locMap = new LinkedHashMap();
+ LinkedHashMap<String, Object> locMap = new LinkedHashMap<>();
locMap.put("type", "string");
locMap.put("default", "");
retInputs.put("location_id", locMap);
@@ -223,7 +222,7 @@ public class Properties {
this.setApplication_config(app);
//set the stream publishes
- ArrayList<DmaapStreams> pubStreams = new ArrayList();
+ ArrayList<DmaapStreams> pubStreams = new ArrayList<>();
if (cs.getStreams().getPublishes() != null) {
for (Publishes publishes : cs.getStreams().getPublishes()) {
if (isMessageRouterType(publishes.getType())) {
@@ -245,7 +244,7 @@ public class Properties {
}
//set the stream subscribes
- ArrayList<DmaapStreams> subStreams = new ArrayList();
+ ArrayList<DmaapStreams> subStreams = new ArrayList<>();
if (cs.getStreams().getSubscribes() != null) {
for (Subscribes subscribes : cs.getStreams().getSubscribes()) {
if (isMessageRouterType(subscribes.getType())) {
@@ -266,10 +265,10 @@ public class Properties {
}
}
- if (pubStreams.size() != 0) {
+ if (!pubStreams.isEmpty()) {
this.setStreams_publishes(pubStreams);
}
- if (subStreams.size() != 0) {
+ if (!subStreams.isEmpty()) {
this.setStreams_subscribes(subStreams);
}
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/ResourceConfig.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/ResourceConfig.java
index 13aa0d0..6595a67 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/ResourceConfig.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/ResourceConfig.java
@@ -71,13 +71,12 @@ public class ResourceConfig {
* @return the tree map
*/
public TreeMap<String, LinkedHashMap<String, Object>> createResourceConfig(TreeMap<String, LinkedHashMap<String, Object>> inps, String name){
- TreeMap<String, LinkedHashMap<String, Object>> retInputs = inps;
- LinkedHashMap<String, Object> mi = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> mi = new LinkedHashMap<>();
mi.put("type", "string");
mi.put("default", "128Mi");
- LinkedHashMap<String, Object> m = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> m = new LinkedHashMap<>();
m.put("type", "string");
m.put("default", "250m");
@@ -87,7 +86,7 @@ public class ResourceConfig {
}
//set the limits
- TreeMap<String, GetInput> lim = new TreeMap<String, GetInput>();
+ TreeMap<String, GetInput> lim = new TreeMap<>();
GetInput cpu = new GetInput();
cpu.setBpInputName(name + "cpu_limit");
@@ -97,13 +96,13 @@ public class ResourceConfig {
memL.setBpInputName(name + "memory_limit");
lim.put("memory", memL);
- retInputs.put(name + "cpu_limit", m);
- retInputs.put(name + "memory_limit", mi);
+ inps.put(name + "cpu_limit", m);
+ inps.put(name + "memory_limit", mi);
this.setLimits(lim);
//set the requests
- TreeMap<String, GetInput> req = new TreeMap<String, GetInput>();
+ TreeMap<String, GetInput> req = new TreeMap<>();
GetInput cpuR = new GetInput();
cpuR.setBpInputName(name + "cpu_request");
@@ -113,12 +112,12 @@ public class ResourceConfig {
memR.setBpInputName(name + "memory_request");
req.put("memory", memR);
- retInputs.put(name + "cpu_request", m);
- retInputs.put(name + "memory_request", mi);
+ inps.put(name + "cpu_request", m);
+ inps.put(name + "memory_request", mi);
this.setRequests(req);
- return retInputs;
+ return inps;
}
}
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Start.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Start.java
index d9c885d..0b03777 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Start.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/Start.java
@@ -36,14 +36,12 @@ public class Start {
private LinkedHashMap<String, Object> envs;
public TreeMap<String, LinkedHashMap<String, Object>> createOnapStart(TreeMap<String, LinkedHashMap<String, Object>> inps, ComponentSpec cs) {
- TreeMap<String, LinkedHashMap<String, Object>> retInputs = inps;
- retInputs = inps;
-
+
//create the start inputs
StartInputs inputs = new StartInputs();
- inputs.createOnapStartInputs(retInputs, cs);
+ inputs.createOnapStartInputs(inps, cs);
this.setInputs(inputs);
- return retInputs;
+ return inps;
}
}
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/StartInputs.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/StartInputs.java
index 1055fbd..a0cfe20 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/StartInputs.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/StartInputs.java
@@ -41,10 +41,9 @@ public class StartInputs {
private Object envs;
public TreeMap<String, LinkedHashMap<String, Object>> createOnapStartInputs(TreeMap<String, LinkedHashMap<String, Object>> inps, ComponentSpec cs){
- TreeMap<String, LinkedHashMap<String, Object>> retInputs = inps;
int count = 0;
- ArrayList<String> portList = new ArrayList();
+ ArrayList<String> portList = new ArrayList<>();
Auxilary aux = cs.getAuxilary();
if (aux.getPorts() != null) {
@@ -56,10 +55,10 @@ public class StartInputs {
, ports[0], count);
portList.add(internal);
- LinkedHashMap<String, Object> portType = new LinkedHashMap();
+ LinkedHashMap<String, Object> portType = new LinkedHashMap<>();
portType.put("type", "string");
portType.put("default", ports[1]);
- retInputs.put("external_port_" + count, portType);
+ inps.put("external_port_" + count, portType);
count++;
}
@@ -98,7 +97,7 @@ public class StartInputs {
// }
//set the envs
- LinkedHashMap<String, Object> eMap = new LinkedHashMap();
+ LinkedHashMap<String, Object> eMap = new LinkedHashMap<>();
if(cs.getAuxilary().getDatabases() != null){
//set db env variables
LinkedHashMap<String, Object> envVars = PgaasNodeBuilder.getEnvVariables(cs.getAuxilary().getDatabases());
@@ -111,9 +110,9 @@ public class StartInputs {
this.setEnvs(env);
eMap.put("default", "{}");
}
- retInputs.put("envs", eMap);
+ inps.put("envs", eMap);
- return retInputs;
+ return inps;
}
}
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapInfo.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapInfo.java
index 464fc4a..0cec284 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapInfo.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapInfo.java
@@ -46,9 +46,7 @@ public class DmaapInfo {
public TreeMap<String, LinkedHashMap<String, Object>> createOnapDmaapMRInfo(
TreeMap<String, LinkedHashMap<String, Object>> inps, String config, char type) {
- TreeMap<String, LinkedHashMap<String, Object>> retInputs = new TreeMap<String, LinkedHashMap<String, Object>>();
- retInputs = inps;
- LinkedHashMap<String, Object> stringType = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> stringType = new LinkedHashMap<>();
stringType.put("type", "string");
config = config.replaceAll("-", "_");
@@ -62,9 +60,9 @@ public class DmaapInfo {
topic.setBpInputName(config);
this.setTopic_url(topic);
- retInputs.put(config, stringType);
+ inps.put(config, stringType);
- return retInputs;
+ return inps;
}
public TreeMap<String, LinkedHashMap<String, Object>> createOnapDmaapDRInfo(
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapObj.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapObj.java
index 6af69e5..30f59e2 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapObj.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/blueprint/dmaap/DmaapObj.java
@@ -40,10 +40,8 @@ public class DmaapObj {
public TreeMap<String, LinkedHashMap<String, Object>> createOnapDmaapMRObj(TreeMap<String, LinkedHashMap<String, Object>> inps,
String config, char type, String n, String num, boolean isDmaap) {
- TreeMap<String, LinkedHashMap<String, Object>> retInputs = new TreeMap<String, LinkedHashMap<String, Object>>();
- LinkedHashMap<String, Object> stringType = new LinkedHashMap();
+ LinkedHashMap<String, Object> stringType = new LinkedHashMap<>();
stringType.put("type", "string");
- retInputs = inps;
//set the dmaapinfo
DmaapInfo info = new DmaapInfo();
@@ -58,20 +56,18 @@ public class DmaapObj {
GetInput u = new GetInput();
u.setBpInputName(config + "_" + num +"_aaf_username");
this.setUser(u);
- retInputs.put(config + "_" + num +"_aaf_username", stringType);
+ inps.put(config + "_" + num +"_aaf_username", stringType);
//set password
GetInput p = new GetInput();
p.setBpInputName(config + "_" + num +"_aaf_password");
this.setPass(p);
- retInputs.put(config + "_" + num +"_aaf_password", stringType);
+ inps.put(config + "_" + num +"_aaf_password", stringType);
}
- return retInputs;
+ return inps;
}
public TreeMap<String, LinkedHashMap<String, Object>> createOnapDmaapDRObj(TreeMap<String, LinkedHashMap<String, Object>> inps, String config, char type, String n, String num, boolean isDmaap) {
- TreeMap<String, LinkedHashMap<String, Object>> retInputs = new TreeMap<String, LinkedHashMap<String, Object>>();
- retInputs = inps;
-
+
//set the dmaapinfo
DmaapInfo info = new DmaapInfo();
if(!isDmaap){
@@ -82,6 +78,6 @@ public class DmaapObj {
String infoType = "<<" + n + ">>";
this.setDmaap_info(infoType);
}
- return retInputs;
+ return inps;
}
}
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Artifacts.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Artifacts.java
index f7f5a03..198dc19 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Artifacts.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Artifacts.java
@@ -21,13 +21,11 @@
package org.onap.blueprintgenerator.models.componentspec;
-
import com.fasterxml.jackson.annotation.JsonInclude;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -53,6 +51,7 @@ import lombok.NoArgsConstructor;
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
+@EqualsAndHashCode
//Called in Component Spec Object
public class Artifacts {
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Auxilary.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Auxilary.java
index a36deb5..58e1e0c 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Auxilary.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Auxilary.java
@@ -22,19 +22,15 @@
package org.onap.blueprintgenerator.models.componentspec;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.TreeMap;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import java.util.ArrayList;
+import java.util.TreeMap;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -64,6 +60,7 @@ import lombok.NoArgsConstructor;
*/
@JsonInclude(value=Include.NON_NULL)
+@EqualsAndHashCode
//Called in component Spec Object
public class Auxilary {
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/CallsObj.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/CallsObj.java
index 0b7dcee..d130632 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/CallsObj.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/CallsObj.java
@@ -24,11 +24,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
-import lombok.NoArgsConstructor;
-
// TODO: Auto-generated Javadoc
/**
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ConstraintsObj.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ConstraintsObj.java
index 3615605..785df35 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ConstraintsObj.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ConstraintsObj.java
@@ -20,18 +20,10 @@
package org.onap.blueprintgenerator.models.componentspec;
-import java.util.HashMap;
-
-
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
-import lombok.NoArgsConstructor;
-
// TODO: Auto-generated Javadoc
/**
* The Class ConstraintsObj.
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Container.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Container.java
index d94e2bb..cbe02dc 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Container.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Container.java
@@ -22,11 +22,10 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -50,6 +49,7 @@ import lombok.NoArgsConstructor;
*/
@JsonInclude(value=Include.NON_NULL)
+@EqualsAndHashCode
public class Container {
/** The bind. */
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/EntrySchemaObj.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/EntrySchemaObj.java
index 45f9091..ef33aaf 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/EntrySchemaObj.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/EntrySchemaObj.java
@@ -24,11 +24,9 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/**
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/HealthCheck.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/HealthCheck.java
index acc9379..76e1036 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/HealthCheck.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/HealthCheck.java
@@ -23,11 +23,10 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -53,6 +52,7 @@ import lombok.NoArgsConstructor;
*/
@JsonInclude(value=Include.NON_NULL)
+@EqualsAndHashCode
//Called in Auxillary Object
public class HealthCheck {
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Host.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Host.java
index 91734ad..f178c94 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Host.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Host.java
@@ -22,11 +22,10 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -46,6 +45,7 @@ import lombok.NoArgsConstructor;
* @param mode the mode
*/
@JsonInclude(value=Include.NON_NULL)
+@EqualsAndHashCode
public class Host{
/** The path. */
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Parameters.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Parameters.java
index 515ecc7..eb95202 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Parameters.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Parameters.java
@@ -20,17 +20,13 @@
package org.onap.blueprintgenerator.models.componentspec;
-import java.util.ArrayList;
-
-
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/**
@@ -68,6 +64,7 @@ import lombok.NoArgsConstructor;
* @param constraints the constraints
*/
@JsonInclude(value=Include.NON_NULL)
+@EqualsAndHashCode
//Called in component Spec Object
public class Parameters {
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Policy.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Policy.java
index 3cc14fe..d295ca4 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Policy.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Policy.java
@@ -23,11 +23,10 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -51,6 +50,7 @@ import lombok.NoArgsConstructor;
* @param script_path the script path
*/
@JsonInclude(value=Include.NON_NULL)
+@EqualsAndHashCode
//called in auxilary
public class Policy {
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/PolicySchemaObj.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/PolicySchemaObj.java
index 7af16d6..aa38271 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/PolicySchemaObj.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/PolicySchemaObj.java
@@ -24,11 +24,9 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/**
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ProvidesObj.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ProvidesObj.java
index ad9c87d..9ad24c3 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ProvidesObj.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ProvidesObj.java
@@ -21,11 +21,9 @@
package org.onap.blueprintgenerator.models.componentspec;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Publishes.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Publishes.java
index 3ee47b9..4f46313 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Publishes.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Publishes.java
@@ -23,11 +23,10 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -54,6 +53,7 @@ import lombok.NoArgsConstructor;
*/
@JsonInclude(value=Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
+@EqualsAndHashCode
//Called in Streams Object
public class Publishes {
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ReconfigsObj.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ReconfigsObj.java
index 6c389d6..6d78805 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ReconfigsObj.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/ReconfigsObj.java
@@ -23,11 +23,10 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -50,7 +49,7 @@ import lombok.NoArgsConstructor;
* @param policy the policy
*/
@JsonInclude(value=Include.NON_NULL)
-
+@EqualsAndHashCode
public class ReconfigsObj {
/** The dti. */
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/RequestResponseObj.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/RequestResponseObj.java
index 2aaf60b..7ca1830 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/RequestResponseObj.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/RequestResponseObj.java
@@ -25,11 +25,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
-import lombok.NoArgsConstructor;
-
// TODO: Auto-generated Javadoc
/**
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Self.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Self.java
index a566661..8b5f35e 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Self.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Self.java
@@ -20,16 +20,13 @@
package org.onap.blueprintgenerator.models.componentspec;
-import java.util.Map;
-
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -55,6 +52,7 @@ import lombok.NoArgsConstructor;
*/
@JsonInclude(value=Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
+@EqualsAndHashCode
//called in Component Spec object
public class Self {
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Services.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Services.java
index afe0904..772d859 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Services.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Services.java
@@ -24,11 +24,9 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Streams.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Streams.java
index 1b7dcd3..500f32d 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Streams.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Streams.java
@@ -24,11 +24,10 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -52,6 +51,7 @@ import lombok.NoArgsConstructor;
*/
@JsonInclude(value=Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
+@EqualsAndHashCode
//Called in Component Spec Object
public class Streams {
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Subscribes.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Subscribes.java
index 14485a0..ec4aa41 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Subscribes.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Subscribes.java
@@ -23,11 +23,10 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -57,6 +56,7 @@ import lombok.NoArgsConstructor;
@JsonInclude(value=Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
+@EqualsAndHashCode
//Called in Streams Object
public class Subscribes {
diff --git a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Volumes.java b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Volumes.java
index 1034242..777bdeb 100644
--- a/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Volumes.java
+++ b/mod/bpgenerator/src/main/java/org/onap/blueprintgenerator/models/componentspec/Volumes.java
@@ -23,11 +23,10 @@ package org.onap.blueprintgenerator.models.componentspec;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter; import lombok.Setter;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
// TODO: Auto-generated Javadoc
/* (non-Javadoc)
@@ -50,6 +49,7 @@ import lombok.NoArgsConstructor;
* @param host the host
*/
@JsonInclude(value=Include.NON_NULL)
+@EqualsAndHashCode
//Called in Auxillary Object
public class Volumes {
@@ -58,4 +58,4 @@ public class Volumes {
/** The host. */
private Host host;
-} \ No newline at end of file
+}
diff --git a/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/core/BlueprintGeneratorTest.java b/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/core/BlueprintGeneratorTest.java
index 1c7e592..b978701 100644
--- a/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/core/BlueprintGeneratorTest.java
+++ b/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/core/BlueprintGeneratorTest.java
@@ -21,15 +21,14 @@
package org.onap.blueprintgenerator.core;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@@ -39,22 +38,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.onap.blueprintgenerator.models.blueprint.Blueprint;
import org.onap.blueprintgenerator.models.blueprint.GetInput;
-import org.onap.blueprintgenerator.models.componentspec.Artifacts;
-import org.onap.blueprintgenerator.models.componentspec.Auxilary;
-import org.onap.blueprintgenerator.models.componentspec.CallsObj;
import org.onap.blueprintgenerator.models.componentspec.ComponentSpec;
-import org.onap.blueprintgenerator.models.componentspec.Container;
-import org.onap.blueprintgenerator.models.componentspec.HealthCheck;
-import org.onap.blueprintgenerator.models.componentspec.Host;
-import org.onap.blueprintgenerator.models.componentspec.Parameters;
-import org.onap.blueprintgenerator.models.componentspec.Policy;
-import org.onap.blueprintgenerator.models.componentspec.ProvidesObj;
-import org.onap.blueprintgenerator.models.componentspec.Publishes;
-import org.onap.blueprintgenerator.models.componentspec.Self;
-import org.onap.blueprintgenerator.models.componentspec.Services;
-import org.onap.blueprintgenerator.models.componentspec.Streams;
-import org.onap.blueprintgenerator.models.componentspec.Subscribes;
-import org.onap.blueprintgenerator.models.componentspec.Volumes;
import org.onap.blueprintgenerator.models.dmaapbp.DmaapNode;
import org.onap.blueprintgenerator.models.onapbp.OnapNode;
import org.onap.blueprintgenerator.models.policymodel.PolicyModel;
@@ -70,146 +54,20 @@ public class BlueprintGeneratorTest {
/**
* Component spec test.
*
- * @throws JsonParseException the json parse exception
- * @throws JsonMappingException the json mapping exception
- * @throws IOException Signals that an I/O exception has occurred.
*/
-
@Test
- public void componentSpecTest() throws JsonParseException, JsonMappingException, IOException {
-
+ public void componentSpecTest() {
ComponentSpec spec = new ComponentSpec();
TestComponentSpec test = new TestComponentSpec();
- spec.createComponentSpecFromString(test.getCs());
-
- //Manually fill a component spec object with the values from the file itself
- ComponentSpec manualSpec = new ComponentSpec();
-
- Self self = new Self();
- self.setComponent_type("docker");
- self.setDescription("Test component spec");
- self.setName("test.component.spec");
- self.setVersion("1.0.1");
- manualSpec.setSelf(self);
-
- //assertEquals(manualSpec.getSelf(), spec.getSelf());
-
- Services services = new Services();
- CallsObj[] calls = new CallsObj[0];
- ProvidesObj[] provides = new ProvidesObj[0];
- services.setCalls(calls);
- services.setProvides(provides);
- manualSpec.setServices(null);
-
- //assertEquals(manualSpec.getServices(), spec.getServices());
-
- Streams streams = new Streams();
- Publishes[] publishes = new Publishes[2];
- Publishes pub1 = new Publishes();
- pub1.setConfig_key("TEST-PUB-DR");
- pub1.setFormat("dataformat_Hello_World_PM");
- pub1.setType("data_router");
- pub1.setVersion("1.0.0");
-
- Publishes pub2 = new Publishes();
- pub2.setConfig_key("TEST-PUB-MR");
- pub2.setFormat("dataformat_Hello_World_PM");
- pub2.setType("message_router");
- pub2.setVersion("1.0.0");
- publishes[0] = pub1;
- publishes[1] = pub2;
- streams.setPublishes(publishes);
-
- Subscribes[] subscribes = new Subscribes[2];
- Subscribes sub1 = new Subscribes();
- sub1.setConfig_key("TEST-SUB-MR");
- sub1.setFormat("dataformat_Hello_World_PM");
- sub1.setRoute("/TEST_HELLO_WORLD_SUB_MR");
- sub1.setType("message_router");
- sub1.setVersion("1.0.0");
-
- Subscribes sub2 = new Subscribes();
- sub2.setConfig_key("TEST-SUB-DR");
- sub2.setFormat("dataformat_Hello_World_PM");
- sub2.setRoute("/TEST-HELLO-WORLD-SUB-DR");
- sub2.setType("data_router");
- sub2.setVersion("1.0.0");
- subscribes[0] = sub1;
- subscribes[1] = sub2;
- streams.setSubscribes(subscribes);
-
- manualSpec.setStreams(streams);
-
- //assertEquals(manualSpec.getStreams(), spec.getStreams());
-
- Parameters[] parameters = new Parameters[1];
- Parameters par1 = new Parameters();
- par1.setName("testParam1");
- par1.setValue("test-param-1");
- par1.setDescription("test parameter 1");
- par1.setSourced_at_deployment(true);
- par1.setDesigner_editable(true);
- par1.setPolicy_editable(true);
- par1.setPolicy_group("Test_Parameters");
- par1.setRequired(true);
- par1.setType("string");
- parameters[0] = par1;
-
- manualSpec.setParameters(parameters);
-
- //assertEquals(manualSpec.getParameters(), spec.getParameters());
-
- Auxilary auxilary = new Auxilary();
- HealthCheck healthcheck = new HealthCheck();
- healthcheck.setInterval("300s");
- healthcheck.setTimeout("120s");
- healthcheck.setScript("/etc/init.d/nagios status");
- healthcheck.setType("docker");
- auxilary.setHealthcheck(healthcheck);
-
- Volumes[] volumes = new Volumes[1];
- Volumes vol1 = new Volumes();
- Container con1 = new Container();
- con1.setBind("/opt/app/manager/config/hostname");
- Host host1 = new Host();
- host1.setPath("/etc/hostname");
- host1.setMode("ro");
- vol1.setContainer(con1);
- vol1.setHost(host1);
-
- volumes[0] = vol1;
-
- auxilary.setVolumes(volumes);
-
- ArrayList<Object> ports = new ArrayList();
- ports.add("80:90");
- ports.add("99:99");
-
- TreeMap<String, String> dataBases = new TreeMap<String, String>();
- dataBases.put("TestDB1", "PGaaS");
- dataBases.put("TestDB2", "PGaaS");
- auxilary.setDatabases(dataBases);
-
- Policy pol = new Policy();
- pol.setTrigger_type("docker");
- pol.setScript_path("/opt/app/manager/bin/reconfigure.sh");
- auxilary.setPolicy(pol);
-
- auxilary.setPorts(ports);
-
- manualSpec.setAuxilary(auxilary);
-
- //assertEquals(manualSpec.getAuxilary(), spec.getAuxilary());
-
- Artifacts[] artifacts = new Artifacts[1];
- Artifacts art = new Artifacts();
- art.setType("docker image");
- art.setUri("test.tester");
-
- artifacts[0] = art;
- manualSpec.setArtifacts(artifacts);
-
- //assertEquals(manualSpec.getArtifacts(), spec.getArtifacts());
+ spec.createComponentSpecFromString(test.getComponentSpecAsString());
+ ComponentSpec expectedSpec = test.getComponentSpec();
+
+ assertEquals(expectedSpec.getSelf(), spec.getSelf());
+ assertEquals(expectedSpec.getServices(), spec.getServices());
+ assertEquals(expectedSpec.getStreams(), spec.getStreams());
+ assertArrayEquals(expectedSpec.getParameters(), spec.getParameters());
+ assertEquals(expectedSpec.getAuxilary(), spec.getAuxilary());
+ assertArrayEquals(expectedSpec.getArtifacts(), spec.getArtifacts());
}
/**
@@ -219,11 +77,11 @@ public class BlueprintGeneratorTest {
public void toscaDefinitionTest() {
ComponentSpec cs = new ComponentSpec();
TestComponentSpec test = new TestComponentSpec();
- cs.createComponentSpecFromString(test.getCs());
+ cs.createComponentSpecFromString(test.getComponentSpecAsString());
Blueprint bp = new Blueprint();
bp = bp.createBlueprint(cs, "", 'o', "", "");
- assertEquals(bp.getTosca_definitions_version(), "cloudify_dsl_1_3");
+ assertEquals("cloudify_dsl_1_3", bp.getTosca_definitions_version());
}
/**
@@ -233,19 +91,16 @@ public class BlueprintGeneratorTest {
public void importsTest() {
ComponentSpec cs = new ComponentSpec();
TestComponentSpec test = new TestComponentSpec();
- cs.createComponentSpecFromString(test.getCs());
+ cs.createComponentSpecFromString(test.getComponentSpecAsString());
Blueprint bp = new Blueprint();
bp = bp.createBlueprint(cs, "", 'o', "", "");
- ArrayList<String> imps = new ArrayList<String>();
-
- imps.add("http://www.getcloudify.org/spec/cloudify/3.4/types.yaml");
- imps.add(
- "https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R6/k8splugin/1.7.2/k8splugin_types.yaml");
- imps.add(
- "https://nexus.onap.org/service/local/repositories/raw/content/org.onap.dcaegen2.platform.plugins/R6/dcaepolicyplugin/2.4.0/dcaepolicyplugin_types.yaml");
- assertEquals(bp.getImports(), imps);
+ ArrayList<String> imps = new ArrayList<>();
+ imps.add("https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml");
+ imps.add("plugin:k8splugin?version=3.4.2");
+ imps.add("plugin:dcaepolicyplugin?version=2.4.0");
+ assertEquals(imps, bp.getImports());
}
@Test
@@ -256,50 +111,49 @@ public class BlueprintGeneratorTest {
Blueprint bp = new Blueprint();
bp = bp.createBlueprint(cs, "", 'o', "", "");
- TreeMap<String, LinkedHashMap<String, Object>> inputs = new TreeMap<String, LinkedHashMap<String, Object>>();
+ TreeMap<String, LinkedHashMap<String, Object>> inputs = new TreeMap<>();
//mr inputs
- LinkedHashMap<String, Object> stringType = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> stringType = new LinkedHashMap<>();
stringType.put("type", "string");
//necessary inputs
- LinkedHashMap<String, Object> tag = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> tag = new LinkedHashMap<>();
tag.put("type", "string");
String tester = "test.tester";
tag.put("default", '"' + tester + '"');
- String tagVersion = "tag_version";
inputs.put("tag_version", tag);
inputs.put("log_directory", stringType);
- LinkedHashMap cert = new LinkedHashMap();
+ LinkedHashMap<String, Object> cert = new LinkedHashMap<>();
cert.put("type", "string");
cert.put("default", "");
inputs.put("cert_directory", cert);
- LinkedHashMap<String, Object> env = new LinkedHashMap();
+ LinkedHashMap<String, Object> env = new LinkedHashMap<>();
env.put("default", "{}");
inputs.put("envs", env);
- LinkedHashMap port = new LinkedHashMap();
+ LinkedHashMap<String, Object> port = new LinkedHashMap<>();
port.put("type", "string");
port.put("description", "Kubernetes node port on which collector is exposed");
port.put("default", "99");
inputs.put("external_port", port);
- LinkedHashMap<String, Object> rep = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> rep = new LinkedHashMap<>();
rep.put("type", "integer");
rep.put("description", "number of instances");
rep.put("default", 1);
inputs.put("replicas", rep);
- LinkedHashMap<String, Object> aaf = new LinkedHashMap();
+ LinkedHashMap<String, Object> aaf = new LinkedHashMap<>();
aaf.put("type", "boolean");
aaf.put("default", false);
inputs.put("use_tls", aaf);
//parmaeter input
- LinkedHashMap<String, Object> test = new LinkedHashMap<String, Object>();
+ LinkedHashMap<String, Object> test = new LinkedHashMap<>();
test.put("type", "string");
String testParam = "test-param-1";
test.put("default", '"' + testParam + '"');
@@ -325,19 +179,17 @@ public class BlueprintGeneratorTest {
inputs.put("topic0_name", stringType);
inputs.put("topic1_name", stringType);
- LinkedHashMap<String, Object> cpu = new LinkedHashMap();
+ LinkedHashMap<String, Object> cpu = new LinkedHashMap<>();
cpu.put("type", "string");
cpu.put("default", "250m");
inputs.put("test.component.spec_cpu_limit", cpu);
inputs.put("test.component.spec_cpu_request", cpu);
- LinkedHashMap<String, Object> mem = new LinkedHashMap();
+ LinkedHashMap<String, Object> mem = new LinkedHashMap<>();
mem.put("type", "string");
mem.put("default", "128Mi");
inputs.put("test.component.spec_memory_limit", mem);
inputs.put("test.component.spec_memory_request", mem);
-
- assertEquals(true, true);
}
@Test
@@ -355,10 +207,9 @@ public class BlueprintGeneratorTest {
//set the type
testNode.setType("dcae.nodes.ContainerizedServiceComponent");
- ArrayList<String> ports = new ArrayList<String>();
+ ArrayList<String> ports = new ArrayList<>();
ports.add("concat: [\"80:\", {get_input: external_port }]");
ports.add("concat: [\"99:\", {get_input: external_port }]");
- assertEquals(true, true);
}
@Test
@@ -372,7 +223,7 @@ public class BlueprintGeneratorTest {
OnapNode node = (OnapNode) bp.getNode_templates().get("test.component.spec");
GetInput par = (GetInput) node.getProperties().getApplication_config().getParams().get("testParam1");
- assertEquals(par.getBpInputName(), "testParam1");
+ assertEquals("testParam1", par.getBpInputName());
}
@Test
@@ -385,13 +236,7 @@ public class BlueprintGeneratorTest {
OnapNode node = (OnapNode) bp.getNode_templates().get("test.component.spec");
- boolean test = false;
- if (!node.getProperties().getApplication_config().getStreams_publishes().isEmpty()) {
- test = true;
- System.out.println("tst");
- }
-
- assertEquals(true, test);
+ assertFalse(node.getProperties().getApplication_config().getStreams_publishes().isEmpty());
}
@Test
@@ -405,13 +250,8 @@ public class BlueprintGeneratorTest {
DmaapNode dmaap = (DmaapNode) bp.getNode_templates().get("test.component.spec");
//check if the stream publishes and subscribes are not null to see if the dmaap plugin was invoked properly
- boolean d = false;
-
- if (dmaap.getProperties().getStreams_publishes() != null
- || dmaap.getProperties().getStreams_subscribes() != null) {
- d = true;
- }
- assertEquals(true, d);
+ assertNotNull(dmaap.getProperties().getStreams_publishes());
+ assertNotNull(dmaap.getProperties().getStreams_subscribes());
}
@Test
@@ -442,17 +282,5 @@ public class BlueprintGeneratorTest {
PolicyModel p = new PolicyModel();
p.createPolicyModels(cs, "TestModels");
-
- assertEquals(true, true);
- }
-
- private void assertContainsInputWithDefault(Blueprint bp, String inputName, Object defaultValue) {
- LinkedHashMap<String, Object> input = bp.getInputs().get(inputName);
- assertNotNull(input);
- assertEquals(defaultValue, input.get("default"));
- }
-
- private String inQuotes(String filedName) {
- return String.format("\"%s\"", filedName);
}
}
diff --git a/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/models/blueprint/ImportsTest.java b/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/models/blueprint/ImportsTest.java
new file mode 100644
index 0000000..1ce296a
--- /dev/null
+++ b/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/models/blueprint/ImportsTest.java
@@ -0,0 +1,52 @@
+/*============LICENSE_START=======================================================
+ org.onap.dcae
+ ================================================================================
+ Copyright (c) 2020 Nokia Intellectual Property. All rights reserved.
+ ================================================================================
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ============LICENSE_END=========================================================
+ */
+
+package org.onap.blueprintgenerator.models.blueprint;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Test;
+
+public class ImportsTest {
+
+ private final List<String> expectedImports = Arrays.asList(
+ "https://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml",
+ "plugin:k8splugin?version=3.4.1",
+ "plugin:pgaas?version=1.3.0",
+ "plugin:clamppolicyplugin?version=1.1.0",
+ "plugin:dmaap?version=1.5.0"
+ );
+
+ @Test
+ public void shouldReadImportsFromFile() {
+ ArrayList<String> importsFromFile = Imports.createImportsFromFile("TestCases/imports/imports.yaml");
+ assertEquals(expectedImports, importsFromFile);
+ }
+
+ @Test
+ public void shouldRemoveBlankImportsFromFile() {
+ ArrayList<String> importsFromFile =
+ Imports.createImportsFromFile("TestCases/imports/importsWithBlanks.yaml");
+ assertEquals(expectedImports, importsFromFile);
+ }
+
+}
diff --git a/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/models/blueprint/tls/ExternalCertificateParametersFactoryTest.java b/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/models/blueprint/tls/ExternalCertificateParametersFactoryTest.java
index e854b19..1cdb58b 100644
--- a/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/models/blueprint/tls/ExternalCertificateParametersFactoryTest.java
+++ b/mod/bpgenerator/src/test/java/org/onap/blueprintgenerator/models/blueprint/tls/ExternalCertificateParametersFactoryTest.java
@@ -25,7 +25,7 @@ import org.onap.blueprintgenerator.models.blueprint.tls.impl.ExternalCertificate
import java.util.LinkedHashMap;
import java.util.Map;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
import static org.onap.blueprintgenerator.models.blueprint.tls.TlsConstants.COMMON_NAME_FIELD;
import static org.onap.blueprintgenerator.models.blueprint.tls.TlsConstants.DEFAULT_COMMON_NAME;
import static org.onap.blueprintgenerator.models.blueprint.tls.TlsConstants.DEFAULT_SANS;
diff --git a/mod/runtimeapi/pom.xml b/mod/runtimeapi/pom.xml
index 75b68ce..112a9d7 100644
--- a/mod/runtimeapi/pom.xml
+++ b/mod/runtimeapi/pom.xml
@@ -34,7 +34,7 @@ limitations under the License.
</parent>
<groupId>org.onap.dcaegen2.platform.mod</groupId>
<artifactId>runtimeapi</artifactId>
- <version>1.0.2</version>
+ <version>1.1.0</version>
<name>dcaegen2-platform-mod-runtimeapi</name>
<description>MOD Runtime API</description>
<properties>
diff --git a/mod/runtimeapi/runtime-core/pom.xml b/mod/runtimeapi/runtime-core/pom.xml
index 226d4e8..15eda39 100644
--- a/mod/runtimeapi/runtime-core/pom.xml
+++ b/mod/runtimeapi/runtime-core/pom.xml
@@ -25,12 +25,12 @@ limitations under the License.
<parent>
<artifactId>runtimeapi</artifactId>
<groupId>org.onap.dcaegen2.platform.mod</groupId>
- <version>1.0.2</version>
+ <version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>runtime-core</artifactId>
- <version>1.0.1</version>
+ <version>1.1.0</version>
<dependencies>
<dependency>
@@ -46,7 +46,7 @@ limitations under the License.
<dependency>
<groupId>org.onap.dcaegen2.platform.mod</groupId>
<artifactId>blueprint-generator</artifactId>
- <version>1.4.0</version>
+ <version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
diff --git a/mod/runtimeapi/runtime-web/pom.xml b/mod/runtimeapi/runtime-web/pom.xml
index c8ce84a..6842cba 100644
--- a/mod/runtimeapi/runtime-web/pom.xml
+++ b/mod/runtimeapi/runtime-web/pom.xml
@@ -24,10 +24,10 @@ limitations under the License.
<parent>
<groupId>org.onap.dcaegen2.platform.mod</groupId>
<artifactId>runtimeapi</artifactId>
- <version>1.0.2</version>
+ <version>1.1.0</version>
</parent>
<artifactId>runtime-web</artifactId>
- <version>1.0.6-SNAPSHOT</version>
+ <version>1.1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>runtime-web</name>
<description>MOD Runtime Web Module</description>
@@ -35,7 +35,7 @@ limitations under the License.
<dependency>
<groupId>org.onap.dcaegen2.platform.mod</groupId>
<artifactId>runtime-core</artifactId>
- <version>1.0.1</version>
+ <version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
diff --git a/mod2/auth-service/Dockerfile b/mod2/auth-service/Dockerfile
new file mode 100644
index 0000000..c427bda
--- /dev/null
+++ b/mod2/auth-service/Dockerfile
@@ -0,0 +1,11 @@
+FROM onap/integration-java11:7.1.0
+WORKDIR /usr/app
+VOLUME /tmp
+
+ADD target/auth-service-1.0.0-SNAPSHOT.jar auth-service-1.0.0-SNAPSHOT.jar
+
+EXPOSE 8082
+
+ENTRYPOINT ["java", \
+ "-Djava.security.egd=file:/dev/./urandom", \
+ "-jar", "auth-service-1.0.0-SNAPSHOT.jar"] \ No newline at end of file
diff --git a/mod2/auth-service/pom.xml b/mod2/auth-service/pom.xml
new file mode 100644
index 0000000..1fd4f02
--- /dev/null
+++ b/mod2/auth-service/pom.xml
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ /*
+ ~ * ============LICENSE_START=======================================================
+ ~ * org.onap.dcae
+ ~ * ================================================================================
+ ~ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ ~ * ================================================================================
+ ~ * Licensed under the Apache License, Version 2.0 (the "License");
+ ~ * you may not use this file except in compliance with the License.
+ ~ * You may obtain a copy of the License at
+ ~ *
+ ~ * http://www.apache.org/licenses/LICENSE-2.0
+ ~ *
+ ~ * Unless required by applicable law or agreed to in writing, software
+ ~ * distributed under the License is distributed on an "AS IS" BASIS,
+ ~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ * See the License for the specific language governing permissions and
+ ~ * limitations under the License.
+ ~ * ============LICENSE_END=========================================================
+ ~ */
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.oparent</groupId>
+ <artifactId>oparent</artifactId>
+ <version>2.0.0</version>
+ </parent>
+ <groupId>org.onap.dcaegen2.platform.mod</groupId>
+ <artifactId>auth-service</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>auth-service</name>
+ <description>REST APIs to serve Auth Service</description>
+
+ <properties>
+ <java.version>11</java.version>
+ <maven.compiler.source>${java.version}</maven.compiler.source>
+ <maven.compiler.target>${java.version}</maven.compiler.target>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-mongodb</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.8.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.jsonwebtoken</groupId>
+ <artifactId>jjwt</artifactId>
+ <version>0.9.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-webflux</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-validation</artifactId>
+ </dependency>
+ <!-- CODE GENERATION -->
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>okhttp</artifactId>
+ <version>4.0.1</version>
+ </dependency>
+
+ <!--TEST DEPENDENCIES-->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>mockwebserver</artifactId>
+ <version>4.0.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.projectreactor</groupId>
+ <artifactId>reactor-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ <version>2.3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>RELEASE</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <!-- Import dependency management from Spring Boot -->
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-dependencies</artifactId>
+ <version>2.2.5.RELEASE</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>2.2.5.RELEASE</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.22.2</version>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/AuthServiceApplication.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/AuthServiceApplication.java
new file mode 100644
index 0000000..5b147bf
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/AuthServiceApplication.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Auth Service Application
+ */
+@SpringBootApplication
+public class AuthServiceApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AuthServiceApplication.class, args);
+ }
+
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/DataLoader.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/DataLoader.java
new file mode 100644
index 0000000..959b450
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/DataLoader.java
@@ -0,0 +1,97 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod;
+
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.models.Role;
+import org.onap.dcaegen2.platform.mod.repositories.RoleRepository;
+import org.onap.dcaegen2.platform.mod.repositories.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * To Initialize Roles and create Default Admin User
+ */
+@Component
+public class DataLoader implements ApplicationRunner {
+
+ @Autowired
+ private RoleRepository roleRepository;
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ PasswordEncoder passwordEncoder;
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ populateRoles();
+ populateAdminUser();
+ }
+
+ private void populateRoles() {
+ List<Role> roles = createRoles();
+ roles.forEach((role) -> {
+ boolean roleNotPresent = !roleRepository.findByName(role.getName()).isPresent();
+ if(roleNotPresent)
+ roleRepository.save(role);
+ });
+
+ }
+
+ private List<Role> createRoles() {
+ Role admin = new Role("ROLE_ADMIN");
+ Role user = new Role("ROLE_USER");
+ Role developer = new Role("ROLE_DEVELOPER");
+ return Arrays.asList(admin, user, developer);
+ }
+
+ private void populateAdminUser() {
+ boolean adminNotPresent = !userRepository.findByUsername("admin").isPresent();
+ if(adminNotPresent) {
+ ModUser admin = createAdmin();
+ userRepository.save(admin);
+ }
+ }
+
+ private ModUser createAdmin() {
+ ModUser admin = new ModUser();
+ admin.setUsername("admin");
+ admin.setFullName("Admin");
+ admin.setPassword(passwordEncoder.encode("admin@mod"));
+ HashSet<Role> roleAdmin = new HashSet<>();
+ roleAdmin.add(roleRepository.findByName("ROLE_ADMIN").get());
+ admin.setRoles(roleAdmin);
+ return admin;
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/AuthController.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/AuthController.java
new file mode 100644
index 0000000..6612138
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/AuthController.java
@@ -0,0 +1,171 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.controllers;
+
+import org.onap.dcaegen2.platform.mod.exceptions.RoleNotExistsException;
+import org.onap.dcaegen2.platform.mod.exceptions.UserAlreadyExistsException;
+import org.onap.dcaegen2.platform.mod.models.LoginRequest;
+import org.onap.dcaegen2.platform.mod.models.JwtResponse;
+import org.onap.dcaegen2.platform.mod.models.SignupRequest;
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.models.GenericResponse;
+import org.onap.dcaegen2.platform.mod.models.Role;
+import org.onap.dcaegen2.platform.mod.repositories.RoleRepository;
+import org.onap.dcaegen2.platform.mod.repositories.UserRepository;
+import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils;
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+import javax.validation.Valid;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Authentication Operations
+ */
+@RestController
+@RequestMapping("/api/auth")
+@CrossOrigin(origins = "*")
+public class AuthController {
+
+ @Autowired
+ AuthenticationManager authenticationManager;
+
+ @Autowired
+ UserRepository userRepository;
+
+ @Autowired
+ RoleRepository roleRepository;
+
+ @Autowired
+ PasswordEncoder passwordEncoder;
+
+ @Autowired
+ JwtUtils jwtUtils;
+
+ @PreAuthorize("isAuthenticated()")
+ @PostMapping("/validate-token")
+ public ResponseEntity<?> validateToken() {
+ return new ResponseEntity("true", HttpStatus.OK);
+ }
+
+ @PostMapping("/signin")
+ public ResponseEntity<?> authenticateUser(@RequestBody @Valid LoginRequest loginRequest) {
+ Authentication authentication = authenticateLoginRequest(loginRequest);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ String jwt = jwtUtils.generateJwtToken(authentication);
+ return setUserContext(authentication, jwt);
+ }
+
+ private Authentication authenticateLoginRequest(@RequestBody @Valid LoginRequest loginRequest) {
+ return authenticationManager.authenticate(
+ new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())
+ );
+ }
+
+ private ResponseEntity<?> setUserContext(Authentication authentication, String jwt) {
+ UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
+ List<String> roles = setRolesFromUserDetails(userDetails);
+ return buildUserContext(jwt, userDetails, roles);
+ }
+
+ private List<String> setRolesFromUserDetails(UserDetailsImpl userDetails) {
+ return userDetails.getAuthorities().stream()
+ .map(item -> ((GrantedAuthority) item).getAuthority())
+ .collect(Collectors.toList());
+ }
+
+ private ResponseEntity<JwtResponse> buildUserContext(String jwt, UserDetailsImpl userDetails, List<String> roles) {
+ return ResponseEntity.ok(JwtResponse.builder()
+ .id(userDetails.getId())
+ .roles(roles)
+ .username(userDetails.getUsername())
+ .token(jwt)
+ .fullName(userDetails.getFullName())
+ .build()
+ );
+ }
+
+ @PreAuthorize("hasRole('ADMIN')")
+ @PostMapping("/signup")
+ public ResponseEntity<?> registerUser(@RequestBody @Valid SignupRequest request) {
+ checkIfUserExists(request);
+ ModUser user = createNewUser(request);
+ userRepository.save(user);
+ return ResponseEntity.ok(new GenericResponse("User registered successfully!"));
+ }
+
+ private void checkIfUserExists(@RequestBody @Valid SignupRequest signUpRequest) {
+ if (userRepository.existsByUsername(signUpRequest.getUsername()))
+ throw new UserAlreadyExistsException("Username already exists!");
+ }
+
+ private ModUser createNewUser(@RequestBody @Valid SignupRequest request) {
+ ModUser user = new ModUser();
+ user.setUsername(request.getUsername());
+ user.setFullName(request.getFullName());
+ user.setPassword(getEncodedPassword(request));
+ Set<Role> roles = createRoles(request.getRoles());
+ user.setRoles(roles);
+ return user;
+ }
+
+ private String getEncodedPassword(@RequestBody @Valid SignupRequest request) {
+ return passwordEncoder.encode(request.getPassword());
+ }
+
+ public Set<Role> createRoles(Set<String> roleStrings) {
+ Set<Role> roles = new HashSet<>();
+ for (String roleStr : roleStrings) {
+ roles.add(getRole(roleStr));
+ }
+ return roles;
+ }
+
+ private Role getRole(String roleStr) {
+ return roleRepository.findByName(roleStr).orElseThrow(
+ () -> new RoleNotExistsException(String.format("Role %s does not exist", roleStr)));
+ }
+}
+
+
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/RoleController.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/RoleController.java
new file mode 100644
index 0000000..e129cda
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/RoleController.java
@@ -0,0 +1,58 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.controllers;
+
+import org.onap.dcaegen2.platform.mod.repositories.RoleRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Role Operations
+ */
+@RestController
+@RequestMapping("/api/roles")
+@CrossOrigin(origins = "*")
+public class RoleController {
+
+ @Autowired
+ RoleRepository roleRepository;
+
+ @GetMapping
+ @ResponseStatus(HttpStatus.OK)
+ public List<String> getRoles(){
+ return roleRepository.findAll()
+ .stream()
+ .map(role -> role.getName())
+ .collect(Collectors.toList());
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/UserController.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/UserController.java
new file mode 100644
index 0000000..90e7b62
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/controllers/UserController.java
@@ -0,0 +1,96 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.controllers;
+
+import org.onap.dcaegen2.platform.mod.exceptions.UserNotFoundException;
+import org.onap.dcaegen2.platform.mod.models.GenericResponse;
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.models.UpdateUserRequest;
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl;
+import org.onap.dcaegen2.platform.mod.services.MODUserDetailService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+
+/**
+ * @author
+ * @date 09/08/2020
+ * User Operations
+ */
+@RestController
+@RequestMapping("/api/users")
+@CrossOrigin(origins = "*")
+public class UserController {
+
+ @Autowired
+ private MODUserDetailService modUserDetailService;
+
+ @Autowired
+ private UserDetailsServiceImpl userDetailsService;
+
+ @PreAuthorize("hasRole('ADMIN')")
+ @GetMapping("/getAll")
+ @ResponseStatus(HttpStatus.OK)
+ public List<ModUser> getAllUsers() {
+ return modUserDetailService.findAll();
+ }
+
+ @PreAuthorize("hasRole('ADMIN') or hasRole('USER')")
+ @GetMapping("/{username}")
+ public UserDetails getUser(@PathVariable String username) {
+ return userDetailsService.loadUserByUsername(username);
+ }
+
+ @PreAuthorize("hasRole('ADMIN')")
+ @PatchMapping("/admin/{username}")
+ public ModUser adminUpdateUserProfile(@PathVariable String username, @RequestBody @Valid UpdateUserRequest
+ userRequest, @RequestHeader (name="Authorization") String token) {
+ return userDetailsService.adminUpdateUser(username, userRequest, token);
+ }
+
+ @PreAuthorize("hasRole('USER') or hasRole('DEVELOPER')")
+ @PatchMapping("/user/{username}")
+ public ModUser userUpdateOwnProfile(@PathVariable String username, @RequestBody @Valid UpdateUserRequest
+ userRequest, @RequestHeader (name="Authorization") String token) {
+ return userDetailsService.userUpdateOwnProfile(username, userRequest, token);
+ }
+
+ @PreAuthorize("hasRole('ADMIN')")
+ @DeleteMapping("/{username}")
+ public ResponseEntity<?> deleteUser(@PathVariable String username) {
+ modUserDetailService.deleteUserByUsername(username);
+ return ResponseEntity.ok(new GenericResponse("User " + username + " was removed"));
+ }
+
+ @ExceptionHandler
+ @ResponseStatus(HttpStatus.NOT_FOUND)
+ public void userNotFoundHandler(UserNotFoundException ex) {
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/AppExceptionHandler.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/AppExceptionHandler.java
new file mode 100644
index 0000000..e029e69
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/AppExceptionHandler.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.exceptions;
+
+import org.onap.dcaegen2.platform.mod.models.GenericResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Exception handler for the Auth Service Application
+ */
+@ControllerAdvice
+@Slf4j
+public class AppExceptionHandler {
+
+ @ExceptionHandler
+ public ResponseEntity<GenericResponse> resolveRuntimeException(UserAlreadyExistsException ex){
+ log.error(ex.getMessage());
+ return new ResponseEntity<>(new GenericResponse(ex.getMessage()), HttpStatus.CONFLICT);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<GenericResponse> resolveRoleNotFoundException(RoleNotExistsException ex){
+ log.error(ex.getMessage());
+ return new ResponseEntity<>(new GenericResponse(ex.getMessage()), HttpStatus.BAD_REQUEST);
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/IllegalUserOperationException.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/IllegalUserOperationException.java
new file mode 100644
index 0000000..4a5837a
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/IllegalUserOperationException.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.exceptions;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Exception for Illegal Operation
+ */
+public class IllegalUserOperationException extends RuntimeException {
+ public IllegalUserOperationException(String s) {
+ super(s);
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/RoleNotExistsException.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/RoleNotExistsException.java
new file mode 100644
index 0000000..dfa6efb
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/RoleNotExistsException.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.exceptions;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Exception for Role not exist
+ */
+public class RoleNotExistsException extends RuntimeException {
+ public RoleNotExistsException(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserAlreadyExistsException.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserAlreadyExistsException.java
new file mode 100644
index 0000000..475dc44
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserAlreadyExistsException.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.exceptions;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Exception for User already exists
+ */
+public class UserAlreadyExistsException extends RuntimeException {
+ public UserAlreadyExistsException(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserNotFoundException.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserNotFoundException.java
new file mode 100644
index 0000000..95c6a70
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/exceptions/UserNotFoundException.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.exceptions;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Exception for User Not Found
+ */
+public class UserNotFoundException extends RuntimeException {
+ public UserNotFoundException(String s) {
+ super(s);
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/GenericResponse.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/GenericResponse.java
new file mode 100644
index 0000000..c4625a4
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/GenericResponse.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.models;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Generic Response for the Auth Service Request
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+public class GenericResponse {
+
+ private String message;
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/JwtResponse.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/JwtResponse.java
new file mode 100644
index 0000000..8855245
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/JwtResponse.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.models;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * JWT Response for the Auth Service Request
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class JwtResponse {
+
+ private String token;
+ private String type = "Bearer";
+ private String id;
+ private String username;
+ private String fullName;
+ private List<String> roles;
+
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/LoginRequest.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/LoginRequest.java
new file mode 100644
index 0000000..af0f710
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/LoginRequest.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.models;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Login request
+ */
+@Data
+public class LoginRequest {
+
+ @NotBlank
+ private String username;
+
+ @NotBlank
+ private String password;
+
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/ModUser.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/ModUser.java
new file mode 100644
index 0000000..4da5c98
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/ModUser.java
@@ -0,0 +1,75 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.models;
+
+import lombok.Data;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Assigning Roles to User
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Getter
+@Setter
+@Document(collection = "users")
+public class ModUser implements Serializable {
+
+ @Id
+ public String _id;
+
+ @NotBlank
+ @Size(max = 10)
+ private String username;
+
+ @NotBlank
+ private String password;
+
+ @NotBlank
+ private String fullName;
+
+ @DBRef
+ private Set<Role> roles = new HashSet<>();
+
+ public ModUser(@NotBlank @Size(max = 10) String username, @NotBlank String password, @NotBlank String fullName) {
+ this.username = username;
+ this.password = password;
+ this.fullName=fullName;
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/Role.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/Role.java
new file mode 100644
index 0000000..8cce344
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/Role.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.models;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Roles
+ */
+@Document(collection = "roles")
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Role {
+
+ @Id
+ private String id;
+
+ private String name;
+
+ public Role(String name) {
+ this.name = name;
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/SignupRequest.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/SignupRequest.java
new file mode 100644
index 0000000..f705d76
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/SignupRequest.java
@@ -0,0 +1,53 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.models;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.Set;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * To validate User enter Details
+ */
+@Data
+public class SignupRequest {
+
+ @NotBlank(message = "username must not be blank")
+ @Size(min = 5, max = 10, message = "username must be between 5 and 10 characters.")
+ private String username;
+
+ @NotNull(message = "username must not be null")
+ @Size(min = 1, message = "At least 1 role must be passed")
+ private Set<String> roles;
+
+ @NotBlank(message = "password must not be blank")
+ private String password;
+
+ @NotBlank(message = "Full name must not be blank")
+ private String fullName;
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/UpdateUserRequest.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/UpdateUserRequest.java
new file mode 100644
index 0000000..6e3abf6
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/models/UpdateUserRequest.java
@@ -0,0 +1,47 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.models;
+
+import lombok.Data;
+
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import java.util.Set;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * To update User Details of Name and Password
+ */
+@Data
+public class UpdateUserRequest {
+
+ @Size(min = 1, message = "At least 1 role must be passed")
+ private Set<String> roles;
+
+ @Pattern(regexp = "^(?!\\s*$).+", message = "password must not be blank")
+ private String password;
+
+ @Pattern(regexp = "^(?!\\s*$).+", message = "fullName must not be blank")
+ private String fullName;
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/RoleRepository.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/RoleRepository.java
new file mode 100644
index 0000000..6efad17
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/RoleRepository.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.repositories;
+
+import org.onap.dcaegen2.platform.mod.models.Role;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+import java.util.Optional;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Interface to find user exists or not
+ */
+public interface RoleRepository extends MongoRepository<Role, String> {
+ Optional<Role> findByName(String name);
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/UserRepository.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/UserRepository.java
new file mode 100644
index 0000000..442ebf1
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/repositories/UserRepository.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.repositories;
+
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+import java.util.Optional;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Interface to Find/Valid/Delete user
+ */
+public interface UserRepository extends MongoRepository<ModUser, String>{
+ Optional<ModUser> findByUsername(String username);
+ Boolean existsByUsername(String username);
+ void deleteByUsername(String username);
+}
+
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/WebSecurityConfigurer.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/WebSecurityConfigurer.java
new file mode 100644
index 0000000..cfccce4
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/WebSecurityConfigurer.java
@@ -0,0 +1,92 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.security;
+
+import org.onap.dcaegen2.platform.mod.security.jwt.AuthEntryPointJwt;
+import org.onap.dcaegen2.platform.mod.security.jwt.AuthTokenFilter;
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Allows customization to the Spring WebSecurity
+ */
+
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
+
+ @Autowired
+ UserDetailsServiceImpl userDetailsService;
+
+ @Autowired
+ private AuthEntryPointJwt unauthorizedHandler;
+
+ @Bean
+ public AuthTokenFilter authenticationJwtTokenFilter(){
+ return new AuthTokenFilter();
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
+ authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
+ }
+
+ @Bean
+ @Override
+ public AuthenticationManager authenticationManagerBean() throws Exception{
+ return super.authenticationManagerBean();
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.cors().and().csrf().disable()
+ .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
+ .authorizeRequests().antMatchers("/api/auth/**").permitAll()
+ .antMatchers("/api/users/**").permitAll()
+ .anyRequest().authenticated();
+
+ http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthEntryPointJwt.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthEntryPointJwt.java
new file mode 100644
index 0000000..310d487
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthEntryPointJwt.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.security.jwt;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * JWT Authentication Entry Point
+ */
+
+@Slf4j
+@Component
+public class AuthEntryPointJwt implements AuthenticationEntryPoint {
+
+ @Override
+ public void commence(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException authException) throws IOException, ServletException {
+ log.error("Unauthorized error: {}", authException.getMessage());
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthTokenFilter.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthTokenFilter.java
new file mode 100644
index 0000000..012c333
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/AuthTokenFilter.java
@@ -0,0 +1,81 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.security.jwt;
+
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * Authentication Token Filter
+ */
+@Slf4j
+public class AuthTokenFilter extends OncePerRequestFilter {
+
+ @Autowired
+ private JwtUtils jwtUtils;
+
+ @Autowired
+ private UserDetailsServiceImpl userDetailsService;
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
+ try{
+ String jwt = parseJwt(httpServletRequest);
+ if (jwt != null && jwtUtils.validateJwtToken(jwt)){
+ String username = jwtUtils.getUserNameFromJwtToken(jwt);
+ UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+ UsernamePasswordAuthenticationToken authenticationToken =
+ new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
+ authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
+ SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+ }
+ }catch (Exception e){
+ logger.error("Cannot set user authentication: {}", e);
+ }
+ filterChain.doFilter(httpServletRequest, httpServletResponse);
+ }
+
+ private String parseJwt(HttpServletRequest httpServletRequest) {
+ String headerAuth = httpServletRequest.getHeader("Authorization");
+
+ if(StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")){
+ return headerAuth.substring(7, headerAuth.length());
+ }
+ return null;
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/JwtUtils.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/JwtUtils.java
new file mode 100644
index 0000000..3b6d311
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/jwt/JwtUtils.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.security.jwt;
+
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsImpl;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.SignatureException;
+import io.jsonwebtoken.MalformedJwtException;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.UnsupportedJwtException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * JWT Utils
+ */
+@Slf4j
+@Component
+public class JwtUtils {
+
+ @Value("${mod-portal.jwt.secret}")
+ private String jwtSecret;
+
+ @Value("${mod-portal.jwt.jwtExpirationMs}")
+ private int jwtExpirationMs;
+
+ public String generateJwtToken(Authentication authentication) {
+
+ UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
+
+ return Jwts.builder()
+ .setSubject((userPrincipal.getUsername()))
+ .claim("roles", userPrincipal.getAuthoritiesAsList())
+ .claim("fullName", userPrincipal.getFullName())
+ .setIssuedAt(new Date())
+ .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
+ .signWith(SignatureAlgorithm.HS512, jwtSecret)
+ .compact();
+ }
+
+ public String getUserNameFromJwtToken(String token) {
+ return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();
+ }
+
+ public boolean validateJwtToken(String authToken) {
+ try {
+ Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
+ return true;
+ } catch (SignatureException e) {
+ log.error("Invalid JWT signature: {}", e.getMessage());
+ } catch (MalformedJwtException e) {
+ log.error("Invalid JWT token: {}", e.getMessage());
+ } catch (ExpiredJwtException e) {
+ log.error("JWT token is expired: {}", e.getMessage());
+ } catch (UnsupportedJwtException e) {
+ log.error("JWT token is unsupported: {}", e.getMessage());
+ } catch (IllegalArgumentException e) {
+ log.error("JWT claims string is empty: {}", e.getMessage());
+ }
+
+ return false;
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsImpl.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsImpl.java
new file mode 100644
index 0000000..82cb577
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsImpl.java
@@ -0,0 +1,127 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.security.services;
+
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.EqualsAndHashCode;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * User Details Implementation
+ */
+@EqualsAndHashCode
+public class UserDetailsImpl implements UserDetails{
+
+ private static final long serialVersionUID = 1L;
+
+ private String id;
+
+ private String username;
+
+ private String fullName;
+
+ @JsonIgnore
+ private String password;
+
+ private Collection<? extends GrantedAuthority> authorities;
+
+ public UserDetailsImpl(String id, String username, String fullName, String password, Collection<?
+ extends GrantedAuthority> authorities) {
+ this.id = id;
+ this.username = username;
+ this.fullName = fullName;
+ this.password = password;
+ this.authorities = authorities;
+ }
+
+ public static UserDetails build(ModUser user) {
+ List<GrantedAuthority> authorities = user.getRoles().stream()
+ .map(role -> new SimpleGrantedAuthority(role.getName()))
+ .collect(Collectors.toList());
+
+ return new UserDetailsImpl(
+ user.get_id(),
+ user.getUsername(),
+ user.getFullName(),
+ user.getPassword(),
+ authorities
+ );
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public Collection<? extends GrantedAuthority> getAuthorities() {
+ return authorities;
+ }
+
+ public List<String> getAuthoritiesAsList(){
+ return authorities.stream().map(GrantedAuthority::getAuthority)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public String getPassword() {
+ return password;
+ }
+
+ @Override
+ public String getUsername() {
+ return username;
+ }
+
+ public String getFullName() {
+ return fullName;
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsServiceImpl.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..5c13e11
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/security/services/UserDetailsServiceImpl.java
@@ -0,0 +1,100 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.security.services;
+
+import org.onap.dcaegen2.platform.mod.controllers.AuthController;
+import org.onap.dcaegen2.platform.mod.exceptions.UserNotFoundException;
+import org.onap.dcaegen2.platform.mod.exceptions.IllegalUserOperationException;
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.models.Role;
+import org.onap.dcaegen2.platform.mod.models.UpdateUserRequest;
+import org.onap.dcaegen2.platform.mod.repositories.UserRepository;
+import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import java.util.Set;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * User Details Service
+ */
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService {
+
+ @Autowired
+ @Setter
+ UserRepository userRepository;
+
+ @Autowired
+ PasswordEncoder passwordEncoder;
+
+ @Autowired
+ AuthController authController;
+
+ @Autowired
+ private JwtUtils jwtUtils;
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ ModUser user = userRepository.findByUsername(username)
+ .orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username));
+
+ return UserDetailsImpl.build(user);
+ }
+
+ public ModUser adminUpdateUser(String username, UpdateUserRequest userRequest, String token) {
+ return updateUserProfile(username, userRequest);
+ }
+
+ public ModUser userUpdateOwnProfile(String username, UpdateUserRequest userRequest, String token) {
+ String usernameFromToken = jwtUtils.getUserNameFromJwtToken(token.substring(7));
+ if (usernameFromToken.equals(username)) {
+ return updateUserProfile(username, userRequest);
+ } else {
+ throw new IllegalUserOperationException("Permission denied to update user profile of " + username);
+ }
+ }
+
+ private ModUser updateUserProfile(String username, UpdateUserRequest userRequest) {
+ ModUser modUser = userRepository.findByUsername(username).orElseThrow(() -> new UserNotFoundException(String.format("User %s not found", username)));
+ modUser = updateUserFields(modUser, userRequest);
+ return userRepository.save(modUser);
+ }
+
+ private ModUser updateUserFields(ModUser modUser, UpdateUserRequest userRequest) {
+ if (userRequest.getFullName() != null) modUser.setFullName(userRequest.getFullName());
+ if (userRequest.getPassword() != null) modUser.setPassword(passwordEncoder.encode(userRequest.getPassword()));
+ if (userRequest.getRoles() != null) {
+ Set<Role> roles = authController.createRoles(userRequest.getRoles());
+ modUser.setRoles(roles);
+ }
+ return modUser;
+ }
+}
diff --git a/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/services/MODUserDetailService.java b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/services/MODUserDetailService.java
new file mode 100644
index 0000000..a6a6de5
--- /dev/null
+++ b/mod2/auth-service/src/main/java/org/onap/dcaegen2/platform/mod/services/MODUserDetailService.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.services;
+
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.repositories.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author
+ * @date 09/08/2020
+ * This Service provides APIs to manage User Entity
+ */
+
+@Service
+public class MODUserDetailService {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ public MODUserDetailService(UserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ public List<ModUser> findAll() {
+ return userRepository.findAll();
+ }
+
+ public void deleteUserByUsername(String username) {
+ userRepository.deleteByUsername(username);
+ }
+
+}
diff --git a/mod2/auth-service/src/main/resources/application.properties b/mod2/auth-service/src/main/resources/application.properties
new file mode 100644
index 0000000..f3f5d37
--- /dev/null
+++ b/mod2/auth-service/src/main/resources/application.properties
@@ -0,0 +1,32 @@
+#
+# /*
+# * ============LICENSE_START=======================================================
+# * org.onap.dcae
+# * ================================================================================
+# * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+# * ================================================================================
+# * Licensed under the Apache License, Version 2.0 (the "License");
+# * you may not use this file except in compliance with the License.
+# * You may obtain a copy of the License at
+# *
+# * http://www.apache.org/licenses/LICENSE-2.0
+# *
+# * Unless required by applicable law or agreed to in writing, software
+# * distributed under the License is distributed on an "AS IS" BASIS,
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# * See the License for the specific language governing permissions and
+# * limitations under the License.
+# * ============LICENSE_END=========================================================
+# */
+#
+
+server.port=8082
+
+#spring.data.mongodb.host=mongo_db
+spring.data.mongodb.host=localhost
+#spring.data.mongodb.host=zlecdyh2bdcc1s2dokr05.ec53e7.dyh2b.tci.att.com
+spring.data.mongodb.port=27017
+spring.data.mongodb.database=dcae_mod
+
+mod-portal.jwt.secret=mod2020!
+mod-portal.jwt.jwtExpirationMs=43200000 \ No newline at end of file
diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/AuthObjectMother.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/AuthObjectMother.java
new file mode 100644
index 0000000..3a22af3
--- /dev/null
+++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/AuthObjectMother.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.objectmothers;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.onap.dcaegen2.platform.mod.models.LoginRequest;
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.models.Role;
+import org.onap.dcaegen2.platform.mod.models.SignupRequest;
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsImpl;
+import org.onap.dcaegen2.platform.mod.util.TestUtil;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author
+ * @date 09/22/2020
+ * Mock for AuthenticationController Test Case
+ */
+
+public class AuthObjectMother {
+ public static final String LOGIN_REQUEST = "src/test/resources/http/requests/AuthLoginRequest.json";
+ public static final String SIGNUP_REQUEST = "src/test/resources/http/requests/AuthSignupRequest.json";
+
+ public static String asJsonString(final Object object) {
+ try {
+ return new ObjectMapper().writeValueAsString(object);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static LoginRequest getLoginRequest() {
+ return TestUtil.deserializeJsonFileToModel(LOGIN_REQUEST, LoginRequest.class);
+ }
+
+ public static SignupRequest getSignupRequest() {
+ return TestUtil.deserializeJsonFileToModel(SIGNUP_REQUEST, SignupRequest.class);
+ }
+
+ public static UserDetailsImpl getUserDetailsImpl() {
+ SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");
+ List authorities = new ArrayList();
+ authorities.add(simpleGrantedAuthority);
+ return new UserDetailsImpl("admin123", "admin123", "admin123", "admin123", authorities);
+ }
+
+ public static ModUser getModUser() {
+ ModUser user = new ModUser();
+ user.setUsername("test");
+ user.setFullName("test");
+ user.setPassword("password");
+ Set<Role> roles = new HashSet<>();
+ Role role = new Role();
+ role.setName("test");
+ role.setId("123");
+ roles.add(role);
+ user.setRoles(roles);
+ return user;
+ }
+}
diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/RoleObjectMother.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/RoleObjectMother.java
new file mode 100644
index 0000000..68002ac
--- /dev/null
+++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/RoleObjectMother.java
@@ -0,0 +1,56 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.objectmothers;
+
+
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.models.Role;
+import org.onap.dcaegen2.platform.mod.repositories.RoleRepository;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author
+ * @date 09/22/2020
+ * Mock for RoleController Test Case
+ */
+public class RoleObjectMother {
+
+ public static List<Role> getRoles() {
+ List<Role> roles = new ArrayList();
+ Role role1 = new Role();
+ role1.setId("123");
+ role1.setName("Admin123");
+
+ Role role2 = new Role();
+ role2.setId("1234");
+ role2.setName("Admin1234");
+
+ roles.add(role1);
+ roles.add(role2);
+
+ return roles;
+ }
+
+}
diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/UserObjectMother.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/UserObjectMother.java
new file mode 100644
index 0000000..301b81f
--- /dev/null
+++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/UserObjectMother.java
@@ -0,0 +1,100 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.objectmothers;
+
+
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.models.Role;
+import org.onap.dcaegen2.platform.mod.models.UpdateUserRequest;
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsImpl;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author
+ * @date 09/22/2020
+ * Mock for UserController Test Case
+ */
+public class UserObjectMother {
+
+ public static final String userId = "admin";
+
+ public static List<ModUser> getUsers() {
+ List<ModUser> users = new ArrayList();
+ ModUser modUser1 = new ModUser();
+ modUser1.set_id("123");
+ modUser1.setFullName("Admin123");
+ modUser1.setPassword("Admin123");
+ Set<Role> roles = new HashSet<>();
+ Role role = new Role();
+ role.setName("test");
+ role.setId("123");
+ roles.add(role);
+ modUser1.setRoles(roles);
+
+ ModUser modUser2 = new ModUser();
+ modUser2.set_id("1234");
+ modUser2.setFullName("Admin1234");
+ modUser2.setPassword("Admin1234");
+ Set<Role> roles1 = new HashSet<>();
+ Role role1 = new Role();
+ role.setName("test1");
+ role.setId("1234");
+ roles.add(role1);
+ modUser2.setRoles(roles1);
+
+ users.add(modUser1);
+ users.add(modUser2);
+
+ return users;
+ }
+
+ public static ModUser getModUser() {
+ ModUser user = new ModUser();
+ user.setUsername("test");
+ user.setFullName("test");
+ user.setPassword("password");
+ Set<Role> roles = new HashSet<>();
+ Role role = new Role();
+ role.setName("test");
+ role.setId("123");
+ roles.add(role);
+ user.setRoles(roles);
+ return user;
+ }
+
+ public static UpdateUserRequest getUpdateUserRequest(){
+ UpdateUserRequest user = new UpdateUserRequest();
+ user.setFullName("test");
+ user.setPassword("password");
+ Set<String> roles = new HashSet<>();
+ roles.add("ROLE_PST");
+ user.setRoles(roles);
+ return user;
+ }
+
+}
diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java
new file mode 100644
index 0000000..111653f
--- /dev/null
+++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java
@@ -0,0 +1,60 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.util;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * @author
+ * @date 09/22/2020
+ * TestUtils for test cases
+ */
+public class TestUtil {
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private TestUtil() {}
+
+ public static Map<String, Object> readJsonFileAsObjectMap(String filePath) {
+ try {
+ return MAPPER.readValue(new File(filePath), new TypeReference<Map<String, Object>>() {});
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException();
+ }
+ }
+
+ public static <T> T deserializeJsonFileToModel(String filePath, Class<T> modelClass) {
+ try {
+ return MAPPER.readValue(new File(filePath), modelClass);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/AuthControllerTest.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/AuthControllerTest.java
new file mode 100644
index 0000000..2aad289
--- /dev/null
+++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/AuthControllerTest.java
@@ -0,0 +1,149 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.onap.dcaegen2.platform.mod.controllers.AuthController;
+import org.onap.dcaegen2.platform.mod.models.*;
+import org.onap.dcaegen2.platform.mod.repositories.RoleRepository;
+import org.onap.dcaegen2.platform.mod.repositories.UserRepository;
+import org.onap.dcaegen2.platform.mod.security.jwt.AuthEntryPointJwt;
+import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils;
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.*;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.web.client.RestTemplate;
+import org.testng.annotations.BeforeTest;
+
+import java.io.IOException;
+import java.util.Optional;
+
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.mockito.Mockito.*;
+import static org.onap.dcaegen2.platform.mod.objectmothers.AuthObjectMother.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * @author
+ * @date 09/22/2020
+ * Mock Test cases for AuthenticationController
+ */
+@WebMvcTest(AuthController.class)
+public class AuthControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
+ JwtUtils jwtUtils;
+
+ @MockBean
+ AuthenticationManager authenticationManager;
+
+ @MockBean
+ UserRepository userRepository;
+
+ @MockBean
+ RoleRepository roleRepository;
+
+ @MockBean
+ PasswordEncoder passwordEncoder;
+
+ @MockBean
+ UserDetailsServiceImpl userDetailsService;
+
+ @MockBean
+ AuthEntryPointJwt authEntryPointJwt;
+
+ @Mock
+ Authentication authentication;
+
+ @BeforeEach
+ void setUp() {
+ }
+
+
+ @Test
+ void test_signin_returnsSuccessResponse() throws Exception {
+
+ LoginRequest loginRequest = getLoginRequest();
+
+ when(authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()))).thenReturn(authentication);
+ when(authentication.getPrincipal()).thenReturn(getUserDetailsImpl());
+ when(jwtUtils.generateJwtToken(any())).thenReturn("Demo");
+
+ mockMvc.perform(post("/api/auth/signin")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(asJsonString(loginRequest)).accept(MediaType.APPLICATION_JSON))
+ .andExpect(jsonPath("$.token", notNullValue()))
+ .andExpect(status().isOk());
+
+ verify(authenticationManager, times(1)).authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
+ verify(jwtUtils, times(1)).generateJwtToken(any());
+ }
+
+
+ @WithMockUser(roles="ADMIN")
+ @Test
+ void test_signup_returnsSuccessResponse() throws Exception {
+
+ SignupRequest signUpRequest = getSignupRequest();
+
+ when(userRepository.existsByUsername(signUpRequest.getUsername())).thenReturn(false);
+ when(passwordEncoder.encode(signUpRequest.getPassword())).thenReturn("password");
+ when(roleRepository.findByName(anyString())).thenReturn(Optional.of(new Role()));
+ when(userRepository.save(any())).thenReturn(getModUser());
+
+ mockMvc.perform(post("/api/auth/signup")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(asJsonString(signUpRequest)).accept(MediaType.APPLICATION_JSON))
+ .andExpect(jsonPath("$.message", notNullValue()))
+ .andExpect(status().isOk());
+
+ verify(userRepository, times(1)).existsByUsername(signUpRequest.getUsername());
+ verify(passwordEncoder, times(1)).encode(signUpRequest.getPassword());
+ verify(roleRepository, times(1)).findByName(anyString());
+ verify(userRepository, times(1)).save(any());
+ }
+
+
+}
diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/RoleControllerTest.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/RoleControllerTest.java
new file mode 100644
index 0000000..48b5d4b
--- /dev/null
+++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/RoleControllerTest.java
@@ -0,0 +1,109 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.web;
+
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.onap.dcaegen2.platform.mod.controllers.RoleController;
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.models.Role;
+import org.onap.dcaegen2.platform.mod.repositories.RoleRepository;
+import org.onap.dcaegen2.platform.mod.security.jwt.AuthEntryPointJwt;
+import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils;
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.security.core.Authentication;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.onap.dcaegen2.platform.mod.objectmothers.AuthObjectMother.asJsonString;
+import static org.onap.dcaegen2.platform.mod.objectmothers.RoleObjectMother.getRoles;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * @author
+ * @date 09/22/2020
+ * Mock Test cases for RoleController
+ */
+@WebMvcTest(RoleController.class)
+public class RoleControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
+ RoleRepository roleRepository;
+
+ @MockBean
+ UserDetailsServiceImpl userDetailsService;
+
+ @MockBean
+ AuthEntryPointJwt authEntryPointJwt;
+
+ @MockBean
+ JwtUtils jwtUtils;
+
+ @Mock
+ Authentication authentication;
+
+ @BeforeEach
+ void setUp() {
+ }
+
+
+ @Test
+ void test_getRoles() throws Exception {
+
+ Mockito.when(roleRepository.findAll()).thenReturn(getRoles());
+
+ MvcResult result = mockMvc.perform(get("/api/roles")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+
+ Assert.assertNotNull(result.getResponse().getContentAsString());
+
+ }
+
+}
diff --git a/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/UserControllerTest.java b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/UserControllerTest.java
new file mode 100644
index 0000000..1374e0e
--- /dev/null
+++ b/mod2/auth-service/src/test/java/org/onap/dcaegen2/platform/mod/web/UserControllerTest.java
@@ -0,0 +1,168 @@
+/*
+ *
+ * * ============LICENSE_START=======================================================
+ * * org.onap.dcae
+ * * ================================================================================
+ * * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * * ================================================================================
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * http://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ * * ============LICENSE_END=========================================================
+ *
+ */
+
+package org.onap.dcaegen2.platform.mod.web;
+
+import org.apache.tools.ant.taskdefs.optional.extension.Specification;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.Request;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.onap.dcaegen2.platform.mod.controllers.RoleController;
+import org.onap.dcaegen2.platform.mod.controllers.UserController;
+import org.onap.dcaegen2.platform.mod.models.LoginRequest;
+import org.onap.dcaegen2.platform.mod.models.ModUser;
+import org.onap.dcaegen2.platform.mod.models.UpdateUserRequest;
+import org.onap.dcaegen2.platform.mod.repositories.RoleRepository;
+import org.onap.dcaegen2.platform.mod.repositories.UserRepository;
+import org.onap.dcaegen2.platform.mod.security.jwt.AuthEntryPointJwt;
+import org.onap.dcaegen2.platform.mod.security.jwt.JwtUtils;
+import org.onap.dcaegen2.platform.mod.security.services.UserDetailsServiceImpl;
+import org.onap.dcaegen2.platform.mod.services.MODUserDetailService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.web.client.RequestMatcher;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.ResultMatcher;
+
+import java.util.Optional;
+
+import static org.hamcrest.Matchers.notNullValue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.*;
+import static org.onap.dcaegen2.platform.mod.objectmothers.AuthObjectMother.asJsonString;
+import static org.onap.dcaegen2.platform.mod.objectmothers.AuthObjectMother.getModUser;
+import static org.onap.dcaegen2.platform.mod.objectmothers.RoleObjectMother.getRoles;
+import static org.onap.dcaegen2.platform.mod.objectmothers.UserObjectMother.*;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * @author
+ * @date 09/22/2020
+ * Mock Test cases for UserController
+ */
+@WebMvcTest(UserController.class)
+public class UserControllerTest {
+
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
+ UserDetailsServiceImpl userDetailsService;
+
+ @MockBean
+ UserRepository userRepository;
+
+ @MockBean
+ MODUserDetailService modUserDetailService;
+
+ @MockBean
+ RoleRepository roleRepository;
+
+ @MockBean
+ AuthEntryPointJwt authEntryPointJwt;
+
+ @MockBean
+ JwtUtils jwtUtils;
+
+ @Mock
+ Authentication authentication;
+
+
+ @BeforeEach
+ void setUp() {
+ }
+
+ @WithMockUser(roles="ADMIN")
+ @Test
+ void test_getUsername() throws Exception {
+
+ when(userRepository.findByUsername(any())).thenReturn(Optional.of(new ModUser()));
+
+ MvcResult result = mockMvc.perform(get("/api/users/" + userId)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+
+ Assert.assertNotNull(result.getResponse().getContentAsString());
+ verify(userRepository, times(1)).findByUsername(any());
+ }
+
+ @Test
+ void test_getAllUsers() throws Exception {
+
+ when(modUserDetailService.findAll()).thenReturn(getUsers());
+
+ MvcResult result = mockMvc.perform(get("/api/users/getAll")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+
+ Assert.assertNotNull(result.getResponse().getContentAsString());
+ verify(modUserDetailService, times(1)).findAll();
+ }
+
+
+ @WithMockUser(roles="ADMIN")
+ @Test
+ void test_deleteUser() throws Exception {
+
+ doNothing().when(modUserDetailService).deleteUserByUsername(any(String.class));
+
+ MvcResult result = mockMvc.perform(delete("/api/users/" + userId)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk()).andReturn();
+
+ Assert.assertNotNull(result.getResponse().getContentAsString());
+ verify(modUserDetailService, times(1)).deleteUserByUsername(any(String.class));
+ }
+
+
+ @WithMockUser(username="ADMIN")
+ @Test
+ void test_userUpdateOwnProfile_returnsSuccessResponse() throws Exception {
+ //arrange
+ UpdateUserRequest updateUserRequest = getUpdateUserRequest();
+
+ when(userDetailsService.adminUpdateUser(userId,updateUserRequest,"token")).thenReturn(getModUser());
+
+ mockMvc.perform(patch("/api/users/admin/" + userId)
+ //.header("Authorization", "token")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(asJsonString(updateUserRequest)).accept(MediaType.APPLICATION_JSON))
+ //.andExpect(jsonPath("$.message", notNullValue()))
+ .andExpect(status().isOk()).andReturn();
+
+ verify(userDetailsService, times(1)).adminUpdateUser(anyString(),updateUserRequest,anyString());
+ }
+
+
+} \ No newline at end of file
diff --git a/mod2/auth-service/src/test/resources/application.properties b/mod2/auth-service/src/test/resources/application.properties
new file mode 100644
index 0000000..d6a913c
--- /dev/null
+++ b/mod2/auth-service/src/test/resources/application.properties
@@ -0,0 +1 @@
+#spring.data.mongodb.port=0 \ No newline at end of file
diff --git a/mod2/auth-service/src/test/resources/http/requests/AuthLoginRequest.json b/mod2/auth-service/src/test/resources/http/requests/AuthLoginRequest.json
new file mode 100644
index 0000000..fbdc4a9
--- /dev/null
+++ b/mod2/auth-service/src/test/resources/http/requests/AuthLoginRequest.json
@@ -0,0 +1,4 @@
+{
+ "username": "admin",
+ "password": "admin@mod"
+}
diff --git a/mod2/auth-service/src/test/resources/http/requests/AuthSignupRequest.json b/mod2/auth-service/src/test/resources/http/requests/AuthSignupRequest.json
new file mode 100644
index 0000000..25be086
--- /dev/null
+++ b/mod2/auth-service/src/test/resources/http/requests/AuthSignupRequest.json
@@ -0,0 +1,6 @@
+{
+ "username": "admin1",
+ "fullName": "Administrator",
+ "password": "admin@mod",
+ "roles": ["ROLE_PST"]
+} \ No newline at end of file
diff --git a/mod2/auth-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json b/mod2/auth-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json
new file mode 100644
index 0000000..0ad6b6e
--- /dev/null
+++ b/mod2/auth-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json
@@ -0,0 +1,149 @@
+{
+ "self": {
+ "component_type": "docker",
+ "description": "Hello World mS for subscribing the data from local DMaaP, DR or MR, processing them and publishing them as PM files to local DMaaP DR",
+ "name": "dcae-collectors-vcc-helloworld-pm",
+ "version": "1.0.1"
+ },
+
+ "services": {
+ "calls": [],
+ "provides": []
+ },
+
+ "streams": {
+ "publishes": [{
+ "config_key": "DCAE-HELLO-WORLD-PUB-DR",
+ "format": "dataformat_Hello_World_PM",
+ "type": "data_router",
+ "version": "1.0.0"
+ },
+ {
+ "config_key": "DCAE-HELLO-WORLD-PUB-MR",
+ "format": "dataformat_Hello_World_PM",
+ "type": "message_router",
+ "version": "1.0.0"
+ }
+ ],
+
+ "subscribes": [{
+ "config_key": "DCAE-HELLO-WORLD-SUB-MR",
+ "format": "dataformat_Hello_World_PM",
+ "route": "/DCAE_HELLO_WORLD_SUB_MR",
+ "type": "message_router",
+ "version": "1.0.0"
+ },
+ {
+ "config_key": "DCAE-HELLO-WORLD-SUB-DR",
+ "format": "dataformat_Hello_World_PM",
+ "route": "/DCAE-HELLO-WORLD-SUB-DR",
+ "type": "data_router",
+ "version": "1.0.0"
+ }
+ ]
+ },
+
+ "parameters":
+ [
+ {
+ "name": "vcc_hello_name",
+ "value": "120",
+ "type": "integer",
+ "description": "the name entered for specific person",
+ "sourced_at_deployment": false,
+ "designer_editable": false,
+ "policy_editable": false
+ },
+
+ {
+ "name": "useDtiConfig",
+ "value": false,
+ "type" : "boolean",
+ "description": "component depends on configuration from dti.",
+ "sourced_at_deployment": false,
+ "designer_editable": true,
+ "policy_editable": false,
+ "required" : true
+ },
+
+ {
+ "name": "isSelfServeComponent",
+ "value": false,
+ "type": "boolean",
+ "description": "Is this used as self serve component.",
+ "sourced_at_deployment": false,
+ "designer_editable": true,
+ "policy_editable": false,
+ "required" : true
+ }
+ ],
+
+ "auxilary": {
+ "healthcheck": {
+ "interval": "60s",
+ "initialDelaySeconds": "120s",
+ "timeout": "20s",
+ "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh",
+ "type": "docker"
+ },
+ "livehealthcheck": {
+ "interval": "60s",
+ "initialDelaySeconds": "120s",
+ "timeout": "20s",
+ "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh",
+ "type": "docker"
+ },
+ "reconfigs":{
+ "app_reconfig" : "abc"
+ },
+
+ "volumes": [
+ {
+ "container": {
+ "bind": "/opt/app/dcae-certificate"
+ },
+ "host": {
+ "path": "/opt/app/dcae-certificate"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/logs/DCAE/dmd/AGENT"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/dmd/AGENT"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/logs/DCAE/dmd/WATCHER"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/dmd/WATCHER"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/app/vcc/logs/DCAE"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/vcc-logs"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/app/vcc/archive/data"
+ },
+ "host": {
+ "path": "/opt/data/DCAE/helloworldpm/vcc-archive"
+ }
+ }
+
+ ]
+
+ },
+ "artifacts": [{
+ "type": "docker image",
+ "uri": "dockercentral.it.att.com:5100/com.att.sample/dcae-controller-vcc-helloworld-pm:18.02-001"
+ }]
+} \ No newline at end of file
diff --git a/mod2/auth-service/src/test/resources/specification/policy_json_sample_3.json b/mod2/auth-service/src/test/resources/specification/policy_json_sample_3.json
new file mode 100644
index 0000000..4a8c76f
--- /dev/null
+++ b/mod2/auth-service/src/test/resources/specification/policy_json_sample_3.json
@@ -0,0 +1,28 @@
+{
+ "policies": [
+ {
+ "configAttributes": "",
+ "configName": "",
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_",
+ "unique": false
+ },
+ {
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_",
+ "unique": true
+ },
+ {
+ "configAttributes": "",
+ "configName": "",
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_*",
+ "unique": false
+ }
+ ],
+ "policy": [
+ {
+ "policy_id" : "id_0"
+ }
+ ]
+} \ No newline at end of file
diff --git a/mod2/catalog-service/Dockerfile b/mod2/catalog-service/Dockerfile
new file mode 100644
index 0000000..0870a21
--- /dev/null
+++ b/mod2/catalog-service/Dockerfile
@@ -0,0 +1,14 @@
+FROM onap/integration-java11:7.1.0
+
+ARG PROJECT_BUILD_DIR_NAME
+ARG FINAL_JAR
+
+WORKDIR /usr/app
+VOLUME /tmp
+
+COPY ${PROJECT_BUILD_DIR_NAME}/${FINAL_JAR} .
+
+EXPOSE 8080
+ENTRYPOINT ["java", \
+ "-Djava.security.egd=file:/dev/./urandom", \
+ "-jar", "mod-catalog-service.jar"]
diff --git a/mod2/catalog-service/lombok.config b/mod2/catalog-service/lombok.config
new file mode 100644
index 0000000..8f7e8aa
--- /dev/null
+++ b/mod2/catalog-service/lombok.config
@@ -0,0 +1 @@
+lombok.addLombokGeneratedAnnotation = true \ No newline at end of file
diff --git a/mod2/catalog-service/pom.xml b/mod2/catalog-service/pom.xml
new file mode 100644
index 0000000..78cced4
--- /dev/null
+++ b/mod2/catalog-service/pom.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ org.onap.dcae
+ ~ ================================================================================
+ ~ Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ ~ ================================================================================
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ============LICENSE_END=========================================================
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.oparent</groupId>
+ <artifactId>oparent</artifactId>
+ <version>2.0.0</version>
+ </parent>
+ <groupId>org.onap.dcaegen2.platform.mod</groupId>
+ <artifactId>catalog-service</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+
+ <properties>
+ <java.version>11</java.version>
+ <maven.compiler.source>${java.version}</maven.compiler.source>
+ <maven.compiler.target>${java.version}</maven.compiler.target>
+ <spring-boot.version>2.2.5.RELEASE</spring-boot.version>
+ <dockerfile-maven-plugin.version>1.4.1</dockerfile-maven-plugin.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.8.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-webflux</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-validation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>io.projectreactor</groupId>
+ <artifactId>reactor-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger2</artifactId>
+ <version>2.9.2</version>
+ </dependency>
+ <dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger-ui</artifactId>
+ <version>2.9.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <version>1.18.10</version>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>okhttp</artifactId>
+ <version>4.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>com.squareup.okhttp3</groupId>
+ <artifactId>mockwebserver</artifactId>
+ <version>4.0.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <!-- Import dependency management from Spring Boot -->
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-dependencies</artifactId>
+ <version>2.2.5.RELEASE</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${spring-boot.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>com.spotify</groupId>
+ <artifactId>dockerfile-maven-plugin</artifactId>
+ <version>${dockerfile-maven-plugin.version}</version>
+ <configuration>
+ <contextDirectory>${project.basedir}</contextDirectory>
+ <repository>onap/${project.groupId}.${project.artifactId}</repository>
+ <buildArgs>
+ <PROJECT_BUILD_DIR_NAME>target</PROJECT_BUILD_DIR_NAME>
+ <FINAL_JAR>${project.build.finalName}.jar</FINAL_JAR>
+ </buildArgs>
+ </configuration>
+ <executions>
+ <execution>
+ <id>build-image</id>
+ <phase>package</phase>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>tag-and-push-image-latest</id>
+ <phase>package</phase>
+ <goals>
+ <goal>tag</goal>
+ <goal>push</goal>
+ </goals>
+ <configuration>
+ <repository>onap/${project.groupId}.${project.artifactId}</repository>
+ <tag>latest</tag>
+ <useMavenSettingsForAuth>true</useMavenSettingsForAuth>
+ </configuration>
+ </execution>
+ <execution>
+ <id>tag-and-push-image-with-version</id>
+ <phase>package</phase>
+ <goals>
+ <goal>tag</goal>
+ <goal>push</goal>
+ </goals>
+ <configuration>
+ <repository>onap/${project.groupId}.${project.artifactId}</repository>
+ <tag>${project.version}</tag>
+ <useMavenSettingsForAuth>true</useMavenSettingsForAuth>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.22.2</version>
+ </plugin>
+ </plugins>
+ <finalName>mod-catalog-service</finalName>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>cobertura-maven-plugin</artifactId>
+ <version>2.7</version>
+ </plugin>
+ </plugins>
+ </reporting>
+</project> \ No newline at end of file
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/ModCatalogApplication.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/ModCatalogApplication.java
new file mode 100644
index 0000000..d514a69
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/ModCatalogApplication.java
@@ -0,0 +1,68 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+
+/**
+ * The application class
+ */
+@SpringBootApplication
+@EnableSwagger2
+public class ModCatalogApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ModCatalogApplication.class, args);
+ }
+
+ @Bean
+ public Docket swaggerConfiguration(){
+ // return a prepared Docket instance
+ return new Docket(DocumentationType.SWAGGER_2)
+ .select()
+ //.paths(PathSelectors.ant("/api/*"))
+ .apis(RequestHandlerSelectors.basePackage("org.onap.dcaegen2.platform.mod"))
+ .build()
+ .apiInfo(apiDetails());
+ }
+
+ private ApiInfo apiDetails() {
+ Contact DEFAULT_CONTACT = new Contact("", "", "");
+ return new ApiInfo(
+ "MOD APIs",
+ "APIs for MOD",
+ "1.0.0"
+ ,"", DEFAULT_CONTACT, "", "", new ArrayList<>()
+ );
+ }
+ //http://localhost:8080/swagger-ui.html for web page view
+ //http://localhost:8080/v2/api-docs for json view
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mock/MockDeploymentArtifactGenerator.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mock/MockDeploymentArtifactGenerator.java
new file mode 100644
index 0000000..24c31ed
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mock/MockDeploymentArtifactGenerator.java
@@ -0,0 +1,45 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mock;
+
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.onap.dcaegen2.platform.mod.web.service.deploymentartifact.DeploymentArtifactGeneratorStrategy;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * Mock implementation for DeploymentArtifactGenerator
+ */
+@Component
+public class MockDeploymentArtifactGenerator implements DeploymentArtifactGeneratorStrategy {
+
+ /**
+ * null implementation.
+ * @param activeSpec
+ * @param release
+ * @return
+ */
+ @Override
+ public Map<String, Object> generateForRelease(Specification activeSpec, String release) {
+ return null;
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mock/MockSpecificationValidationStratergy.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mock/MockSpecificationValidationStratergy.java
new file mode 100644
index 0000000..8f9f921
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mock/MockSpecificationValidationStratergy.java
@@ -0,0 +1,42 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mock;
+
+import org.onap.dcaegen2.platform.mod.model.restapi.SpecificationRequest;
+import org.onap.dcaegen2.platform.mod.web.service.specification.SpecificationValidationStratergy;
+import org.springframework.stereotype.Component;
+
+/**
+ * Mock implementation for SpecificationValidationStrategy
+ */
+@Component
+public class MockSpecificationValidationStratergy implements SpecificationValidationStratergy {
+
+ /**
+ * Mock implementation
+ * @param specificationRequest
+ * @param release
+ */
+ @Override
+ public void validate(SpecificationRequest specificationRequest, String release) {
+ //do nothing
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMicroservice.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMicroservice.java
new file mode 100644
index 0000000..3e5891f
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMicroservice.java
@@ -0,0 +1,65 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.basemicroservice;
+
+import org.onap.dcaegen2.platform.mod.model.common.AuditFields;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A model class which represents Base-Microservice entity
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+//TODO: migrate the document to microservices
+@Document("base-microservices")
+public class BaseMicroservice {
+ private String id;
+
+ @ApiModelProperty(required = true)
+ private String name;
+
+ @ApiModelProperty(required = true)
+ private String tag;
+
+ private String serviceName;
+
+ private BaseMsType type;
+
+ private BaseMsLocation location;
+
+ private String namespace;
+
+ private BaseMsStatus status;
+
+ private AuditFields metadata;
+
+ private List<Map<String, String>> msInstances = new ArrayList<>();
+}
+
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsLocation.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsLocation.java
new file mode 100644
index 0000000..e8114a5
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsLocation.java
@@ -0,0 +1,29 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.basemicroservice;
+/**
+ * Supported values for Base-Microservice location
+ */
+public enum BaseMsLocation {
+ CENTRAL,
+ EDGE,
+ UNSPECIFIED
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsStatus.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsStatus.java
new file mode 100644
index 0000000..4460e04
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsStatus.java
@@ -0,0 +1,28 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.basemicroservice;
+
+/**
+ * Supported statuses for Base-Microservice entity
+ */
+public enum BaseMsStatus {
+ ACTIVE, RETIRED
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsType.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsType.java
new file mode 100644
index 0000000..1cc81e8
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/basemicroservice/BaseMsType.java
@@ -0,0 +1,32 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.basemicroservice;
+
+/**
+ * Supported Types for Base-Microservice
+ */
+public enum BaseMsType {
+ TICK,
+ FM_COLLECTOR,
+ PM_COLLECTOR,
+ ANALYTIC,
+ OTHER
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/common/AuditFields.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/common/AuditFields.java
new file mode 100644
index 0000000..d062456
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/common/AuditFields.java
@@ -0,0 +1,51 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.common;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * A model class for auditfields
+ */
+@Data
+@Builder
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class AuditFields {
+
+ private String createdBy;
+ private Date createdOn;
+ private String updatedBy;
+ private Date updatedOn;
+ //TODO set default empty values if not exist
+ private String notes = "";
+ private List<String> labels = new ArrayList<>();
+
+ public void setLabels(Object labels) {
+ if(labels instanceof List)
+ this.labels = (List<String>) labels;
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifact.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifact.java
new file mode 100644
index 0000000..600c735
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifact.java
@@ -0,0 +1,51 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.deploymentartifact;
+
+import lombok.Data;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Map;
+
+/**
+ * A model class which represents Deployment-Artifact entity
+ */
+@Data
+@Document("deployment-artifact")
+public class DeploymentArtifact {
+
+ private String id;
+
+ private Integer version;
+
+ private String content;
+
+ private String fileName;
+
+ private DeploymentArtifactStatus status;
+
+ private Map<String, Object> metadata;
+
+ private MsInstanceInfo msInstanceInfo;
+
+ private Map<String, Object> specificationInfo;
+
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactFilter.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactFilter.java
new file mode 100644
index 0000000..870ca46
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactFilter.java
@@ -0,0 +1,40 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.deploymentartifact;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * A model class to construct a filter that can be passed in DeploymentArtifactSearch
+ * @see org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactSearch
+ */
+@Data
+public class DeploymentArtifactFilter {
+ @JsonProperty("release")
+ private String release;
+
+ @JsonProperty("status")
+ private DeploymentArtifactStatus status;
+
+ @JsonProperty("tag")
+ private String tag;
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactSearch.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactSearch.java
new file mode 100644
index 0000000..9e955cd
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactSearch.java
@@ -0,0 +1,38 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.deploymentartifact;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * A model class to define Deployment-Artifact's searching criteria.
+ */
+@Data
+public class DeploymentArtifactSearch {
+
+ @JsonProperty("filter")
+ private DeploymentArtifactFilter filter;
+
+ public DeploymentArtifactSearch() {
+ this.filter = new DeploymentArtifactFilter();
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactStatus.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactStatus.java
new file mode 100644
index 0000000..4ee4e0e
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/DeploymentArtifactStatus.java
@@ -0,0 +1,30 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.deploymentartifact;
+
+/**
+ * Supported Statuses for a Deployment-Artifact
+ */
+public enum DeploymentArtifactStatus {
+
+ IN_DEV, NOT_NEEDED, DEV_COMPLETE,
+ IN_PROD, PROD_FAILED
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/MsInstanceInfo.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/MsInstanceInfo.java
new file mode 100644
index 0000000..665961c
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/deploymentartifact/MsInstanceInfo.java
@@ -0,0 +1,33 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.deploymentartifact;
+
+import lombok.Data;
+
+/**
+ * MsInstance Reference model used in DeploymentArtifact entity
+ */
+@Data
+public class MsInstanceInfo {
+ String id;
+ String name;
+ String release;
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ErrorMessages.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ErrorMessages.java
new file mode 100644
index 0000000..9b96066
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ErrorMessages.java
@@ -0,0 +1,33 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions;
+
+public class ErrorMessages {
+
+ public static final String MICROSERVICE_NAME_CONFLICT_MESSAGE = "Microservice with this name already exists.";
+ public static final String MICROSERVICE_TAG_CONFLICT_MESSAGE = "Microservice with this tag name already exists.";
+ public static final String MS_TAG_NAME_VALIDATION_MESSAGE =
+ "Microservice tag name is Invalid. Accepts lowercase letters and hyphens." +
+ " Tag name length cannot exceed 50 characters";
+ public static final String MS_SERVICE_NAME_CONFLICT_MESSAGE = "Microservice with this core name already exists.";
+ public static final String MS_SERVICE_NAME_VALIDATION_MESSAGE =
+ "Service name is Invalid. Accepts lowercase letters and hyphens";
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/MissingRequestBodyException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/MissingRequestBodyException.java
new file mode 100644
index 0000000..2d7d785
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/MissingRequestBodyException.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions;
+
+public class MissingRequestBodyException extends RuntimeException {
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/OperationNotAllowedException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/OperationNotAllowedException.java
new file mode 100644
index 0000000..47dafc9
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/OperationNotAllowedException.java
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions;
+
+public class OperationNotAllowedException extends RuntimeException {
+ public OperationNotAllowedException(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ReleaseNotSupportedException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ReleaseNotSupportedException.java
new file mode 100644
index 0000000..7ea6834
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ReleaseNotSupportedException.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions;
+
+public class ReleaseNotSupportedException extends RuntimeException{
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ResourceConflictException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ResourceConflictException.java
new file mode 100644
index 0000000..d81c68c
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/ResourceConflictException.java
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions;
+
+public class ResourceConflictException extends RuntimeException{
+ public ResourceConflictException(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceNotFoundException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceNotFoundException.java
new file mode 100644
index 0000000..3ee81e4
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceNotFoundException.java
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.basemicroservice;
+
+public class BaseMicroserviceNotFoundException extends RuntimeException {
+ public BaseMicroserviceNotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceTagAlreadyExists.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceTagAlreadyExists.java
new file mode 100644
index 0000000..e0bd119
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceTagAlreadyExists.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.basemicroservice;
+
+public class BaseMicroserviceTagAlreadyExists extends RuntimeException {
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceTagInvalid.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceTagInvalid.java
new file mode 100644
index 0000000..79282aa
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMicroserviceTagInvalid.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.basemicroservice;
+
+public class BaseMicroserviceTagInvalid extends RuntimeException {
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMsServiceNameAlreadyExists.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMsServiceNameAlreadyExists.java
new file mode 100644
index 0000000..3ae1b6f
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMsServiceNameAlreadyExists.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.basemicroservice;
+
+public class BaseMsServiceNameAlreadyExists extends RuntimeException {
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMsServiceNameInvalid.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMsServiceNameInvalid.java
new file mode 100644
index 0000000..6de3014
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/basemicroservice/BaseMsServiceNameInvalid.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.basemicroservice;
+
+public class BaseMsServiceNameInvalid extends RuntimeException {
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/common/UserNotPassedException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/common/UserNotPassedException.java
new file mode 100644
index 0000000..b34e065
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/common/UserNotPassedException.java
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.common;
+
+public class UserNotPassedException extends RuntimeException {
+ public UserNotPassedException(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/BlueprintFileNameCreateException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/BlueprintFileNameCreateException.java
new file mode 100644
index 0000000..5f52885
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/BlueprintFileNameCreateException.java
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact;
+
+public class BlueprintFileNameCreateException extends RuntimeException{
+ public BlueprintFileNameCreateException(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/DeploymentArtifactNotFound.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/DeploymentArtifactNotFound.java
new file mode 100644
index 0000000..e10c54e
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/DeploymentArtifactNotFound.java
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact;
+
+public class DeploymentArtifactNotFound extends RuntimeException{
+ public DeploymentArtifactNotFound(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/StatusChangeNotValidException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/StatusChangeNotValidException.java
new file mode 100644
index 0000000..99faf50
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/deploymentartifact/StatusChangeNotValidException.java
@@ -0,0 +1,28 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact;
+
+public class StatusChangeNotValidException extends RuntimeException {
+
+ public StatusChangeNotValidException(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/msinstance/MsInstanceAlreadyExistsException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/msinstance/MsInstanceAlreadyExistsException.java
new file mode 100644
index 0000000..80778ea
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/msinstance/MsInstanceAlreadyExistsException.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.msinstance;
+
+public class MsInstanceAlreadyExistsException extends RuntimeException {
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/msinstance/MsInstanceNotFoundException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/msinstance/MsInstanceNotFoundException.java
new file mode 100644
index 0000000..9ea977c
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/msinstance/MsInstanceNotFoundException.java
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.msinstance;
+
+public class MsInstanceNotFoundException extends RuntimeException{
+ public MsInstanceNotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/specification/SpecificationInvalid.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/specification/SpecificationInvalid.java
new file mode 100644
index 0000000..1b56d35
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/specification/SpecificationInvalid.java
@@ -0,0 +1,38 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.specification;
+
+import java.util.Map;
+
+public class SpecificationInvalid extends RuntimeException {
+
+ Map<String, Object> errorsMap;
+
+ public SpecificationInvalid(String message) {
+ super(message);
+ }
+
+ public SpecificationInvalid(Map<String, Object> errorsMap){
+ this.errorsMap = errorsMap;
+ }
+
+
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/specification/SpecificationNotFoundException.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/specification/SpecificationNotFoundException.java
new file mode 100644
index 0000000..9728b15
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/exceptions/specification/SpecificationNotFoundException.java
@@ -0,0 +1,24 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.exceptions.specification;
+
+public class SpecificationNotFoundException extends RuntimeException {
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/DeploymentArtifactsRef.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/DeploymentArtifactsRef.java
new file mode 100644
index 0000000..fe1aed5
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/DeploymentArtifactsRef.java
@@ -0,0 +1,36 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.microserviceinstance;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * DeploymentArtifacts Reference model used in Microservice-Instance entity
+ */
+@Data
+public class DeploymentArtifactsRef {
+
+ private int mostRecentVersion;
+ private List<String> deploymentArtifacts;
+
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/MsInstance.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/MsInstance.java
new file mode 100644
index 0000000..d305aa4
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/MsInstance.java
@@ -0,0 +1,56 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.microserviceinstance;
+
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Map;
+
+/**
+ * A model class which represents Microservice-Instance entity
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Document("ms-instance")
+public class MsInstance {
+ @Id
+ private String id;
+ private String name;
+ private String release;
+ private String version;
+ private MsInstanceStatus status;
+ private Map<String, Object> metadata;
+ private Map<String,Object> msInfo;
+
+ @DBRef
+ private Specification activeSpec;
+
+ private DeploymentArtifactsRef deploymentArtifactsInfo;
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/MsInstanceStatus.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/MsInstanceStatus.java
new file mode 100644
index 0000000..223f3dc
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/microserviceinstance/MsInstanceStatus.java
@@ -0,0 +1,28 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.microserviceinstance;
+
+/**
+ * Supported Statuses for Microservice-Instance entity
+ */
+public enum MsInstanceStatus {
+ NEW, IN_DEV, DEV_COMPLETE, IN_TEST, CERTIFIED, PROD_DEPLOYED
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/DeploymentArtifactPatchRequest.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/DeploymentArtifactPatchRequest.java
new file mode 100644
index 0000000..8d52488
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/DeploymentArtifactPatchRequest.java
@@ -0,0 +1,40 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.restapi;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.Map;
+
+/**
+ * A model that represent request body to patch DeploymentArtifact entity.
+ */
+@Data
+public class DeploymentArtifactPatchRequest {
+
+ @JsonProperty("status")
+ private DeploymentArtifactStatus status;
+
+ @JsonProperty("metadata")
+ private Map<String, Object> metaData;
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/ErrorResponse.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/ErrorResponse.java
new file mode 100644
index 0000000..fe78f94
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/ErrorResponse.java
@@ -0,0 +1,35 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.restapi;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * A model that represent response body to send a simple error response.
+ */
+@Data
+@AllArgsConstructor
+public class ErrorResponse {
+
+ private String message;
+
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/GenericErrorResponse.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/GenericErrorResponse.java
new file mode 100644
index 0000000..76597e2
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/GenericErrorResponse.java
@@ -0,0 +1,54 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.restapi;
+
+import lombok.Data;
+import org.springframework.http.HttpStatus;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A model that represent response body to send a detailed error response.
+ */
+@Data
+public class GenericErrorResponse {
+ private List<String> errors = new ArrayList<>();
+ private HttpStatus status;
+ private String message;
+
+ public GenericErrorResponse() {
+ }
+
+ public GenericErrorResponse(List<String> errors, HttpStatus status, String message) {
+ this.errors = errors;
+ this.status = status;
+ this.message = message;
+ }
+
+ public GenericErrorResponse(String error, HttpStatus status, String message) {
+ this.status = status;
+ this.message = message;
+ errors = Arrays.asList(error);
+ }
+
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MicroserviceCreateRequest.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MicroserviceCreateRequest.java
new file mode 100644
index 0000000..f8288cb
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MicroserviceCreateRequest.java
@@ -0,0 +1,59 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.restapi;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsLocation;
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsType;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import java.util.Map;
+
+/**
+ * A model that represent request body to create a Microservice entity.
+ */
+@NoArgsConstructor
+@Data
+public class MicroserviceCreateRequest {
+
+ @NotBlank(message = "Microservice tag can not be blank")
+ @Pattern(regexp = "^([a-z0-9](-[a-z0-9])*)+$", message = "Microservice tag name is Invalid. Accepts alphanumerics and hyphens.")
+ @Size(min = 5, max = 50, message = "Tag name length cannot exceed 50 characters")
+ private String tag;
+
+ @NotBlank(message = "Microservice name cannot be blank")
+ private String name;
+
+ @Pattern(regexp = "^[a-z-]*$", message = "Microservice core name is Invalid. Accepts lowercase letters and hyphens.")
+ private String serviceName;
+
+ private BaseMsType type;
+ private BaseMsLocation location;
+ private String namespace;
+ private Map<String, Object> metadata;
+
+ @NotBlank(message = "user can not be blank")
+ private String user;
+
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MicroserviceUpdateRequest.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MicroserviceUpdateRequest.java
new file mode 100644
index 0000000..a7262d6
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MicroserviceUpdateRequest.java
@@ -0,0 +1,52 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.restapi;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsLocation;
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsType;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import java.util.Map;
+
+/**
+ * A model that represent request body to update a Microservice entity.
+ */
+@NoArgsConstructor
+@Data
+public class MicroserviceUpdateRequest {
+
+ @Pattern(regexp = "^(?!\\s*$).+", message = "must not be blank")
+ private String name;
+
+ @Pattern(regexp = "^[a-z-]*$", message = "Microservice core name is Invalid. Accepts lowercase letters and hyphens.")
+ private String serviceName;
+
+ private BaseMsType type;
+ private BaseMsLocation location;
+ private String namespace;
+ private Map<String, Object> metadata;
+
+ @NotBlank(message = "user cannot be blank")
+ private String user;
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MsInstanceRequest.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MsInstanceRequest.java
new file mode 100644
index 0000000..803d417
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MsInstanceRequest.java
@@ -0,0 +1,52 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.restapi;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+import java.util.Map;
+
+/**
+ * A model that represent request body to create MsInsance entity.
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class MsInstanceRequest {
+
+ @NotBlank
+ private String name;
+
+ @NotBlank
+ private String release;
+
+ private String version;
+
+ @NotBlank
+ private String user;
+
+ private Map<String,Object> metadata;
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MsInstanceUpdateRequest.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MsInstanceUpdateRequest.java
new file mode 100644
index 0000000..2af61a8
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/MsInstanceUpdateRequest.java
@@ -0,0 +1,42 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.restapi;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.util.Map;
+
+/**
+ * A model that represent request body to patch MsInstance entity.
+ */
+@Data
+public class MsInstanceUpdateRequest {
+
+ private String release;
+ private String version;
+ private Map<String,Object> metadata;
+
+ @NotBlank(message = "User cannot be blank.")
+ private String user;
+}
+
+
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/SpecificationRequest.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/SpecificationRequest.java
new file mode 100644
index 0000000..e34379e
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/SpecificationRequest.java
@@ -0,0 +1,45 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.restapi;
+
+import org.onap.dcaegen2.platform.mod.model.specification.DeploymentType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+
+/**
+ * A model that represent request body to create Specification entity.
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class SpecificationRequest {
+
+ private Map<String,Object> specContent;
+ private Map<String, Object> policyJson;
+ private DeploymentType type;
+ private String user;
+ private Map<String,Object> metadata;
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/SuccessResponse.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/SuccessResponse.java
new file mode 100644
index 0000000..d428407
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/restapi/SuccessResponse.java
@@ -0,0 +1,34 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.restapi;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * A model that represent a simple Success response body.
+ */
+@Data
+@AllArgsConstructor
+public class SuccessResponse {
+
+ private String message;
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/DeploymentType.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/DeploymentType.java
new file mode 100644
index 0000000..815a529
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/DeploymentType.java
@@ -0,0 +1,28 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.specification;
+
+/**
+ * Supported Deployment Types in Specification entity
+ */
+public enum DeploymentType {
+ K8S, DOCKER
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/Specification.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/Specification.java
new file mode 100644
index 0000000..32778a3
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/Specification.java
@@ -0,0 +1,52 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.specification;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Map;
+
+/**
+ * A model class which represents Specification entity
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Document("specification")
+public class Specification {
+
+ @Id
+ private String id;
+ private SpecificationStatus status;
+ private Map<String,Object> specContent;
+ private Map<String, Object> policyJson;
+ private DeploymentType type;
+ private Map<String,Object> metadata;
+ private Map<String,Object> msInstanceInfo;
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/SpecificationStatus.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/SpecificationStatus.java
new file mode 100644
index 0000000..3e6cd1a
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/model/specification/SpecificationStatus.java
@@ -0,0 +1,28 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.model.specification;
+
+/**
+ * Supported statuses for Specification entity
+ */
+public enum SpecificationStatus {
+ ACTIVE, INACTIVE
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/basemicroservice/BaseMicroserviceMongoGateway.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/basemicroservice/BaseMicroserviceMongoGateway.java
new file mode 100644
index 0000000..9101234
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/basemicroservice/BaseMicroserviceMongoGateway.java
@@ -0,0 +1,71 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mongo.basemicroservice;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.web.service.basemicroservice.BaseMicroserviceGateway;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Mongo implementation of BaseMicroserviceGateway
+ */
+@Service
+public class BaseMicroserviceMongoGateway implements BaseMicroserviceGateway {
+
+ @Autowired
+ BaseMicroserviceMongoRepo repo;
+
+ @Override
+ public Optional<BaseMicroservice> findByName(String name) {
+ return repo.findByNameIgnoreCase(name);
+ }
+
+ @Override
+ public Optional<BaseMicroservice> findByTag(String tag) {
+ return repo.findByTagIgnoreCase(tag);
+ }
+
+ @Override
+ public Optional<BaseMicroservice> findByServiceName(String serviceName) {
+ return repo.findByServiceNameIgnoreCase(serviceName);
+ }
+
+ @Override
+ public BaseMicroservice save(BaseMicroservice microservice) {
+ return repo.save(microservice);
+ }
+
+ @Override
+ public List<BaseMicroservice> findAll() {
+ Sort sortByCreatedDate = Sort.by(Sort.Direction.DESC, "metadata.createdOn");
+ return repo.findAll(sortByCreatedDate);
+ }
+
+ @Override
+ public Optional<BaseMicroservice> findById(String msId) {
+ return Optional.empty();
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/basemicroservice/BaseMicroserviceMongoRepo.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/basemicroservice/BaseMicroserviceMongoRepo.java
new file mode 100644
index 0000000..b3795b2
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/basemicroservice/BaseMicroserviceMongoRepo.java
@@ -0,0 +1,40 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mongo.basemicroservice;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+/**
+ * An interface to use Spring MongoRepository
+ */
+@Repository
+public interface BaseMicroserviceMongoRepo extends MongoRepository<BaseMicroservice, String> {
+
+ Optional<BaseMicroservice> findByNameIgnoreCase(String name);
+
+ Optional<BaseMicroservice> findByTagIgnoreCase(String tag);
+
+ Optional<BaseMicroservice> findByServiceNameIgnoreCase(String serviceName);
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/deploymentartifact/DeploymentArtifactMongoGateway.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/deploymentartifact/DeploymentArtifactMongoGateway.java
new file mode 100644
index 0000000..72e9ec6
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/deploymentartifact/DeploymentArtifactMongoGateway.java
@@ -0,0 +1,86 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mongo.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactSearch;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.MsInstanceInfo;
+import org.onap.dcaegen2.platform.mod.web.service.deploymentartifact.DeploymentArtifactGateway;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Mongo implementation of BaseMicroserviceGateway
+ */
+@Service
+public class DeploymentArtifactMongoGateway implements DeploymentArtifactGateway {
+
+ @Autowired
+ DeploymentArtifactMongoRepo crudRepo;
+
+ public DeploymentArtifactMongoGateway(DeploymentArtifactMongoRepo repo) {
+ this.crudRepo = repo;
+ }
+
+ @Override
+ public List<DeploymentArtifact> findAll() {
+ return crudRepo.findAll();
+ }
+
+ @Override
+ public List<DeploymentArtifact> findByMsInstanceId(String id) {
+ return crudRepo.findByMsInstanceInfo_Id(id);
+ }
+
+ @Override
+ public Optional<DeploymentArtifact> findById(String id) {
+ return crudRepo.findById(id);
+ }
+
+ @Override
+ public void deleteById(String deploymentArtifactId) {
+ crudRepo.deleteById(deploymentArtifactId);
+ }
+
+ @Override
+ public DeploymentArtifact save(DeploymentArtifact deploymentArtifact) {
+ return crudRepo.save(deploymentArtifact);
+ }
+
+ @Override
+ public List<DeploymentArtifact> findAll(DeploymentArtifactSearch search) {
+ DeploymentArtifact artifact = new DeploymentArtifact();
+ artifact.setStatus(search.getFilter().getStatus());
+ //Currently searching tag in filename as it is not present in DeploymentArtifact record
+ artifact.setFileName(search.getFilter().getTag());
+
+ MsInstanceInfo msInstanceInfo = new MsInstanceInfo();
+ msInstanceInfo.setRelease(search.getFilter().getRelease());
+ artifact.setMsInstanceInfo(msInstanceInfo);
+
+ return crudRepo.findAll(Example.of(artifact,ExampleMatcher.matching().withIgnoreCase()));
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/deploymentartifact/DeploymentArtifactMongoRepo.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/deploymentartifact/DeploymentArtifactMongoRepo.java
new file mode 100644
index 0000000..cb8d0bb
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/deploymentartifact/DeploymentArtifactMongoRepo.java
@@ -0,0 +1,37 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mongo.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * An interface to use Spring MongoRepository
+ */
+@Repository
+public interface DeploymentArtifactMongoRepo extends MongoRepository<DeploymentArtifact, String> {
+
+ List<DeploymentArtifact> findByMsInstanceInfo_Id(String id);
+
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/microserviceinstance/MsInstanceMongoGateway.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/microserviceinstance/MsInstanceMongoGateway.java
new file mode 100644
index 0000000..d6d0d35
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/microserviceinstance/MsInstanceMongoGateway.java
@@ -0,0 +1,61 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mongo.microserviceinstance;
+
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceGateway;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Mongo implementation of MsInstance
+ */
+@Service
+public class MsInstanceMongoGateway implements MsInstanceGateway {
+
+ @Autowired
+ private MsInstanceMongoRepo repo;
+
+ @Override
+ public Optional<MsInstance> findByNameAndRelease(String name, String release) {
+ return repo.findByNameIgnoreCaseAndReleaseIgnoreCase(name, release);
+ }
+
+ @Override
+ public Optional<MsInstance> findById(String msInstanceId) {
+ return repo.findById(msInstanceId);
+ }
+
+ @Override
+ public List<MsInstance> findAll() {
+ Sort sortByCreatedDate = Sort.by(Sort.Direction.DESC, "metadata.createdOn");
+ return repo.findAll(sortByCreatedDate);
+ }
+
+ @Override
+ public MsInstance save(MsInstance msInstance) {
+ return repo.save(msInstance);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/microserviceinstance/MsInstanceMongoRepo.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/microserviceinstance/MsInstanceMongoRepo.java
new file mode 100644
index 0000000..1d6a277
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/microserviceinstance/MsInstanceMongoRepo.java
@@ -0,0 +1,38 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mongo.microserviceinstance;
+
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+/**
+ * An interface to use Spring MongoRepository
+ */
+@Repository
+public interface MsInstanceMongoRepo extends MongoRepository<MsInstance, String> {
+
+ Optional<MsInstance> findByNameIgnoreCaseAndReleaseIgnoreCase(String name, String release);
+
+
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/specification/SpecificationMongoGateway.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/specification/SpecificationMongoGateway.java
new file mode 100644
index 0000000..ae3a421
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/specification/SpecificationMongoGateway.java
@@ -0,0 +1,48 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mongo.specification;
+
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.onap.dcaegen2.platform.mod.web.service.specification.SpecificationGateway;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * Mongo implementation of Specification
+ */
+@Service
+public class SpecificationMongoGateway implements SpecificationGateway {
+
+ @Autowired
+ private SpecificationMongoRepo repo;
+
+ @Override
+ public List<Specification> getSpecificationByMsInstanceId(String id) {
+ return repo.getSpecificationsByMsInstaceId(id);
+ }
+
+ @Override
+ public Specification save(Specification newSpec) {
+ return repo.save(newSpec);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/specification/SpecificationMongoRepo.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/specification/SpecificationMongoRepo.java
new file mode 100644
index 0000000..306e78a
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/mongo/specification/SpecificationMongoRepo.java
@@ -0,0 +1,38 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.mongo.specification;
+
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * An interface to use Spring MongoRepository
+ */
+@Repository
+public interface SpecificationMongoRepo extends MongoRepository<Specification, String> {
+
+ @Query(value = "{'msInstanceInfo.id':?0}")
+ List<Specification> getSpecificationsByMsInstaceId(String id);
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/AppExceptionHandler.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/AppExceptionHandler.java
new file mode 100644
index 0000000..1a2f5f9
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/AppExceptionHandler.java
@@ -0,0 +1,149 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.controller;
+
+import org.onap.dcaegen2.platform.mod.model.exceptions.MissingRequestBodyException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.OperationNotAllowedException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.ResourceConflictException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.basemicroservice.BaseMicroserviceNotFoundException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.common.UserNotPassedException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.DeploymentArtifactNotFound;
+import org.onap.dcaegen2.platform.mod.model.exceptions.msinstance.MsInstanceNotFoundException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.specification.SpecificationInvalid;
+import org.onap.dcaegen2.platform.mod.model.restapi.ErrorResponse;
+import org.onap.dcaegen2.platform.mod.model.restapi.GenericErrorResponse;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.google.gson.Gson;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * a class to manage all exceptions
+ */
+@ControllerAdvice
+@Slf4j
+public class AppExceptionHandler {
+
+ @ExceptionHandler(value = {WebClientResponseException.class})
+ public ResponseEntity<ErrorResponse> handleCompSpecInvalidException
+ (WebClientResponseException ex, WebRequest request) {
+ return new ResponseEntity<ErrorResponse>
+ (new ErrorResponse(ex.getResponseBodyAsString()), HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ @ExceptionHandler(value = {JsonParseException.class})
+ public ResponseEntity<GenericErrorResponse> handleJsonParsedException
+ (JsonParseException ex, WebRequest request) {
+
+ GenericErrorResponse response = new GenericErrorResponse();
+ response.setStatus(HttpStatus.BAD_REQUEST);
+ response.setMessage("Invalid JSON request body format.");
+ response.setErrors(Arrays.asList(ex.getMessage()));
+ return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<GenericErrorResponse> specificationInvalid(SpecificationInvalid ex) {
+ Map<String, Object> errorResponse = new Gson().fromJson(ex.getMessage(), Map.class);
+ GenericErrorResponse response = new GenericErrorResponse();
+ response.setMessage((String) errorResponse.get("summary"));
+ response.setStatus(HttpStatus.BAD_REQUEST);
+ response.setErrors((List<String>) errorResponse.get("errors"));
+ return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<GenericErrorResponse> missingRequestBodyException(MissingRequestBodyException ex){
+ GenericErrorResponse response = new GenericErrorResponse();
+ response.setMessage("Missing paramaters");
+ response.setStatus(HttpStatus.BAD_REQUEST);
+ response.setErrors(Arrays.asList("Missing required request body paramaters"));
+ return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<ErrorResponse> resolveUserNotPassedException(UserNotPassedException ex){
+ return new ResponseEntity<>(new ErrorResponse(ex.getMessage()), HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<ErrorResponse> resolveMsInstanceNotFoundException(MsInstanceNotFoundException ex) {
+ log.error(ex.getMessage());
+ return new ResponseEntity<>(new ErrorResponse(ex.getMessage()), HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<ErrorResponse> resolveDeploymentArtifactNotFound(DeploymentArtifactNotFound ex) {
+ log.error(ex.getMessage());
+ return new ResponseEntity<>(new ErrorResponse(ex.getMessage()),
+ HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<ErrorResponse> resolveOperationNotAllowed(OperationNotAllowedException ex) {
+ log.error(ex.getMessage());
+ return new ResponseEntity<>(new ErrorResponse(ex.getMessage()),
+ HttpStatus.CONFLICT);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<ErrorResponse> resolveResourceConflict(ResourceConflictException ex) {
+ return new ResponseEntity<>(new ErrorResponse(ex.getMessage()), HttpStatus.CONFLICT);
+ }
+
+ @ExceptionHandler(value = {BaseMicroserviceNotFoundException.class})
+ public ResponseEntity<ErrorResponse> resolveResourceNotFoundExcetions(RuntimeException ex) {
+ log.error(ex.getMessage(), ex);
+ return new ResponseEntity<>(new ErrorResponse(ex.getMessage()), HttpStatus.CONFLICT);
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity<GenericErrorResponse> resolveBeanValidationException(MethodArgumentNotValidException ex){
+ log.error(ex.getMessage());
+ GenericErrorResponse response = new GenericErrorResponse();
+ response.setMessage("Validation failed.");
+ response.setStatus(HttpStatus.BAD_REQUEST);
+ response.setErrors(getBeanValidationErrors(ex));
+ return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
+ }
+
+ private List<String> getBeanValidationErrors(MethodArgumentNotValidException ex) {
+ List<String> errors = new ArrayList<>();
+ ex.getBindingResult().getAllErrors().forEach((error) -> {
+ String fieldName = ((FieldError) error).getField();
+ String errorMessage = error.getDefaultMessage();
+ errors.add(String.format("%s: %s", fieldName, errorMessage));
+ });
+ return errors;
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/BaseMicroserviceController.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/BaseMicroserviceController.java
new file mode 100644
index 0000000..073b93a
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/BaseMicroserviceController.java
@@ -0,0 +1,70 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.controller;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceCreateRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceUpdateRequest;
+import org.onap.dcaegen2.platform.mod.web.service.basemicroservice.MsService;
+import io.swagger.annotations.Api;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+import static org.onap.dcaegen2.platform.mod.web.controller.BaseMicroserviceController.API_BASE_MICROSERVICE;
+
+/**
+ * Controller class to manage Microservice's REST endpoints
+ */
+@CrossOrigin
+@RestController
+@RequestMapping(API_BASE_MICROSERVICE)
+@Api(tags = "Base Microservice", description = "APIs to manage Base Microservice")
+public class BaseMicroserviceController {
+
+ public static final String API_BASE_MICROSERVICE = "/api/base-microservice";
+ @Autowired
+ @Setter
+ MsService baseMsService;
+
+ @GetMapping
+ public List<BaseMicroservice> getAll() {
+ return baseMsService.getAllMicroservices();
+ }
+
+
+ @PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
+ public BaseMicroservice createMicroservice(@RequestBody @Valid MicroserviceCreateRequest request) {
+ return baseMsService.createMicroservice(request);
+ }
+
+ @PatchMapping(value = "/{msId}")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ public void updateMicroservice(@RequestBody @Valid MicroserviceUpdateRequest request,
+ @PathVariable("msId") String msId){
+ baseMsService.updateMicroservice(msId, request);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/DeploymentArtifactController.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/DeploymentArtifactController.java
new file mode 100644
index 0000000..e1cd512
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/DeploymentArtifactController.java
@@ -0,0 +1,115 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.controller;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactSearch;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.BlueprintFileNameCreateException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.StatusChangeNotValidException;
+import org.onap.dcaegen2.platform.mod.model.restapi.DeploymentArtifactPatchRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.ErrorResponse;
+import org.onap.dcaegen2.platform.mod.model.restapi.SuccessResponse;
+import org.onap.dcaegen2.platform.mod.web.service.deploymentartifact.DeploymentArtifactService;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.onap.dcaegen2.platform.mod.web.controller.DeploymentArtifactController.DEPLOYMENT_ARTIFACTS_BASE_URL;
+
+/**
+ * Controller class to manage DeploymentArtifact's REST endpoints
+ */
+@RestController
+@CrossOrigin
+@RequestMapping(DEPLOYMENT_ARTIFACTS_BASE_URL)
+@Slf4j
+@Api(tags = "Deployment Artifact", value = "APIs to manage Deployment Artifacts")
+public class DeploymentArtifactController {
+
+ public static final String DEPLOYMENT_ARTIFACTS_BASE_URL = "/api/deployment-artifact";
+
+ public static final String GET_STATUSES = "/statuses";
+
+ @Autowired
+ private DeploymentArtifactService service;
+
+ @PostMapping("/{msInstanceId}")
+ @ResponseStatus(HttpStatus.CREATED)
+ public DeploymentArtifact generateDeploymentArtifactForMSInstance(@PathVariable String msInstanceId,
+ @RequestParam String user ){
+ return service.generateDeploymentArtifact(msInstanceId, user);
+ }
+
+ @GetMapping
+ @ResponseStatus(HttpStatus.OK)
+ public List<DeploymentArtifact> getAllDeploymentArtifacts(){
+ return service.getAllDeploymentArtifacts();
+ }
+
+ @PostMapping("/search")
+ @ResponseStatus(HttpStatus.OK)
+ public List<DeploymentArtifact> searchDeploymentArtifacts(@RequestBody DeploymentArtifactSearch searchRequest){
+ log.info("Search on deployment artifacts: {}", searchRequest);
+ return service.searchDeploymentArtifacts(searchRequest);
+ }
+
+ @GetMapping(GET_STATUSES)
+ @ResponseStatus(HttpStatus.OK)
+ public List<DeploymentArtifactStatus> getDeploymentArtifactStatuses(){
+ return Arrays.asList(DeploymentArtifactStatus.values());
+ }
+
+ @PatchMapping(value = "/{deploymentArtifactId}", params = {"user!="})
+ public ResponseEntity<SuccessResponse> patchDeploymentArtifact(@PathVariable("deploymentArtifactId") String id,
+ @RequestBody DeploymentArtifactPatchRequest deploymentArtifactPatchRequest,
+ @RequestParam("user") String user){
+ log.info("***Received request {} to update DeploymentArtifact id {} by {}", deploymentArtifactPatchRequest, id, user);
+ service.updateDeploymentArtifact(id, deploymentArtifactPatchRequest, user);
+ return new ResponseEntity<>(new SuccessResponse("Deployment Artifact was updated."),HttpStatus.OK);
+ }
+
+ @DeleteMapping( value = "/{deploymentArtifactId}", params = {"user!="})
+ public ResponseEntity<SuccessResponse> deleteDeploymentArtifact(@PathVariable("deploymentArtifactId") String id,
+ @RequestParam("user") String user){
+ log.info("***Received request to delete DeploymentArtifact id {} by {}", id, user);
+ service.deleteDeploymentArtifact(id);
+ return new ResponseEntity<>(new SuccessResponse("Deployment Artifact was deleted"), HttpStatus.OK);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<ErrorResponse> resolveBaseMsServiceNameRegex(BlueprintFileNameCreateException ex) {
+ return new ResponseEntity<>(new ErrorResponse(ex.getMessage()),
+ HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<ErrorResponse> resolveStatusValidationFailure(StatusChangeNotValidException ex) {
+ return new ResponseEntity<>(new ErrorResponse(ex.getMessage()),
+ HttpStatus.BAD_REQUEST);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/MicroserviceInstanceController.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/MicroserviceInstanceController.java
new file mode 100644
index 0000000..14eb154
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/MicroserviceInstanceController.java
@@ -0,0 +1,75 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.controller;
+
+import org.onap.dcaegen2.platform.mod.model.exceptions.msinstance.MsInstanceAlreadyExistsException;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.ErrorResponse;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceUpdateRequest;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * Controller class to manage MicroserviceInstance's REST endpoints
+ */
+@CrossOrigin
+@RestController
+@Api(tags = "Microservice Instance", description = "APIs to manage Microservice Instance")
+@RequestMapping("/api/microservice-instance")
+public class MicroserviceInstanceController {
+
+ @Autowired
+ MsInstanceService msInstanceService;
+
+ @GetMapping
+ @ApiOperation("Get all Microservices Instances")
+ public List<MsInstance> getAll() {
+ return msInstanceService.getAll();
+ }
+
+
+ @PostMapping("/{msName}")
+ @ApiOperation("Create a Microservice Instance")
+ @ResponseStatus(HttpStatus.CREATED)
+ public MsInstance createMsInstance(@PathVariable String msName, @RequestBody MsInstanceRequest request) {
+ return msInstanceService.createMicroserviceInstance(msName, request);
+ }
+
+ @PatchMapping("/{msId}")
+ @ApiOperation("Patch a Microservice Instance")
+ @ResponseStatus(HttpStatus.OK)
+ public MsInstance patchMsInstance(@RequestBody MsInstanceUpdateRequest request, @PathVariable String msId){
+ return msInstanceService.updateMsInstance(request, msId);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity<ErrorResponse> resolveMsInstanceConflict(MsInstanceAlreadyExistsException ex) {
+ return new ResponseEntity<>(new ErrorResponse("Microservice Instance for the given name and release already exists"), HttpStatus.CONFLICT);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/SpecificationController.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/SpecificationController.java
new file mode 100644
index 0000000..854e7e6
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/controller/SpecificationController.java
@@ -0,0 +1,62 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.controller;
+
+import org.onap.dcaegen2.platform.mod.model.restapi.SpecificationRequest;
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.onap.dcaegen2.platform.mod.web.service.specification.SpecificationService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * Controller class to manage Specification's REST endpoints
+ */
+@CrossOrigin
+@RestController
+@Api(tags = "Component Specification", description = "APIs to manage Component Specifications")
+@RequestMapping("/api/specification")
+@Slf4j
+public class SpecificationController {
+
+ @Autowired
+ SpecificationService specificationService;
+
+ @GetMapping("/{msInstanceId}")
+ @ApiOperation("Get all specifications for a Microservice Instance")
+ public List<Specification> getAllSpecsByMsInstanceId(@PathVariable String msInstanceId) {
+ log.info(msInstanceId);
+ return specificationService.getAllSpecsByMsInstanceId(msInstanceId);
+ }
+
+ @PostMapping("/{msInstanceId}")
+ @ApiOperation("Create Specification for a Microservice Instance")
+ @ResponseStatus(HttpStatus.CREATED)
+ public Specification createSpecification(@PathVariable String msInstanceId, @RequestBody SpecificationRequest request) {
+ log.info(request.toString());
+ return specificationService.createSpecification(msInstanceId, request);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/BaseMicroserviceGateway.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/BaseMicroserviceGateway.java
new file mode 100644
index 0000000..a516d90
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/BaseMicroserviceGateway.java
@@ -0,0 +1,45 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.basemicroservice;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * An interface to interact with BaseMicroservice persistence
+ */
+public interface BaseMicroserviceGateway {
+
+ List<BaseMicroservice> findAll();
+
+ Optional<BaseMicroservice> findByName(String name);
+
+ Optional<BaseMicroservice> findByTag(String tag);
+
+ Optional<BaseMicroservice> findByServiceName(String serviceName);
+
+ BaseMicroservice save(BaseMicroservice microservice);
+
+ Optional<BaseMicroservice> findById(String msId);
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/MsService.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/MsService.java
new file mode 100644
index 0000000..cdc1921
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/MsService.java
@@ -0,0 +1,47 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.basemicroservice;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceCreateRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceUpdateRequest;
+
+import java.util.List;
+
+/**
+ * An interface to access Ms Services
+ */
+public interface MsService {
+ BaseMicroservice createMicroservice(MicroserviceCreateRequest microserviceRequest);
+
+ List<BaseMicroservice> getAllMicroservices();
+
+ BaseMicroservice getMicroserviceById(String baseMsId);
+
+ BaseMicroservice getMicroserviceByName(String msName);
+
+ void updateMicroservice(String requestedMsId, MicroserviceUpdateRequest updateRequest);
+
+ void saveMsInstanceReferenceToMs(BaseMicroservice microservice, MsInstance msInstance);
+
+ void updateMsInstanceRef(MsInstance msInstance);
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/MsServiceImpl.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/MsServiceImpl.java
new file mode 100644
index 0000000..9cf46e6
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/basemicroservice/MsServiceImpl.java
@@ -0,0 +1,257 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.basemicroservice;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsStatus;
+import org.onap.dcaegen2.platform.mod.model.common.AuditFields;
+import org.onap.dcaegen2.platform.mod.model.exceptions.ErrorMessages;
+import org.onap.dcaegen2.platform.mod.model.exceptions.ResourceConflictException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.basemicroservice.BaseMicroserviceNotFoundException;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceCreateRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceUpdateRequest;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceService;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * MsService implementation
+ */
+@Service
+public class MsServiceImpl implements MsService {
+
+ @Autowired
+ @Setter
+ private BaseMicroserviceGateway repository;
+
+ @Autowired
+ @Setter
+ private MsInstanceService msInstanceService;
+
+ /**
+ * creates Microservice record
+ * @param microserviceRequest
+ * @return
+ */
+ @Override
+ public BaseMicroservice createMicroservice(MicroserviceCreateRequest microserviceRequest) {
+ checkIfThereAreAnyConflicts(microserviceRequest); //TODO: Make fields unique in entity itself
+ BaseMicroservice microservice = new BaseMsCreator().create(microserviceRequest);
+ return repository.save(microservice);
+ }
+
+ /**
+ * name, tag and serviceName are unique for the given ms. This method make sure that.
+ * */
+ private void checkIfThereAreAnyConflicts(MicroserviceCreateRequest microserviceRequest) {
+ checkIfMsNameAlreadyExists(microserviceRequest.getName());
+ checkIfMsTagAlreadyExists(microserviceRequest.getTag());
+ checkiIfServiceNameAlreadyExists(microserviceRequest.getServiceName());
+ }
+
+ private void checkIfMsNameAlreadyExists(String msName) {
+ if (repository.findByName(msName).isPresent())
+ throw new ResourceConflictException(ErrorMessages.MICROSERVICE_NAME_CONFLICT_MESSAGE);
+ }
+
+ private void checkIfMsTagAlreadyExists(String msTag) {
+ if (repository.findByTag(msTag).isPresent())
+ throw new ResourceConflictException(ErrorMessages.MICROSERVICE_TAG_CONFLICT_MESSAGE);
+ }
+
+ private void checkiIfServiceNameAlreadyExists(String serviceName) {
+ boolean serviceNameIsEmpty = serviceName == null || serviceName.isEmpty();
+ if(serviceNameIsEmpty)
+ return;
+ if (repository.findByServiceName(serviceName).isPresent())
+ throw new ResourceConflictException(ErrorMessages.MS_SERVICE_NAME_CONFLICT_MESSAGE);
+ }
+
+ /**
+ * lists all microservice records
+ * @return
+ */
+ @Override
+ public List<BaseMicroservice> getAllMicroservices() {
+ return repository.findAll();
+ }
+
+ /**
+ * gets a Mioroservice by id
+ * @param baseMsId
+ * @return
+ */
+ @Override
+ public BaseMicroservice getMicroserviceById(String baseMsId) {
+ return repository.findById(baseMsId).orElseThrow(() ->
+ new BaseMicroserviceNotFoundException(String.format("Microservice with id %s not found", baseMsId)));
+ }
+
+ /**
+ * gets a Microservice by name
+ * @param msName
+ * @return
+ */
+ @Override
+ public BaseMicroservice getMicroserviceByName(String msName) {
+ return repository.findByName(msName).orElseThrow(() ->
+ new BaseMicroserviceNotFoundException(String.format("Microservice with name %s not found", msName)));
+ }
+
+ /**
+ * updates a Microservice
+ * @param requestedMsId
+ * @param updateRequest
+ */
+ @Override
+ public void updateMicroservice(String requestedMsId, MicroserviceUpdateRequest updateRequest) {
+ BaseMicroservice microservice = getMicroserviceById(requestedMsId);
+ updateMetadata(updateRequest, microservice);
+ updateOtherFields(updateRequest, microservice);
+ repository.save(microservice);
+ msInstanceService.updateMicroserviceReference(microservice);
+ }
+
+ //TODO: Get rid of nulls!
+ private void updateMetadata(MicroserviceUpdateRequest updateRequest, BaseMicroservice microservice) {
+ if(updateRequest.getUser() != null){
+ microservice.getMetadata().setUpdatedBy(updateRequest.getUser());
+ }
+ if(updateRequest.getMetadata() != null && updateRequest.getMetadata().containsKey("notes")){
+ microservice.getMetadata().setNotes((String) updateRequest.getMetadata().get("notes"));
+ }
+ if(updateRequest.getMetadata() != null && updateRequest.getMetadata().containsKey("labels")){
+ microservice.getMetadata().setLabels((List<String>) updateRequest.getMetadata().get("labels"));
+ }
+ microservice.getMetadata().setUpdatedOn(new Date());
+ }
+
+ private void updateOtherFields(MicroserviceUpdateRequest updateRequest, BaseMicroservice microservice) {
+ if(updateRequest.getName() != null){
+ updateName(updateRequest, microservice);
+ }
+ if(updateRequest.getType() != null){
+ microservice.setType(updateRequest.getType());
+ }
+ if(updateRequest.getLocation() != null){
+ microservice.setLocation(updateRequest.getLocation());
+ }
+ if(updateRequest.getServiceName() != null){
+ updateServiceName(updateRequest, microservice);
+ }
+ if(updateRequest.getNamespace() != null){
+ microservice.setNamespace(updateRequest.getNamespace());
+ }
+ }
+
+ /**
+ * If name requested in the updateRequest doesn't match the name of the ms record which is being worked on,
+ * then only check for the uniqueness.
+ */
+ private void updateName(MicroserviceUpdateRequest updateRequest, BaseMicroservice microservice) {
+ boolean notMatchesWithCurrentName = !updateRequest.getName().equals(microservice.getName());
+ if(notMatchesWithCurrentName)
+ checkIfMsNameAlreadyExists(updateRequest.getName());
+ microservice.setName(updateRequest.getName());
+ }
+
+ /**
+ * If serviceName requested in the updateRequest doesn't match the serviceName of the ms record which is
+ * being worked on, then only check for the uniqueness.
+ */
+ private void updateServiceName(MicroserviceUpdateRequest updateRequest, BaseMicroservice microservice) {
+ boolean notMatchesWithCurrentServiceName = !updateRequest.getServiceName().equals(microservice.getServiceName());
+ if(notMatchesWithCurrentServiceName)
+ checkiIfServiceNameAlreadyExists(updateRequest.getServiceName());
+ microservice.setServiceName(updateRequest.getServiceName());
+ }
+
+ /**
+ * saves msInstance reference in a given Microservice
+ * @param microservice
+ * @param msInstance
+ */
+ @Override
+ public void saveMsInstanceReferenceToMs(BaseMicroservice microservice, MsInstance msInstance) {
+ microservice.getMsInstances().add(getMsInstanceReference(msInstance));
+ repository.save(microservice);
+ }
+
+ /**
+ * updates MsIntstance ref in Microservice record
+ * @param msInstance
+ */
+ @Override
+ public void updateMsInstanceRef(MsInstance msInstance) {
+ BaseMicroservice microservice = getMicroserviceById((String) msInstance.getMsInfo().get("id"));
+ List<Map<String, String>> msInstancesRef = microservice.getMsInstances();
+ msInstancesRef.forEach((ref) -> {
+ if(ref.get("id").equals(msInstance.getId()))
+ ref.put("name", msInstance.getName());
+ });
+ repository.save(microservice);
+ }
+
+ private Map<String, String> getMsInstanceReference(MsInstance msInstance) {
+ Map<String,String> msInstanceInfo = new HashMap<>();
+ msInstanceInfo.put("id", msInstance.getId());
+ msInstanceInfo.put("name", msInstance.getName());
+ return msInstanceInfo;
+ }
+
+ private class BaseMsCreator {
+
+ BaseMicroservice create(MicroserviceCreateRequest createRequest) {
+ BaseMicroservice microservice = new BaseMicroservice();
+ microservice.setLocation(createRequest.getLocation());
+ microservice.setName(createRequest.getName());
+ microservice.setTag(createRequest.getTag());
+ microservice.setServiceName(createRequest.getServiceName());
+ microservice.setNamespace(createRequest.getNamespace());
+ microservice.setStatus(BaseMsStatus.ACTIVE);
+ microservice.setType(createRequest.getType());
+ microservice.setMetadata(getMetadataFields(createRequest));
+ return microservice;
+ }
+
+ private AuditFields getMetadataFields(MicroserviceCreateRequest request) {
+ AuditFields auditFields = AuditFields.builder().build();
+ auditFields.setCreatedBy(request.getUser());
+ auditFields.setCreatedOn(new Date());
+
+ if (request.getMetadata().containsKey("notes"))
+ auditFields.setNotes((String) request.getMetadata().get("notes"));
+ if (request.getMetadata().containsKey("labels"))
+// auditFields.setLabels((List<String>) request.getMetadata().get("labels"));
+ auditFields.setLabels(request.getMetadata().get("labels"));
+
+ return auditFields;
+
+ }
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/ArtifactFileNameCreator.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/ArtifactFileNameCreator.java
new file mode 100644
index 0000000..7713020
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/ArtifactFileNameCreator.java
@@ -0,0 +1,59 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.BlueprintFileNameCreateException;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.springframework.stereotype.Component;
+
+/**
+ * A name creator for Deployment Artifact files.
+ */
+@Component
+public class ArtifactFileNameCreator {
+
+ private static final String FILE_FORMAT = ".yaml";
+
+ /**
+ * creates a file name
+ * @param msInstance
+ * @param version
+ * @return
+ */
+ public String createFileName(MsInstance msInstance, int version) {
+ if(msInstance.getMsInfo() == null || !msInstance.getMsInfo().containsKey("tag")){
+ throwException("MS-tag");
+ }
+ if(msInstance.getActiveSpec() == null){
+ throwException("active-spec");
+ }
+ return msInstance.getMsInfo().get("tag") + "_"
+ + msInstance.getActiveSpec().getType().toString().toLowerCase() + "_"
+ + msInstance.getRelease() + "_"
+ + version
+ + FILE_FORMAT;
+ }
+
+ private void throwException(String missingProperty) {
+ throw new BlueprintFileNameCreateException("Can not create bluerprint file name: "
+ + missingProperty + " is missing");
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactGateway.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactGateway.java
new file mode 100644
index 0000000..6bf2c2a
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactGateway.java
@@ -0,0 +1,45 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactSearch;
+
+import java.util.List;
+import java.util.Optional;
+
+ /**
+ * An interface to interact with DeploymentArtifact persistence
+ */
+public interface DeploymentArtifactGateway {
+
+ List<DeploymentArtifact> findAll();
+
+ List<DeploymentArtifact> findByMsInstanceId(String id);
+
+ Optional<DeploymentArtifact> findById(String id);
+
+ void deleteById(String deploymentArtifactId);
+
+ DeploymentArtifact save(DeploymentArtifact deploymentArtifact);
+
+ List<DeploymentArtifact> findAll(DeploymentArtifactSearch search);
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactGeneratorStrategy.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactGeneratorStrategy.java
new file mode 100644
index 0000000..9bb0870
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactGeneratorStrategy.java
@@ -0,0 +1,32 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+
+import java.util.Map;
+
+/**
+ * provides abstraction to generate Deployment Artifacts
+ */
+public interface DeploymentArtifactGeneratorStrategy {
+ Map<String, Object> generateForRelease(Specification activeSpec, String release);
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactService.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactService.java
new file mode 100644
index 0000000..3e7f899
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactService.java
@@ -0,0 +1,51 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactSearch;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.DeploymentArtifactPatchRequest;
+
+import java.util.List;
+
+/**
+ * An interface to access DeploymentArtifact Services
+ */
+public interface DeploymentArtifactService {
+
+ DeploymentArtifact generateDeploymentArtifact(String msInstanceId, String user);
+
+ List<DeploymentArtifact> getAllDeploymentArtifacts();
+
+ DeploymentArtifact findDeploymentArtifactById(String id);
+
+ void updateDeploymentArtifact(String deploymentArtifactId, DeploymentArtifactPatchRequest deploymentArtifactPatchRequest, String user);
+
+ List<DeploymentArtifact> findByMsInstanceId(String msInstanceId);
+
+ void deleteDeploymentArtifact(String deploymentArtifactId);
+
+ void updateMsInstanceRef(MsInstance msInstance);
+
+ List<DeploymentArtifact> searchDeploymentArtifacts(DeploymentArtifactSearch search);
+}
+
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactServiceImpl.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactServiceImpl.java
new file mode 100644
index 0000000..8b97bba
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactServiceImpl.java
@@ -0,0 +1,205 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactSearch;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.MsInstanceInfo;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.DeploymentArtifactNotFound;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.DeploymentArtifactsRef;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.DeploymentArtifactPatchRequest;
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceService;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+
+/**
+ * DeploymentArtifact Service implementation
+ */
+@Service
+@Slf4j
+@Setter
+public class DeploymentArtifactServiceImpl implements DeploymentArtifactService{
+
+ private static final String VERSION_KEY = "mostRecentVersion";
+
+ @Autowired
+ private MsInstanceService msInstanceService;
+
+ @Autowired
+ private DeploymentArtifactGeneratorStrategy deploymentArtifactGeneratorStrategy;
+
+ @Autowired
+ private DeploymentArtifactGateway deploymentArtifactGateway;
+
+ @Autowired
+ private ArtifactFileNameCreator fileNameCreator;
+
+ @Autowired
+ private DeploymentArtifactStatusChangeHandler statusChangeHandler;
+
+ ///////////////FIND METHODS//////////////////////////
+ @Override
+ public List<DeploymentArtifact> getAllDeploymentArtifacts() {
+ return deploymentArtifactGateway.findAll();
+ }
+
+ @Override
+ public List<DeploymentArtifact> searchDeploymentArtifacts(DeploymentArtifactSearch search) {
+ return deploymentArtifactGateway.findAll(search);
+ }
+
+ @Override
+ public DeploymentArtifact findDeploymentArtifactById(String id){
+ return deploymentArtifactGateway.findById(id).orElseThrow(
+ () -> new DeploymentArtifactNotFound("Deployment Artifact with id " + id + " not found")
+ );
+ }
+
+ @Override
+ public List<DeploymentArtifact> findByMsInstanceId(String msInstanceId) {
+ return deploymentArtifactGateway.findByMsInstanceId(msInstanceId);
+ }
+
+ @Override
+ @Transactional
+ public void deleteDeploymentArtifact(String deploymentArtifactId) {
+ DeploymentArtifact deploymentArtifact = findDeploymentArtifactById(deploymentArtifactId);
+ log.info("deleting {}", deploymentArtifact.getFileName());
+ deploymentArtifactGateway.deleteById(deploymentArtifactId);
+ msInstanceService.removeDeploymentArtifactFromMsInstance(deploymentArtifact);
+ }
+
+ @Override
+ @Transactional
+ public void updateMsInstanceRef(MsInstance msInstance) {
+ List<DeploymentArtifact> deploymentArtifacts = findByMsInstanceId(msInstance.getId());
+ deploymentArtifacts.forEach((deploymentArtifact) -> {
+ deploymentArtifact.getMsInstanceInfo().setName(msInstance.getName());
+ deploymentArtifact.getMsInstanceInfo().setRelease(msInstance.getRelease());
+ deploymentArtifactGateway.save(deploymentArtifact);
+ });
+ }
+
+ //////////////////////////////////////////////////////
+
+ @Override
+ @Transactional
+ //only status update was implemented
+ public void updateDeploymentArtifact(String deploymentArtifactId, DeploymentArtifactPatchRequest deploymentArtifactPatchRequest,
+ String user) {
+ DeploymentArtifact deploymentArtifact = findDeploymentArtifactById(deploymentArtifactId);
+ updateStatus(deploymentArtifactPatchRequest, deploymentArtifact);
+ updateMetadata(user, deploymentArtifact);
+ log.info("Updating the artifact in database..");
+ deploymentArtifactGateway.save(deploymentArtifact);
+ msInstanceService.updateStatusBasedOnDeploymentArtifactsStatuses(deploymentArtifact.getMsInstanceInfo().getId());
+ }
+
+ private void updateMetadata(String user, DeploymentArtifact deploymentArtifact) {
+ deploymentArtifact.getMetadata().put("updatedBy", user);
+ deploymentArtifact.getMetadata().put("updatedOn", new Date());
+ }
+
+ private void updateStatus(DeploymentArtifactPatchRequest deploymentArtifactPatchRequest, DeploymentArtifact deploymentArtifact) {
+ DeploymentArtifactStatus changeToStatus = deploymentArtifactPatchRequest.getStatus();
+ if(changeToStatus != null){
+ log.info("Sent request to deployment artifact status change handler: {}", changeToStatus);
+ statusChangeHandler.handleStatusChange(changeToStatus, deploymentArtifact);
+ }
+ }
+
+ @Override
+ @Transactional
+ public DeploymentArtifact generateDeploymentArtifact(String msInstanceId, String user) {
+ MsInstance msInstance = msInstanceService.getMsInstanceById(msInstanceId);
+
+ //Generate the Blueprint for the active specification for the instance
+ Map<String, Object> deploymentArtifact = deploymentArtifactGeneratorStrategy.generateForRelease(msInstance.getActiveSpec(), msInstance.getRelease());
+
+ DeploymentArtifact artifact = new DeploymentArtifact();
+ artifact.setContent(String.valueOf(deploymentArtifact.get("content")));
+ artifact.setVersion(updateLatestVersion(msInstance.getDeploymentArtifactsInfo()));
+ artifact.setStatus(DeploymentArtifactStatus.IN_DEV);
+ artifact.setMsInstanceInfo(createMsInstanceReferenceInfo(msInstance));
+ artifact.setSpecificationInfo(createSpecificationReferenceInfo(msInstance.getActiveSpec()));
+ artifact.setMetadata(createMetadata(user));
+
+ artifact.setFileName(fileNameCreator.createFileName(msInstance, artifact.getVersion()));
+
+ DeploymentArtifact savedDao = deploymentArtifactGateway.save(artifact);
+ artifact.setId(savedDao.getId());
+
+ msInstance.setDeploymentArtifactsInfo(updateMsDeploymentArtifactRef(msInstance.getDeploymentArtifactsInfo(), savedDao.getId()));
+ msInstanceService.updateMsInstance(msInstance);
+
+ return artifact;
+ }
+
+ private int updateLatestVersion(DeploymentArtifactsRef ref) {
+ if(ref == null) return 1;
+ else return ref.getMostRecentVersion() + 1;
+ }
+
+ private DeploymentArtifactsRef updateMsDeploymentArtifactRef(DeploymentArtifactsRef ref, String deploymentArtifactId) {
+ if(ref == null){
+ ref = new DeploymentArtifactsRef();
+ ref.setMostRecentVersion(1);
+ List<String> deploymentArtifacts = new ArrayList<>();
+ deploymentArtifacts.add(deploymentArtifactId);
+ ref.setDeploymentArtifacts(deploymentArtifacts);
+ }
+ else{
+ ref.setMostRecentVersion(ref.getMostRecentVersion() + 1);
+ List<String> deploymentArtifactList = ref.getDeploymentArtifacts();
+ deploymentArtifactList.add(deploymentArtifactId);
+ }
+ return ref;
+ }
+
+ private Map<String, Object> createMetadata(String user) {
+ Map<String, Object> metadata = new HashMap<>();
+ metadata.put("createdOn", new Date());
+ metadata.put("createdBy", user);
+ return metadata;
+ }
+
+ private Map<String, Object> createSpecificationReferenceInfo(Specification activeSpec) {
+ Map<String, Object> specInfo = new HashMap<>();
+ specInfo.put("id", activeSpec.getId());
+ return specInfo;
+ }
+
+ private MsInstanceInfo createMsInstanceReferenceInfo(MsInstance msInstance) {
+ MsInstanceInfo msInstanceInfo = new MsInstanceInfo();
+ msInstanceInfo.setId(msInstance.getId());
+ msInstanceInfo.setName(msInstance.getName());
+ msInstanceInfo.setRelease(msInstance.getRelease());
+ return msInstanceInfo;
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactStatusChangeHandler.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactStatusChangeHandler.java
new file mode 100644
index 0000000..48b18bf
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactStatusChangeHandler.java
@@ -0,0 +1,77 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.StatusChangeNotValidException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * A class responsible for handling status changes of Deployment Artifacts
+ */
+@Component
+@Slf4j
+public class DeploymentArtifactStatusChangeHandler {
+
+ @Autowired
+ DeploymentArtifactService deploymentArtifactService;
+
+ /**
+ * setter
+ * @param deploymentArtifactService
+ */
+ public void setDeploymentArtifactService(DeploymentArtifactService deploymentArtifactService) {
+ this.deploymentArtifactService = deploymentArtifactService;
+ }
+
+ /**
+ * handles status changes
+ * @param status
+ * @param deploymentArtifact
+ */
+ public void handleStatusChange(DeploymentArtifactStatus status, DeploymentArtifact deploymentArtifact) {
+ String msInstanceId = deploymentArtifact.getMsInstanceInfo().getId();
+ List<DeploymentArtifact> artifacts = deploymentArtifactService.findByMsInstanceId(msInstanceId);
+ if( status == DeploymentArtifactStatus.DEV_COMPLETE){
+ for(DeploymentArtifact artifact : artifacts){
+ if(artifact.getStatus() == DeploymentArtifactStatus.DEV_COMPLETE){
+ log.error("Status change is not allowed.");
+ throw new StatusChangeNotValidException(createValidationErrorMessage(deploymentArtifact));
+ }
+ }
+ }
+ deploymentArtifact.setStatus(status);
+ log.info("Deployment Artifact's status changed successfully.");
+ }
+
+ private String createValidationErrorMessage(DeploymentArtifact artifact) {
+ return String.format( "%s (v%d) for %s - Status change not allowed."
+ + " Only 1 blueprint can be in the DEV_COMPLETE state. " +
+ "Change the current DEV_COMPLETE blueprint to NOT_NEEDED or IN_DEV before changing another"
+ + " to DEV_COMPLETE.", artifact.getMsInstanceInfo().getName(),
+ artifact.getVersion(), artifact.getMsInstanceInfo().getRelease());
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceGateway.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceGateway.java
new file mode 100644
index 0000000..12a510a
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceGateway.java
@@ -0,0 +1,40 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.microserviceinstance;
+
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * An interface to interact with MsInstance persistence
+ */
+public interface MsInstanceGateway {
+
+ Optional<MsInstance> findByNameAndRelease(String name, String release);
+
+ Optional<MsInstance> findById(String msInstanceId);
+
+ List<MsInstance> findAll();
+
+ MsInstance save(MsInstance msInstance);
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceService.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceService.java
new file mode 100644
index 0000000..3c28f4d
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceService.java
@@ -0,0 +1,51 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.microserviceinstance;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceUpdateRequest;
+
+import java.util.List;
+
+/**
+ * An interface to access MsInstance Services
+ */
+public interface MsInstanceService {
+
+ List<MsInstance> getAll();
+
+ MsInstance createMicroserviceInstance(String msName, MsInstanceRequest request);
+
+ MsInstance getMsInstanceById(String id);
+
+ void updateMsInstance(MsInstance msInstance);
+
+ void updateStatusBasedOnDeploymentArtifactsStatuses(String msInstanceId);
+
+ void removeDeploymentArtifactFromMsInstance(DeploymentArtifact deploymentArtifact);
+
+ void updateMicroserviceReference(BaseMicroservice msToBeUpdated);
+
+ MsInstance updateMsInstance(MsInstanceUpdateRequest updateRequest, String msInstanceId);
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceServiceImpl.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceServiceImpl.java
new file mode 100644
index 0000000..e4d5694
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceServiceImpl.java
@@ -0,0 +1,213 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.microserviceinstance;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.exceptions.msinstance.MsInstanceAlreadyExistsException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.msinstance.MsInstanceNotFoundException;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstanceStatus;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceUpdateRequest;
+import org.onap.dcaegen2.platform.mod.web.service.basemicroservice.MsService;
+import org.onap.dcaegen2.platform.mod.web.service.deploymentartifact.DeploymentArtifactService;
+import org.onap.dcaegen2.platform.mod.web.service.specification.SpecificationService;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * MsInstance Service implementation
+ */
+@Service
+@Setter
+@Slf4j
+public class MsInstanceServiceImpl implements MsInstanceService {
+
+ @Autowired
+ private MsInstanceGateway msInstanceRepository;
+
+ @Autowired
+ private MsService msService;
+
+ @Autowired
+ private MsInstanceStatusChangeHandler msInstanceStatusChangeHandler;
+
+ @Autowired
+ private SpecificationService specificationService;
+
+ @Autowired
+ private DeploymentArtifactService deploymentArtifactService;
+
+ @Override
+ public List<MsInstance> getAll() {
+ return msInstanceRepository.findAll();
+ }
+
+ @Override
+ @Transactional
+ public MsInstance createMicroserviceInstance(String msName, MsInstanceRequest request) {
+ BaseMicroservice microservice = msService.getMicroserviceByName(msName);
+ checkIftheCombinationOfNameAndReleaseIsUnique(request.getName(), request.getRelease());
+ MsInstance msInstance = new MsInstanceCreator(request, microservice).create();
+ MsInstance savedMsInstance = msInstanceRepository.save(msInstance);
+ msService.saveMsInstanceReferenceToMs(microservice, savedMsInstance);
+ return savedMsInstance;
+ }
+
+ private void checkIftheCombinationOfNameAndReleaseIsUnique(String name, String release) {
+ if (msInstanceRepository.findByNameAndRelease(name, release).isPresent())
+ throw new MsInstanceAlreadyExistsException();
+ }
+
+ @Override
+ public MsInstance getMsInstanceById(String id) {
+ return msInstanceRepository.findById(id).orElseThrow(() ->
+ new MsInstanceNotFoundException(String.format("Ms Instance with id %s not found", id)));
+ }
+
+ @Override
+ public void updateMsInstance(MsInstance msInstance) {
+ log.info("Saving the msInstance {} to database..", msInstance);
+ if(msInstance != null) msInstanceRepository.save(msInstance);
+ }
+
+ @Override
+ public void updateStatusBasedOnDeploymentArtifactsStatuses(String msInstanceId) {
+ MsInstance msInstance = getMsInstanceById(msInstanceId);
+ msInstanceStatusChangeHandler.updateStatusBasedOnDeploymentArtifactsStatuses(msInstance);
+ updateMsInstance(msInstance);
+ }
+
+ @Override
+ @Transactional
+ public void removeDeploymentArtifactFromMsInstance(DeploymentArtifact deploymentArtifact) {
+ MsInstance msInstance = getMsInstanceById(deploymentArtifact.getMsInstanceInfo().getId());
+ removeDeploymentArtifactReferenceFromMsInstance(msInstance, deploymentArtifact.getId());
+ msInstanceStatusChangeHandler.updateStatusBasedOnDeploymentArtifactsStatuses(msInstance);
+ updateMsInstance(msInstance);
+ }
+
+ @Override
+ //TODO: update msInstanceReference in specification and deployment artifact
+ public void updateMicroserviceReference(BaseMicroservice microservice) {
+ List<Map<String, String>> msInstanceRefs = microservice.getMsInstances();
+ for(Map<String, String> ref : msInstanceRefs){
+ MsInstance msInstance = getMsInstanceById(ref.get("id"));
+ msInstance.setName(microservice.getName());
+ msInstance.getMsInfo().put("name", microservice.getName());
+ cascadeUpdates(msInstance);
+ msInstanceRepository.save(msInstance);
+ }
+ }
+
+ @Override
+ @Transactional
+ public MsInstance updateMsInstance(MsInstanceUpdateRequest updateRequest, String msInstanceId) {
+ MsInstance msInstance = getMsInstanceById(msInstanceId);
+ updateRelease(updateRequest, msInstance);
+ updateVersion(updateRequest, msInstance);
+ updateMetadata(updateRequest, msInstance);
+ cascadeUpdates(msInstance);
+ return msInstanceRepository.save(msInstance);
+ }
+
+ private void cascadeUpdates(MsInstance msInstance) {
+ specificationService.updateMsInstanceRef(msInstance);
+ deploymentArtifactService.updateMsInstanceRef(msInstance);
+ msService.updateMsInstanceRef(msInstance);
+ }
+
+ private void updateMetadata(MsInstanceUpdateRequest updateRequest, MsInstance msInstance) {
+ if(updateRequest.getMetadata() != null){
+ msInstance.getMetadata().putAll(updateRequest.getMetadata());
+ }
+
+ msInstance.getMetadata().put("updatedOn", new Date());
+ msInstance.getMetadata().put("updatedBy", updateRequest.getUser());
+ }
+
+ private void updateVersion(MsInstanceUpdateRequest updateRequest, MsInstance msInstance) {
+ if(updateRequest.getVersion() != null){
+ msInstance.setVersion(updateRequest.getVersion());
+ }
+ }
+
+ private void updateRelease(MsInstanceUpdateRequest updateRequest, MsInstance msInstance) {
+ if(updateRequest.getRelease() != null) {
+ if(!updateRequest.getRelease().equals(msInstance.getRelease()))
+ checkIftheCombinationOfNameAndReleaseIsUnique(msInstance.getName(), updateRequest.getRelease());
+ msInstance.setRelease(updateRequest.getRelease());
+ }
+ }
+
+ private void removeDeploymentArtifactReferenceFromMsInstance(MsInstance msInstance, String deploymentArtifactId) {
+ if(msInstance.getDeploymentArtifactsInfo() != null){
+ List<String> refIds = msInstance.getDeploymentArtifactsInfo().getDeploymentArtifacts();
+ refIds.remove(deploymentArtifactId);
+ }
+ }
+
+ private class MsInstanceCreator {
+ private MsInstanceRequest request;
+ private BaseMicroservice microserviceDAO;
+
+ MsInstanceCreator(MsInstanceRequest request, BaseMicroservice microserviceDAO) {
+ this.request = request;
+ this.microserviceDAO = microserviceDAO;
+ }
+
+ MsInstance create() {
+ //prepare MsInstance from the request
+ return MsInstance.builder()
+ .name(request.getName())
+ .release(request.getRelease())
+ .status(MsInstanceStatus.NEW)
+ .version(request.getVersion())
+ .msInfo(getMsReference(microserviceDAO))
+ .metadata(getMetadata(request))
+ .build();
+ }
+
+ private Map<String, Object> getMsReference(BaseMicroservice microserviceDAO) {
+ Map<String,Object> msInfo = new HashMap<>();
+ msInfo.put("id", microserviceDAO.getId());
+ msInfo.put("name", microserviceDAO.getName());
+ msInfo.put("tag", microserviceDAO.getTag());
+ return msInfo;
+ }
+
+ private Map<String, Object> getMetadata(MsInstanceRequest request) {
+ Map<String, Object> metadata = request.getMetadata();
+ metadata.put("createdBy", request.getUser());
+ metadata.put("createdOn", new Date());
+ return metadata;
+ }
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceStatusChangeHandler.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceStatusChangeHandler.java
new file mode 100644
index 0000000..bc26fab
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/microserviceinstance/MsInstanceStatusChangeHandler.java
@@ -0,0 +1,75 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.microserviceinstance;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstanceStatus;
+import org.onap.dcaegen2.platform.mod.web.service.deploymentartifact.DeploymentArtifactService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * A class responsible for handling status changes of Ms Instances
+ */
+@Component
+@Slf4j
+public class MsInstanceStatusChangeHandler {
+
+ @Autowired
+ private MsInstanceService msInstanceService;
+
+ @Autowired
+ private DeploymentArtifactService deploymentArtifactService;
+
+ public void setMsInstanceService(MsInstanceService msInstanceService) {
+ this.msInstanceService = msInstanceService;
+ }
+
+ public void setDeploymentArtifactService(DeploymentArtifactService deploymentArtifactService) {
+ this.deploymentArtifactService = deploymentArtifactService;
+ }
+
+ public void updateStatusBasedOnDeploymentArtifactsStatuses(MsInstance msInstance) {
+ log.info("Checking if any Status change required for msInstance {}...", msInstance);
+ List<DeploymentArtifact> artifacts = deploymentArtifactService.findByMsInstanceId(msInstance.getId());
+ MsInstanceStatus newStatus = getValidStatusBasedOnArtifacts(artifacts);
+ msInstance.setStatus(newStatus);
+ log.info("Changed Status to {}", newStatus);
+ }
+
+ private MsInstanceStatus getValidStatusBasedOnArtifacts(List<DeploymentArtifact> artifacts) {
+ if(atLeastOneArtifactHasDevCompleteStatus(artifacts)){
+ return MsInstanceStatus.DEV_COMPLETE;
+ }
+ return MsInstanceStatus.IN_DEV;
+ }
+
+ private boolean atLeastOneArtifactHasDevCompleteStatus(List<DeploymentArtifact> artifacts) {
+ return artifacts
+ .stream()
+ .anyMatch(artifact -> artifact.getStatus() == DeploymentArtifactStatus.DEV_COMPLETE);
+ }
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationGateway.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationGateway.java
new file mode 100644
index 0000000..5fcfbb1
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationGateway.java
@@ -0,0 +1,37 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.specification;
+
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * An interface to interact with Specification persistence
+ */
+@Repository
+public interface SpecificationGateway{
+
+ List<Specification> getSpecificationByMsInstanceId(String id);
+
+ Specification save(Specification newSpec);
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationService.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationService.java
new file mode 100644
index 0000000..33724ac
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationService.java
@@ -0,0 +1,40 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.specification;
+
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.SpecificationRequest;
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+
+import java.util.List;
+
+/**
+ * An interface to access Specification Services
+ */
+public interface SpecificationService {
+
+ List<Specification> getAllSpecsByMsInstanceId(String id);
+
+ Specification createSpecification(String msInstanceId, SpecificationRequest request);
+
+ void updateMsInstanceRef(MsInstance msInstance);
+}
+
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationServiceImpl.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationServiceImpl.java
new file mode 100644
index 0000000..7869801
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationServiceImpl.java
@@ -0,0 +1,138 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.specification;
+
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstanceStatus;
+import org.onap.dcaegen2.platform.mod.model.restapi.SpecificationRequest;
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.onap.dcaegen2.platform.mod.model.specification.SpecificationStatus;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceService;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Specification Service implementation
+ */
+@Service
+@Setter
+public class SpecificationServiceImpl implements SpecificationService {
+
+ @Autowired
+ private SpecificationGateway specificationGateway;
+
+ @Autowired
+ private MsInstanceService msInstanceService;
+
+ @Autowired
+ private SpecificationValidatorService specificationValidatorService;
+
+ /**
+ * Lists all Ms Instances
+ * @param id
+ * @return
+ */
+ @Override
+ public List<Specification> getAllSpecsByMsInstanceId(String id) {
+ return specificationGateway.getSpecificationByMsInstanceId(id);
+ }
+
+ /**
+ * creates a Specification
+ * @param msInstanceId
+ * @param request
+ * @return
+ */
+ @Override
+ @Transactional
+ public Specification createSpecification(String msInstanceId, SpecificationRequest request) {
+ MsInstance msInstance = msInstanceService.getMsInstanceById(msInstanceId);
+ specificationValidatorService.validateSpecForRelease(request, msInstance.getRelease());
+ Specification newSpec = createSpecification(request, msInstance);
+ makePreviousSpecInactive(msInstance);
+ Specification savedSpec = specificationGateway.save(newSpec);
+ updateMsInstance(msInstance, savedSpec);
+ return savedSpec;
+ }
+
+ private Specification createSpecification(SpecificationRequest request, MsInstance msInstance) {
+ return Specification.builder()
+ .status(SpecificationStatus.ACTIVE)
+ .specContent(request.getSpecContent())
+ .policyJson(request.getPolicyJson())
+ .type(request.getType())
+ .metadata(getMetadata(request))
+ .msInstanceInfo(buildMsInstanceInfo(msInstance))
+ .build();
+ }
+
+ private void updateMsInstance(MsInstance msInstance, Specification savedSpecification) {
+ msInstance.setActiveSpec(savedSpecification);
+ msInstance.setStatus(MsInstanceStatus.IN_DEV);
+ msInstanceService.updateMsInstance(msInstance);
+ }
+
+ private void makePreviousSpecInactive(MsInstance msInstance) {
+ if (msInstance.getActiveSpec() != null) {
+ msInstance.getActiveSpec().setStatus(SpecificationStatus.INACTIVE);
+ specificationGateway.save(msInstance.getActiveSpec());
+ }
+ }
+
+ private Map<String, Object> getMetadata(SpecificationRequest request) {
+ Map<String, Object> metadata = request.getMetadata();
+ metadata.put("createdBy", request.getUser());
+ metadata.put("createdOn", new Date());
+ return metadata;
+ }
+
+ private Map<String, Object> buildMsInstanceInfo(MsInstance msInstance) {
+ Map<String, Object> msInstanceInfo = new HashMap<>();
+ msInstanceInfo.put("id", msInstance.getId());
+ msInstanceInfo.put("name", msInstance.getName());
+ msInstanceInfo.put("release", msInstance.getRelease());
+ return msInstanceInfo;
+ }
+
+ /**
+ * Updates a MsInstance reference in a Specification record
+ * @param msInstance
+ */
+ @Override
+ @Transactional
+ public void updateMsInstanceRef(MsInstance msInstance) {
+ List<Specification> specifications = getAllSpecsByMsInstanceId(msInstance.getId());
+ specifications.forEach((specification) ->{
+ specification.getMsInstanceInfo().put("name", msInstance.getName());
+ specification.getMsInstanceInfo().put("release", msInstance.getRelease());
+ specificationGateway.save(specification);
+ });
+ }
+
+
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationValidationStratergy.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationValidationStratergy.java
new file mode 100644
index 0000000..58eff19
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationValidationStratergy.java
@@ -0,0 +1,30 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.specification;
+
+import org.onap.dcaegen2.platform.mod.model.restapi.SpecificationRequest;
+
+/**
+ * Abstraction for Specification Validation.
+ */
+public interface SpecificationValidationStratergy {
+ public void validate(SpecificationRequest specificationRequest, String release);
+}
diff --git a/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationValidatorService.java b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationValidatorService.java
new file mode 100644
index 0000000..6d10aee
--- /dev/null
+++ b/mod2/catalog-service/src/main/java/org/onap/dcaegen2/platform/mod/web/service/specification/SpecificationValidatorService.java
@@ -0,0 +1,61 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.specification;
+
+import org.onap.dcaegen2.platform.mod.model.restapi.SpecificationRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * A service to validate specification
+ */
+@Service
+public class SpecificationValidatorService {
+
+ @Autowired
+ SpecificationValidationStratergy specValidator;
+
+ public void validateSpecForRelease(SpecificationRequest specificationRequest, String release) {
+ specValidator.validate(specificationRequest, release);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mod2/catalog-service/src/main/resources/application.properties b/mod2/catalog-service/src/main/resources/application.properties
new file mode 100644
index 0000000..1f20c6a
--- /dev/null
+++ b/mod2/catalog-service/src/main/resources/application.properties
@@ -0,0 +1,24 @@
+#
+# ============LICENSE_START=======================================================
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+#
+
+#add connection to mongo db once its up and running
+spring.data.mongodb.host=mongo_db
+spring.data.mongodb.port=27017
+spring.data.mongodb.database=dcae_mod \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/BaseMsObjectMother.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/BaseMsObjectMother.java
new file mode 100644
index 0000000..fc57442
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/BaseMsObjectMother.java
@@ -0,0 +1,131 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.objectmothers;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsLocation;
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsStatus;
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsType;
+import org.onap.dcaegen2.platform.mod.model.common.AuditFields;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceCreateRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceUpdateRequest;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.*;
+
+public class BaseMsObjectMother {
+
+ public static final String BASE_MS_NAME = "ms-1";
+ public static final String BASE_MS_ID = "id123";
+ public static final BaseMsType BASE_MS_TYPE = BaseMsType.TICK;
+ public static final BaseMsLocation LOCATION = BaseMsLocation.CENTRAL;
+ public static final String NAMESPACE = "sam.collector.namespace";
+ public static final String NOTE = "Sample Note";
+ public static final String LABEL_1 = "mylabel1";
+ public static final String LABEL_2 = "mylabel2";
+ public static final String USER = "abc123";
+ private static final String BASE_MS_TAG = "sample-ms-tag" ;
+ private static final String BASE_MS_SERVICE_NAME = "sample-core";
+
+
+ public static MicroserviceCreateRequest createMockMsRequest() {
+ Map<String, Object> metadata = new HashMap();
+ metadata.put("notes", NOTE);
+ metadata.put("labels", Arrays.asList(LABEL_1, LABEL_2));
+
+ MicroserviceCreateRequest request = new MicroserviceCreateRequest();
+ request.setName(BASE_MS_NAME);
+ request.setTag(BASE_MS_TAG);
+ request.setServiceName(BASE_MS_SERVICE_NAME);
+ request.setType(BASE_MS_TYPE);
+ request.setLocation(LOCATION);
+ request.setNamespace(NAMESPACE);
+ request.setMetadata(metadata);
+ request.setUser(USER);
+
+ return request;
+ }
+
+ public static BaseMicroservice createMockMsObject() {
+ BaseMicroservice microservice = new BaseMicroservice();
+ microservice.setId(BASE_MS_ID);
+ microservice.setName(BASE_MS_NAME);
+ microservice.setServiceName(BASE_MS_SERVICE_NAME);
+ microservice.setTag(BASE_MS_TAG);
+ microservice.setType(BASE_MS_TYPE);
+ microservice.setLocation(LOCATION);
+ microservice.setNamespace(NAMESPACE);
+ microservice.setStatus(BaseMsStatus.ACTIVE);
+ microservice.setMetadata(prepareAuditFields());
+ microservice.setMsInstances(createMsInstanceReferences());
+ return microservice;
+ }
+
+ private static List<Map<String, String>> createMsInstanceReferences() {
+ List<Map<String, String>> msInstanceRefs = new ArrayList<>();
+ Map<String, String> msInstance_1 = new HashMap<>();
+ msInstance_1.put("name", BASE_MS_NAME);
+ msInstance_1.put("id", "instance-1");
+ Map<String, String> msInstance_2 = new HashMap<>();
+ msInstance_2.put("name", BASE_MS_NAME);
+ msInstance_2.put("id", "instance-2");
+ msInstanceRefs.add(msInstance_1);
+ msInstanceRefs.add(msInstance_2);
+ return msInstanceRefs;
+ }
+
+
+ public static AuditFields prepareAuditFields() {
+ return AuditFields.builder()
+ .createdBy(USER) // prepared by core
+ .createdOn(new Date(12323132L))
+ .updatedBy(USER)
+ .updatedOn(new Date(12323133L))
+ .notes(NOTE)
+ .labels(Arrays.asList(LABEL_1, LABEL_2))
+ .build();
+
+ }
+
+ public static MicroserviceUpdateRequest createUpdateMsRequest() {
+ MicroserviceUpdateRequest updateRequest = new MicroserviceUpdateRequest();
+ updateRequest.setName("updatedName");
+ updateRequest.setLocation(BaseMsLocation.EDGE);
+ updateRequest.setServiceName("updated-core-name");
+ updateRequest.setNamespace("updatedNameSpace");
+ updateRequest.setType(BaseMsType.ANALYTIC);
+ updateRequest.setUser("updater");
+
+ Map<String, Object> metadata = new HashMap();
+ metadata.put("notes", "updatedNote");
+ metadata.put("labels", Arrays.asList("updatedLabel1", "updatedLabel2"));
+ updateRequest.setMetadata(metadata);
+ return updateRequest;
+ }
+
+ public static String asJsonString(final Object object) {
+ try {
+ return new ObjectMapper().writeValueAsString(object);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/DeploymentArtifactObjectMother.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/DeploymentArtifactObjectMother.java
new file mode 100644
index 0000000..da52624
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/DeploymentArtifactObjectMother.java
@@ -0,0 +1,222 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.objectmothers;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.MsInstanceInfo;
+
+import java.util.*;
+
+import static org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother.USER;
+
+public class DeploymentArtifactObjectMother {
+
+
+ public static final String BLUEPRINT_FILENAME = "hello-world-k8s-blueprint.yaml";
+ public static final String BLUEPRINT_CONTENT = "\\n#Basic java app to print out at&t buzzwords\\n#1.0" +
+ ".0\\n#\\n---\\" + "ntosca_definitions_version: cloudify_dsl_1_3\\nimports:\\n- http://www.getcloudify" +
+ ".org/spec/cloudify/4.4/types" + ".yaml\\n- http://dockercentral.it.att" +
+ ".com:8093/nexus/repository/rawcentral/com.att.dcae.controller/type_files/" + "k8splugin/1.7.4/node-type" +
+ ".yaml\\n- http://dockercentral.it.att.com:8093/nexus/repository/rawcentral/com.att.d" + "cae.controller" +
+ "/type_files/relationship/2006001.1.0/types.yaml\\n- http://dockercentral.it.att.com:8093/nexus/" +
+ "repository/rawcentral/com.att.dcae.controller/type_files/cloudifydmaapplugin/1.4.10/node-type.yaml\\n- " +
+ "http:/" + "/dockercentral.it.att.com:8093/nexus/repository/rawcentral/com.att.dcae" +
+ ".controller/type_files/dcaepolicyplugi" + "n/2.3.3/node-type.yaml\\n- http://dockercentral.it.att" +
+ ".com:8093/nexus/repository/rawcentral/com.att.dcae.cont" + "roller/type_files/pgaas/0.3.2/pgaas_types" +
+ ".yaml\\ninputs:\\n ConsulTest1:\\n type: string\\n description" + ": test description\\n " +
+ "default: 'TEST1'\\n ConsulTest2:\\n type: string\\n description: test description\\n default: " +
+ "'TEST2'\\n aaf_cert_directory:\\n type: string\\n default: '/opt/app/aafcertman'\\n " +
+ "description: directory location for the aaf-tls certs\\n additionalsans:\\n type: string\\n " +
+ "default: ''\\n description: additional sans (string)\\n annotations:\\n default: {}\\n " +
+ "app_name:\\n type: string\\n default: 'dcae'\\n description: This is used to generateForRelease different" +
+ " secret code for DCAE or D2A based\\n on Tosca or Helm based BP\\n dcae_service_location:\\n " +
+ "type: string\\n description: Docker host override for docker bps (string)\\n " +
+ "dti_sidecar_cpu_limit:\\n type: string\\n default: '250m'\\n description: cpu limit for " +
+ "deployment (string)\\n dti_sidecar_cpu_request:\\n type: string\\n default: '250m'\\n " +
+ "description: cpu requested for deployment (string)\\n dti_sidecar_image:\\n type: string\\n " +
+ "default: 'dockercentral.it.att.com:5100/com.att.dcae.controller/dcae-controller-sidecar:19.11-001'\\n " +
+ " description: dti side car image for dti (string)\\n dti_sidecar_memory_limit:\\n type: string\\n " +
+ " default: '128Mi'\\n description: memory limit for deployment (string)\\n " +
+ "dti_sidecar_memory_request:\\n type: string\\n default: '128Mi'\\n description: memory " +
+ "requested for deployment (string)\\n dti_sidecar_port:\\n type: string\\n default: ''\\n " +
+ "description: Port for the side car (string)\\n hello-buzzword_cpu_limit:\\n type: string\\n " +
+ "default: '250m'\\n description: cpu limit for deployment (string)\\n hello-buzzword_cpu_request:\\n " +
+ " type: string\\n default: '250m'\\n description: cpu requested for deployment (string)\\n " +
+ "hello-buzzword_memory_limit:\\n type: string\\n default: '128Mi'\\n description: memory limit " +
+ "for deployment (string)\\n hello-buzzword_memory_request:\\n type: string\\n default: '128Mi'\\n " +
+ " description: memory requested for deployment (string)\\n idns_fqdn:\\n type: string\\n " +
+ "default: ''\\n description: The idns you will be using for your deployment (string)\\n image:\\n " +
+ "type: string\\n default: 'test-image-uri'\\n description: The docker image for your microservice " +
+ "(string)\\n namespace:\\n type: string\\n replicas:\\n type: integer\\n default: 1\\n " +
+ "description: The number of replicas for your kubernetes deployment (integer)\\n " +
+ "service_component_name_override:\\n type: string\\n default: 'hello-buzzword'\\n description: " +
+ "Unique identifier for your deployment (string)\\n use_aaf_tls:\\n type: boolean\\n default: " +
+ "false\\n description: To use or not use the aaf section (boolean)\\n use_dti_info:\\n type: " +
+ "boolean\\n default: true\\n description: Flag to use or not use dti (boolean)\\nnode_templates:\\n" +
+ " hello-buzzword_hello-buzzword:\\n type: dcae.nodes.ContainerizedServiceComponent\\n " +
+ "properties:\\n application_config:\\n services_calls: []\\n streams_publishes: {}\\n " +
+ " streams_subscribes: {}\\n ConsulTest1:\\n get_input: ConsulTest1\\n " +
+ "ConsulTest2:\\n get_input: ConsulTest2\\n docker_config:\\n healthcheck:\\n " +
+ " interval: 180s\\n timeout: 30s\\n script: \\\"true\\\"\\n type: docker\\n " +
+ " livehealthcheck:\\n interval: 180s\\n timeout: 30s\\n script: " +
+ "\\\"true\\\"\\n type: docker\\n reconfigs:\\n dti: dti/test-script\\n " +
+ "app_reconfig: /app-reconfig/test-script\\n env:\\n - name: DTI_DATA_DIR\\n value:" +
+ " /dtidata\\n - name: KUBE_CLUSTER_FQDN\\n value: {get_secret: " +
+ "kc-kubernetes_master_ip}\\n image:\\n get_input: image\\n location_id:\\n " +
+ "get_input: dcae_service_location\\n service_component_type: hello-buzzword\\n replicas:\\n " +
+ " get_input: replicas\\n service_component_name_override:\\n concat:\\n - " +
+ "get_secret: location_id\\n - '-'\\n - get_input: service_component_name_override\\n " +
+ "k8s_controller_type: statefulset\\n configuration:\\n file_content:\\n apiVersion: " +
+ "v1\\n clusters:\\n - name: default-cluster\\n cluster:\\n " +
+ "server:\\n concat:\\n - https://\\n - get_secret: " +
+ "kc-kubernetes_master_ip\\n - ':'\\n - get_secret: " +
+ "kc-kubernetes_master_port\\n insecure-skip-tls-verify: true\\n contexts:\\n " +
+ " - name: default-context\\n context:\\n cluster: default-cluster\\n " +
+ " namespace:\\n get_input: namespace\\n user: default-user\\n " +
+ "kind: Config\\n preferences: {}\\n users:\\n - name: default-user\\n " +
+ " user:\\n token:\\n get_secret:\\n concat:\\n " +
+ " - get_input: app_name\\n - -mechid-k8s-token\\n current-context: " +
+ "default-context\\n resource_config:\\n limits:\\n cpu:\\n get_input: " +
+ "hello-buzzword_cpu_limit\\n memory:\\n get_input: hello-buzzword_memory_limit\\n " +
+ " requests:\\n cpu:\\n get_input: hello-buzzword_cpu_request\\n " +
+ "memory:\\n get_input: hello-buzzword_memory_request\\n aaf_tls_info:\\n " +
+ "use_aaf_tls:\\n get_input: use_aaf_tls\\n cert_directory:\\n get_input: " +
+ "aaf_cert_directory\\n image: dockercentral.it.att.com:5100/com.att.ecompcntr" +
+ ".public/ecompc-aaf-init-container:1.0.2\\n env:\\n - name: NAMESPACE\\n " +
+ "valueFrom:\\n fieldRef:\\n fieldPath: metadata.namespace\\n - name: " +
+ "deployer_id\\n valueFrom:\\n secretKeyRef:\\n name:\\n " +
+ "concat:\\n - get_input: namespace\\n - -cert-secret\\n key: " +
+ "deployerid\\n - name: deployer_pass\\n valueFrom:\\n secretKeyRef:\\n " +
+ " name:\\n concat:\\n - get_input: namespace\\n - " +
+ "-cert-secret\\n key: deployerpass\\n - name: cert_id\\n valueFrom:\\n " +
+ " secretKeyRef:\\n name:\\n concat:\\n - get_input: " +
+ "namespace\\n - -cert-secret\\n key: certid\\n - name: cm_url\\n " +
+ " valueFrom:\\n secretKeyRef:\\n name:\\n concat:\\n " +
+ " - get_input: namespace\\n - -cert-secret\\n key: cmurl\\n - " +
+ "name: idns_fqdn\\n value:\\n get_input: idns_fqdn\\n - name: " +
+ "app_service_names\\n value:\\n concat:\\n - get_secret: location_id\\n " +
+ " - '-'\\n - get_input: service_component_name_override\\n args:\\n - " +
+ "place\\n - cmtemplate\\n - -idnsfqdn=$(idns_fqdn)\\n - -cmurl=$(cm_url)\\n -" +
+ " -deployerid=$(deployer_id)\\n - -deployerpass=$(deployer_pass)\\n - -certid=$(cert_id)\\n" +
+ " - -namespace=$(NAMESPACE)\\n - -services=$(app_service_names)\\n - concat:\\n " +
+ " - -additionalsans=\\n - get_input: additionalsans\\n use_aaf_tls_renewal: true\\n " +
+ " renewal_args:\\n - renew\\n - -idnsfqdn=$(idns_fqdn)\\n - -cmurl=$(cm_url)\\n" +
+ " resource_config:\\n limits:\\n cpu: 250m\\n memory: 256Mi\\n " +
+ " requests:\\n cpu: 100m\\n memory: 256Mi\\n annotations:\\n " +
+ "get_input: annotations\\n dti_info:\\n image:\\n get_input: dti_sidecar_image\\n " +
+ " use_dti_info:\\n get_input: use_dti_info\\n healthcheck:\\n interval: " +
+ "90s\\n timeout: 60s\\n type: https\\n endpoint: /healthcheck\\n " +
+ "livehealthcheck:\\n interval: 90s\\n timeout: 60s\\n type: https\\n " +
+ "endpoint: /healthcheck\\n dtidata_directory: /dtidata\\n resource_config:\\n " +
+ "limits:\\n cpu:\\n get_input: dti_sidecar_cpu_limit\\n memory:\\n " +
+ " get_input: dti_sidecar_memory_limit\\n requests:\\n cpu:\\n " +
+ "get_input: dti_sidecar_cpu_request\\n memory:\\n get_input: " +
+ "dti_sidecar_memory_request\\n env:\\n - name: DTI_DATA_DIR\\n value: /dtidata\\n " +
+ " - name: KUBE_CLUSTER_FQDN\\n value: {get_secret: kc-kubernetes_master_ip}\\n - " +
+ "name: KUBE_PROXY_FQDN\\n value: {get_secret: kube_proxy_fqdn}\\n - name: POD_SVC_PORT\\n" +
+ " value: '9999'\\n ports:\\n - concat:\\n - '9999:'\\n - " +
+ "get_input: dti_sidecar_port\\n relationships: []";
+
+ public static final String SPEC_FILE_AS_STRING = String.format("{\r\n\t\"self\": {\r\n\t\t\"component_type\": " +
+ "\"docker\",\r\n\t\t\"description\": \"Basic java app to print out at&t buzzwords\",\r\n\t\t\"name\": " +
+ "\"hello-buzzword\",\r\n\t\t\"version\": \"1.0.0\"\r\n\t},\r\n\t\r\n\t\"services\": {\r\n\t\t\"calls\": " +
+ "[],\r\n\t\t\"provides\": []\r\n\t},\r\n\t\"streams\": {\r\n\t\t\"publishes\": [],\r\n\t\t\"subscribes\":" +
+ " []\r\n\t},\r\n\t\"parameters\": [\r\n\t\t{\r\n \"name\": \"ConsulTest1\",\r\n " +
+ "\"value\": \"TEST1\",\r\n \"description\": \"Test consul output\"," +
+ "\r\n\t\t\t\"sourced_at_deployment\": true,\r\n\t\t\t\"designer_editable\": true," +
+ "\r\n\t\t\t\"policy_editable\": false,\r\n\t\t\t\"type\": \"string\" ,\r\n\t\t\t\"description\": \"test " +
+ "description\" \r\n },\r\n {\r\n \"name\": \"ConsulTest2\",\r\n " +
+ " \"value\": \"TEST2\",\r\n\t\t\t\"sourced_at_deployment\": true,\r\n\t\t\t\"designer_editable\": true," +
+ "\r\n\t\t\t\"policy_editable\": false,\r\n\t\t\t\"type\": \"string\",\r\n\t\t\t\"description\": \"test " +
+ "description\" \r\n }\r\n \r\n\t],\r\n\r\n\t\"auxilary\": {\r\n\t\t\"healthcheck\": " +
+ "{\r\n\t\t\t\"type\": \"docker\",\r\n \t\"script\": \"true\",\r\n \t\"timeout\": \"30s\"," +
+ "\r\n \t\"interval\": \"180s\"\r\n\t\t},\r\n\t\t\"livehealthcheck\": {\r\n\t\t\t\"type\": " +
+ "\"docker\",\r\n \t\"script\": \"true\",\r\n \t\"timeout\": \"30s\",\r\n " +
+ "\t\"interval\": \"180s\"\r\n\t\t},\r\n\t\t\"reconfigs\": {\r\n\t\t\t\"app_reconfig\" : " +
+ "\"/app-reconfig/test-script\",\r\n\t\t\t\"dti\" : \"dti/test-script\"}}," +
+ "\r\n\t\"artifacts\": [{\r\n\t\t\"type\": \"docker image\",\r\n\t\t\"uri\": " +
+ "\"test-image-uri\"\r\n\t}]\r\n}");
+
+ public static DeploymentArtifact createDeploymentArtifactDAO(DeploymentArtifactStatus status) {
+ DeploymentArtifact artifact = new DeploymentArtifact();
+ artifact.setId("id-123");
+ artifact.setFileName("helloworld-k8s-blueprint.yaml");
+ artifact.setContent("some " + "yaml content");
+ artifact.setStatus(status);
+ artifact.setVersion(1);
+ artifact.setMetadata(createMetaData());
+ artifact.setMsInstanceInfo(createMsInstanceInfo());
+ artifact.setSpecificationInfo(createSpecificationInfo());
+
+ return artifact;
+ }
+
+ private static Map<String, Object> createSpecificationInfo() {
+ Map<String, Object> msInstanceInfo = new HashMap<>();
+ msInstanceInfo.put("id", "id-123");
+ return msInstanceInfo;
+ }
+
+ private static MsInstanceInfo createMsInstanceInfo() {
+ MsInstanceInfo msInstanceInfo = new MsInstanceInfo();
+ msInstanceInfo.setId(MsInstanceObjectMother.MS_INSTANCE_ID);
+ msInstanceInfo.setName(MsInstanceObjectMother.MS_INSTANCE_NAME);
+ msInstanceInfo.setRelease(MsInstanceObjectMother.RELEASE);
+ return msInstanceInfo;
+ }
+
+ private static Map<String, Object> createMetaData() {
+ Map<String, Object> metadata = new HashMap<>();
+ metadata.put("createdBy", USER);
+ metadata.put("createdOn", "someDate");
+ metadata.put("notes", "This is a test Deployment Artifact");
+ metadata.put("labels", Arrays.asList("hello", "world"));
+ return metadata;
+ }
+
+ public static Map<String, Object> createBlueprintResponse() {
+ Map<String, Object> blueprintMap = new HashMap<>();
+ blueprintMap.put("fileName", BLUEPRINT_FILENAME);
+ blueprintMap.put("content", BLUEPRINT_CONTENT); return blueprintMap;
+ }
+
+ public static Map<String, Object> createToolboxBlueprintResponse() {
+ Map<String, Object> blueprintResponseMap = new HashMap<>();
+ blueprintResponseMap.put("blueprint_name", "hello-buzzword-eom-k8s");
+ blueprintResponseMap.put("blueprint_content", BLUEPRINT_CONTENT);
+ blueprintResponseMap.put("componentSpecValidated", true);
+ return blueprintResponseMap;
+ }
+
+ public static List<DeploymentArtifact> createMockDeploymentArtifactsWithDifferentStatuses
+ (boolean devCompleteRequire) {
+ DeploymentArtifact d1;
+ if(devCompleteRequire){
+ d1 = createDeploymentArtifactDAO(DeploymentArtifactStatus.DEV_COMPLETE);
+ }else {
+ d1 = createDeploymentArtifactDAO(DeploymentArtifactStatus.NOT_NEEDED);
+ }
+ DeploymentArtifact d2 = createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+ return new ArrayList<>(Arrays.asList(d1, d2));
+ }
+
+}
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/MsInstanceObjectMother.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/MsInstanceObjectMother.java
new file mode 100644
index 0000000..976e31c
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/MsInstanceObjectMother.java
@@ -0,0 +1,112 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.objectmothers;
+
+import org.onap.dcaegen2.platform.mod.model.specification.DeploymentType;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.DeploymentArtifactsRef;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstanceStatus;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceRequest;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class MsInstanceObjectMother {
+
+ public static final String MS_INSTANCE_NAME = "ms-instance-1";
+ public static final String MS_INSTANCE_ID = "id-123";
+ public static final String RELEASE = "2002";
+ public static final String VERSION = "1.1";
+ public static final String USER = "user-1";
+ public static final String BASE_MS_TAG = "ms-instance-1-tag";
+ public static final String SCRUMLEAD = "Sam";
+ public static final String SYSTEMSENGINEER = "John";
+
+ public static MsInstanceRequest getMsInstanceMockRequest() {
+ Map<String, Object> metadataFromRequest = buildMockMetadataForRequest();
+
+ MsInstanceRequest request = MsInstanceRequest.builder()
+ .name(MS_INSTANCE_NAME)
+ .release(RELEASE)
+ .version(VERSION)
+ .user(USER)
+ .metadata(metadataFromRequest)
+ .build();
+
+ return request;
+ }
+
+ private static Map<String, Object> buildMockMetadataForRequest() {
+ Map<String, Object> metadataFromRequest = new HashMap<>();
+ metadataFromRequest.put("pstDueDate", "14-04-2020");
+ metadataFromRequest.put("pstDueIteration", "1.2");
+ metadataFromRequest.put("eteDueDate", "21-05-2020");
+ metadataFromRequest.put("eteDueIteration", "1.3");
+ metadataFromRequest.put("scrumLead", SCRUMLEAD);
+ metadataFromRequest.put("systemsEngineer", SYSTEMSENGINEER);
+ return metadataFromRequest;
+ }
+
+
+ public static MsInstance createMsInstance() {
+ Map<String, Object> metadataFromResponse = buildMockMetadataForRequest().entrySet()
+ .stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ metadataFromResponse.put("createdOn", "currentDate");
+ metadataFromResponse.put("createdBy", USER);
+ metadataFromResponse.put("scrumLead", SCRUMLEAD);
+ metadataFromResponse.put("systemsEngineer", SYSTEMSENGINEER);
+
+ Map<String, Object> msInfo = new HashMap<>();
+ msInfo.put("id", BaseMsObjectMother.BASE_MS_ID);
+ msInfo.put("name", BaseMsObjectMother.BASE_MS_NAME);
+ msInfo.put("tag", BASE_MS_TAG);
+
+ MsInstance msInstance = MsInstance.builder()
+ .id(MS_INSTANCE_ID)
+ .name(MS_INSTANCE_NAME)
+ .release(RELEASE)
+ .version(VERSION)
+ .status(MsInstanceStatus.NEW)
+ .metadata(metadataFromResponse)
+ .msInfo(msInfo)
+ .activeSpec(SpecificationObjectMother.getMockSpecification(DeploymentType.DOCKER))
+ .build();
+
+ return msInstance;
+ }
+
+ public static MsInstance getMsInstanceWithExistingDeploymentArtifactRef() {
+ MsInstance msInstance = createMsInstance();
+
+ DeploymentArtifactsRef deploymentArtifactRef = new DeploymentArtifactsRef();
+ deploymentArtifactRef.setMostRecentVersion(1);
+
+ ArrayList<String> deploymentArtifactList = new ArrayList<>();
+ deploymentArtifactList.add("id-456");
+ deploymentArtifactRef.setDeploymentArtifacts(deploymentArtifactList);
+
+ msInstance.setDeploymentArtifactsInfo(deploymentArtifactRef);
+
+ return msInstance;
+ }
+}
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/SpecificationObjectMother.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/SpecificationObjectMother.java
new file mode 100644
index 0000000..3390998
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/objectmothers/SpecificationObjectMother.java
@@ -0,0 +1,41 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.objectmothers;
+
+import org.onap.dcaegen2.platform.mod.model.specification.DeploymentType;
+import org.onap.dcaegen2.platform.mod.model.restapi.SpecificationRequest;
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.onap.dcaegen2.platform.mod.util.TestUtil;
+
+public class SpecificationObjectMother {
+ public static final String SPEC_REQUEST = "src/test/resources/http/requests/CreateSpecificationRequest.json";
+ public static final String SPEC_RESPONSE = "src/test/resources/http/requests/CreateSpecificationResponse.json";
+
+ public static SpecificationRequest getSpecificationRequest() {
+ return TestUtil.deserializeJsonFileToModel(SPEC_REQUEST, SpecificationRequest.class);
+ }
+
+ public static Specification getMockSpecification(DeploymentType type) {
+ Specification specification = TestUtil.deserializeJsonFileToModel(SPEC_RESPONSE, Specification.class);
+ specification.setType(type);
+ return specification;
+ }
+}
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/persistence/DeploymentArtifactGatewayTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/persistence/DeploymentArtifactGatewayTest.java
new file mode 100644
index 0000000..9bcd46c
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/persistence/DeploymentArtifactGatewayTest.java
@@ -0,0 +1,147 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.persistence;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactFilter;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactSearch;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.mongo.deploymentartifact.DeploymentArtifactMongoGateway;
+import org.onap.dcaegen2.platform.mod.mongo.deploymentartifact.DeploymentArtifactMongoRepo;
+import org.onap.dcaegen2.platform.mod.objectmothers.DeploymentArtifactObjectMother;
+import org.onap.dcaegen2.platform.mod.web.service.deploymentartifact.DeploymentArtifactGateway;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Disabled("Embedded mongodb jar is not available in the maven repo.")
+@SpringBootTest
+@ExtendWith(SpringExtension.class)
+public class DeploymentArtifactGatewayTest {
+
+ DeploymentArtifactGateway gateway;
+
+ @Autowired
+ DeploymentArtifactMongoRepo repo;
+
+ @Autowired
+ MongoOperations operations;
+
+ @BeforeEach
+ public void setUp(){
+ gateway = new DeploymentArtifactMongoGateway(repo);
+
+ operations.dropCollection(DeploymentArtifact.class);
+
+ String r_2008 = "2008";
+ String r_2010 = "2010";
+
+ DeploymentArtifactStatus inDev = DeploymentArtifactStatus.IN_DEV;
+ DeploymentArtifactStatus devComplete = DeploymentArtifactStatus.DEV_COMPLETE;
+
+ String tag_1 = "hello-one";
+ String tag_2 = "hello-two";
+ String tag_3 = "hello-three";
+
+ DeploymentArtifact artifact_1 = getDeploymentArtifact(r_2008, inDev, tag_1);
+ DeploymentArtifact artifact_2 = getDeploymentArtifact(r_2010, devComplete, tag_2);
+ DeploymentArtifact artifact_3 = getDeploymentArtifact(r_2008, devComplete, tag_3);
+
+ operations.insertAll(Arrays.asList(artifact_1, artifact_2, artifact_3));
+ operations.findAll(DeploymentArtifact.class).forEach(System.out::println);
+
+ System.out.println();
+ }
+
+ private static DeploymentArtifact getDeploymentArtifact(String r_2008, DeploymentArtifactStatus inDev,
+ String tag) {
+ DeploymentArtifact artifact_1 = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(inDev);
+ artifact_1.getMsInstanceInfo().setRelease(r_2008);
+ //Currently searching tag in filename as it is not present in DeploymentArtifact record
+ artifact_1.setFileName(tag);
+ artifact_1.setId(null);
+
+ return artifact_1;
+ }
+
+ @Test
+ public void findByOnlyRelease() throws Exception {
+ DeploymentArtifactSearch search = new DeploymentArtifactSearch();
+ DeploymentArtifactFilter filter = new DeploymentArtifactFilter();
+ filter.setRelease("2008");
+ search.setFilter(filter);
+
+ List<DeploymentArtifact> artifacts = gateway.findAll(search);
+ Assertions.assertThat(artifacts.size()).isEqualTo(2);
+ }
+
+ @Test
+ public void findWithOnlyStatus() throws Exception {
+ DeploymentArtifactSearch search = new DeploymentArtifactSearch();
+ DeploymentArtifactFilter filter = new DeploymentArtifactFilter();
+ filter.setStatus(DeploymentArtifactStatus.IN_DEV);
+ search.setFilter(filter);
+
+ List<DeploymentArtifact> artifacts = gateway.findAll(search);
+
+ Assertions.assertThat(artifacts.size()).isEqualTo(1);
+ }
+
+ @Test
+ public void findWithStatusAndRelease() throws Exception {
+ DeploymentArtifactSearch search = new DeploymentArtifactSearch();
+ DeploymentArtifactFilter filter = new DeploymentArtifactFilter();
+ filter.setStatus(DeploymentArtifactStatus.DEV_COMPLETE);
+ filter.setRelease("2008");
+ search.setFilter(filter);
+
+ List<DeploymentArtifact> artifacts = gateway.findAll(search);
+
+ Assertions.assertThat(artifacts.size()).isEqualTo(3);
+ }
+
+ @Test
+ public void findWithTag() throws Exception {
+ DeploymentArtifactSearch search = new DeploymentArtifactSearch();
+ DeploymentArtifactFilter filter = new DeploymentArtifactFilter();
+ filter.setTag("hello-one");
+ search.setFilter(filter);
+
+ List<DeploymentArtifact> artifacts = gateway.findAll(search);
+
+ Assertions.assertThat(artifacts.size()).isEqualTo(1);
+ }
+
+ @Test
+ public void findWithNoQuery() throws Exception {
+ List<DeploymentArtifact> artifacts = gateway.findAll(new DeploymentArtifactSearch());
+ Assertions.assertThat(artifacts.size()).isEqualTo(0);
+ }
+}
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java
new file mode 100644
index 0000000..f9a45da
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/util/TestUtil.java
@@ -0,0 +1,53 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.util;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+public class TestUtil {
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private TestUtil() {}
+
+ public static Map<String, Object> readJsonFileAsObjectMap(String filePath) {
+ try {
+ return MAPPER.readValue(new File(filePath), new TypeReference<Map<String, Object>>() {});
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException();
+ }
+ }
+
+ public static <T> T deserializeJsonFileToModel(String filePath, Class<T> modelClass) {
+ try {
+ return MAPPER.readValue(new File(filePath), modelClass);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/BaseMicroserviceControllerTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/BaseMicroserviceControllerTest.java
new file mode 100644
index 0000000..c89b4dc
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/BaseMicroserviceControllerTest.java
@@ -0,0 +1,165 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.model.exceptions.OperationNotAllowedException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.ResourceConflictException;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceCreateRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceUpdateRequest;
+import org.onap.dcaegen2.platform.mod.objectmothers.BaseMsObjectMother;
+import org.onap.dcaegen2.platform.mod.web.controller.BaseMicroserviceController;
+import org.onap.dcaegen2.platform.mod.web.service.basemicroservice.MsService;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+
+import java.util.Arrays;
+
+import static org.onap.dcaegen2.platform.mod.model.exceptions.ErrorMessages.MICROSERVICE_NAME_CONFLICT_MESSAGE;
+
+@ExtendWith(SpringExtension.class)
+@WebMvcTest(BaseMicroserviceController.class)
+class BaseMicroserviceControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
+ private MsService mockBaseMsService;
+
+ @BeforeEach
+ void setUp() {
+ }
+
+ @Test
+ void test_GetAllBaseMicroservices_returnsListOfDTOs() throws Exception {
+ //arrange
+ BaseMicroservice ms1 = new BaseMicroservice();
+ ms1.setName("HelloWorld1");
+ BaseMicroservice ms2 = new BaseMicroservice();
+ ms2.setName("HelloWorld2");
+
+ Mockito.when(mockBaseMsService.getAllMicroservices()).thenReturn(Arrays.asList(ms1, ms2));
+
+ //act/assert
+ mockMvc.perform(MockMvcRequestBuilders.get("/api/base-microservice")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2)));
+ }
+
+ @Test
+ void test_addBaseMicroservice_returnsMicroservice() throws Exception {
+ //arrange
+ MicroserviceCreateRequest microserviceRequest = BaseMsObjectMother.createMockMsRequest();
+
+ //response
+ BaseMicroservice microserviceDao = BaseMsObjectMother.createMockMsObject();
+
+ Mockito.when(mockBaseMsService.createMicroservice(microserviceRequest)).thenReturn(microserviceDao);
+
+ //act/assert
+ mockMvc.perform(MockMvcRequestBuilders.post("/api/base-microservice")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(microserviceRequest))
+ .characterEncoding("utf-8"))
+ .andExpect(MockMvcResultMatchers.status().isCreated())
+ .andExpect((MockMvcResultMatchers.jsonPath("$.id", Matchers.equalTo(BaseMsObjectMother.BASE_MS_ID))))
+ .andExpect(MockMvcResultMatchers.jsonPath("$.name", Matchers.equalTo(BaseMsObjectMother.BASE_MS_NAME)))
+ .andExpect(MockMvcResultMatchers.jsonPath("$.metadata.createdBy", Matchers.equalTo(BaseMsObjectMother.USER)));
+ }
+
+ @Test
+ void test_addBaseMicroserviceWithDuplicateName_shouldThrowConflictError() throws Exception{
+ //arrange
+ MicroserviceCreateRequest microserviceRequest = BaseMsObjectMother.createMockMsRequest();
+ Mockito.when(mockBaseMsService.createMicroservice(ArgumentMatchers.any())).thenThrow(new ResourceConflictException(MICROSERVICE_NAME_CONFLICT_MESSAGE));
+
+ //act/assert
+ mockMvc.perform(MockMvcRequestBuilders.post("/api/base-microservice")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(microserviceRequest)))
+ .andExpect(MockMvcResultMatchers.status().isConflict());
+ }
+
+ @Test
+ void test_updateBaseMicroserviceEndpoint() throws Exception{
+ MicroserviceUpdateRequest microserviceRequest = BaseMsObjectMother.createUpdateMsRequest();
+ String requestedMsId = "id-123";
+
+ mockMvc.perform(MockMvcRequestBuilders.patch(String.format(BaseMicroserviceController.API_BASE_MICROSERVICE + "/%s", requestedMsId))
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(microserviceRequest))
+ .characterEncoding("utf-8"))
+ .andExpect(MockMvcResultMatchers.status().isNoContent());
+ Mockito.verify(mockBaseMsService, Mockito.times(1)).updateMicroservice(requestedMsId, microserviceRequest);
+ }
+
+ @Test
+ void test_OperationNotAllowedExceptionThrows409() throws Exception{
+ MicroserviceUpdateRequest microserviceRequest = BaseMsObjectMother.createUpdateMsRequest();
+ String requestedMsId = "id-123";
+ Mockito.doThrow(new OperationNotAllowedException("")).
+ when(mockBaseMsService).updateMicroservice(requestedMsId, microserviceRequest);
+
+ mockMvc.perform(MockMvcRequestBuilders.patch(String.format(BaseMicroserviceController.API_BASE_MICROSERVICE + "/%s", requestedMsId))
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(microserviceRequest)))
+ .andExpect(MockMvcResultMatchers.status().isConflict());
+ }
+
+ @Test
+ void test_validateMsRequestShouldThrowCorrectResponse() throws Exception {
+ //arrange
+ MicroserviceCreateRequest microserviceRequest = BaseMsObjectMother.createMockMsRequest();
+ microserviceRequest.setName(" ");
+ microserviceRequest.setTag("123");
+ microserviceRequest.setServiceName("123");
+ microserviceRequest.setUser(" ");
+
+ //response
+ BaseMicroservice microserviceDao = BaseMsObjectMother.createMockMsObject();
+
+ Mockito.when(mockBaseMsService.createMicroservice(microserviceRequest)).thenReturn(microserviceDao);
+
+ //act/assert
+ mockMvc.perform(MockMvcRequestBuilders.post("/api/base-microservice")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(microserviceRequest))
+ .characterEncoding("utf-8"))
+ .andExpect(MockMvcResultMatchers.status().isBadRequest())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.message", Matchers.equalTo("Validation failed.")))
+ .andExpect(MockMvcResultMatchers.jsonPath("$.errors", Matchers.hasSize(4)))
+ ;
+ }
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/DeploymentArtifactControllerTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/DeploymentArtifactControllerTest.java
new file mode 100644
index 0000000..c8942b1
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/DeploymentArtifactControllerTest.java
@@ -0,0 +1,170 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.BlueprintFileNameCreateException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.DeploymentArtifactNotFound;
+import org.onap.dcaegen2.platform.mod.model.restapi.DeploymentArtifactPatchRequest;
+import org.onap.dcaegen2.platform.mod.objectmothers.BaseMsObjectMother;
+import org.onap.dcaegen2.platform.mod.objectmothers.DeploymentArtifactObjectMother;
+import org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother;
+import org.onap.dcaegen2.platform.mod.web.controller.DeploymentArtifactController;
+import org.onap.dcaegen2.platform.mod.web.service.deploymentartifact.DeploymentArtifactService;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+
+@WebMvcTest(DeploymentArtifactController.class)
+class DeploymentArtifactControllerTest {
+
+ @Autowired
+ MockMvc mockMvc;
+
+ @MockBean
+ DeploymentArtifactService service;
+
+ @BeforeEach
+ void setUp() {
+ }
+
+ @Test
+ void test_GenerateDeploymentArtifactEndpoint_returnsBlueprint() throws Exception{
+ String url = String.format("/api/deployment-artifact/%s?user=%s", MsInstanceObjectMother.MS_INSTANCE_ID, MsInstanceObjectMother.USER);
+ DeploymentArtifact response = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+
+ Mockito.when(service.generateDeploymentArtifact(MsInstanceObjectMother.MS_INSTANCE_ID, MsInstanceObjectMother.USER)).thenReturn(response);
+
+ mockMvc.perform(post(url))
+ .andExpect(MockMvcResultMatchers.status().isCreated())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.fileName").exists())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.content").exists());
+
+ Mockito.verify(service, Mockito.times(1)).generateDeploymentArtifact(MsInstanceObjectMother.MS_INSTANCE_ID, MsInstanceObjectMother.USER);
+ }
+
+ @Test
+ void test_RaiseExceptionIfBlueprintNameCanNotBeCreated() throws Exception{
+ String url = String.format("/api/deployment-artifact/%s?user=%s", MsInstanceObjectMother.MS_INSTANCE_ID,
+ MsInstanceObjectMother.USER);
+ DeploymentArtifact response = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+
+ Mockito.when(service.generateDeploymentArtifact(MsInstanceObjectMother.MS_INSTANCE_ID, MsInstanceObjectMother.USER)).thenThrow(new BlueprintFileNameCreateException(""));
+
+ mockMvc.perform(post(url))
+ .andExpect(MockMvcResultMatchers.status().is4xxClientError());
+ }
+
+ @Test
+ void test_GetAllDeploymentArtifactsShouldReturnList() throws Exception{
+ List<DeploymentArtifact> daos = createDaos();
+ Mockito.when(service.getAllDeploymentArtifacts()).thenReturn(daos);
+
+ mockMvc.perform(get("/api/deployment-artifact"))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2)));
+
+ }
+
+ private List<DeploymentArtifact> createDaos() {
+ DeploymentArtifact dao1 = new DeploymentArtifact();
+ dao1.setId("123");
+ DeploymentArtifact dao2 = new DeploymentArtifact();
+ dao2.setId("456");
+
+ return Arrays.asList(dao1, dao2);
+ }
+
+ @Test
+ void test_GetAllDeploymentArtifactTestShouldReturnAList() throws Exception{
+
+ mockMvc.perform(get(DeploymentArtifactController.DEPLOYMENT_ARTIFACTS_BASE_URL + DeploymentArtifactController.GET_STATUSES))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(DeploymentArtifactStatus.values().length)));
+ }
+
+ @Test
+ void test_ifUserIsNullRaiseException() throws Exception{
+ String id = "id-123";
+ String user = "";
+
+ mockMvc.perform(patch(DeploymentArtifactController.DEPLOYMENT_ARTIFACTS_BASE_URL + "/" + id + "?user=" + user)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(new DeploymentArtifactPatchRequest())))
+ .andExpect(MockMvcResultMatchers.status().isBadRequest());
+ }
+
+ @Test
+ void test_ChangeStatusOfDeploymentArtifact() throws Exception{
+
+ String id = "id-123";
+ String user = "user1";
+ DeploymentArtifactPatchRequest partialDto = new DeploymentArtifactPatchRequest();
+ partialDto.setStatus(DeploymentArtifactStatus.DEV_COMPLETE);
+
+ mockMvc.perform(patch(DeploymentArtifactController.DEPLOYMENT_ARTIFACTS_BASE_URL + "/" + id + "?user=" + user)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(partialDto)))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.message").exists());
+
+ Mockito.verify(service, Mockito.times(1)).updateDeploymentArtifact(id, partialDto, user);
+
+ }
+
+ @Test
+ void test_deploymentArtifactIdNotFound() throws Exception{
+ String wrongId = "wrong-id";
+ DeploymentArtifactPatchRequest partialDto = new DeploymentArtifactPatchRequest();
+ partialDto.setStatus(DeploymentArtifactStatus.DEV_COMPLETE);
+
+ Mockito.doThrow(new DeploymentArtifactNotFound("")).when(service).
+ updateDeploymentArtifact(wrongId, partialDto, "user-1");
+
+ mockMvc.perform(patch(DeploymentArtifactController.DEPLOYMENT_ARTIFACTS_BASE_URL + "/" + wrongId + "?user=" + "user-1")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(partialDto)))
+ .andExpect(MockMvcResultMatchers.status().isBadRequest());
+ }
+
+ @Test
+ void test_deleteDeploymentArtifactEndpoint() throws Exception{
+ String deploymentArtifactId = "id-123";
+ String user = "user-1";
+ mockMvc.perform(delete(DeploymentArtifactController.DEPLOYMENT_ARTIFACTS_BASE_URL + "/" + deploymentArtifactId + "?user=" + user))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.message").exists());
+ Mockito.verify(service, Mockito.times(1)).deleteDeploymentArtifact(deploymentArtifactId);
+ }
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/MicroserviceInstanceControllerTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/MicroserviceInstanceControllerTest.java
new file mode 100644
index 0000000..852fb10
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/MicroserviceInstanceControllerTest.java
@@ -0,0 +1,145 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web;
+
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceUpdateRequest;
+import org.onap.dcaegen2.platform.mod.objectmothers.BaseMsObjectMother;
+import org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother;
+import org.onap.dcaegen2.platform.mod.web.controller.MicroserviceInstanceController;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother.*;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasSize;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@ExtendWith(SpringExtension.class)
+@WebMvcTest(MicroserviceInstanceController.class)
+class MicroserviceInstanceControllerTest {
+
+ @MockBean
+ MsInstanceService service;
+
+ @Autowired
+ MockMvc mockMvc;
+
+ @BeforeEach
+ void setUp() {
+ }
+
+ @Test
+ void getAll() throws Exception {
+ MsInstance instance_1 = MsInstance.builder().id("123").build();
+ MsInstance instance_2 = MsInstance.builder().id("345").build();
+
+ when(service.getAll()).thenReturn(Arrays.asList(instance_1,instance_2));
+
+ mockMvc.perform(get("/api/microservice-instance")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$",hasSize(2)));
+ verify(service, times(1)).getAll();
+ }
+
+ @Test
+ void createMsInstance_shouldReturn201AndResponseBody() throws Exception {
+
+ MsInstanceRequest request = getMsInstanceMockRequest();
+ MsInstance msInstance = createMsInstance();
+
+ when(service.createMicroserviceInstance(BaseMsObjectMother.BASE_MS_NAME, request)).thenReturn(msInstance);
+
+ mockMvc.perform(MockMvcRequestBuilders.post("/api/microservice-instance/"+ BaseMsObjectMother.BASE_MS_NAME)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(request)).accept(MediaType.APPLICATION_JSON))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.name",equalTo(MS_INSTANCE_NAME)));
+
+ verify(service, times(1)).createMicroserviceInstance(BaseMsObjectMother.BASE_MS_NAME,request);
+ }
+
+ @Test
+ void patchMsInstance_shouldReturn204NoContent() throws Exception{
+ //given
+ String updatedVersion = "updatedVersion";
+ String updatedRelease = "updatedRelease";
+
+ MsInstance mockedMsInstance = prepareMockMsInstance(updatedVersion, updatedRelease);
+ String msInstanceId = mockedMsInstance.getId();
+
+ MsInstanceUpdateRequest updateRequest = prepareMsInstanceUpdateRequest(updatedVersion, updatedRelease);
+
+ when(service.updateMsInstance(updateRequest, msInstanceId)).thenReturn(mockedMsInstance);
+
+ mockMvc.perform(patch("/api/microservice-instance/" + msInstanceId)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(BaseMsObjectMother.asJsonString(updateRequest)))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.release", equalTo(updatedRelease)))
+ .andExpect(jsonPath("$.version", equalTo(updatedVersion)))
+ .andExpect(jsonPath("$.metadata.scrumLead", equalTo("updatedScrumLead")));
+
+ verify(service, times(1)).updateMsInstance(updateRequest, msInstanceId);
+ }
+
+ private MsInstanceUpdateRequest prepareMsInstanceUpdateRequest(String updatedVersion, String updatedRelease) {
+ MsInstanceUpdateRequest updateRequest = new MsInstanceUpdateRequest();
+ updateRequest.setRelease(updatedRelease);
+ updateRequest.setVersion(updatedVersion);
+ updateRequest.setMetadata(prepareMetadataToBeUpdated());
+ return updateRequest;
+ }
+
+ private Map<String, Object> prepareMetadataToBeUpdated() {
+ Map<String, Object> metadata = new HashMap<>();
+ metadata.put("scrumLead", "updatedScrumLead");
+ return metadata;
+ }
+
+ private MsInstance prepareMockMsInstance(String updatedVersion, String updatedRelease) {
+ MsInstance msInstanceToBeUpdated = MsInstanceObjectMother.createMsInstance();
+ msInstanceToBeUpdated.setVersion(updatedVersion);
+ msInstanceToBeUpdated.setRelease(updatedRelease);
+ msInstanceToBeUpdated.getMetadata().put("scrumLead", "updatedScrumLead");
+ return msInstanceToBeUpdated;
+ }
+
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/MsRequestValidationTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/MsRequestValidationTest.java
new file mode 100644
index 0000000..d71f8dd
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/MsRequestValidationTest.java
@@ -0,0 +1,87 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web;
+
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceCreateRequest;
+import org.onap.dcaegen2.platform.mod.objectmothers.BaseMsObjectMother;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import java.util.Set;
+
+public class MsRequestValidationTest {
+
+ public Validator validator;
+ private MicroserviceCreateRequest request;
+
+ @BeforeEach
+ public void setup(){
+ validator = Validation.buildDefaultValidatorFactory().getValidator();
+ request = BaseMsObjectMother.createMockMsRequest();
+ }
+
+ @Test
+ void test_msNameShouldNotBeBlank(){
+ request.setName(" ");
+ Set<ConstraintViolation<MicroserviceCreateRequest>> violations = validator.validate(request);
+ Assertions.assertThat(violations.size()).isEqualTo(1);
+ }
+
+ @Test
+ void test_msTagShouldNotBeNull(){
+ request.setTag(null);
+ Set<ConstraintViolation<MicroserviceCreateRequest>> violations = validator.validate(request);
+ Assertions.assertThat(violations.size()).isEqualTo(1);
+
+ }
+
+ @Test
+ void test_msTagShouldFollowRegex() throws Exception{
+ request.setTag("ms-1");
+ Set<ConstraintViolation<MicroserviceCreateRequest>> violations = validator.validate(request);
+ Assertions.assertThat(violations.size()).isEqualTo(1);
+ }
+
+ @Test
+ void test_msTagSizeValidation() throws Exception {
+ request.setTag("core-name-should-not-exceed-fifty-chars-core-name-should-not-exceed-fifty-chars");
+ Set<ConstraintViolation<MicroserviceCreateRequest>> violations = validator.validate(request);
+ Assertions.assertThat(violations.size()).isEqualTo(1);
+ }
+
+ @Test
+ void test_msServiceNameShouldFollowRegex() throws Exception{
+ request.setServiceName("ms-1");
+ Set<ConstraintViolation<MicroserviceCreateRequest>> violations = validator.validate(request);
+ Assertions.assertThat(violations.size()).isEqualTo(1);
+ }
+
+ @Test
+ void test_userShouldNotBeBlank(){
+ request.setUser(" ");
+ Set<ConstraintViolation<MicroserviceCreateRequest>> violations = validator.validate(request);
+ Assertions.assertThat(violations.size()).isEqualTo(1);
+ }
+}
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/SpecificationControllerTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/SpecificationControllerTest.java
new file mode 100644
index 0000000..64f9c00
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/SpecificationControllerTest.java
@@ -0,0 +1,79 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web;
+
+import org.onap.dcaegen2.platform.mod.model.specification.DeploymentType;
+import org.onap.dcaegen2.platform.mod.model.restapi.SpecificationRequest;
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.onap.dcaegen2.platform.mod.web.controller.SpecificationController;
+import org.onap.dcaegen2.platform.mod.web.service.specification.SpecificationService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.onap.dcaegen2.platform.mod.objectmothers.BaseMsObjectMother.asJsonString;
+import static org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother.MS_INSTANCE_ID;
+import static org.onap.dcaegen2.platform.mod.objectmothers.SpecificationObjectMother.getMockSpecification;
+import static org.onap.dcaegen2.platform.mod.objectmothers.SpecificationObjectMother.getSpecificationRequest;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@ExtendWith(SpringExtension.class)
+@WebMvcTest(SpecificationController.class)
+public class SpecificationControllerTest {
+
+ @Autowired
+ MockMvc mockMvc;
+
+ @MockBean
+ private SpecificationService mockSpecificationService;
+
+ @BeforeEach
+ void setup() {
+ }
+
+ @Test
+ void test_addSpecification_returnsSpecification() throws Exception {
+ //arrange
+ SpecificationRequest specificationRequest = getSpecificationRequest();
+ Specification specification = getMockSpecification(DeploymentType.DOCKER);
+
+ when(mockSpecificationService.createSpecification(MS_INSTANCE_ID, specificationRequest)).thenReturn(specification);
+
+ //act/assert
+ mockMvc.perform(post("/api/specification/" + MS_INSTANCE_ID)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(asJsonString(specificationRequest)).accept(MediaType.APPLICATION_JSON))
+ .andExpect(jsonPath("$.id", notNullValue()))
+ .andExpect(status().isCreated());
+ verify(mockSpecificationService, times(1)).createSpecification(MS_INSTANCE_ID, specificationRequest);
+ }
+
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsInstanceServiceImplTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsInstanceServiceImplTest.java
new file mode 100644
index 0000000..1d84b60
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsInstanceServiceImplTest.java
@@ -0,0 +1,209 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.MsInstanceInfo;
+import org.onap.dcaegen2.platform.mod.model.exceptions.msinstance.MsInstanceNotFoundException;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.MsInstanceRequest;
+import org.onap.dcaegen2.platform.mod.objectmothers.BaseMsObjectMother;
+import org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother;
+import org.onap.dcaegen2.platform.mod.web.service.basemicroservice.MsService;
+import org.onap.dcaegen2.platform.mod.web.service.deploymentartifact.DeploymentArtifactService;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceGateway;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceServiceImpl;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceStatusChangeHandler;
+import org.onap.dcaegen2.platform.mod.web.service.specification.SpecificationService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import static org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class MsInstanceServiceImplTest {
+
+ @Spy
+ private MsInstanceServiceImpl service = new MsInstanceServiceImpl();
+
+ @Mock
+ private MsInstanceGateway msInstanceRepository;
+
+ @Mock
+ private MsService msService;
+
+ @Mock
+ private SpecificationService specificationService;
+
+ @Mock
+ private DeploymentArtifactService deploymentArtifactService;
+
+ @Mock
+ private MsInstanceStatusChangeHandler msInstanceStatusChangeHandler;
+
+
+ @BeforeEach
+ void setUp() {
+ service.setMsService(msService);
+ service.setSpecificationService(specificationService);
+ service.setDeploymentArtifactService(deploymentArtifactService);
+ service.setMsInstanceRepository(msInstanceRepository);
+ service.setMsInstanceStatusChangeHandler(msInstanceStatusChangeHandler);
+ }
+
+ @Test
+ void getAll() {
+ MsInstance instance_1 = MsInstance.builder().id("123").build();
+ MsInstance instance_2 = MsInstance.builder().id("345").build();
+
+ when(msInstanceRepository.findAll()).thenReturn(Arrays.asList(instance_1, instance_2));
+
+ List<MsInstance> instances = service.getAll();
+
+ assertThat(instances.size()).isEqualTo(2);
+ verify(msInstanceRepository, times(1)).findAll();
+ }
+
+ @Test
+ void test_getMsInstanceById() throws Exception{
+ MsInstance expected = MsInstanceObjectMother.createMsInstance();
+
+ when(msInstanceRepository.findById(MS_INSTANCE_ID)).thenReturn(Optional.of(expected));
+
+ MsInstance original = service.getMsInstanceById(MS_INSTANCE_ID);
+
+ assertThat(original.getId()).isEqualTo(expected.getId());
+ }
+
+ @Test
+ void test_msIntanceNotFound_willRaiseException() throws Exception{
+ when(msInstanceRepository.findById(MS_INSTANCE_ID)).thenReturn(Optional.empty());
+ assertThatExceptionOfType(MsInstanceNotFoundException.class).isThrownBy(
+ () -> service.getMsInstanceById(MS_INSTANCE_ID));
+ }
+
+ //TODO require cleaning and more assertions
+ @Test
+ void createMicroserviceInstance() {
+
+ BaseMicroservice microservice = BaseMsObjectMother.createMockMsObject();
+ MsInstanceRequest request = getMsInstanceMockRequest();
+ MsInstance msInstanceMockDao = createMsInstance();
+
+ when(msService.getMicroserviceByName(BaseMsObjectMother.BASE_MS_NAME)).thenReturn(microservice);
+ when(msInstanceRepository.findByNameAndRelease(request.getName(), request.getRelease()))
+ .thenReturn(Optional.empty());
+ when(msInstanceRepository.save(any())).thenReturn(msInstanceMockDao);
+
+ MsInstance msInstance = service.createMicroserviceInstance(BaseMsObjectMother.BASE_MS_NAME,request);
+
+ assertThat(msInstance.getId()).isEqualTo(msInstance.getId());
+ assertThat(msInstance.getName()).isEqualTo(msInstance.getName());
+ assertThat(msInstance.getMsInfo().keySet()).isEqualTo(msInstanceMockDao.getMsInfo().keySet());
+
+ verify(msService, times(1)).getMicroserviceByName(BaseMsObjectMother.BASE_MS_NAME);
+ verify(msInstanceRepository, times(1)).save(any(MsInstance.class));
+ verify(msService, times(1)).
+ saveMsInstanceReferenceToMs(microservice, msInstance);
+
+ }
+
+ @Test
+ void test_updateMsInstance() {
+
+ }
+
+ @Test
+ void updateStatusBasedOnDeploymentArtifactsStatuses() {
+ MsInstance msInstance = MsInstanceObjectMother.getMsInstanceWithExistingDeploymentArtifactRef();
+ when(msInstanceRepository.findById(msInstance.getId())).thenReturn(Optional.of(msInstance));
+
+ service.updateStatusBasedOnDeploymentArtifactsStatuses(msInstance.getId());
+
+ verify(msInstanceStatusChangeHandler, times(1)).updateStatusBasedOnDeploymentArtifactsStatuses(msInstance);
+ verify(service, times(1)).updateMsInstance(msInstance);
+
+ }
+
+ @Test
+ void test_removeDeploymentArtifactFromMsInstance() {
+ MsInstance msInstance = MsInstanceObjectMother.getMsInstanceWithExistingDeploymentArtifactRef();
+ DeploymentArtifact deploymentArtifact = createDeploymentArtifact(msInstance);
+
+ when(msInstanceRepository.findById(msInstance.getId())).thenReturn(Optional.of(msInstance));
+ //when(msInstanceStatusChangeHandler.updateStatusBasedOnDeploymentArtifactsStatuses(any())).thenReturn(msInstance);
+
+ service.removeDeploymentArtifactFromMsInstance(deploymentArtifact);
+
+ assertThat(msInstance.getDeploymentArtifactsInfo().getDeploymentArtifacts().contains(deploymentArtifact.getId())).isFalse();
+ verify(msInstanceStatusChangeHandler, times(1)).updateStatusBasedOnDeploymentArtifactsStatuses(msInstance);
+ verify(service, times(1)).updateMsInstance(msInstance);
+
+ }
+
+ @Test
+ void updateMicroserviceReference() throws Exception{
+ BaseMicroservice microservice = BaseMsObjectMother.createMockMsObject();
+ MsInstance msInstance_1 = MsInstanceObjectMother.getMsInstanceWithExistingDeploymentArtifactRef();
+ msInstance_1.setId("instance-1");
+ msInstance_1.getMsInfo().put("name", "old-ms");
+ MsInstance msInstance_2 = MsInstanceObjectMother.getMsInstanceWithExistingDeploymentArtifactRef();
+ msInstance_2.setId("instance-2");
+ msInstance_2.getMsInfo().put("name", "old-ms");
+
+ when(msInstanceRepository.findById("instance-1")).thenReturn(Optional.of(msInstance_1));
+ when(msInstanceRepository.findById("instance-2")).thenReturn(Optional.of(msInstance_2));
+
+ service.updateMicroserviceReference(microservice);
+
+ assertThat(msInstance_1.getName()).isEqualTo(microservice.getName());
+ assertThat(msInstance_2.getName()).isEqualTo(microservice.getName());
+
+ assertThat(msInstance_1.getMsInfo().get("name")).isEqualTo(microservice.getName());
+ assertThat(msInstance_2.getMsInfo().get("name")).isEqualTo(microservice.getName());
+
+ verify(service, times(2)).getMsInstanceById(anyString());
+ verify(msInstanceRepository, times(2)).save(any(MsInstance.class));
+ }
+
+ private DeploymentArtifact createDeploymentArtifact(MsInstance msInstance) {
+ DeploymentArtifact deploymentArtifact = new DeploymentArtifact();
+ deploymentArtifact.setId(msInstance.getDeploymentArtifactsInfo().getDeploymentArtifacts().get(0));
+
+ MsInstanceInfo msInstanceInfo = new MsInstanceInfo();
+ msInstanceInfo.setId(msInstance.getId());
+ deploymentArtifact.setMsInstanceInfo(msInstanceInfo);
+ return deploymentArtifact;
+ }
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsInstanceStatusChangeHandlerTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsInstanceStatusChangeHandlerTest.java
new file mode 100644
index 0000000..9339b26
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsInstanceStatusChangeHandlerTest.java
@@ -0,0 +1,92 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service;
+
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstanceStatus;
+import org.onap.dcaegen2.platform.mod.objectmothers.DeploymentArtifactObjectMother;
+import org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother;
+import org.onap.dcaegen2.platform.mod.web.service.deploymentartifact.DeploymentArtifactService;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceService;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceStatusChangeHandler;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class MsInstanceStatusChangeHandlerTest {
+
+ MsInstanceStatusChangeHandler statusChangeHandler;
+
+ @Mock
+ MsInstanceService msInstanceService;
+
+ @Mock
+ DeploymentArtifactService deploymentArtifactService;
+
+ @BeforeEach
+ void setup() throws Exception{
+ statusChangeHandler = new MsInstanceStatusChangeHandler();
+ statusChangeHandler.setMsInstanceService(msInstanceService);
+ statusChangeHandler.setDeploymentArtifactService(deploymentArtifactService);
+ }
+
+ @Test
+ void handleStatusChangeFromDeploymentArtifactsWithDevComplete() {
+ //arrange
+ MsInstance msInstance = MsInstanceObjectMother.getMsInstanceWithExistingDeploymentArtifactRef();
+
+ when(deploymentArtifactService.findByMsInstanceId(msInstance.getId())).thenReturn(
+ DeploymentArtifactObjectMother.createMockDeploymentArtifactsWithDifferentStatuses(true)
+ );
+
+ //act
+ statusChangeHandler.updateStatusBasedOnDeploymentArtifactsStatuses(msInstance);
+
+ //assert
+ assertThat(msInstance.getStatus()).isEqualTo(MsInstanceStatus.DEV_COMPLETE);
+ verify(deploymentArtifactService, times(1)).findByMsInstanceId(msInstance.getId());
+ }
+
+ @Test
+ void handleStatusChangeFromDeploymentArtifactsWithoutDevComplete() {
+ //arrange
+ MsInstance msInstance = MsInstanceObjectMother.getMsInstanceWithExistingDeploymentArtifactRef();
+
+ //when(msInstanceService.getMsInstanceById(msInstance.getId())).thenReturn(msInstance);
+ when(deploymentArtifactService.findByMsInstanceId(msInstance.getId())).thenReturn(
+ DeploymentArtifactObjectMother.createMockDeploymentArtifactsWithDifferentStatuses(false)
+ );
+
+ //act
+ statusChangeHandler.updateStatusBasedOnDeploymentArtifactsStatuses(msInstance);
+
+ //assert
+ assertThat(msInstance.getStatus()).isEqualTo(MsInstanceStatus.IN_DEV);
+ verify(deploymentArtifactService, times(1)).findByMsInstanceId(msInstance.getId());
+ }
+
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsServiceImplTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsServiceImplTest.java
new file mode 100644
index 0000000..8604f1a
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/MsServiceImplTest.java
@@ -0,0 +1,217 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service;
+
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMicroservice;
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsLocation;
+import org.onap.dcaegen2.platform.mod.model.basemicroservice.BaseMsType;
+import org.onap.dcaegen2.platform.mod.model.exceptions.ResourceConflictException;
+import org.onap.dcaegen2.platform.mod.model.exceptions.basemicroservice.BaseMicroserviceNotFoundException;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceCreateRequest;
+import org.onap.dcaegen2.platform.mod.model.restapi.MicroserviceUpdateRequest;
+import org.onap.dcaegen2.platform.mod.objectmothers.BaseMsObjectMother;
+import org.onap.dcaegen2.platform.mod.web.service.basemicroservice.BaseMicroserviceGateway;
+import org.onap.dcaegen2.platform.mod.web.service.basemicroservice.MsServiceImpl;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.*;
+
+import static org.onap.dcaegen2.platform.mod.model.exceptions.ErrorMessages.MICROSERVICE_NAME_CONFLICT_MESSAGE;
+import static org.onap.dcaegen2.platform.mod.model.exceptions.ErrorMessages.MICROSERVICE_TAG_CONFLICT_MESSAGE;
+import static org.onap.dcaegen2.platform.mod.objectmothers.BaseMsObjectMother.createMockMsObject;
+import static org.onap.dcaegen2.platform.mod.objectmothers.BaseMsObjectMother.createMockMsRequest;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class MsServiceImplTest {
+
+ @Mock
+ private BaseMicroserviceGateway repository;
+
+ @Mock
+ private MsInstanceService msInstanceService;
+
+ @Spy
+ private MsServiceImpl baseMsService = new MsServiceImpl();
+
+ @BeforeEach
+ void setup() throws Exception{
+ baseMsService.setRepository(repository);
+ baseMsService.setMsInstanceService(msInstanceService);
+ }
+
+ /**GET MICROSERVICE TESTS*/
+ @Test
+ void getAll() {
+ //arrange
+ BaseMicroservice ms1 = new BaseMicroservice();
+ ms1.setName("HelloWorld1");
+ BaseMicroservice ms2 = new BaseMicroservice();
+ ms2.setName("HelloWorld2");
+
+ when(repository.findAll()).thenReturn(Arrays.asList(ms1, ms2));
+
+ //act
+ List<BaseMicroservice> microservices = baseMsService.getAllMicroservices();
+
+ //assert
+ assertThat(microservices).hasSizeGreaterThan(0);
+ }
+
+ @Test
+ void test_getMicroserviceById() throws Exception{
+ BaseMicroservice expectedMicroservice = BaseMsObjectMother.createMockMsObject();
+ String baseMsId = BaseMsObjectMother.BASE_MS_ID;
+
+ when(repository.findById(baseMsId)).thenReturn(Optional.of(expectedMicroservice));
+
+ BaseMicroservice resultMicroservice = baseMsService.getMicroserviceById(baseMsId);
+
+ assertThat(resultMicroservice).isEqualTo(expectedMicroservice);
+ verify(repository, times(1)).findById(baseMsId);
+ }
+
+ @Test
+ void test_ifMicroserviceNotFoundRaiseException() throws Exception{
+ BaseMicroservice expectedMicroservice = BaseMsObjectMother.createMockMsObject();
+ String baseMsId = BaseMsObjectMother.BASE_MS_ID;
+
+ when(repository.findById(baseMsId)).thenReturn(Optional.empty());
+
+ assertThatExceptionOfType(BaseMicroserviceNotFoundException.class).isThrownBy(
+ () -> baseMsService.getMicroserviceById(baseMsId)
+ );
+ }
+
+ /**CREATE MICROSERVICE TESTS*/
+ @Test
+ void createMicroservice() {
+ //arrange
+ MicroserviceCreateRequest microserviceRequest = createMockMsRequest();
+ BaseMicroservice expected = createMockMsObject();
+
+ when(repository.save(any())).thenReturn(expected);
+
+ //act
+ BaseMicroservice actual = baseMsService.createMicroservice(microserviceRequest);
+
+ //assert
+ assertThat(actual.getMetadata().getCreatedBy()).isEqualTo(microserviceRequest.getUser());
+ assertThat(actual.getMetadata().getUpdatedBy()).isEqualTo(microserviceRequest.getUser());
+ }
+
+ @Test
+ void AddingMsWithDuplicateName_shouldThrowException() throws Exception{
+ //arrange
+ MicroserviceCreateRequest microserviceRequest = createMockMsRequest();
+ BaseMicroservice existedMicroservice = createMockMsObject();
+
+ when(repository.findByName(any())).thenReturn(Optional.of(existedMicroservice));
+
+ //act/assert
+ assertThatThrownBy(() -> baseMsService.createMicroservice((microserviceRequest)))
+ .isInstanceOf(ResourceConflictException.class)
+ .hasMessage(MICROSERVICE_NAME_CONFLICT_MESSAGE);
+ }
+ @Test
+ void AddingMsWithDuplicateTag_shouldThrowException() throws Exception{
+ //arrange
+ MicroserviceCreateRequest microserviceRequest = createMockMsRequest();
+ BaseMicroservice existedMicroservice = createMockMsObject();
+
+ when(repository.findByTag(any())).thenReturn(Optional.of(existedMicroservice));
+
+ //act/assert
+ assertThatThrownBy(() -> baseMsService.createMicroservice((microserviceRequest)))
+ .isInstanceOf(ResourceConflictException.class)
+ .hasMessage(MICROSERVICE_TAG_CONFLICT_MESSAGE);
+ }
+
+ /**UPDATE MICROSERVICE TESTS*/
+ @Test
+ void test_updateMicroservice() throws Exception{
+ MicroserviceUpdateRequest updateRequest = createUpdateMsRequest();
+
+ BaseMicroservice msToBeUpdated = BaseMsObjectMother.createMockMsObject();
+ Date updateTimeBefore = new Date(msToBeUpdated.getMetadata().getUpdatedOn().getTime());
+
+ String baseMsId = BaseMsObjectMother.BASE_MS_ID;
+
+ when(repository.findById(baseMsId)).thenReturn(Optional.of(msToBeUpdated));
+
+ baseMsService.updateMicroservice(baseMsId, updateRequest);
+
+ //assert
+ assertUpdatedMsFileds(updateRequest, msToBeUpdated, updateTimeBefore);
+ verify(baseMsService, times(1)).getMicroserviceById(baseMsId);
+ verify(msInstanceService, times(1)).updateMicroserviceReference(msToBeUpdated);
+ verify(repository, times(1)).save(msToBeUpdated);
+ }
+
+/* @Test
+ void test_msTagChangeShouldNotBeAllowed() throws Exception{
+ MicroserviceCreateRequest updateRequest = new MicroserviceCreateRequest();
+ updateRequest.setTag("updateTag");
+ String baseMsId = BaseMsObjectMother.BASE_MS_ID;
+
+ assertThatExceptionOfType(OperationNotAllowedException.class).isThrownBy(
+ () -> baseMsService.updateMicroservice(baseMsId, updateRequest)
+ );
+ }*/
+
+ private void assertUpdatedMsFileds(MicroserviceUpdateRequest updateRequest, BaseMicroservice msToBeUpdated,
+ Date updateTimeBefore) {
+ assertThat(msToBeUpdated.getName()).isEqualTo(updateRequest.getName());
+ assertThat(msToBeUpdated.getLocation()).isEqualTo(updateRequest.getLocation());
+ assertThat(msToBeUpdated.getServiceName()).isEqualTo(updateRequest.getServiceName());
+ assertThat(msToBeUpdated.getNamespace()).isEqualTo(updateRequest.getNamespace());
+ assertThat(msToBeUpdated.getType()).isEqualTo(updateRequest.getType());
+
+ assertThat(msToBeUpdated.getMetadata().getUpdatedBy()).isEqualTo(updateRequest.getUser());
+ assertThat(msToBeUpdated.getMetadata().getUpdatedOn()).isNotEqualTo(updateTimeBefore);
+
+ assertThat(msToBeUpdated.getMetadata().getNotes()).isEqualTo(updateRequest.getMetadata().get("notes"));
+ assertThat(msToBeUpdated.getMetadata().getLabels()).isEqualTo(updateRequest.getMetadata().get("labels"));
+ }
+
+ private MicroserviceUpdateRequest createUpdateMsRequest() {
+ MicroserviceUpdateRequest updateRequest = new MicroserviceUpdateRequest();
+ updateRequest.setName("updatedName");
+ updateRequest.setLocation(BaseMsLocation.EDGE);
+ updateRequest.setServiceName("updatedServiceName");
+ updateRequest.setNamespace("updatedNameSpace");
+ updateRequest.setType(BaseMsType.ANALYTIC);
+ updateRequest.setUser("updater");
+
+ Map<String, Object> metadata = new HashMap();
+ metadata.put("notes", "updatedNote");
+ metadata.put("labels", Arrays.asList("updatedLabel1", "updatedLabel2"));
+ updateRequest.setMetadata(metadata);
+ return updateRequest;
+ }
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/SpecificationServiceTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/SpecificationServiceTest.java
new file mode 100644
index 0000000..dff0727
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/SpecificationServiceTest.java
@@ -0,0 +1,103 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service;
+
+import org.onap.dcaegen2.platform.mod.model.specification.DeploymentType;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.SpecificationRequest;
+import org.onap.dcaegen2.platform.mod.model.specification.Specification;
+import org.onap.dcaegen2.platform.mod.model.specification.SpecificationStatus;
+import org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceService;
+import org.onap.dcaegen2.platform.mod.web.service.specification.SpecificationGateway;
+import org.onap.dcaegen2.platform.mod.web.service.specification.SpecificationServiceImpl;
+import org.onap.dcaegen2.platform.mod.web.service.specification.SpecificationValidatorService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother.MS_INSTANCE_ID;
+import static org.onap.dcaegen2.platform.mod.objectmothers.SpecificationObjectMother.getMockSpecification;
+import static org.onap.dcaegen2.platform.mod.objectmothers.SpecificationObjectMother.getSpecificationRequest;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ExtendWith({MockitoExtension.class})
+public class SpecificationServiceTest {
+
+ private SpecificationServiceImpl service;
+
+ @Mock
+ private SpecificationGateway specRepo;
+
+ @Mock
+ private MsInstanceService msInstanceService;
+
+ @Mock
+ private SpecificationValidatorService validatorService;
+
+ @BeforeEach
+ void setUp() {
+ service = new SpecificationServiceImpl();
+ service.setMsInstanceService(msInstanceService);
+ service.setSpecificationValidatorService(validatorService);
+ service.setSpecificationGateway(specRepo);
+ }
+
+ @Test
+ void createSpecificationTest() throws Exception {
+ //given
+ SpecificationRequest request = getSpecificationRequest();
+ Specification specFromRepo = getMockSpecification(DeploymentType.K8S);
+ MsInstance msInstance = MsInstanceObjectMother.createMsInstance();
+
+ when(msInstanceService.getMsInstanceById(MS_INSTANCE_ID)).thenReturn(msInstance);
+ when(specRepo.save(any(Specification.class))).thenReturn(specFromRepo);
+
+ //when
+ Specification spec = service.createSpecification(MS_INSTANCE_ID, request);
+
+ //then
+ assertThatFieldsAreCorrect(request, spec);
+ verifyCalls(request, msInstance);
+
+ }
+
+ private void assertThatFieldsAreCorrect(SpecificationRequest request, Specification spec) {
+ assertThat(spec.getStatus()).isEqualTo(SpecificationStatus.ACTIVE);
+ assertThat(spec.getSpecContent()).isEqualTo(request.getSpecContent());
+ assertThat(spec.getPolicyJson()).isEqualTo(request.getPolicyJson());
+ assertThat(spec.getType()).isEqualTo(request.getType());
+ assertThat(spec.getMetadata().get("createdBy")).isEqualTo(request.getUser());
+ assertThat(spec.getMetadata().get("createdOn")).isNotNull();
+ assertThat(spec.getMsInstanceInfo()).isNotNull();
+ }
+
+ private void verifyCalls(SpecificationRequest request, MsInstance msInstance) {
+ verify(msInstanceService, times(1)).getMsInstanceById(MS_INSTANCE_ID);
+ verify(validatorService, times(1)).validateSpecForRelease(request, msInstance.getRelease());
+ verify(specRepo, times(2)).save(any(Specification.class));
+ verify(msInstanceService, times(1)).updateMsInstance(msInstance);
+ }
+}
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/ArtifactFileNameCreatorTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/ArtifactFileNameCreatorTest.java
new file mode 100644
index 0000000..12a7dd2
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/ArtifactFileNameCreatorTest.java
@@ -0,0 +1,89 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.specification.DeploymentType;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.BlueprintFileNameCreateException;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+
+class ArtifactFileNameCreatorTest {
+
+ private ArtifactFileNameCreator fileNameCreator;
+
+ @BeforeEach
+ void setUp() {
+ fileNameCreator = new ArtifactFileNameCreator();
+ }
+
+ @Test
+ void test_createCorrectBlueprintFileName() throws Exception{
+ //arrange
+ MsInstance msInstance = MsInstanceObjectMother.createMsInstance();
+ String expectedName = createExpectedName(msInstance);
+
+ //act
+ String fileName = fileNameCreator.createFileName(msInstance, 1);
+
+ //assert
+ Assertions.assertThat(fileName).isEqualTo(expectedName);
+ }
+
+ @Test
+ void test_missingTagForFileNameCreation_ShouldRaiseException() throws Exception{
+
+ //arrange
+ MsInstance msInstance = MsInstanceObjectMother.createMsInstance();
+ msInstance.setMsInfo(new HashMap<>());
+
+ Assertions.assertThatExceptionOfType(BlueprintFileNameCreateException.class).isThrownBy(
+ () -> fileNameCreator.createFileName(msInstance, 1)
+ );
+ }
+
+ @Test
+ void test_missingSpecForFileNameCreation_ShouldRaiseException() throws Exception{
+
+ //arrange
+ MsInstance msInstance = MsInstanceObjectMother.createMsInstance();
+ msInstance.setActiveSpec(null);
+
+ Assertions.assertThatExceptionOfType(BlueprintFileNameCreateException.class).isThrownBy(
+ () -> fileNameCreator.createFileName(msInstance, 1)
+ );
+ }
+
+
+ private String createExpectedName(MsInstance msInstance) {
+ String fileName = MsInstanceObjectMother.BASE_MS_TAG + "_"
+ + DeploymentType.DOCKER.toString().toLowerCase() + "_"
+ + msInstance.getRelease() + "_"
+ + "1"
+ + ".yaml";
+
+ return fileName;
+ }
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactServiceImplTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactServiceImplTest.java
new file mode 100644
index 0000000..749d8b1
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactServiceImplTest.java
@@ -0,0 +1,250 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.DeploymentArtifactNotFound;
+import org.onap.dcaegen2.platform.mod.model.microserviceinstance.MsInstance;
+import org.onap.dcaegen2.platform.mod.model.restapi.DeploymentArtifactPatchRequest;
+import org.onap.dcaegen2.platform.mod.objectmothers.DeploymentArtifactObjectMother;
+import org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother;
+import org.onap.dcaegen2.platform.mod.web.service.microserviceinstance.MsInstanceService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import static org.onap.dcaegen2.platform.mod.objectmothers.MsInstanceObjectMother.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class DeploymentArtifactServiceImplTest {
+
+ private DeploymentArtifactServiceImpl deploymentArtifactService;
+
+ @Mock
+ private MsInstanceService msInstanceService;
+
+ @Mock
+ private DeploymentArtifactGeneratorStrategy deploymentArtifactGeneratorStrategy;
+
+ @Mock
+ private DeploymentArtifactGateway repository;
+
+ @Mock
+ private ArtifactFileNameCreator fileNameCreator;
+
+ @Mock
+ private DeploymentArtifactStatusChangeHandler deploymentArtifactStatusChangeHandler;
+
+ private MsInstance msInstance;
+
+ DeploymentArtifact deploymentArtifact;
+
+ @BeforeEach
+ void setUp() {
+ //Initiated the deployment artifact core with mocks
+ deploymentArtifactService = new DeploymentArtifactServiceImpl();
+ deploymentArtifactService.setDeploymentArtifactGeneratorStrategy(deploymentArtifactGeneratorStrategy);
+ deploymentArtifactService.setDeploymentArtifactGateway(repository);
+ deploymentArtifactService.setMsInstanceService(msInstanceService);
+ deploymentArtifactService.setFileNameCreator(fileNameCreator);
+ deploymentArtifactService.setStatusChangeHandler(deploymentArtifactStatusChangeHandler);
+ }
+
+ private void setupMockBehaviours() {
+ //Mock methods
+ deploymentArtifact = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+ msInstance = MsInstanceObjectMother.createMsInstance();
+
+ when(deploymentArtifactGeneratorStrategy.generateForRelease(msInstance.getActiveSpec(), msInstance.getRelease()))
+ .thenReturn(DeploymentArtifactObjectMother.createBlueprintResponse());
+ when(repository.save(any())).thenReturn(deploymentArtifact);
+ when(fileNameCreator.createFileName(any(MsInstance.class), any(Integer.class))).thenReturn(BASE_MS_TAG + "_" +
+ msInstance.getActiveSpec().getType().toString().toLowerCase() + "_" + msInstance.getRelease() + "_1.yaml");
+ }
+
+ @Test
+ void test_getAllDeploymentArtifactInstance() throws Exception{
+ when(repository.findAll()).thenReturn(Arrays.asList(deploymentArtifact));
+ List<DeploymentArtifact> deployments = deploymentArtifactService.getAllDeploymentArtifacts();
+ assertThat(deployments.size()).isEqualTo(1);
+ }
+
+ @Test
+ void test_GenerateBlueprint_shouldReturnCorrectBlueprint() throws Exception{
+
+ setupMockBehaviours();
+ when(msInstanceService.getMsInstanceById(MS_INSTANCE_ID)).thenReturn(msInstance);
+
+ //act
+ DeploymentArtifact resultDAO = deploymentArtifactService.generateDeploymentArtifact(MS_INSTANCE_ID, USER);
+
+ //assert
+ verify(msInstanceService, atLeastOnce()).getMsInstanceById(MS_INSTANCE_ID);
+ verify(repository, times(1)).save(any());
+ assertThat(resultDAO.getContent()).contains("tosca_definitions_version");
+ assertThat(resultDAO.getId()).isNotEmpty();
+ assertThat(resultDAO.getVersion()).isEqualTo(1);
+ assertThat(resultDAO.getStatus()).isEqualTo(DeploymentArtifactStatus.IN_DEV);
+ assertThat(resultDAO.getMsInstanceInfo().getId()).isEqualTo(MS_INSTANCE_ID);
+ assertThat(resultDAO.getMsInstanceInfo().getName()).isEqualTo(msInstance.getName());
+ assertThat(resultDAO.getMsInstanceInfo().getRelease()).isEqualTo(msInstance.getRelease());
+ assertThat(resultDAO.getSpecificationInfo().get("id")).isNotNull();
+ assertThat(resultDAO.getMetadata().get("createdBy")).isEqualTo(USER);
+
+ }
+
+ @Test
+ void test_deploymentVersionIsInitatedWith1() throws Exception{
+ setupMockBehaviours();
+ when(msInstanceService.getMsInstanceById(MS_INSTANCE_ID)).thenReturn(msInstance);
+ DeploymentArtifact resultDAO = deploymentArtifactService.generateDeploymentArtifact(MS_INSTANCE_ID, USER);
+ assertThat(resultDAO.getVersion()).isEqualTo(1);
+ }
+
+ @Test
+ void test_deploymentVersionIncrementsForEachAddForAnInstance() throws Exception{
+ setupMockBehaviours();
+ MsInstance msInstanceWithRef = MsInstanceObjectMother.getMsInstanceWithExistingDeploymentArtifactRef();
+ when(msInstanceService.getMsInstanceById(MS_INSTANCE_ID)).thenReturn(msInstanceWithRef);
+
+ DeploymentArtifact resultDAO = deploymentArtifactService.generateDeploymentArtifact(MS_INSTANCE_ID, USER);
+
+ assertThat(resultDAO.getVersion()).isEqualTo(2);
+ }
+
+ @Test
+ void test_deploymentArtifactRefAddedToMsInstanceForFirstTime() throws Exception{
+ setupMockBehaviours();
+ when(msInstanceService.getMsInstanceById(MS_INSTANCE_ID)).thenReturn(msInstance);
+
+ DeploymentArtifact resultDAO = deploymentArtifactService.generateDeploymentArtifact(MS_INSTANCE_ID, USER);
+ assertThat(msInstance.getDeploymentArtifactsInfo().getMostRecentVersion()).isEqualTo(1);
+
+ List<String> deploymentArtifactList = msInstance.getDeploymentArtifactsInfo().getDeploymentArtifacts();
+ assertThat(deploymentArtifactList.size()).isEqualTo(1);
+ assertThat(deploymentArtifactList.get(0)).isEqualTo(resultDAO.getId());
+ }
+
+ @Test
+ void test_deploymentArtifactRefAddedToMsInstanceForSecondTime() throws Exception{
+ setupMockBehaviours();
+ MsInstance msInstanceWithRef = MsInstanceObjectMother.getMsInstanceWithExistingDeploymentArtifactRef();
+ when(msInstanceService.getMsInstanceById(MS_INSTANCE_ID)).thenReturn(msInstanceWithRef);
+
+ DeploymentArtifact resultDAO = deploymentArtifactService.generateDeploymentArtifact(MS_INSTANCE_ID, USER);
+ assertThat(msInstanceWithRef.getDeploymentArtifactsInfo().getMostRecentVersion()).isEqualTo(2);
+
+ List<String> deploymentArtifactList = msInstanceWithRef.getDeploymentArtifactsInfo().getDeploymentArtifacts();
+ assertThat(deploymentArtifactList.size()).isEqualTo(2);
+ assertThat(deploymentArtifactList.get(1)).isEqualTo(resultDAO.getId());
+ }
+
+ @Test
+ void test_ifMsInstanceIsPersistedAfterDeploymentArtifactCreation() throws Exception{
+ setupMockBehaviours();
+ when(msInstanceService.getMsInstanceById(MS_INSTANCE_ID)).thenReturn(msInstance);
+ deploymentArtifactService.generateDeploymentArtifact(MS_INSTANCE_ID, USER);
+ verify(msInstanceService, times(1)).updateMsInstance(msInstance);
+ }
+
+ @Test
+ void test_blueprintFileNameValidation() throws Exception{
+ setupMockBehaviours();
+ when(msInstanceService.getMsInstanceById(MS_INSTANCE_ID)).thenReturn(msInstance);
+ DeploymentArtifact resultDAO = deploymentArtifactService.generateDeploymentArtifact(MS_INSTANCE_ID, USER);
+ System.out.println(resultDAO.getFileName());
+ assertThat(resultDAO.getFileName().contains(BASE_MS_TAG)).isTrue();
+ }
+
+ @Test
+ void test_updateStatusForDeploymentArtifact() throws Exception{
+ //arrange
+ deploymentArtifact = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+
+ DeploymentArtifactPatchRequest dtoWithStatus = new DeploymentArtifactPatchRequest();
+ dtoWithStatus.setStatus(DeploymentArtifactStatus.NOT_NEEDED);
+
+ when(repository.findById("id-123")).thenReturn(Optional.of(deploymentArtifact));
+
+ //Mocking void method from DeploymentArtifactStatusChangeHandler
+ doAnswer(invocation -> {
+ deploymentArtifact.setStatus(DeploymentArtifactStatus.NOT_NEEDED);
+ return null;
+ }).when(deploymentArtifactStatusChangeHandler).handleStatusChange(dtoWithStatus.getStatus(), deploymentArtifact);
+
+ //act
+ deploymentArtifactService.updateDeploymentArtifact("id-123", dtoWithStatus, "user1");
+
+ //assert
+ assertThat(deploymentArtifact.getStatus()).isEqualTo(DeploymentArtifactStatus.NOT_NEEDED);
+ assertThat(deploymentArtifact.getMetadata().get("updatedBy")).isEqualTo("user1");
+ assertThat(deploymentArtifact.getMetadata().get("updatedOn")).isNotNull();
+
+ verify(deploymentArtifactStatusChangeHandler, times(1)).handleStatusChange(dtoWithStatus.getStatus(),
+ deploymentArtifact);
+ verify(msInstanceService, times(1)).
+ updateStatusBasedOnDeploymentArtifactsStatuses(deploymentArtifact.getMsInstanceInfo().getId());
+ verify(repository, times(1)).save(deploymentArtifact);
+ }
+
+ @Test
+ void test_findDeploymentArtifactById() throws Exception{
+ //arrange
+ deploymentArtifact = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+ when(repository.findById("id-123")).thenReturn(Optional.of(deploymentArtifact));
+
+ DeploymentArtifact result = deploymentArtifactService.findDeploymentArtifactById("id-123");
+
+ assertThat(result).isEqualTo(deploymentArtifact);
+ }
+
+ @Test
+ void test_findByIdWithInvalidId() throws Exception{
+ when(repository.findById("invalid-id")).thenReturn(Optional.empty());
+ assertThatExceptionOfType(DeploymentArtifactNotFound.class).isThrownBy(
+ () -> deploymentArtifactService.findDeploymentArtifactById("invalid-id"));
+ }
+
+ @Test
+ void test_deleteDeploymentArtifact() throws Exception{
+ DeploymentArtifact deploymentArtifact =
+ DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+ String id = deploymentArtifact.getId();
+
+ when(repository.findById(id)).thenReturn(Optional.of(deploymentArtifact));
+
+ deploymentArtifactService.deleteDeploymentArtifact(id);
+ verify(msInstanceService, times(1))
+ .removeDeploymentArtifactFromMsInstance(deploymentArtifact);
+ verify(repository, times(1)).deleteById(id);
+ }
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactStatusChangeHandlerTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactStatusChangeHandlerTest.java
new file mode 100644
index 0000000..5e9acfa
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/DeploymentArtifactStatusChangeHandlerTest.java
@@ -0,0 +1,106 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.model.exceptions.deploymentartifact.StatusChangeNotValidException;
+import org.onap.dcaegen2.platform.mod.objectmothers.DeploymentArtifactObjectMother;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class DeploymentArtifactStatusChangeHandlerTest {
+
+ DeploymentArtifactStatusChangeHandler artifactStatusChangeHandler;
+
+ @Mock
+ DeploymentArtifactService deploymentArtifactService;
+
+ @BeforeEach
+ void setUp() {
+ artifactStatusChangeHandler = new DeploymentArtifactStatusChangeHandler();
+ artifactStatusChangeHandler.setDeploymentArtifactService(deploymentArtifactService);
+ }
+
+ @Test
+ void test_DevCompleteToNotNeeded() throws Exception{
+ //arrange
+ List<DeploymentArtifact> mockDeploymentArticats = DeploymentArtifactObjectMother.createMockDeploymentArtifactsWithDifferentStatuses(true);
+ DeploymentArtifact givenDAO = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.DEV_COMPLETE);
+ String msInstaneId = givenDAO.getMsInstanceInfo().getId();
+
+ when(deploymentArtifactService.findByMsInstanceId(msInstaneId)).thenReturn(mockDeploymentArticats);
+
+ //act
+ artifactStatusChangeHandler.handleStatusChange(DeploymentArtifactStatus.NOT_NEEDED, givenDAO);
+
+ assertThat(givenDAO.getStatus()).isEqualTo(DeploymentArtifactStatus.NOT_NEEDED);
+// verify(msInstanceStatusChangeHandler, times(1))
+// .updateStatusBasedOnDeploymentArtifactsStatuses(msInstaneId);
+
+ }
+
+ @Test
+ void test_ValidateIfArtifactWithDevCompleteStatusNotFoundForTheSameInstance() throws Exception{
+ //arrange
+ DeploymentArtifact givenDAO = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+ String msInstaneId = givenDAO.getMsInstanceInfo().getId();
+
+ List<DeploymentArtifact> mockDeploymentArticats = DeploymentArtifactObjectMother.createMockDeploymentArtifactsWithDifferentStatuses(false);
+ when(deploymentArtifactService.findByMsInstanceId(msInstaneId)).thenReturn(mockDeploymentArticats);
+
+ //act
+ artifactStatusChangeHandler.handleStatusChange(DeploymentArtifactStatus.DEV_COMPLETE, givenDAO);
+
+ //assert
+ assertThat(givenDAO.getStatus()).isEqualTo(DeploymentArtifactStatus.DEV_COMPLETE);
+ verify(deploymentArtifactService, times(1)).
+ findByMsInstanceId(givenDAO.getMsInstanceInfo().getId());
+// verify(msInstanceStatusChangeHandler, times(1))
+// .updateStatusBasedOnDeploymentArtifactsStatuses(msInstaneId);
+
+ }
+
+ @Test
+ void DoesntValidateIfArtifactWithDevCompleteStatusAlreadyExistsForTheSameInstance() throws Exception{
+ //arrange
+ DeploymentArtifact givenDAO = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+ List<DeploymentArtifact> mockDeploymentArticats = DeploymentArtifactObjectMother.createMockDeploymentArtifactsWithDifferentStatuses(true);
+ when(deploymentArtifactService.findByMsInstanceId("id-123")).thenReturn(mockDeploymentArticats);
+
+ //act/assert
+ assertThatExceptionOfType(StatusChangeNotValidException.class).isThrownBy(
+ () -> artifactStatusChangeHandler.handleStatusChange(DeploymentArtifactStatus.DEV_COMPLETE, givenDAO)
+ );
+
+ }
+
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/SearchDeploymentArtifactsTest.java b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/SearchDeploymentArtifactsTest.java
new file mode 100644
index 0000000..bc1a3a0
--- /dev/null
+++ b/mod2/catalog-service/src/test/java/org/onap/dcaegen2/platform/mod/web/service/deploymentartifact/SearchDeploymentArtifactsTest.java
@@ -0,0 +1,90 @@
+/*
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcaegen2.platform.mod.web.service.deploymentartifact;
+
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifact;
+import org.onap.dcaegen2.platform.mod.model.deploymentartifact.DeploymentArtifactStatus;
+import org.onap.dcaegen2.platform.mod.objectmothers.DeploymentArtifactObjectMother;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+public class SearchDeploymentArtifactsTest {
+
+ private DeploymentArtifactServiceImpl service;
+
+ @Mock
+ private DeploymentArtifactGateway repository;
+
+ private DeploymentArtifact artifact_1;
+ private DeploymentArtifact artifact_2;
+ private DeploymentArtifact artifact_3;
+
+ @BeforeEach
+ void setUp() {
+ service = new DeploymentArtifactServiceImpl();
+ service.setDeploymentArtifactGateway(repository);
+
+ //given
+ artifact_1 = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.IN_DEV);
+ artifact_1.getMsInstanceInfo().setRelease("2008");
+ artifact_2 = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.DEV_COMPLETE);
+ artifact_2.getMsInstanceInfo().setRelease("2010");
+ artifact_3 = DeploymentArtifactObjectMother.createDeploymentArtifactDAO(DeploymentArtifactStatus.DEV_COMPLETE);
+ artifact_3.getMsInstanceInfo().setRelease("2008");
+
+ }
+
+// @Test
+// void findArtifacts_filteredWithRelease() throws Exception {
+// List<DeploymentArtifact> artifacts = Arrays.asList(artifact_1, artifact_3);
+// when(repository.findByReleaseOrStatusOfMsInstance("2008", null)).thenReturn(artifacts);
+//
+// //when
+// DeploymentArtifactSearch search = new DeploymentArtifactSearch();
+// DeploymentArtifactFilter filter = new DeploymentArtifactFilter();
+// filter.setRelease("2008");
+// search.setFilter(filter);
+//
+// List<DeploymentArtifact> result = core.searchDeploymentArtifacts(search);
+//
+// //assert
+// assertThat(result.size()).isEqualTo(2);
+// }
+//
+// @Test
+// void findArtifacts_filteredWithStatus() throws Exception{
+// List<DeploymentArtifact> artifacts = Arrays.asList(artifact_2, artifact_3);
+// when(repository.findByReleaseOrStatusOfMsInstance(null, DeploymentArtifactStatus.DEV_COMPLETE))
+// .thenReturn(artifacts);
+//
+// DeploymentArtifactSearch search = new DeploymentArtifactSearch();
+// DeploymentArtifactFilter filter = new DeploymentArtifactFilter();
+// filter.setStatus(DeploymentArtifactStatus.DEV_COMPLETE);
+// search.setFilter(filter);
+//
+// List<DeploymentArtifact> result = core.searchDeploymentArtifacts(search);
+// assertThat(result.size()).isEqualTo(2);
+//
+// }
+}
diff --git a/mod2/catalog-service/src/test/resources/application.properties b/mod2/catalog-service/src/test/resources/application.properties
new file mode 100644
index 0000000..d6a913c
--- /dev/null
+++ b/mod2/catalog-service/src/test/resources/application.properties
@@ -0,0 +1 @@
+#spring.data.mongodb.port=0 \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/resources/http/requests/CreateSpecificationRequest.json b/mod2/catalog-service/src/test/resources/http/requests/CreateSpecificationRequest.json
new file mode 100644
index 0000000..a0465d8
--- /dev/null
+++ b/mod2/catalog-service/src/test/resources/http/requests/CreateSpecificationRequest.json
@@ -0,0 +1,180 @@
+{
+ "specContent": {
+ "self": {
+ "component_type": "docker",
+ "description": "Hello World mS for subscribing the data from local DMaaP, DR or MR, processing them and publishing them as PM files to local DMaaP DR",
+ "name": "dcae-collectors-vcc-helloworld-pm",
+ "version": "1.0.1"
+ },
+ "services": {
+ "calls": [],
+ "provides": []
+ },
+ "streams": {
+ "publishes": [
+ {
+ "config_key": "DCAE-HELLO-WORLD-PUB-DR",
+ "format": "dataformat_Hello_World_PM",
+ "type": "data_router",
+ "version": "1.0.0"
+ },
+ {
+ "config_key": "DCAE-HELLO-WORLD-PUB-MR",
+ "format": "dataformat_Hello_World_PM",
+ "type": "message_router",
+ "version": "1.0.0"
+ }
+ ],
+ "subscribes": [
+ {
+ "config_key": "DCAE-HELLO-WORLD-SUB-MR",
+ "format": "dataformat_Hello_World_PM",
+ "route": "/DCAE_HELLO_WORLD_SUB_MR",
+ "type": "message_router",
+ "version": "1.0.0"
+ },
+ {
+ "config_key": "DCAE-HELLO-WORLD-SUB-DR",
+ "format": "dataformat_Hello_World_PM",
+ "route": "/DCAE-HELLO-WORLD-SUB-DR",
+ "type": "data_router",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ "parameters": [
+ {
+ "name": "vcc_hello_name",
+ "value": "120",
+ "type": "integer",
+ "description": "the name entered for specific person",
+ "sourced_at_deployment": false,
+ "designer_editable": false,
+ "policy_editable": false
+ },
+ {
+ "name": "useDtiConfig",
+ "value": false,
+ "type": "boolean",
+ "description": "component depends on configuration from dti.",
+ "sourced_at_deployment": false,
+ "designer_editable": true,
+ "policy_editable": false,
+ "required": true
+ },
+ {
+ "name": "isSelfServeComponent",
+ "value": false,
+ "type": "boolean",
+ "description": "Is this used as self serve component.",
+ "sourced_at_deployment": false,
+ "designer_editable": true,
+ "policy_editable": false,
+ "required": true
+ }
+ ],
+ "auxilary": {
+ "healthcheck": {
+ "interval": "60s",
+ "initialDelaySeconds": "120s",
+ "timeout": "20s",
+ "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh",
+ "type": "docker"
+ },
+ "livehealthcheck": {
+ "interval": "60s",
+ "initialDelaySeconds": "120s",
+ "timeout": "20s",
+ "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh",
+ "type": "docker"
+ },
+ "reconfigs": {
+ "app_reconfig": "abc"
+ },
+ "volumes": [
+ {
+ "container": {
+ "bind": "/opt/app/dcae-certificate"
+ },
+ "host": {
+ "path": "/opt/app/dcae-certificate"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/logs/DCAE/dmd/AGENT"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/dmd/AGENT"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/logs/DCAE/dmd/WATCHER"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/dmd/WATCHER"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/app/vcc/logs/DCAE"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/vcc-logs"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/app/vcc/archive/data"
+ },
+ "host": {
+ "path": "/opt/data/DCAE/helloworldpm/vcc-archive"
+ }
+ }
+ ]
+ },
+ "artifacts": [
+ {
+ "type": "docker image",
+ "uri": "dockercentral.it.att.com:5100/com.att.sample/dcae-controller-vcc-helloworld-pm:18.02-001"
+ }
+ ]
+ },
+ "policyJson": {
+ "policies": [
+ {
+ "configAttributes": "",
+ "configName": "",
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_",
+ "unique": false
+ },
+ {
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_",
+ "unique": true
+ },
+ {
+ "configAttributes": "",
+ "configName": "",
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_*",
+ "unique": false
+ }
+ ],
+ "policy": [
+ {
+ "policy_id": "id_0"
+ }
+ ]
+ },
+ "type": "K8S",
+ "user": "abc123",
+ "metadata": {
+ "notes": "Sample 812-1",
+ "labels": [
+ "LATEST"
+ ]
+ }
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/resources/http/requests/CreateSpecificationResponse.json b/mod2/catalog-service/src/test/resources/http/requests/CreateSpecificationResponse.json
new file mode 100644
index 0000000..3cb6dcf
--- /dev/null
+++ b/mod2/catalog-service/src/test/resources/http/requests/CreateSpecificationResponse.json
@@ -0,0 +1,188 @@
+{
+ "id": "5f3417a26aef7f07bc91350a",
+ "status": "ACTIVE",
+ "specContent": {
+ "self": {
+ "component_type": "docker",
+ "description": "Hello World mS for subscribing the data from local DMaaP, DR or MR, processing them and publishing them as PM files to local DMaaP DR",
+ "name": "dcae-collectors-vcc-helloworld-pm",
+ "version": "1.0.1"
+ },
+ "services": {
+ "calls": [],
+ "provides": []
+ },
+ "streams": {
+ "publishes": [
+ {
+ "config_key": "DCAE-HELLO-WORLD-PUB-DR",
+ "format": "dataformat_Hello_World_PM",
+ "type": "data_router",
+ "version": "1.0.0"
+ },
+ {
+ "config_key": "DCAE-HELLO-WORLD-PUB-MR",
+ "format": "dataformat_Hello_World_PM",
+ "type": "message_router",
+ "version": "1.0.0"
+ }
+ ],
+ "subscribes": [
+ {
+ "config_key": "DCAE-HELLO-WORLD-SUB-MR",
+ "format": "dataformat_Hello_World_PM",
+ "route": "/DCAE_HELLO_WORLD_SUB_MR",
+ "type": "message_router",
+ "version": "1.0.0"
+ },
+ {
+ "config_key": "DCAE-HELLO-WORLD-SUB-DR",
+ "format": "dataformat_Hello_World_PM",
+ "route": "/DCAE-HELLO-WORLD-SUB-DR",
+ "type": "data_router",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ "parameters": [
+ {
+ "name": "vcc_hello_name",
+ "value": "120",
+ "type": "integer",
+ "description": "the name entered for specific person",
+ "sourced_at_deployment": false,
+ "designer_editable": false,
+ "policy_editable": false
+ },
+ {
+ "name": "useDtiConfig",
+ "value": false,
+ "type": "boolean",
+ "description": "component depends on configuration from dti.",
+ "sourced_at_deployment": false,
+ "designer_editable": true,
+ "policy_editable": false,
+ "required": true
+ },
+ {
+ "name": "isSelfServeComponent",
+ "value": false,
+ "type": "boolean",
+ "description": "Is this used as self serve component.",
+ "sourced_at_deployment": false,
+ "designer_editable": true,
+ "policy_editable": false,
+ "required": true
+ }
+ ],
+ "auxilary": {
+ "healthcheck": {
+ "interval": "60s",
+ "initialDelaySeconds": "120s",
+ "timeout": "20s",
+ "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh",
+ "type": "docker"
+ },
+ "livehealthcheck": {
+ "interval": "60s",
+ "initialDelaySeconds": "120s",
+ "timeout": "20s",
+ "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh",
+ "type": "docker"
+ },
+ "reconfigs": {
+ "app_reconfig": "abc"
+ },
+ "volumes": [
+ {
+ "container": {
+ "bind": "/opt/app/dcae-certificate"
+ },
+ "host": {
+ "path": "/opt/app/dcae-certificate"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/logs/DCAE/dmd/AGENT"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/dmd/AGENT"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/logs/DCAE/dmd/WATCHER"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/dmd/WATCHER"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/app/vcc/logs/DCAE"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/vcc-logs"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/app/vcc/archive/data"
+ },
+ "host": {
+ "path": "/opt/data/DCAE/helloworldpm/vcc-archive"
+ }
+ }
+ ]
+ },
+ "artifacts": [
+ {
+ "type": "docker image",
+ "uri": "dockercentral.it.att.com:5100/com.att.sample/dcae-controller-vcc-helloworld-pm:18.02-001"
+ }
+ ]
+ },
+ "policyJson": {
+ "policies": [
+ {
+ "configAttributes": "",
+ "configName": "",
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_",
+ "unique": false
+ },
+ {
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_",
+ "unique": true
+ },
+ {
+ "configAttributes": "",
+ "configName": "",
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_*",
+ "unique": false
+ }
+ ],
+ "policy": [
+ {
+ "policy_id": "id_0"
+ }
+ ]
+ },
+ "type": "K8S",
+ "metadata": {
+ "notes": "Sample 812-1",
+ "labels": [
+ "LATEST"
+ ],
+ "createdBy": "abc123",
+ "createdOn": "2020-08-12T16:24:02.621+0000"
+ },
+ "msInstanceInfo": {
+ "release": "2006",
+ "name": "hello-804",
+ "id": "5f1592ffb551b604628316b0"
+ }
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json b/mod2/catalog-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json
new file mode 100644
index 0000000..0ad6b6e
--- /dev/null
+++ b/mod2/catalog-service/src/test/resources/specification/componentSpec_hello_world-with-dmaap.json
@@ -0,0 +1,149 @@
+{
+ "self": {
+ "component_type": "docker",
+ "description": "Hello World mS for subscribing the data from local DMaaP, DR or MR, processing them and publishing them as PM files to local DMaaP DR",
+ "name": "dcae-collectors-vcc-helloworld-pm",
+ "version": "1.0.1"
+ },
+
+ "services": {
+ "calls": [],
+ "provides": []
+ },
+
+ "streams": {
+ "publishes": [{
+ "config_key": "DCAE-HELLO-WORLD-PUB-DR",
+ "format": "dataformat_Hello_World_PM",
+ "type": "data_router",
+ "version": "1.0.0"
+ },
+ {
+ "config_key": "DCAE-HELLO-WORLD-PUB-MR",
+ "format": "dataformat_Hello_World_PM",
+ "type": "message_router",
+ "version": "1.0.0"
+ }
+ ],
+
+ "subscribes": [{
+ "config_key": "DCAE-HELLO-WORLD-SUB-MR",
+ "format": "dataformat_Hello_World_PM",
+ "route": "/DCAE_HELLO_WORLD_SUB_MR",
+ "type": "message_router",
+ "version": "1.0.0"
+ },
+ {
+ "config_key": "DCAE-HELLO-WORLD-SUB-DR",
+ "format": "dataformat_Hello_World_PM",
+ "route": "/DCAE-HELLO-WORLD-SUB-DR",
+ "type": "data_router",
+ "version": "1.0.0"
+ }
+ ]
+ },
+
+ "parameters":
+ [
+ {
+ "name": "vcc_hello_name",
+ "value": "120",
+ "type": "integer",
+ "description": "the name entered for specific person",
+ "sourced_at_deployment": false,
+ "designer_editable": false,
+ "policy_editable": false
+ },
+
+ {
+ "name": "useDtiConfig",
+ "value": false,
+ "type" : "boolean",
+ "description": "component depends on configuration from dti.",
+ "sourced_at_deployment": false,
+ "designer_editable": true,
+ "policy_editable": false,
+ "required" : true
+ },
+
+ {
+ "name": "isSelfServeComponent",
+ "value": false,
+ "type": "boolean",
+ "description": "Is this used as self serve component.",
+ "sourced_at_deployment": false,
+ "designer_editable": true,
+ "policy_editable": false,
+ "required" : true
+ }
+ ],
+
+ "auxilary": {
+ "healthcheck": {
+ "interval": "60s",
+ "initialDelaySeconds": "120s",
+ "timeout": "20s",
+ "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh",
+ "type": "docker"
+ },
+ "livehealthcheck": {
+ "interval": "60s",
+ "initialDelaySeconds": "120s",
+ "timeout": "20s",
+ "script": "/opt/app/vcc/bin/common/HealthCheck_HelloWorld.sh",
+ "type": "docker"
+ },
+ "reconfigs":{
+ "app_reconfig" : "abc"
+ },
+
+ "volumes": [
+ {
+ "container": {
+ "bind": "/opt/app/dcae-certificate"
+ },
+ "host": {
+ "path": "/opt/app/dcae-certificate"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/logs/DCAE/dmd/AGENT"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/dmd/AGENT"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/logs/DCAE/dmd/WATCHER"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/dmd/WATCHER"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/app/vcc/logs/DCAE"
+ },
+ "host": {
+ "path": "/opt/logs/DCAE/helloworldpm/vcc-logs"
+ }
+ },
+ {
+ "container": {
+ "bind": "/opt/app/vcc/archive/data"
+ },
+ "host": {
+ "path": "/opt/data/DCAE/helloworldpm/vcc-archive"
+ }
+ }
+
+ ]
+
+ },
+ "artifacts": [{
+ "type": "docker image",
+ "uri": "dockercentral.it.att.com:5100/com.att.sample/dcae-controller-vcc-helloworld-pm:18.02-001"
+ }]
+} \ No newline at end of file
diff --git a/mod2/catalog-service/src/test/resources/specification/policy_json_sample_3.json b/mod2/catalog-service/src/test/resources/specification/policy_json_sample_3.json
new file mode 100644
index 0000000..4a8c76f
--- /dev/null
+++ b/mod2/catalog-service/src/test/resources/specification/policy_json_sample_3.json
@@ -0,0 +1,28 @@
+{
+ "policies": [
+ {
+ "configAttributes": "",
+ "configName": "",
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_",
+ "unique": false
+ },
+ {
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_",
+ "unique": true
+ },
+ {
+ "configAttributes": "",
+ "configName": "",
+ "onapName": "DCAE",
+ "policyName": "DCAE.Config_*",
+ "unique": false
+ }
+ ],
+ "policy": [
+ {
+ "policy_id" : "id_0"
+ }
+ ]
+} \ No newline at end of file
diff --git a/mod2/ui/.editorconfig b/mod2/ui/.editorconfig
new file mode 100644
index 0000000..e89330a
--- /dev/null
+++ b/mod2/ui/.editorconfig
@@ -0,0 +1,13 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/mod2/ui/.gitignore b/mod2/ui/.gitignore
new file mode 100644
index 0000000..f4f46a5
--- /dev/null
+++ b/mod2/ui/.gitignore
@@ -0,0 +1,46 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# compiled output
+/dist
+/tmp
+/out-tsc
+# Only exists if Bazel was run
+/bazel-out
+
+# dependencies
+/node_modules
+
+# profiling files
+chrome-profiler-events.json
+speed-measure-plugin.json
+
+# IDEs and editors
+/.idea
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# IDE - VSCode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+
+# misc
+/.sass-cache
+/connect.lock
+/coverage
+/libpeerconnection.log
+npm-debug.log
+yarn-error.log
+testem.log
+/typings
+
+# System Files
+.DS_Store
+Thumbs.db
diff --git a/mod2/ui/Dockerfile b/mod2/ui/Dockerfile
new file mode 100644
index 0000000..67744d4
--- /dev/null
+++ b/mod2/ui/Dockerfile
@@ -0,0 +1,26 @@
+# ---- Base Node ----
+FROM alpine:12.4.0 AS base
+
+#RUN fs.inotify.max_user_watches=524288
+
+WORKDIR /app
+
+#run in prod mode
+# RUN ng build --prod
+
+# copy project file
+COPY . .
+
+#to make healthcheck executable
+RUN chmod +x healthcheck.sh
+
+# COPY package.json /app
+RUN npm install -g @angular/cli@8.0.6
+
+#to install all dev dependencies explicitly
+RUN npm i --only=dev
+RUN npm install --save-dev @angular-devkit/build-angular
+
+# RUN npm run build --prod
+EXPOSE 4200
+CMD ng serve --host 0.0.0.0 --disableHostCheck --proxy-config proxy.conf.json
diff --git a/mod2/ui/Jenkinsfile b/mod2/ui/Jenkinsfile
new file mode 100644
index 0000000..d51287f
--- /dev/null
+++ b/mod2/ui/Jenkinsfile
@@ -0,0 +1,3 @@
+// @Library('common@develop') _
+
+pythonPipeline() \ No newline at end of file
diff --git a/mod2/ui/README.md b/mod2/ui/README.md
new file mode 100644
index 0000000..e08fb38
--- /dev/null
+++ b/mod2/ui/README.md
@@ -0,0 +1,27 @@
+# DcaeModFe
+
+This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.1.
+
+## Development server
+
+Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
+
+## Code scaffolding
+
+Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
+
+## Build
+
+Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
+
+## Running unit tests
+
+Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
+
+## Running end-to-end tests
+
+Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
+
+## Further help
+
+To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
diff --git a/mod2/ui/angular.json b/mod2/ui/angular.json
new file mode 100644
index 0000000..48a973b
--- /dev/null
+++ b/mod2/ui/angular.json
@@ -0,0 +1,128 @@
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "projects",
+ "projects": {
+ "dcae-mod-fe": {
+ "projectType": "application",
+ "schematics": {},
+ "root": "",
+ "sourceRoot": "src",
+ "prefix": "app",
+ "architect": {
+ "build": {
+ "builder": "@angular-builders/custom-webpack:browser",
+ "options": {
+ "customWebpackConfig": {
+ "path": "extra-webpack.config.js"
+ },
+ "outputPath": "dist/dcae-mod-fe",
+ "index": "src/index.html",
+ "main": "src/main.ts",
+ "polyfills": "src/polyfills.ts",
+ "tsConfig": "tsconfig.app.json",
+ "assets": [
+ "src/favicon.ico",
+ "src/assets"
+ ],
+ "styles": [
+ "./node_modules/@angular/material/prebuilt-themes/purple-green.css",
+ "src/styles.css",
+ "./node_modules/primeng/resources/primeng.min.css",
+ "./node_modules/primeng/resources/themes/nova-light/theme.css",
+ "./node_modules/primeicons/primeicons.css"
+ ],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "fileReplacements": [
+ {
+ "replace": "src/environments/environment.ts",
+ "with": "src/environments/environment.prod.ts"
+ }
+ ],
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": false,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "2mb",
+ "maximumError": "5mb"
+ }
+ ]
+ }
+ }
+ },
+ "serve": {
+ "builder": "@angular-builders/custom-webpack:dev-server",
+ "options": {
+ "browserTarget": "dcae-mod-fe:build"
+ },
+ "configurations": {
+ "production": {
+ "browserTarget": "dcae-mod-fe:build:production"
+ }
+ }
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "dcae-mod-fe:build"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "src/test.ts",
+ "polyfills": "src/polyfills.ts",
+ "tsConfig": "tsconfig.spec.json",
+ "karmaConfig": "karma.conf.js",
+ "assets": [
+ "src/favicon.ico",
+ "src/assets"
+ ],
+ "styles": [
+ "./node_modules/@angular/material/prebuilt-themes/purple-green.css",
+ "src/styles.css"
+ ],
+ "scripts": []
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "tsconfig.app.json",
+ "tsconfig.spec.json",
+ "e2e/tsconfig.json"
+ ],
+ "exclude": [
+ "**/node_modules/**"
+ ]
+ }
+ },
+ "e2e": {
+ "builder": "@angular-devkit/build-angular:protractor",
+ "options": {
+ "protractorConfig": "e2e/protractor.conf.js",
+ "devServerTarget": "dcae-mod-fe:serve"
+ },
+ "configurations": {
+ "production": {
+ "devServerTarget": "dcae-mod-fe:serve:production"
+ }
+ }
+ }
+ }
+ }
+ },
+ "defaultProject": "dcae-mod-fe"
+} \ No newline at end of file
diff --git a/mod2/ui/browserslist b/mod2/ui/browserslist
new file mode 100644
index 0000000..8084853
--- /dev/null
+++ b/mod2/ui/browserslist
@@ -0,0 +1,12 @@
+# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+
+# You can see what browsers were selected by your queries by running:
+# npx browserslist
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file
diff --git a/mod2/ui/dependenciesFile b/mod2/ui/dependenciesFile
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mod2/ui/dependenciesFile
diff --git a/mod2/ui/e2e/protractor.conf.js b/mod2/ui/e2e/protractor.conf.js
new file mode 100644
index 0000000..ff9b518
--- /dev/null
+++ b/mod2/ui/e2e/protractor.conf.js
@@ -0,0 +1,50 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+// @ts-check
+// Protractor configuration file, see link for more information
+// https://github.com/angular/protractor/blob/master/lib/config.ts
+
+const { SpecReporter } = require('jasmine-spec-reporter');
+
+/**
+ * @type { import("protractor").Config }
+ */
+exports.config = {
+ allScriptsTimeout: 11000,
+ specs: [
+ './src/**/*.e2e-spec.ts'
+ ],
+ capabilities: {
+ 'browserName': 'chrome'
+ },
+ directConnect: true,
+ baseUrl: 'http://localhost:4200/',
+ framework: 'jasmine',
+ jasmineNodeOpts: {
+ showColors: true,
+ defaultTimeoutInterval: 30000,
+ print: function() {}
+ },
+ onPrepare() {
+ require('ts-node').register({
+ project: require('path').join(__dirname, './tsconfig.json')
+ });
+ jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
+ }
+}; \ No newline at end of file
diff --git a/mod2/ui/e2e/src/app.e2e-spec.ts b/mod2/ui/e2e/src/app.e2e-spec.ts
new file mode 100644
index 0000000..f25e135
--- /dev/null
+++ b/mod2/ui/e2e/src/app.e2e-spec.ts
@@ -0,0 +1,41 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { AppPage } from './app.po';
+import { browser, logging } from 'protractor';
+
+describe('workspace-project App', () => {
+ let page: AppPage;
+
+ beforeEach(() => {
+ page = new AppPage();
+ });
+
+ it('should display welcome message', () => {
+ page.navigateTo();
+ expect(page.getTitleText()).toEqual('Welcome to dcae-mod-fe!');
+ });
+
+ afterEach(async () => {
+ // Assert that there are no errors emitted from the browser
+ const logs = await browser.manage().logs().get(logging.Type.BROWSER);
+ expect(logs).not.toContain(jasmine.objectContaining({
+ level: logging.Level.SEVERE,
+ } as logging.Entry));
+ });
+});
diff --git a/mod2/ui/e2e/src/app.po.ts b/mod2/ui/e2e/src/app.po.ts
new file mode 100644
index 0000000..b26c21a
--- /dev/null
+++ b/mod2/ui/e2e/src/app.po.ts
@@ -0,0 +1,29 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { browser, by, element } from 'protractor';
+
+export class AppPage {
+ navigateTo() {
+ return browser.get(browser.baseUrl) as Promise<any>;
+ }
+
+ getTitleText() {
+ return element(by.css('app-root h1')).getText() as Promise<string>;
+ }
+}
diff --git a/mod2/ui/e2e/tsconfig.json b/mod2/ui/e2e/tsconfig.json
new file mode 100644
index 0000000..39b800f
--- /dev/null
+++ b/mod2/ui/e2e/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../out-tsc/e2e",
+ "module": "commonjs",
+ "target": "es5",
+ "types": [
+ "jasmine",
+ "jasminewd2",
+ "node"
+ ]
+ }
+}
diff --git a/mod2/ui/extra-webpack.config.js b/mod2/ui/extra-webpack.config.js
new file mode 100644
index 0000000..dd85485
--- /dev/null
+++ b/mod2/ui/extra-webpack.config.js
@@ -0,0 +1,29 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+const webpack = require('webpack')
+
+module.exports = {
+ plugins: [
+ new webpack.DefinePlugin({
+ 'process.env': {
+ DCAE_HOSTNAME: JSON.stringify(process.env.DCAE_HOSTNAME)
+ }
+ })
+ ]
+} \ No newline at end of file
diff --git a/mod2/ui/healthcheck.sh b/mod2/ui/healthcheck.sh
new file mode 100644
index 0000000..d36705b
--- /dev/null
+++ b/mod2/ui/healthcheck.sh
@@ -0,0 +1,20 @@
+__='
+* # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+'
+
+#!/bin/bash
+exit 0 \ No newline at end of file
diff --git a/mod2/ui/karma.conf.js b/mod2/ui/karma.conf.js
new file mode 100644
index 0000000..13d1962
--- /dev/null
+++ b/mod2/ui/karma.conf.js
@@ -0,0 +1,50 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+
+module.exports = function (config) {
+ config.set({
+ basePath: '',
+ frameworks: ['jasmine', '@angular-devkit/build-angular'],
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-chrome-launcher'),
+ require('karma-jasmine-html-reporter'),
+ require('karma-coverage-istanbul-reporter'),
+ require('@angular-devkit/build-angular/plugins/karma')
+ ],
+ client: {
+ clearContext: false // leave Jasmine Spec Runner output visible in browser
+ },
+ coverageIstanbulReporter: {
+ dir: require('path').join(__dirname, './coverage/dcae-mod-fe'),
+ reports: ['html', 'lcovonly', 'text-summary'],
+ fixWebpackSourcePaths: true
+ },
+ reporters: ['progress', 'kjhtml'],
+ port: 9876,
+ colors: true,
+ logLevel: config.LOG_INFO,
+ autoWatch: true,
+ browsers: ['Chrome'],
+ singleRun: false,
+ restartOnFileChange: true
+ });
+};
diff --git a/mod2/ui/package-lock.json b/mod2/ui/package-lock.json
new file mode 100644
index 0000000..f744c0b
--- /dev/null
+++ b/mod2/ui/package-lock.json
@@ -0,0 +1,10747 @@
+{
+ "name": "dcae-mod-fe",
+ "version": "0.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@angular-builders/custom-webpack": {
+ "version": "8.4.1",
+ "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-8.4.1.tgz",
+ "integrity": "sha512-FbBt4mFbAxETdYLb6tTX869pIpm8nMiCpT34jROejuqLtsljymdqXhSCEWogWlel8ULAYus6BNdzZyRLyAkfqQ==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.10",
+ "ts-node": "^8.5.2",
+ "webpack-merge": "^4.2.1"
+ },
+ "dependencies": {
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "source-map-support": {
+ "version": "0.5.18",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.18.tgz",
+ "integrity": "sha512-9luZr/BZ2QeU6tO2uG8N2aZpVSli4TSAOAqFOyTO51AJcD9P99c0K1h6dD6r6qo5dyT44BR5exweOaLLeldTkQ==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "ts-node": {
+ "version": "8.9.0",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.9.0.tgz",
+ "integrity": "sha512-rwkXfOs9zmoHrV8xE++dmNd6ZIS+nmHHCxcV53ekGJrxFLMbp+pizpPS07ARvhwneCIECPppOwbZHvw9sQtU4w==",
+ "dev": true,
+ "requires": {
+ "arg": "^4.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "source-map-support": "^0.5.17",
+ "yn": "3.1.1"
+ }
+ },
+ "yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true
+ }
+ }
+ },
+ "@angular-builders/dev-server": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/@angular-builders/dev-server/-/dev-server-7.3.1.tgz",
+ "integrity": "sha512-rFr0NyFcwTb4RkkboYQN5JeR9ZraOkfUrQYljMSe/O01MM3SJvE8LYJbsyMwGtp71Rc8T6JrpdxaNEeYCV/4PA==",
+ "dev": true
+ },
+ "@angular-devkit/architect": {
+ "version": "0.800.6",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.800.6.tgz",
+ "integrity": "sha512-946ceRci/1yx09g8iRvULLoVihcB2RW9nhpCCMum4L9wheip8t4FWso3pd3JtPQGJV9dmsnwPzR9s12bncmj3g==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "8.0.6",
+ "rxjs": "6.4.0"
+ }
+ },
+ "@angular-devkit/build-angular": {
+ "version": "0.803.24",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.803.24.tgz",
+ "integrity": "sha512-uA789spMVghXehwAhl5zK0loY/wfxblUiL+y21T24LMCJc15a9QX5dwbXH72ioHz7qdzb/agXk7AK+foc2/0Hw==",
+ "requires": {
+ "@angular-devkit/architect": "0.803.24",
+ "@angular-devkit/build-optimizer": "0.803.24",
+ "@angular-devkit/build-webpack": "0.803.24",
+ "@angular-devkit/core": "8.3.24",
+ "@babel/core": "7.8.3",
+ "@babel/preset-env": "7.8.3",
+ "@ngtools/webpack": "8.3.24",
+ "ajv": "6.10.2",
+ "autoprefixer": "9.6.1",
+ "browserslist": "4.8.3",
+ "cacache": "12.0.2",
+ "caniuse-lite": "1.0.30001019",
+ "circular-dependency-plugin": "5.2.0",
+ "clean-css": "4.2.1",
+ "copy-webpack-plugin": "5.1.1",
+ "core-js": "3.6.4",
+ "coverage-istanbul-loader": "2.0.3",
+ "file-loader": "4.2.0",
+ "find-cache-dir": "3.0.0",
+ "glob": "7.1.4",
+ "jest-worker": "24.9.0",
+ "karma-source-map-support": "1.4.0",
+ "less": "3.9.0",
+ "less-loader": "5.0.0",
+ "license-webpack-plugin": "2.1.2",
+ "loader-utils": "1.2.3",
+ "mini-css-extract-plugin": "0.8.0",
+ "minimatch": "3.0.4",
+ "open": "6.4.0",
+ "parse5": "4.0.0",
+ "postcss": "7.0.17",
+ "postcss-import": "12.0.1",
+ "postcss-loader": "3.0.0",
+ "raw-loader": "3.1.0",
+ "regenerator-runtime": "0.13.3",
+ "rxjs": "6.4.0",
+ "sass": "1.22.9",
+ "sass-loader": "7.2.0",
+ "semver": "6.3.0",
+ "source-map": "0.7.3",
+ "source-map-loader": "0.2.4",
+ "source-map-support": "0.5.13",
+ "speed-measure-webpack-plugin": "1.3.1",
+ "style-loader": "1.0.0",
+ "stylus": "0.54.5",
+ "stylus-loader": "3.0.2",
+ "terser": "4.6.3",
+ "terser-webpack-plugin": "1.4.3",
+ "tree-kill": "1.2.2",
+ "webpack": "4.39.2",
+ "webpack-dev-middleware": "3.7.2",
+ "webpack-dev-server": "3.9.0",
+ "webpack-merge": "4.2.1",
+ "webpack-sources": "1.4.3",
+ "webpack-subresource-integrity": "1.1.0-rc.6",
+ "worker-plugin": "3.2.0"
+ },
+ "dependencies": {
+ "@angular-devkit/architect": {
+ "version": "0.803.24",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.24.tgz",
+ "integrity": "sha512-ONY/Ppzyvtb0tqgwnzQvlGlexb5nTyy58ljgL1aQLTO3cNTkpl4IQYUCTdvn61gGA+FWPAXMCCbNqOPZMsOZCQ==",
+ "requires": {
+ "@angular-devkit/core": "8.3.24",
+ "rxjs": "6.4.0"
+ }
+ },
+ "@angular-devkit/core": {
+ "version": "8.3.24",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.24.tgz",
+ "integrity": "sha512-xpT5yg+ddGDnifryBv2sRSYtq5F3iZIS+lN/K2AhhEa50B7Z+QaCVlEzoV/IfrGd6sLArdnKYwjLHFZ0LElUuw==",
+ "requires": {
+ "ajv": "6.10.2",
+ "fast-json-stable-stringify": "2.0.0",
+ "magic-string": "0.25.3",
+ "rxjs": "6.4.0",
+ "source-map": "0.7.3"
+ }
+ },
+ "ajv": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+ "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "cacache": {
+ "version": "12.0.2",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.2.tgz",
+ "integrity": "sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg==",
+ "requires": {
+ "bluebird": "^3.5.5",
+ "chownr": "^1.1.1",
+ "figgy-pudding": "^3.5.1",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.1.15",
+ "infer-owner": "^1.0.3",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "move-concurrently": "^1.0.1",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^2.6.3",
+ "ssri": "^6.0.1",
+ "unique-filename": "^1.1.1",
+ "y18n": "^4.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+ "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "magic-string": {
+ "version": "0.25.3",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz",
+ "integrity": "sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==",
+ "requires": {
+ "sourcemap-codec": "^1.4.4"
+ }
+ },
+ "open": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz",
+ "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==",
+ "requires": {
+ "is-wsl": "^1.1.0"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ },
+ "source-map-support": {
+ "version": "0.5.13",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
+ "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "webpack-merge": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz",
+ "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==",
+ "requires": {
+ "lodash": "^4.17.5"
+ }
+ }
+ }
+ },
+ "@angular-devkit/build-optimizer": {
+ "version": "0.803.24",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.803.24.tgz",
+ "integrity": "sha512-Z+d7M+WpBq7AWWRwbxzb1l9O9qkylxnDRKxXvq3Tzjn43g+2WyspE91dMyrg1ISc+p8jgX6xKSblRLvtWqpA8w==",
+ "requires": {
+ "loader-utils": "1.2.3",
+ "source-map": "0.7.3",
+ "tslib": "1.10.0",
+ "typescript": "3.5.3",
+ "webpack-sources": "1.4.3"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
+ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
+ },
+ "typescript": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
+ "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g=="
+ }
+ }
+ },
+ "@angular-devkit/build-webpack": {
+ "version": "0.803.24",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.803.24.tgz",
+ "integrity": "sha512-Bbd5KUGaE+edN0sp8K3azuqS/JTBmeWXIumdBEtqWyL6VsohX7fL+toJlSvRkj8lg02LVyozAFetXKnyaBkfCQ==",
+ "requires": {
+ "@angular-devkit/architect": "0.803.24",
+ "@angular-devkit/core": "8.3.24",
+ "rxjs": "6.4.0"
+ },
+ "dependencies": {
+ "@angular-devkit/architect": {
+ "version": "0.803.24",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.24.tgz",
+ "integrity": "sha512-ONY/Ppzyvtb0tqgwnzQvlGlexb5nTyy58ljgL1aQLTO3cNTkpl4IQYUCTdvn61gGA+FWPAXMCCbNqOPZMsOZCQ==",
+ "requires": {
+ "@angular-devkit/core": "8.3.24",
+ "rxjs": "6.4.0"
+ }
+ },
+ "@angular-devkit/core": {
+ "version": "8.3.24",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.24.tgz",
+ "integrity": "sha512-xpT5yg+ddGDnifryBv2sRSYtq5F3iZIS+lN/K2AhhEa50B7Z+QaCVlEzoV/IfrGd6sLArdnKYwjLHFZ0LElUuw==",
+ "requires": {
+ "ajv": "6.10.2",
+ "fast-json-stable-stringify": "2.0.0",
+ "magic-string": "0.25.3",
+ "rxjs": "6.4.0",
+ "source-map": "0.7.3"
+ }
+ },
+ "ajv": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+ "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "magic-string": {
+ "version": "0.25.3",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz",
+ "integrity": "sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==",
+ "requires": {
+ "sourcemap-codec": "^1.4.4"
+ }
+ }
+ }
+ },
+ "@angular-devkit/core": {
+ "version": "8.0.6",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.0.6.tgz",
+ "integrity": "sha512-gbKEVsQuYqBJPzgaxEitvs0aN9NwmUHhTkum28mRyPbS3witay/q8+3ls48M2W+98Da/PQbfndxFY4OCa+qHEA==",
+ "dev": true,
+ "requires": {
+ "ajv": "6.10.0",
+ "fast-json-stable-stringify": "2.0.0",
+ "magic-string": "0.25.2",
+ "rxjs": "6.4.0",
+ "source-map": "0.7.3"
+ }
+ },
+ "@angular-devkit/schematics": {
+ "version": "8.0.6",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.0.6.tgz",
+ "integrity": "sha512-FGPcVKxNvtdFB0A6oHyxtWeugL83nW+kPATlAimgh1hu7TCP94dDpflCV9o/lgZlH817xTYXrhToXJaMZSnDPw==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "8.0.6",
+ "rxjs": "6.4.0"
+ }
+ },
+ "@angular/animations": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-8.0.3.tgz",
+ "integrity": "sha512-9zciJ4YRR0bodFSYgsgXdYMz8wKKyVjch7XZADGkWubXT8mGuwlpdPMlQ6n9Cwj8Ebu0u52WxMeQsX76K9RlYA==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "@angular/cdk": {
+ "version": "8.2.3",
+ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.2.3.tgz",
+ "integrity": "sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA==",
+ "requires": {
+ "parse5": "^5.0.0",
+ "tslib": "^1.7.1"
+ },
+ "dependencies": {
+ "parse5": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
+ "optional": true
+ }
+ }
+ },
+ "@angular/cli": {
+ "version": "8.0.6",
+ "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.0.6.tgz",
+ "integrity": "sha512-COBpeoXyLt8FiOhsmoEnDfQcm0aTdUSUHsH3zNkVTcyxpRzZVspTDGzxhK0UsCpddXS/MMjJiXph6SJ1el3qaQ==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/architect": "0.800.6",
+ "@angular-devkit/core": "8.0.6",
+ "@angular-devkit/schematics": "8.0.6",
+ "@schematics/angular": "8.0.6",
+ "@schematics/update": "0.800.6",
+ "@yarnpkg/lockfile": "1.1.0",
+ "debug": "^4.1.1",
+ "ini": "1.3.5",
+ "inquirer": "6.3.1",
+ "npm-package-arg": "6.1.0",
+ "open": "6.2.0",
+ "pacote": "9.5.0",
+ "read-package-tree": "5.2.2",
+ "semver": "6.0.0",
+ "symbol-observable": "1.2.0",
+ "universal-analytics": "^0.4.20",
+ "uuid": "^3.3.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "@angular/common": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/common/-/common-8.0.3.tgz",
+ "integrity": "sha512-2YLYGVUf9eJZcocRmD3/9UHj4qFHt2t4ftDWJmrFM9zo2PZF+G5O9fASO7qoBbwpx3KFZtQO4dprKl2dFugRjg==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "@angular/compiler": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-8.0.3.tgz",
+ "integrity": "sha512-1/vF8D6l1O6IfWiDtaj6nC+B8CtkVtFgXgooDzLBO6XAkaCuJCnhKT1HnpWG5GtVsGaY9MGoTl1vE9ZMDbRQjg==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "@angular/compiler-cli": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-8.0.3.tgz",
+ "integrity": "sha512-6nckvBnnp1YnrxwCB8UKvhHAMcUa1WvGjbYMEqhgiBreiRT4ub+tKVPNzrRtQFPpcXtY1wlgOWqYHWhHRtcLlg==",
+ "dev": true,
+ "requires": {
+ "canonical-path": "1.0.0",
+ "chokidar": "^2.1.1",
+ "convert-source-map": "^1.5.1",
+ "dependency-graph": "^0.7.2",
+ "magic-string": "^0.25.0",
+ "minimist": "^1.2.0",
+ "reflect-metadata": "^0.1.2",
+ "shelljs": "^0.8.1",
+ "source-map": "^0.6.1",
+ "tslib": "^1.9.0",
+ "yargs": "13.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ },
+ "yargs": {
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.1.0.tgz",
+ "integrity": "sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==",
+ "dev": true,
+ "requires": {
+ "cliui": "^4.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "os-locale": "^3.1.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.0.0"
+ }
+ },
+ "yargs-parser": {
+ "version": "13.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
+ "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ }
+ }
+ },
+ "@angular/core": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/core/-/core-8.0.3.tgz",
+ "integrity": "sha512-IIxrtIPNuv2+HudER9J1nmPGiGJ4aRpeiFM9V4lSiSFv50RzuaoG60XqYIpUyuBdgvyKigcrfSbu9+x1vyN0hw==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "@angular/forms": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-8.0.3.tgz",
+ "integrity": "sha512-22s82QDRQ72K4vMYuNh3NAN+da9uanwoydnfKlp2rb9dZAb2QVX9NN6gSoMrkSSr2O9KTP6pWiw6A3/MW8sGRA==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "@angular/language-service": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-8.0.3.tgz",
+ "integrity": "sha512-04XojOo9FJgEQE/rZafnaJQxPEU+//TSzTgpGoIVzCSMx+joCY/ZSSwJZPWxiHlOE57W/zX02ZY+TwcM81oTdw==",
+ "dev": true
+ },
+ "@angular/material": {
+ "version": "8.2.3",
+ "resolved": "https://registry.npmjs.org/@angular/material/-/material-8.2.3.tgz",
+ "integrity": "sha512-SOczkIaqes+r+9XF/UUiokidfFKBpHkOPIaFK857sFD0FBNPvPEpOr5oHKCG3feERRwAFqHS7Wo2ohVEWypb5A==",
+ "requires": {
+ "tslib": "^1.7.1"
+ }
+ },
+ "@angular/platform-browser": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-8.0.3.tgz",
+ "integrity": "sha512-ceAPP2Ijmk2sZ1rnOU/WNlE3DtT6K6ljpjO9oUfXKMoSMdWirJKAraT3m/BAzmYwMSXpPBxA7c3paZjiLL6t5A==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "@angular/platform-browser-dynamic": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.0.3.tgz",
+ "integrity": "sha512-ZjQjSYslSQAKzM4llvyMFxnSjFpbhT1U9FOdKwscPe475zAKX0087qsHrP2CRwkJRfwtdcmj9wMUQIPlzMpHLA==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "@angular/router": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@angular/router/-/router-8.0.3.tgz",
+ "integrity": "sha512-CU5pLTfQVUnTN93mdIKJrVjXiNldUkk30DPz4lpdxpZjYOqFGXeeSeQWmToHSofLPodNcAB4kkZ41VyXvlBu7w==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "@auth0/angular-jwt": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@auth0/angular-jwt/-/angular-jwt-4.0.0.tgz",
+ "integrity": "sha512-CHvk1zJ9jpQupl0f5y7EmTvYAwugyFvC4ztLsZKr7ZC7anNVaDd1+pDFJYS+ZEU9jLWzE74+AfVKfigImADJuw==",
+ "requires": {
+ "url": "^0.11.0"
+ }
+ },
+ "@babel/code-frame": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
+ "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "requires": {
+ "@babel/highlight": "^7.8.3"
+ }
+ },
+ "@babel/compat-data": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.0.tgz",
+ "integrity": "sha512-ixPUWJpnd9hHvRkyIE3mJ6PY5DEWmR08UkcpdqI5kV5g/d6knT8Wth1LE5v5sVTIJkm9dGpQsXnhwxcf2/PjAg==",
+ "requires": {
+ "browserslist": "^4.8.2",
+ "invariant": "^2.2.4",
+ "semver": "^7.1.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
+ }
+ }
+ },
+ "@babel/core": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz",
+ "integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==",
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.8.3",
+ "@babel/helpers": "^7.8.3",
+ "@babel/parser": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/traverse": "^7.8.3",
+ "@babel/types": "^7.8.3",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.1",
+ "json5": "^2.1.0",
+ "lodash": "^4.17.13",
+ "resolve": "^1.3.2",
+ "semver": "^5.4.1",
+ "source-map": "^0.5.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "json5": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
+ "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "@babel/generator": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz",
+ "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==",
+ "requires": {
+ "@babel/types": "^7.8.3",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.13",
+ "source-map": "^0.5.0"
+ },
+ "dependencies": {
+ "jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "@babel/helper-annotate-as-pure": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz",
+ "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==",
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-builder-binary-assignment-operator-visitor": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz",
+ "integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==",
+ "requires": {
+ "@babel/helper-explode-assignable-expression": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-compilation-targets": {
+ "version": "7.8.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz",
+ "integrity": "sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==",
+ "requires": {
+ "browserslist": "^4.9.1",
+ "invariant": "^2.2.4",
+ "levenary": "^1.1.1",
+ "semver": "^5.5.0"
+ },
+ "dependencies": {
+ "browserslist": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz",
+ "integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==",
+ "requires": {
+ "caniuse-lite": "^1.0.30001043",
+ "electron-to-chromium": "^1.3.413",
+ "node-releases": "^1.1.53",
+ "pkg-up": "^2.0.0"
+ }
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001045",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001045.tgz",
+ "integrity": "sha512-Y8o2Iz1KPcD6FjySbk1sPpvJqchgxk/iow0DABpGyzA1UeQAuxh63Xh0Enj5/BrsYbXtCN32JmR4ZxQTCQ6E6A=="
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ }
+ }
+ },
+ "@babel/helper-create-regexp-features-plugin": {
+ "version": "7.8.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz",
+ "integrity": "sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg==",
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.8.3",
+ "@babel/helper-regex": "^7.8.3",
+ "regexpu-core": "^4.7.0"
+ },
+ "dependencies": {
+ "jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0="
+ },
+ "regexpu-core": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz",
+ "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==",
+ "requires": {
+ "regenerate": "^1.4.0",
+ "regenerate-unicode-properties": "^8.2.0",
+ "regjsgen": "^0.5.1",
+ "regjsparser": "^0.6.4",
+ "unicode-match-property-ecmascript": "^1.0.4",
+ "unicode-match-property-value-ecmascript": "^1.2.0"
+ }
+ },
+ "regjsgen": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz",
+ "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg=="
+ },
+ "regjsparser": {
+ "version": "0.6.4",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz",
+ "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==",
+ "requires": {
+ "jsesc": "~0.5.0"
+ }
+ }
+ }
+ },
+ "@babel/helper-define-map": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz",
+ "integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==",
+ "requires": {
+ "@babel/helper-function-name": "^7.8.3",
+ "@babel/types": "^7.8.3",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/helper-explode-assignable-expression": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz",
+ "integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==",
+ "requires": {
+ "@babel/traverse": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
+ "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-get-function-arity": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
+ "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-hoist-variables": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz",
+ "integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==",
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-member-expression-to-functions": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz",
+ "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==",
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-module-imports": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz",
+ "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==",
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-module-transforms": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz",
+ "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==",
+ "requires": {
+ "@babel/helper-module-imports": "^7.8.3",
+ "@babel/helper-replace-supers": "^7.8.6",
+ "@babel/helper-simple-access": "^7.8.3",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/template": "^7.8.6",
+ "@babel/types": "^7.9.0",
+ "lodash": "^4.17.13"
+ },
+ "dependencies": {
+ "@babel/parser": {
+ "version": "7.9.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz",
+ "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA=="
+ },
+ "@babel/template": {
+ "version": "7.8.6",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz",
+ "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==",
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/parser": "^7.8.6",
+ "@babel/types": "^7.8.6"
+ }
+ },
+ "@babel/types": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz",
+ "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==",
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.9.5",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ }
+ }
+ },
+ "@babel/helper-optimise-call-expression": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz",
+ "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==",
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-plugin-utils": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
+ "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ=="
+ },
+ "@babel/helper-regex": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz",
+ "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==",
+ "requires": {
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/helper-remap-async-to-generator": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz",
+ "integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==",
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.8.3",
+ "@babel/helper-wrap-function": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/traverse": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-replace-supers": {
+ "version": "7.8.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz",
+ "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==",
+ "requires": {
+ "@babel/helper-member-expression-to-functions": "^7.8.3",
+ "@babel/helper-optimise-call-expression": "^7.8.3",
+ "@babel/traverse": "^7.8.6",
+ "@babel/types": "^7.8.6"
+ },
+ "dependencies": {
+ "@babel/generator": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz",
+ "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==",
+ "requires": {
+ "@babel/types": "^7.9.5",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.13",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz",
+ "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==",
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/types": "^7.9.5"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.9.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz",
+ "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA=="
+ },
+ "@babel/traverse": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz",
+ "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==",
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.9.5",
+ "@babel/helper-function-name": "^7.9.5",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/parser": "^7.9.0",
+ "@babel/types": "^7.9.5",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/types": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz",
+ "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==",
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.9.5",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "@babel/helper-simple-access": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz",
+ "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==",
+ "requires": {
+ "@babel/template": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-split-export-declaration": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
+ "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
+ "requires": {
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
+ "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g=="
+ },
+ "@babel/helper-wrap-function": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz",
+ "integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==",
+ "requires": {
+ "@babel/helper-function-name": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/traverse": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/helpers": {
+ "version": "7.9.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz",
+ "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==",
+ "requires": {
+ "@babel/template": "^7.8.3",
+ "@babel/traverse": "^7.9.0",
+ "@babel/types": "^7.9.0"
+ },
+ "dependencies": {
+ "@babel/generator": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz",
+ "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==",
+ "requires": {
+ "@babel/types": "^7.9.5",
+ "jsesc": "^2.5.1",
+ "lodash": "^4.17.13",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/helper-function-name": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz",
+ "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==",
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/types": "^7.9.5"
+ }
+ },
+ "@babel/parser": {
+ "version": "7.9.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz",
+ "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA=="
+ },
+ "@babel/traverse": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz",
+ "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==",
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.9.5",
+ "@babel/helper-function-name": "^7.9.5",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/parser": "^7.9.0",
+ "@babel/types": "^7.9.5",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/types": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz",
+ "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==",
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.9.5",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
+ "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ }
+ }
+ },
+ "@babel/parser": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz",
+ "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw=="
+ },
+ "@babel/plugin-proposal-async-generator-functions": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz",
+ "integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/helper-remap-async-to-generator": "^7.8.3",
+ "@babel/plugin-syntax-async-generators": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-dynamic-import": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz",
+ "integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-json-strings": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz",
+ "integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/plugin-syntax-json-strings": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-nullish-coalescing-operator": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz",
+ "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-object-rest-spread": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.5.tgz",
+ "integrity": "sha512-VP2oXvAf7KCYTthbUHwBlewbl1Iq059f6seJGsxMizaCdgHIeczOr7FBqELhSqfkIl04Fi8okzWzl63UKbQmmg==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
+ "@babel/plugin-transform-parameters": "^7.9.5"
+ }
+ },
+ "@babel/plugin-proposal-optional-catch-binding": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz",
+ "integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-optional-chaining": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz",
+ "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.0"
+ }
+ },
+ "@babel/plugin-proposal-unicode-property-regex": {
+ "version": "7.8.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz",
+ "integrity": "sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A==",
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.8.8",
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-syntax-async-generators": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+ "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-dynamic-import": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
+ "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-json-strings": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+ "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-nullish-coalescing-operator": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+ "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+ "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-optional-catch-binding": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+ "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-optional-chaining": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+ "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ }
+ },
+ "@babel/plugin-syntax-top-level-await": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz",
+ "integrity": "sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-arrow-functions": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz",
+ "integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-async-to-generator": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz",
+ "integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==",
+ "requires": {
+ "@babel/helper-module-imports": "^7.8.3",
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/helper-remap-async-to-generator": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-block-scoped-functions": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz",
+ "integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-block-scoping": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz",
+ "integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "lodash": "^4.17.13"
+ }
+ },
+ "@babel/plugin-transform-classes": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.5.tgz",
+ "integrity": "sha512-x2kZoIuLC//O5iA7PEvecB105o7TLzZo8ofBVhP79N+DO3jaX+KYfww9TQcfBEZD0nikNyYcGB1IKtRq36rdmg==",
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.8.3",
+ "@babel/helper-define-map": "^7.8.3",
+ "@babel/helper-function-name": "^7.9.5",
+ "@babel/helper-optimise-call-expression": "^7.8.3",
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/helper-replace-supers": "^7.8.6",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "globals": "^11.1.0"
+ },
+ "dependencies": {
+ "@babel/helper-function-name": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz",
+ "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==",
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.8.3",
+ "@babel/template": "^7.8.3",
+ "@babel/types": "^7.9.5"
+ }
+ },
+ "@babel/types": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz",
+ "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==",
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.9.5",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ }
+ }
+ }
+ },
+ "@babel/plugin-transform-computed-properties": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz",
+ "integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-destructuring": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.9.5.tgz",
+ "integrity": "sha512-j3OEsGel8nHL/iusv/mRd5fYZ3DrOxWC82x0ogmdN/vHfAP4MYw+AFKYanzWlktNwikKvlzUV//afBW5FTp17Q==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-dotall-regex": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz",
+ "integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==",
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.8.3",
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-duplicate-keys": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz",
+ "integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-exponentiation-operator": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz",
+ "integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==",
+ "requires": {
+ "@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3",
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-for-of": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz",
+ "integrity": "sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-function-name": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz",
+ "integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==",
+ "requires": {
+ "@babel/helper-function-name": "^7.8.3",
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-literals": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz",
+ "integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-member-expression-literals": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz",
+ "integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-modules-amd": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz",
+ "integrity": "sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q==",
+ "requires": {
+ "@babel/helper-module-transforms": "^7.9.0",
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "babel-plugin-dynamic-import-node": "^2.3.0"
+ }
+ },
+ "@babel/plugin-transform-modules-commonjs": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz",
+ "integrity": "sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g==",
+ "requires": {
+ "@babel/helper-module-transforms": "^7.9.0",
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/helper-simple-access": "^7.8.3",
+ "babel-plugin-dynamic-import-node": "^2.3.0"
+ }
+ },
+ "@babel/plugin-transform-modules-systemjs": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz",
+ "integrity": "sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ==",
+ "requires": {
+ "@babel/helper-hoist-variables": "^7.8.3",
+ "@babel/helper-module-transforms": "^7.9.0",
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "babel-plugin-dynamic-import-node": "^2.3.0"
+ }
+ },
+ "@babel/plugin-transform-modules-umd": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz",
+ "integrity": "sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ==",
+ "requires": {
+ "@babel/helper-module-transforms": "^7.9.0",
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-named-capturing-groups-regex": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz",
+ "integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==",
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-new-target": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz",
+ "integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-object-super": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz",
+ "integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/helper-replace-supers": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-parameters": {
+ "version": "7.9.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.5.tgz",
+ "integrity": "sha512-0+1FhHnMfj6lIIhVvS4KGQJeuhe1GI//h5uptK4PvLt+BGBxsoUJbd3/IW002yk//6sZPlFgsG1hY6OHLcy6kA==",
+ "requires": {
+ "@babel/helper-get-function-arity": "^7.8.3",
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-property-literals": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz",
+ "integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-regenerator": {
+ "version": "7.8.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz",
+ "integrity": "sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==",
+ "requires": {
+ "regenerator-transform": "^0.14.2"
+ }
+ },
+ "@babel/plugin-transform-reserved-words": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz",
+ "integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-shorthand-properties": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz",
+ "integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-spread": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz",
+ "integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-sticky-regex": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz",
+ "integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/helper-regex": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-template-literals": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz",
+ "integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==",
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.8.3",
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-typeof-symbol": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz",
+ "integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==",
+ "requires": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/plugin-transform-unicode-regex": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz",
+ "integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==",
+ "requires": {
+ "@babel/helper-create-regexp-features-plugin": "^7.8.3",
+ "@babel/helper-plugin-utils": "^7.8.3"
+ }
+ },
+ "@babel/preset-env": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.3.tgz",
+ "integrity": "sha512-Rs4RPL2KjSLSE2mWAx5/iCH+GC1ikKdxPrhnRS6PfFVaiZeom22VFKN4X8ZthyN61kAaR05tfXTbCvatl9WIQg==",
+ "requires": {
+ "@babel/compat-data": "^7.8.0",
+ "@babel/helper-compilation-targets": "^7.8.3",
+ "@babel/helper-module-imports": "^7.8.3",
+ "@babel/helper-plugin-utils": "^7.8.3",
+ "@babel/plugin-proposal-async-generator-functions": "^7.8.3",
+ "@babel/plugin-proposal-dynamic-import": "^7.8.3",
+ "@babel/plugin-proposal-json-strings": "^7.8.3",
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
+ "@babel/plugin-proposal-object-rest-spread": "^7.8.3",
+ "@babel/plugin-proposal-optional-catch-binding": "^7.8.3",
+ "@babel/plugin-proposal-optional-chaining": "^7.8.3",
+ "@babel/plugin-proposal-unicode-property-regex": "^7.8.3",
+ "@babel/plugin-syntax-async-generators": "^7.8.0",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.0",
+ "@babel/plugin-syntax-json-strings": "^7.8.0",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0",
+ "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.8.0",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.0",
+ "@babel/plugin-syntax-top-level-await": "^7.8.3",
+ "@babel/plugin-transform-arrow-functions": "^7.8.3",
+ "@babel/plugin-transform-async-to-generator": "^7.8.3",
+ "@babel/plugin-transform-block-scoped-functions": "^7.8.3",
+ "@babel/plugin-transform-block-scoping": "^7.8.3",
+ "@babel/plugin-transform-classes": "^7.8.3",
+ "@babel/plugin-transform-computed-properties": "^7.8.3",
+ "@babel/plugin-transform-destructuring": "^7.8.3",
+ "@babel/plugin-transform-dotall-regex": "^7.8.3",
+ "@babel/plugin-transform-duplicate-keys": "^7.8.3",
+ "@babel/plugin-transform-exponentiation-operator": "^7.8.3",
+ "@babel/plugin-transform-for-of": "^7.8.3",
+ "@babel/plugin-transform-function-name": "^7.8.3",
+ "@babel/plugin-transform-literals": "^7.8.3",
+ "@babel/plugin-transform-member-expression-literals": "^7.8.3",
+ "@babel/plugin-transform-modules-amd": "^7.8.3",
+ "@babel/plugin-transform-modules-commonjs": "^7.8.3",
+ "@babel/plugin-transform-modules-systemjs": "^7.8.3",
+ "@babel/plugin-transform-modules-umd": "^7.8.3",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3",
+ "@babel/plugin-transform-new-target": "^7.8.3",
+ "@babel/plugin-transform-object-super": "^7.8.3",
+ "@babel/plugin-transform-parameters": "^7.8.3",
+ "@babel/plugin-transform-property-literals": "^7.8.3",
+ "@babel/plugin-transform-regenerator": "^7.8.3",
+ "@babel/plugin-transform-reserved-words": "^7.8.3",
+ "@babel/plugin-transform-shorthand-properties": "^7.8.3",
+ "@babel/plugin-transform-spread": "^7.8.3",
+ "@babel/plugin-transform-sticky-regex": "^7.8.3",
+ "@babel/plugin-transform-template-literals": "^7.8.3",
+ "@babel/plugin-transform-typeof-symbol": "^7.8.3",
+ "@babel/plugin-transform-unicode-regex": "^7.8.3",
+ "@babel/types": "^7.8.3",
+ "browserslist": "^4.8.2",
+ "core-js-compat": "^3.6.2",
+ "invariant": "^2.2.2",
+ "levenary": "^1.1.0",
+ "semver": "^5.5.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ }
+ }
+ },
+ "@babel/runtime": {
+ "version": "7.9.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz",
+ "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ },
+ "dependencies": {
+ "regenerator-runtime": {
+ "version": "0.13.5",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
+ "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
+ }
+ }
+ },
+ "@babel/template": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz",
+ "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==",
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/parser": "^7.8.3",
+ "@babel/types": "^7.8.3"
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz",
+ "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==",
+ "requires": {
+ "@babel/code-frame": "^7.8.3",
+ "@babel/generator": "^7.8.4",
+ "@babel/helper-function-name": "^7.8.3",
+ "@babel/helper-split-export-declaration": "^7.8.3",
+ "@babel/parser": "^7.8.4",
+ "@babel/types": "^7.8.3",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0",
+ "lodash": "^4.17.13"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
+ "@babel/types": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz",
+ "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==",
+ "requires": {
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.13",
+ "to-fast-properties": "^2.0.0"
+ },
+ "dependencies": {
+ "to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
+ }
+ }
+ },
+ "@fortawesome/fontawesome-free": {
+ "version": "5.13.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.13.0.tgz",
+ "integrity": "sha512-xKOeQEl5O47GPZYIMToj6uuA2syyFlq9EMSl2ui0uytjY9xbe8XS0pexNWmxrdcCyNGyDmLyYw5FtKsalBUeOg=="
+ },
+ "@istanbuljs/schema": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
+ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw=="
+ },
+ "@ngtools/webpack": {
+ "version": "8.3.24",
+ "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-8.3.24.tgz",
+ "integrity": "sha512-OpR7t/99qNOpADayCuM67agBVdYkdbFyEEcOLaDFYh3LsefHOSSxtAGv8M77e7dguvtaljHTiVkMxgcXFsZM0Q==",
+ "requires": {
+ "@angular-devkit/core": "8.3.24",
+ "enhanced-resolve": "4.1.0",
+ "rxjs": "6.4.0",
+ "tree-kill": "1.2.2",
+ "webpack-sources": "1.4.3"
+ },
+ "dependencies": {
+ "@angular-devkit/core": {
+ "version": "8.3.24",
+ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.24.tgz",
+ "integrity": "sha512-xpT5yg+ddGDnifryBv2sRSYtq5F3iZIS+lN/K2AhhEa50B7Z+QaCVlEzoV/IfrGd6sLArdnKYwjLHFZ0LElUuw==",
+ "requires": {
+ "ajv": "6.10.2",
+ "fast-json-stable-stringify": "2.0.0",
+ "magic-string": "0.25.3",
+ "rxjs": "6.4.0",
+ "source-map": "0.7.3"
+ }
+ },
+ "ajv": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+ "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "magic-string": {
+ "version": "0.25.3",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz",
+ "integrity": "sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==",
+ "requires": {
+ "sourcemap-codec": "^1.4.4"
+ }
+ }
+ }
+ },
+ "@schematics/angular": {
+ "version": "8.0.6",
+ "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.0.6.tgz",
+ "integrity": "sha512-F0/MrbvrJQJIjt0GwEkmf9PZUX0xQlCjlDcH6U7yBni0/+R5Gd5g3G0f12fsSa2iAwpwrLkKpiQluj29eFituQ==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "8.0.6",
+ "@angular-devkit/schematics": "8.0.6"
+ }
+ },
+ "@schematics/update": {
+ "version": "0.800.6",
+ "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.800.6.tgz",
+ "integrity": "sha512-vrzGIJtMiwLWl96+aJXMYrPgPtktLRpY8ZiNnlLm3pMDmeg08uButRh/pQGt02HuO/apTNJ5g0bmG8K5wS4I5A==",
+ "dev": true,
+ "requires": {
+ "@angular-devkit/core": "8.0.6",
+ "@angular-devkit/schematics": "8.0.6",
+ "@yarnpkg/lockfile": "1.1.0",
+ "ini": "1.3.5",
+ "pacote": "9.5.0",
+ "rxjs": "6.4.0",
+ "semver": "6.0.0",
+ "semver-intersect": "1.4.0"
+ }
+ },
+ "@types/events": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
+ "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
+ },
+ "@types/glob": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
+ "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
+ "requires": {
+ "@types/events": "*",
+ "@types/minimatch": "*",
+ "@types/node": "*"
+ }
+ },
+ "@types/jasmine": {
+ "version": "3.3.16",
+ "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.3.16.tgz",
+ "integrity": "sha512-Nveep4zKGby8uIvG2AEUyYOwZS8uVeHK9TgbuWYSawUDDdIgfhCKz28QzamTo//Jk7Ztt9PO3f+vzlB6a4GV1Q==",
+ "dev": true
+ },
+ "@types/jasminewd2": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.8.tgz",
+ "integrity": "sha512-d9p31r7Nxk0ZH0U39PTH0hiDlJ+qNVGjlt1ucOoTUptxb2v+Y5VMnsxfwN+i3hK4yQnqBi3FMmoMFcd1JHDxdg==",
+ "dev": true,
+ "requires": {
+ "@types/jasmine": "*"
+ }
+ },
+ "@types/minimatch": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA=="
+ },
+ "@types/node": {
+ "version": "8.9.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz",
+ "integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ=="
+ },
+ "@types/q": {
+ "version": "0.0.32",
+ "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz",
+ "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=",
+ "dev": true
+ },
+ "@types/selenium-webdriver": {
+ "version": "3.0.17",
+ "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.17.tgz",
+ "integrity": "sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw==",
+ "dev": true
+ },
+ "@types/source-list-map": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
+ "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA=="
+ },
+ "@types/webpack-sources": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.7.tgz",
+ "integrity": "sha512-XyaHrJILjK1VHVC4aVlKsdNN5KBTwufMb43cQs+flGxtPAf/1Qwl8+Q0tp5BwEGaI8D6XT1L+9bSWXckgkjTLw==",
+ "requires": {
+ "@types/node": "*",
+ "@types/source-list-map": "*",
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "@webassemblyjs/ast": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
+ "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==",
+ "requires": {
+ "@webassemblyjs/helper-module-context": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/wast-parser": "1.8.5"
+ }
+ },
+ "@webassemblyjs/floating-point-hex-parser": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz",
+ "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ=="
+ },
+ "@webassemblyjs/helper-api-error": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz",
+ "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA=="
+ },
+ "@webassemblyjs/helper-buffer": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz",
+ "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q=="
+ },
+ "@webassemblyjs/helper-code-frame": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz",
+ "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==",
+ "requires": {
+ "@webassemblyjs/wast-printer": "1.8.5"
+ }
+ },
+ "@webassemblyjs/helper-fsm": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz",
+ "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow=="
+ },
+ "@webassemblyjs/helper-module-context": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz",
+ "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "mamacro": "^0.0.3"
+ }
+ },
+ "@webassemblyjs/helper-wasm-bytecode": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz",
+ "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ=="
+ },
+ "@webassemblyjs/helper-wasm-section": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz",
+ "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-buffer": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/wasm-gen": "1.8.5"
+ }
+ },
+ "@webassemblyjs/ieee754": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz",
+ "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==",
+ "requires": {
+ "@xtuc/ieee754": "^1.2.0"
+ }
+ },
+ "@webassemblyjs/leb128": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz",
+ "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==",
+ "requires": {
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webassemblyjs/utf8": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz",
+ "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw=="
+ },
+ "@webassemblyjs/wasm-edit": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz",
+ "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-buffer": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/helper-wasm-section": "1.8.5",
+ "@webassemblyjs/wasm-gen": "1.8.5",
+ "@webassemblyjs/wasm-opt": "1.8.5",
+ "@webassemblyjs/wasm-parser": "1.8.5",
+ "@webassemblyjs/wast-printer": "1.8.5"
+ }
+ },
+ "@webassemblyjs/wasm-gen": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz",
+ "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/ieee754": "1.8.5",
+ "@webassemblyjs/leb128": "1.8.5",
+ "@webassemblyjs/utf8": "1.8.5"
+ }
+ },
+ "@webassemblyjs/wasm-opt": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz",
+ "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-buffer": "1.8.5",
+ "@webassemblyjs/wasm-gen": "1.8.5",
+ "@webassemblyjs/wasm-parser": "1.8.5"
+ }
+ },
+ "@webassemblyjs/wasm-parser": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz",
+ "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-api-error": "1.8.5",
+ "@webassemblyjs/helper-wasm-bytecode": "1.8.5",
+ "@webassemblyjs/ieee754": "1.8.5",
+ "@webassemblyjs/leb128": "1.8.5",
+ "@webassemblyjs/utf8": "1.8.5"
+ }
+ },
+ "@webassemblyjs/wast-parser": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz",
+ "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/floating-point-hex-parser": "1.8.5",
+ "@webassemblyjs/helper-api-error": "1.8.5",
+ "@webassemblyjs/helper-code-frame": "1.8.5",
+ "@webassemblyjs/helper-fsm": "1.8.5",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@webassemblyjs/wast-printer": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz",
+ "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/wast-parser": "1.8.5",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "@xtuc/ieee754": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+ "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="
+ },
+ "@xtuc/long": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
+ },
+ "@yarnpkg/lockfile": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
+ "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
+ "dev": true
+ },
+ "JSONStream": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
+ "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+ "dev": true,
+ "requires": {
+ "jsonparse": "^1.2.0",
+ "through": ">=2.2.7 <3"
+ }
+ },
+ "accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "requires": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ }
+ },
+ "acorn": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+ "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA=="
+ },
+ "adler-32": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz",
+ "integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=",
+ "requires": {
+ "exit-on-epipe": "~1.0.1",
+ "printj": "~1.1.0"
+ }
+ },
+ "adm-zip": {
+ "version": "0.4.14",
+ "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz",
+ "integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g==",
+ "dev": true
+ },
+ "after": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
+ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
+ "dev": true
+ },
+ "agent-base": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+ "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+ "dev": true,
+ "requires": {
+ "es6-promisify": "^5.0.0"
+ }
+ },
+ "agentkeepalive": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz",
+ "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==",
+ "dev": true,
+ "requires": {
+ "humanize-ms": "^1.2.1"
+ }
+ },
+ "ajv": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
+ "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-errors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
+ "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ=="
+ },
+ "ajv-keywords": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz",
+ "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ=="
+ },
+ "amdefine": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
+ },
+ "ansi-colors": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
+ "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA=="
+ },
+ "ansi-escapes": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+ "dev": true
+ },
+ "ansi-html": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
+ "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4="
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ },
+ "dependencies": {
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ }
+ }
+ },
+ "app-root-path": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz",
+ "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==",
+ "dev": true
+ },
+ "append-transform": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz",
+ "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==",
+ "dev": true,
+ "requires": {
+ "default-require-extensions": "^2.0.0"
+ }
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+ },
+ "arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "aria-query": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
+ "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=",
+ "dev": true,
+ "requires": {
+ "ast-types-flow": "0.0.7",
+ "commander": "^2.11.0"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
+ },
+ "array-flatten": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
+ "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ=="
+ },
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
+ },
+ "arraybuffer.slice": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
+ "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
+ "dev": true
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+ "dev": true
+ },
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "asn1.js": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
+ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
+ "requires": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "assert": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
+ "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
+ "requires": {
+ "object-assign": "^4.1.1",
+ "util": "0.10.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "requires": {
+ "inherits": "2.0.1"
+ }
+ }
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
+ },
+ "ast-types-flow": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
+ "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
+ "dev": true
+ },
+ "async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "async-each": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ=="
+ },
+ "async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
+ },
+ "autoprefixer": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz",
+ "integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==",
+ "requires": {
+ "browserslist": "^4.6.3",
+ "caniuse-lite": "^1.0.30000980",
+ "chalk": "^2.4.2",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^7.0.17",
+ "postcss-value-parser": "^4.0.0"
+ }
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ },
+ "aws4": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
+ "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
+ },
+ "axobject-query": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
+ "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
+ "dev": true,
+ "requires": {
+ "ast-types-flow": "0.0.7"
+ }
+ },
+ "babel-code-frame": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "esutils": "^2.0.2",
+ "js-tokens": "^3.0.2"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
+ },
+ "babel-plugin-dynamic-import-node": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
+ "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==",
+ "requires": {
+ "object.assign": "^4.1.0"
+ }
+ },
+ "backo2": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
+ "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "base64-arraybuffer": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
+ "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
+ "dev": true
+ },
+ "base64-js": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
+ },
+ "base64id": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
+ "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=",
+ "dev": true
+ },
+ "batch": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "better-assert": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
+ "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
+ "dev": true,
+ "requires": {
+ "callsite": "1.0.0"
+ }
+ },
+ "big.js": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
+ },
+ "binary-extensions": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw=="
+ },
+ "bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "optional": true,
+ "requires": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
+ "blob": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
+ "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==",
+ "dev": true
+ },
+ "blocking-proxy": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz",
+ "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
+ },
+ "bn.js": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
+ },
+ "body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "requires": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ },
+ "dependencies": {
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+ }
+ }
+ },
+ "bonjour": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
+ "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",
+ "requires": {
+ "array-flatten": "^2.1.0",
+ "deep-equal": "^1.0.1",
+ "dns-equal": "^1.0.0",
+ "dns-txt": "^2.0.2",
+ "multicast-dns": "^6.0.1",
+ "multicast-dns-service-types": "^1.1.0"
+ }
+ },
+ "bootstrap": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.4.1.tgz",
+ "integrity": "sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA=="
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "brorand": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
+ },
+ "browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "requires": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "browserify-cipher": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+ "requires": {
+ "browserify-aes": "^1.0.4",
+ "browserify-des": "^1.0.0",
+ "evp_bytestokey": "^1.0.0"
+ }
+ },
+ "browserify-des": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "des.js": "^1.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "browserify-rsa": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "randombytes": "^2.0.1"
+ }
+ },
+ "browserify-sign": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+ "requires": {
+ "bn.js": "^4.1.1",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.2",
+ "elliptic": "^6.0.0",
+ "inherits": "^2.0.1",
+ "parse-asn1": "^5.0.0"
+ }
+ },
+ "browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "requires": {
+ "pako": "~1.0.5"
+ }
+ },
+ "browserslist": {
+ "version": "4.8.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.3.tgz",
+ "integrity": "sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg==",
+ "requires": {
+ "caniuse-lite": "^1.0.30001017",
+ "electron-to-chromium": "^1.3.322",
+ "node-releases": "^1.1.44"
+ }
+ },
+ "browserstack": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz",
+ "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==",
+ "dev": true,
+ "requires": {
+ "https-proxy-agent": "^2.2.1"
+ }
+ },
+ "buffer": {
+ "version": "4.9.2",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
+ "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4",
+ "isarray": "^1.0.0"
+ }
+ },
+ "buffer-alloc": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+ "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+ "dev": true,
+ "requires": {
+ "buffer-alloc-unsafe": "^1.1.0",
+ "buffer-fill": "^1.0.0"
+ }
+ },
+ "buffer-alloc-unsafe": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+ "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
+ "dev": true
+ },
+ "buffer-fill": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+ "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
+ "dev": true
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
+ },
+ "buffer-indexof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
+ "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g=="
+ },
+ "buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk="
+ },
+ "builtin-modules": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+ "dev": true
+ },
+ "builtin-status-codes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug="
+ },
+ "builtins": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
+ "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=",
+ "dev": true
+ },
+ "bytes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
+ },
+ "cacache": {
+ "version": "11.3.3",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz",
+ "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==",
+ "dev": true,
+ "requires": {
+ "bluebird": "^3.5.5",
+ "chownr": "^1.1.1",
+ "figgy-pudding": "^3.5.1",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.1.15",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "move-concurrently": "^1.0.1",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^2.6.3",
+ "ssri": "^6.0.1",
+ "unique-filename": "^1.1.1",
+ "y18n": "^4.0.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
+ }
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "caller-callsite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+ "requires": {
+ "callsites": "^2.0.0"
+ }
+ },
+ "caller-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+ "requires": {
+ "caller-callsite": "^2.0.0"
+ }
+ },
+ "callsite": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
+ "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
+ "dev": true
+ },
+ "callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA="
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001019",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001019.tgz",
+ "integrity": "sha512-6ljkLtF1KM5fQ+5ZN0wuyVvvebJxgJPTmScOMaFuQN2QuOzvRJnWSKfzQskQU5IOU4Gap3zasYPIinzwUjoj/g=="
+ },
+ "canonical-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz",
+ "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==",
+ "dev": true
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "cdk-table-exporter": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/cdk-table-exporter/-/cdk-table-exporter-9.0.0.tgz",
+ "integrity": "sha512-F//RrIX9ek5wwYFAG2VzgtL3l48tRPw7SLb0VpXobqYOxjcZBQlha+eFsDDhYfBkz/PHxSNNY3rPZen2O9ynVw==",
+ "requires": {
+ "file-saver": "^2.0.2",
+ "xlsx": "^0.14.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.17.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
+ "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
+ },
+ "xlsx": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.14.5.tgz",
+ "integrity": "sha512-s/5f4/mjeWREmIWZ+HtDfh/rnz51ar+dZ4LWKZU3u9VBx2zLdSIWTdXgoa52/pnZ9Oe/Vu1W1qzcKzLVe+lq4w==",
+ "requires": {
+ "adler-32": "~1.2.0",
+ "cfb": "^1.1.2",
+ "codepage": "~1.14.0",
+ "commander": "~2.17.1",
+ "crc-32": "~1.2.0",
+ "exit-on-epipe": "~1.0.1",
+ "ssf": "~0.10.2"
+ }
+ }
+ }
+ },
+ "cfb": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.1.4.tgz",
+ "integrity": "sha512-rwFkl3aFO3f+ljR27YINwC0x8vPjyiEVbYbrTCKzspEf7Q++3THdfHVgJYNUbxNcupJECrLX+L40Mjm9hm/Bgw==",
+ "requires": {
+ "adler-32": "~1.2.0",
+ "commander": "^2.16.0",
+ "crc-32": "~1.2.0",
+ "printj": "~1.1.2"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "dev": true
+ },
+ "chokidar": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "fsevents": "^1.2.7",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.1"
+ }
+ },
+ "chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
+ },
+ "chrome-trace-event": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
+ "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "circular-dependency-plugin": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz",
+ "integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw=="
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "clean-css": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
+ "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
+ "requires": {
+ "source-map": "~0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "^2.0.0"
+ }
+ },
+ "cli-width": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
+ "dev": true
+ },
+ "cliui": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+ "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+ "requires": {
+ "string-width": "^2.1.1",
+ "strip-ansi": "^4.0.0",
+ "wrap-ansi": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "clone": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
+ },
+ "clone-deep": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
+ "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
+ "requires": {
+ "is-plain-object": "^2.0.4",
+ "kind-of": "^6.0.2",
+ "shallow-clone": "^3.0.0"
+ }
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+ },
+ "codelyzer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-5.2.1.tgz",
+ "integrity": "sha512-awBZXFcJUyC5HMYXiHzjr3D24tww2l1D1OqtfA9vUhEtYr32a65A+Gblm/OvsO+HuKLYzn8EDMw1inSM3VbxWA==",
+ "dev": true,
+ "requires": {
+ "app-root-path": "^2.2.1",
+ "aria-query": "^3.0.0",
+ "axobject-query": "2.0.2",
+ "css-selector-tokenizer": "^0.7.1",
+ "cssauron": "^1.4.0",
+ "damerau-levenshtein": "^1.0.4",
+ "semver-dsl": "^1.0.1",
+ "source-map": "^0.5.7",
+ "sprintf-js": "^1.1.2"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "sprintf-js": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
+ "dev": true
+ }
+ }
+ },
+ "codepage": {
+ "version": "1.14.0",
+ "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz",
+ "integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=",
+ "requires": {
+ "commander": "~2.14.1",
+ "exit-on-epipe": "~1.0.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.14.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
+ "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw=="
+ }
+ }
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+ },
+ "colors": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+ "dev": true
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ },
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
+ },
+ "compare-versions": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz",
+ "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==",
+ "dev": true
+ },
+ "component-bind": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
+ "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
+ },
+ "component-inherit": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
+ "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
+ "dev": true
+ },
+ "compressible": {
+ "version": "2.0.18",
+ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
+ "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
+ "requires": {
+ "mime-db": ">= 1.43.0 < 2"
+ }
+ },
+ "compression": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
+ "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
+ "requires": {
+ "accepts": "~1.3.5",
+ "bytes": "3.0.0",
+ "compressible": "~2.0.16",
+ "debug": "2.6.9",
+ "on-headers": "~1.0.2",
+ "safe-buffer": "5.1.2",
+ "vary": "~1.1.2"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "connect": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "finalhandler": "1.1.2",
+ "parseurl": "~1.3.3",
+ "utils-merge": "1.0.1"
+ }
+ },
+ "connect-history-api-fallback": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
+ "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg=="
+ },
+ "console-browserify": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
+ "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA=="
+ },
+ "constants-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U="
+ },
+ "content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
+ "convert-source-map": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+ "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+ "requires": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "cookie": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+ "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "copy-concurrently": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
+ "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
+ "requires": {
+ "aproba": "^1.1.1",
+ "fs-write-stream-atomic": "^1.0.8",
+ "iferr": "^0.1.5",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.4",
+ "run-queue": "^1.0.0"
+ }
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
+ },
+ "copy-webpack-plugin": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz",
+ "integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==",
+ "requires": {
+ "cacache": "^12.0.3",
+ "find-cache-dir": "^2.1.0",
+ "glob-parent": "^3.1.0",
+ "globby": "^7.1.1",
+ "is-glob": "^4.0.1",
+ "loader-utils": "^1.2.3",
+ "minimatch": "^3.0.4",
+ "normalize-path": "^3.0.0",
+ "p-limit": "^2.2.1",
+ "schema-utils": "^1.0.0",
+ "serialize-javascript": "^2.1.2",
+ "webpack-log": "^2.0.0"
+ },
+ "dependencies": {
+ "cacache": {
+ "version": "12.0.4",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
+ "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==",
+ "requires": {
+ "bluebird": "^3.5.5",
+ "chownr": "^1.1.1",
+ "figgy-pudding": "^3.5.1",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.1.15",
+ "infer-owner": "^1.0.3",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "move-concurrently": "^1.0.1",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^2.6.3",
+ "ssri": "^6.0.1",
+ "unique-filename": "^1.1.1",
+ "y18n": "^4.0.0"
+ }
+ },
+ "find-cache-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
+ "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^2.0.0",
+ "pkg-dir": "^3.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
+ }
+ },
+ "core-js": {
+ "version": "3.6.4",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz",
+ "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw=="
+ },
+ "core-js-compat": {
+ "version": "3.6.5",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz",
+ "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==",
+ "requires": {
+ "browserslist": "^4.8.5",
+ "semver": "7.0.0"
+ },
+ "dependencies": {
+ "browserslist": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz",
+ "integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==",
+ "requires": {
+ "caniuse-lite": "^1.0.30001043",
+ "electron-to-chromium": "^1.3.413",
+ "node-releases": "^1.1.53",
+ "pkg-up": "^2.0.0"
+ }
+ },
+ "caniuse-lite": {
+ "version": "1.0.30001045",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001045.tgz",
+ "integrity": "sha512-Y8o2Iz1KPcD6FjySbk1sPpvJqchgxk/iow0DABpGyzA1UeQAuxh63Xh0Enj5/BrsYbXtCN32JmR4ZxQTCQ6E6A=="
+ },
+ "semver": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
+ "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A=="
+ }
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "requires": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ }
+ },
+ "coverage-istanbul-loader": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/coverage-istanbul-loader/-/coverage-istanbul-loader-2.0.3.tgz",
+ "integrity": "sha512-LiGRvyIuzVYs3M1ZYK1tF0HekjH0DJ8zFdUwAZq378EJzqOgToyb1690dp3TAUlP6Y+82uu42LRjuROVeJ54CA==",
+ "requires": {
+ "convert-source-map": "^1.7.0",
+ "istanbul-lib-instrument": "^4.0.0",
+ "loader-utils": "^1.2.3",
+ "merge-source-map": "^1.1.0",
+ "schema-utils": "^2.6.1"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.12.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
+ "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
+ },
+ "schema-utils": {
+ "version": "2.6.6",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz",
+ "integrity": "sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA==",
+ "requires": {
+ "ajv": "^6.12.0",
+ "ajv-keywords": "^3.4.1"
+ }
+ }
+ }
+ },
+ "crc-32": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz",
+ "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==",
+ "requires": {
+ "exit-on-epipe": "~1.0.1",
+ "printj": "~1.1.0"
+ }
+ },
+ "create-ecdh": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
+ "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "elliptic": "^6.0.0"
+ }
+ },
+ "create-hash": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "create-hmac": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "requires": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ }
+ }
+ },
+ "crypto-browserify": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+ "requires": {
+ "browserify-cipher": "^1.0.0",
+ "browserify-sign": "^4.0.0",
+ "create-ecdh": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.0",
+ "diffie-hellman": "^5.0.0",
+ "inherits": "^2.0.1",
+ "pbkdf2": "^3.0.3",
+ "public-encrypt": "^4.0.0",
+ "randombytes": "^2.0.0",
+ "randomfill": "^1.0.3"
+ }
+ },
+ "css-parse": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz",
+ "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs="
+ },
+ "css-selector-tokenizer": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz",
+ "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^0.1.0",
+ "fastparse": "^1.1.1",
+ "regexpu-core": "^1.0.0"
+ }
+ },
+ "cssauron": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
+ "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=",
+ "dev": true,
+ "requires": {
+ "through": "X.X.X"
+ }
+ },
+ "cssesc": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
+ "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=",
+ "dev": true
+ },
+ "custom-event": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
+ "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
+ "dev": true
+ },
+ "cyclist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
+ "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk="
+ },
+ "damerau-levenshtein": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
+ "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==",
+ "dev": true
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "date-format": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
+ "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==",
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "debuglog": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz",
+ "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
+ },
+ "deep-equal": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
+ "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
+ "requires": {
+ "is-arguments": "^1.0.4",
+ "is-date-object": "^1.0.1",
+ "is-regex": "^1.0.4",
+ "object-is": "^1.0.1",
+ "object-keys": "^1.1.1",
+ "regexp.prototype.flags": "^1.2.0"
+ }
+ },
+ "default-gateway": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz",
+ "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==",
+ "requires": {
+ "execa": "^1.0.0",
+ "ip-regex": "^2.1.0"
+ }
+ },
+ "default-require-extensions": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz",
+ "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=",
+ "dev": true,
+ "requires": {
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+ "requires": {
+ "object-keys": "^1.0.12"
+ }
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "del": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz",
+ "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==",
+ "requires": {
+ "@types/glob": "^7.1.1",
+ "globby": "^6.1.0",
+ "is-path-cwd": "^2.0.0",
+ "is-path-in-cwd": "^2.0.0",
+ "p-map": "^2.0.0",
+ "pify": "^4.0.1",
+ "rimraf": "^2.6.3"
+ },
+ "dependencies": {
+ "globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+ "requires": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ }
+ }
+ }
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ },
+ "dependency-graph": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz",
+ "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==",
+ "dev": true
+ },
+ "des.js": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
+ "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
+ "requires": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "detect-node": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
+ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw=="
+ },
+ "dezalgo": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
+ "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
+ "dev": true,
+ "requires": {
+ "asap": "^2.0.0",
+ "wrappy": "1"
+ }
+ },
+ "di": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
+ "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
+ "dev": true
+ },
+ "diff": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+ "dev": true
+ },
+ "diffie-hellman": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "miller-rabin": "^4.0.0",
+ "randombytes": "^2.0.0"
+ }
+ },
+ "dir-glob": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
+ "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
+ "requires": {
+ "path-type": "^3.0.0"
+ }
+ },
+ "dns-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
+ "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0="
+ },
+ "dns-packet": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
+ "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
+ "requires": {
+ "ip": "^1.1.0",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "dns-txt": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
+ "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
+ "requires": {
+ "buffer-indexof": "^1.0.0"
+ }
+ },
+ "dom-serialize": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
+ "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
+ "dev": true,
+ "requires": {
+ "custom-event": "~1.0.0",
+ "ent": "~2.2.0",
+ "extend": "^3.0.0",
+ "void-elements": "^2.0.0"
+ }
+ },
+ "domain-browser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA=="
+ },
+ "dotenv": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
+ "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
+ "dev": true
+ },
+ "duplexify": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+ "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+ "requires": {
+ "end-of-stream": "^1.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "electron-to-chromium": {
+ "version": "1.3.414",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.414.tgz",
+ "integrity": "sha512-UfxhIvED++qLwWrAq9uYVcqF8FdeV9sU2S7qhiHYFODxzXRrd1GZRl/PjITHsTEejgibcWDraD8TQqoHb1aCBQ=="
+ },
+ "elliptic": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
+ "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
+ "requires": {
+ "bn.js": "^4.4.0",
+ "brorand": "^1.0.1",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.0"
+ }
+ },
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
+ "emojis-list": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
+ "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "encoding": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "dev": true,
+ "requires": {
+ "iconv-lite": "~0.4.13"
+ }
+ },
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "engine.io": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz",
+ "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==",
+ "dev": true,
+ "requires": {
+ "accepts": "~1.3.4",
+ "base64id": "1.0.0",
+ "cookie": "0.3.1",
+ "debug": "~3.1.0",
+ "engine.io-parser": "~2.1.0",
+ "ws": "~3.3.1"
+ },
+ "dependencies": {
+ "cookie": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
+ "dev": true
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
+ "engine.io-client": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
+ "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==",
+ "dev": true,
+ "requires": {
+ "component-emitter": "1.2.1",
+ "component-inherit": "0.0.3",
+ "debug": "~3.1.0",
+ "engine.io-parser": "~2.1.1",
+ "has-cors": "1.1.0",
+ "indexof": "0.0.1",
+ "parseqs": "0.0.5",
+ "parseuri": "0.0.5",
+ "ws": "~3.3.1",
+ "xmlhttprequest-ssl": "~1.5.4",
+ "yeast": "0.1.2"
+ },
+ "dependencies": {
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
+ "engine.io-parser": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz",
+ "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==",
+ "dev": true,
+ "requires": {
+ "after": "0.8.2",
+ "arraybuffer.slice": "~0.0.7",
+ "base64-arraybuffer": "0.1.5",
+ "blob": "0.0.5",
+ "has-binary2": "~1.0.2"
+ }
+ },
+ "enhanced-resolve": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz",
+ "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "memory-fs": "^0.4.0",
+ "tapable": "^1.0.0"
+ }
+ },
+ "ent": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
+ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
+ "dev": true
+ },
+ "err-code": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
+ "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=",
+ "dev": true
+ },
+ "errno": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
+ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+ "requires": {
+ "prr": "~1.0.1"
+ }
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.17.5",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
+ "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.1.5",
+ "is-regex": "^1.0.5",
+ "object-inspect": "^1.7.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.0",
+ "string.prototype.trimleft": "^2.1.1",
+ "string.prototype.trimright": "^2.1.1"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "requires": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ }
+ },
+ "es6-promise": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+ "dev": true
+ },
+ "es6-promisify": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+ "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+ "dev": true,
+ "requires": {
+ "es6-promise": "^4.0.3"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ },
+ "eslint-scope": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
+ "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+ },
+ "esrecurse": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "requires": {
+ "estraverse": "^4.1.0"
+ }
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
+ },
+ "esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ },
+ "eventemitter3": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz",
+ "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg=="
+ },
+ "events": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
+ "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg=="
+ },
+ "eventsource": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz",
+ "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==",
+ "requires": {
+ "original": "^1.0.0"
+ }
+ },
+ "evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "requires": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "execa": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+ "requires": {
+ "cross-spawn": "^6.0.0",
+ "get-stream": "^4.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ }
+ },
+ "exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+ "dev": true
+ },
+ "exit-on-epipe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
+ "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw=="
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "express": {
+ "version": "4.17.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+ "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "requires": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+ }
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dev": true,
+ "requires": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+ },
+ "fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
+ "faye-websocket": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
+ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
+ "requires": {
+ "websocket-driver": ">=0.5.1"
+ }
+ },
+ "figgy-pudding": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
+ "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w=="
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-loader": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.2.0.tgz",
+ "integrity": "sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ==",
+ "requires": {
+ "loader-utils": "^1.2.3",
+ "schema-utils": "^2.0.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.12.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
+ "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
+ },
+ "schema-utils": {
+ "version": "2.6.6",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz",
+ "integrity": "sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA==",
+ "requires": {
+ "ajv": "^6.12.0",
+ "ajv-keywords": "^3.4.1"
+ }
+ }
+ }
+ },
+ "file-saver": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.2.tgz",
+ "integrity": "sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw=="
+ },
+ "file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+ "optional": true
+ },
+ "fileset": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz",
+ "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=",
+ "dev": true,
+ "requires": {
+ "glob": "^7.0.3",
+ "minimatch": "^3.0.3"
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "find-cache-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.0.0.tgz",
+ "integrity": "sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw==",
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^3.0.0",
+ "pkg-dir": "^4.1.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "requires": {
+ "semver": "^6.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+ },
+ "pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "requires": {
+ "find-up": "^4.0.0"
+ }
+ }
+ }
+ },
+ "find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "flatted": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
+ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
+ "dev": true
+ },
+ "flush-write-stream": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+ "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.3.6"
+ }
+ },
+ "follow-redirects": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.10.0.tgz",
+ "integrity": "sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ==",
+ "requires": {
+ "debug": "^3.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
+ "font-awesome": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
+ "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM="
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+ },
+ "frac": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
+ "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "from2": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
+ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0"
+ }
+ },
+ "fs-access": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz",
+ "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=",
+ "dev": true,
+ "requires": {
+ "null-check": "^1.0.0"
+ }
+ },
+ "fs-extra": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "fs-minipass": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
+ "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
+ "dev": true,
+ "requires": {
+ "minipass": "^2.6.0"
+ }
+ },
+ "fs-write-stream-atomic": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
+ "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "iferr": "^0.1.5",
+ "imurmurhash": "^0.1.4",
+ "readable-stream": "1 || 2"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "fsevents": {
+ "version": "1.2.11",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz",
+ "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==",
+ "optional": true,
+ "requires": {
+ "bindings": "^1.5.0",
+ "nan": "^2.12.1",
+ "node-pre-gyp": "*"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true,
+ "optional": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "chownr": {
+ "version": "1.1.3",
+ "bundled": true,
+ "optional": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "bundled": true,
+ "optional": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "bundled": true,
+ "optional": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "debug": {
+ "version": "3.2.6",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "bundled": true,
+ "optional": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "bundled": true,
+ "optional": true
+ },
+ "fs-minipass": {
+ "version": "1.2.7",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.6.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.6",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore-walk": {
+ "version": "3.0.3",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "bundled": true,
+ "optional": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "bundled": true,
+ "optional": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "bundled": true,
+ "optional": true
+ },
+ "minipass": {
+ "version": "2.9.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.3.3",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.9.0"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "bundled": true,
+ "optional": true
+ },
+ "needle": {
+ "version": "2.4.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "debug": "^3.2.6",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ }
+ },
+ "node-pre-gyp": {
+ "version": "0.14.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "detect-libc": "^1.0.2",
+ "mkdirp": "^0.5.1",
+ "needle": "^2.2.1",
+ "nopt": "^4.0.1",
+ "npm-packlist": "^1.1.6",
+ "npmlog": "^4.0.2",
+ "rc": "^1.2.7",
+ "rimraf": "^2.6.1",
+ "semver": "^5.3.0",
+ "tar": "^4.4.2"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.1.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "npm-normalize-package-bin": "^1.0.1"
+ }
+ },
+ "npm-normalize-package-bin": {
+ "version": "1.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "npm-packlist": {
+ "version": "1.4.7",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "rc": {
+ "version": "1.2.8",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "bundled": true,
+ "optional": true
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.7.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "bundled": true,
+ "optional": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "bundled": true,
+ "optional": true
+ },
+ "sax": {
+ "version": "1.2.4",
+ "bundled": true,
+ "optional": true
+ },
+ "semver": {
+ "version": "5.7.1",
+ "bundled": true,
+ "optional": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "tar": {
+ "version": "4.4.13",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.8.6",
+ "minizlib": "^1.2.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.3"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "yallist": {
+ "version": "3.1.1",
+ "bundled": true,
+ "optional": true
+ }
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "genfun": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz",
+ "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==",
+ "dev": true
+ },
+ "gensync": {
+ "version": "1.0.0-beta.1",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
+ "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg=="
+ },
+ "get-caller-file": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w=="
+ },
+ "get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
+ },
+ "globby": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz",
+ "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=",
+ "requires": {
+ "array-union": "^1.0.1",
+ "dir-glob": "^2.0.0",
+ "glob": "^7.1.2",
+ "ignore": "^3.3.5",
+ "pify": "^3.0.0",
+ "slash": "^1.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
+ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
+ },
+ "hammerjs": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
+ "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
+ },
+ "handle-thing": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
+ "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg=="
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "has-binary2": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
+ "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
+ "dev": true,
+ "requires": {
+ "isarray": "2.0.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+ "dev": true
+ }
+ }
+ },
+ "has-cors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
+ "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ },
+ "has-symbols": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
+ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "hash-base": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "hash.js": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "hmac-drbg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "requires": {
+ "hash.js": "^1.0.3",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "hosted-git-info": {
+ "version": "2.8.6",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.6.tgz",
+ "integrity": "sha512-Kp6rShEsCHhF5dD3EWKdkgVA8ix90oSUJ0VY4g9goxxa0+f4lx63muTftn0mlJ/+8IESGWyKnP//V2D7S4ZbIQ==",
+ "dev": true
+ },
+ "hpack.js": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
+ "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "obuf": "^1.0.0",
+ "readable-stream": "^2.0.1",
+ "wbuf": "^1.1.0"
+ }
+ },
+ "html-entities": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz",
+ "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA=="
+ },
+ "html-escaper": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz",
+ "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==",
+ "dev": true
+ },
+ "http-cache-semantics": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
+ "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==",
+ "dev": true
+ },
+ "http-deceiver": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
+ "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc="
+ },
+ "http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ }
+ }
+ },
+ "http-parser-js": {
+ "version": "0.4.10",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",
+ "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q="
+ },
+ "http-proxy": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz",
+ "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==",
+ "requires": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "http-proxy-agent": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
+ "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
+ "dev": true,
+ "requires": {
+ "agent-base": "4",
+ "debug": "3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
+ "http-proxy-middleware": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz",
+ "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==",
+ "requires": {
+ "http-proxy": "^1.17.0",
+ "is-glob": "^4.0.0",
+ "lodash": "^4.17.11",
+ "micromatch": "^3.1.10"
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "https-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
+ },
+ "https-proxy-agent": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
+ "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+ "dev": true,
+ "requires": {
+ "agent-base": "^4.3.0",
+ "debug": "^3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
+ "dev": true,
+ "requires": {
+ "ms": "^2.0.0"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ieee754": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
+ },
+ "iferr": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
+ "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
+ },
+ "ignore": {
+ "version": "3.3.10",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
+ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug=="
+ },
+ "ignore-walk": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
+ "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
+ "dev": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "image-size": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
+ "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
+ "optional": true
+ },
+ "immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
+ },
+ "import-cwd": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
+ "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
+ "requires": {
+ "import-from": "^2.1.0"
+ }
+ },
+ "import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+ "requires": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "import-from": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
+ "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
+ "requires": {
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "import-local": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
+ "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==",
+ "requires": {
+ "pkg-dir": "^3.0.0",
+ "resolve-cwd": "^2.0.0"
+ }
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+ },
+ "indexof": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
+ "dev": true
+ },
+ "infer-owner": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
+ "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A=="
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "dev": true
+ },
+ "inquirer": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz",
+ "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "^3.2.0",
+ "chalk": "^2.4.2",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^2.0.0",
+ "lodash": "^4.17.11",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rxjs": "^6.4.0",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^5.1.0",
+ "through": "^2.3.6"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "internal-ip": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
+ "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==",
+ "requires": {
+ "default-gateway": "^4.2.0",
+ "ipaddr.js": "^1.9.0"
+ }
+ },
+ "interpret": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
+ "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
+ "dev": true
+ },
+ "invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "invert-kv": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
+ "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="
+ },
+ "ip": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
+ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+ },
+ "ip-regex": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
+ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
+ "is-absolute-url": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz",
+ "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q=="
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-arguments": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
+ "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA=="
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "requires": {
+ "binary-extensions": "^1.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+ },
+ "is-callable": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
+ "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q=="
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-date-object": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
+ "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g=="
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
+ }
+ }
+ },
+ "is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-path-cwd": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
+ "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ=="
+ },
+ "is-path-in-cwd": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz",
+ "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==",
+ "requires": {
+ "is-path-inside": "^2.1.0"
+ }
+ },
+ "is-path-inside": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz",
+ "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==",
+ "requires": {
+ "path-is-inside": "^1.0.2"
+ }
+ },
+ "is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+ "dev": true
+ },
+ "is-regex": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
+ "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+ },
+ "is-symbol": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
+ "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
+ },
+ "is-wsl": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+ "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "isbinaryfile": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz",
+ "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==",
+ "dev": true,
+ "requires": {
+ "buffer-alloc": "^1.2.0"
+ }
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ },
+ "istanbul-api": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.6.tgz",
+ "integrity": "sha512-x0Eicp6KsShG1k1rMgBAi/1GgY7kFGEBwQpw3PXGEmu+rBcBNhqU8g2DgY9mlepAsLPzrzrbqSgCGANnki4POA==",
+ "dev": true,
+ "requires": {
+ "async": "^2.6.2",
+ "compare-versions": "^3.4.0",
+ "fileset": "^2.0.3",
+ "istanbul-lib-coverage": "^2.0.5",
+ "istanbul-lib-hook": "^2.0.7",
+ "istanbul-lib-instrument": "^3.3.0",
+ "istanbul-lib-report": "^2.0.8",
+ "istanbul-lib-source-maps": "^3.0.6",
+ "istanbul-reports": "^2.2.4",
+ "js-yaml": "^3.13.1",
+ "make-dir": "^2.1.0",
+ "minimatch": "^3.0.4",
+ "once": "^1.4.0"
+ },
+ "dependencies": {
+ "istanbul-lib-coverage": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
+ "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
+ "dev": true
+ },
+ "istanbul-lib-instrument": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz",
+ "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==",
+ "dev": true,
+ "requires": {
+ "@babel/generator": "^7.4.0",
+ "@babel/parser": "^7.4.3",
+ "@babel/template": "^7.4.0",
+ "@babel/traverse": "^7.4.3",
+ "@babel/types": "^7.4.0",
+ "istanbul-lib-coverage": "^2.0.5",
+ "semver": "^6.0.0"
+ }
+ }
+ }
+ },
+ "istanbul-lib-coverage": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
+ "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg=="
+ },
+ "istanbul-lib-hook": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz",
+ "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==",
+ "dev": true,
+ "requires": {
+ "append-transform": "^1.0.0"
+ }
+ },
+ "istanbul-lib-instrument": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz",
+ "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==",
+ "requires": {
+ "@babel/core": "^7.7.5",
+ "@babel/parser": "^7.7.5",
+ "@babel/template": "^7.7.4",
+ "@babel/traverse": "^7.7.4",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.0.0",
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ }
+ }
+ },
+ "istanbul-lib-report": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz",
+ "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==",
+ "dev": true,
+ "requires": {
+ "istanbul-lib-coverage": "^2.0.5",
+ "make-dir": "^2.1.0",
+ "supports-color": "^6.1.0"
+ },
+ "dependencies": {
+ "istanbul-lib-coverage": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
+ "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
+ "dev": true
+ }
+ }
+ },
+ "istanbul-lib-source-maps": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz",
+ "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^2.0.5",
+ "make-dir": "^2.1.0",
+ "rimraf": "^2.6.3",
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "istanbul-lib-coverage": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
+ "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "istanbul-reports": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz",
+ "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==",
+ "dev": true,
+ "requires": {
+ "html-escaper": "^2.0.0"
+ }
+ },
+ "jasmine": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz",
+ "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=",
+ "dev": true,
+ "requires": {
+ "exit": "^0.1.2",
+ "glob": "^7.0.6",
+ "jasmine-core": "~2.8.0"
+ },
+ "dependencies": {
+ "jasmine-core": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz",
+ "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=",
+ "dev": true
+ }
+ }
+ },
+ "jasmine-core": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.4.0.tgz",
+ "integrity": "sha512-HU/YxV4i6GcmiH4duATwAbJQMlE0MsDIR5XmSVxURxKHn3aGAdbY1/ZJFmVRbKtnLwIxxMJD7gYaPsypcbYimg==",
+ "dev": true
+ },
+ "jasmine-spec-reporter": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz",
+ "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==",
+ "dev": true,
+ "requires": {
+ "colors": "1.1.2"
+ }
+ },
+ "jasminewd2": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz",
+ "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=",
+ "dev": true
+ },
+ "jest-worker": {
+ "version": "24.9.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
+ "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==",
+ "requires": {
+ "merge-stream": "^2.0.0",
+ "supports-color": "^6.1.0"
+ }
+ },
+ "js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
+ },
+ "js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+ },
+ "jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ },
+ "json3": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
+ "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA=="
+ },
+ "json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+ "dev": true
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "jszip": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.4.0.tgz",
+ "integrity": "sha512-gZAOYuPl4EhPTXT0GjhI3o+ZAz3su6EhLrKUoAivcKqyqC7laS5JEv4XWZND9BgcDcF83vI85yGbDmDR6UhrIg==",
+ "requires": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "set-immediate-shim": "~1.0.1"
+ }
+ },
+ "karma": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/karma/-/karma-4.1.0.tgz",
+ "integrity": "sha512-xckiDqyNi512U4dXGOOSyLKPwek6X/vUizSy2f3geYevbLj+UIdvNwbn7IwfUIL2g1GXEPWt/87qFD1fBbl/Uw==",
+ "dev": true,
+ "requires": {
+ "bluebird": "^3.3.0",
+ "body-parser": "^1.16.1",
+ "braces": "^2.3.2",
+ "chokidar": "^2.0.3",
+ "colors": "^1.1.0",
+ "connect": "^3.6.0",
+ "core-js": "^2.2.0",
+ "di": "^0.0.1",
+ "dom-serialize": "^2.2.0",
+ "flatted": "^2.0.0",
+ "glob": "^7.1.1",
+ "graceful-fs": "^4.1.2",
+ "http-proxy": "^1.13.0",
+ "isbinaryfile": "^3.0.0",
+ "lodash": "^4.17.11",
+ "log4js": "^4.0.0",
+ "mime": "^2.3.1",
+ "minimatch": "^3.0.2",
+ "optimist": "^0.6.1",
+ "qjobs": "^1.1.4",
+ "range-parser": "^1.2.0",
+ "rimraf": "^2.6.0",
+ "safe-buffer": "^5.0.1",
+ "socket.io": "2.1.1",
+ "source-map": "^0.6.1",
+ "tmp": "0.0.33",
+ "useragent": "2.3.0"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "2.6.11",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
+ "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==",
+ "dev": true
+ },
+ "mime": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
+ "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ }
+ }
+ },
+ "karma-chrome-launcher": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz",
+ "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==",
+ "dev": true,
+ "requires": {
+ "fs-access": "^1.0.0",
+ "which": "^1.2.1"
+ }
+ },
+ "karma-coverage-istanbul-reporter": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.6.tgz",
+ "integrity": "sha512-WFh77RI8bMIKdOvI/1/IBmgnM+Q7NOLhnwG91QJrM8lW+CIXCjTzhhUsT/svLvAkLmR10uWY4RyYbHMLkTglvg==",
+ "dev": true,
+ "requires": {
+ "istanbul-api": "^2.1.6",
+ "minimatch": "^3.0.4"
+ }
+ },
+ "karma-jasmine": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz",
+ "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==",
+ "dev": true,
+ "requires": {
+ "jasmine-core": "^3.3"
+ }
+ },
+ "karma-jasmine-html-reporter": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.5.2.tgz",
+ "integrity": "sha512-ILBPsXqQ3eomq+oaQsM311/jxsypw5/d0LnZXj26XkfThwq7jZ55A2CFSKJVA5VekbbOGvMyv7d3juZj0SeTxA==",
+ "dev": true
+ },
+ "karma-source-map-support": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz",
+ "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==",
+ "requires": {
+ "source-map-support": "^0.5.5"
+ }
+ },
+ "killable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
+ "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg=="
+ },
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
+ },
+ "lcid": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
+ "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
+ "requires": {
+ "invert-kv": "^2.0.0"
+ }
+ },
+ "less": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz",
+ "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==",
+ "requires": {
+ "clone": "^2.1.2",
+ "errno": "^0.1.1",
+ "graceful-fs": "^4.1.2",
+ "image-size": "~0.5.0",
+ "mime": "^1.4.1",
+ "mkdirp": "^0.5.0",
+ "promise": "^7.1.1",
+ "request": "^2.83.0",
+ "source-map": "~0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "optional": true
+ }
+ }
+ },
+ "less-loader": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-5.0.0.tgz",
+ "integrity": "sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg==",
+ "requires": {
+ "clone": "^2.1.1",
+ "loader-utils": "^1.1.0",
+ "pify": "^4.0.1"
+ }
+ },
+ "leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="
+ },
+ "levenary": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz",
+ "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==",
+ "requires": {
+ "leven": "^3.1.0"
+ }
+ },
+ "license-webpack-plugin": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.1.2.tgz",
+ "integrity": "sha512-7poZHRla+ae0eEButlwMrPpkXyhNVBf2EHePYWT0jyLnI6311/OXJkTI2sOIRungRpQgU2oDMpro5bSFPT5F0A==",
+ "requires": {
+ "@types/webpack-sources": "^0.1.5",
+ "webpack-sources": "^1.2.0"
+ }
+ },
+ "lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "requires": {
+ "immediate": "~3.0.5"
+ }
+ },
+ "loader-runner": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
+ "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw=="
+ },
+ "loader-utils": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
+ "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
+ "requires": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^2.0.0",
+ "json5": "^1.0.1"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+ },
+ "lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
+ },
+ "log4js": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz",
+ "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==",
+ "dev": true,
+ "requires": {
+ "date-format": "^2.0.0",
+ "debug": "^4.1.1",
+ "flatted": "^2.0.0",
+ "rfdc": "^1.1.4",
+ "streamroller": "^1.0.6"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "loglevel": {
+ "version": "1.6.8",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz",
+ "integrity": "sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA=="
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "requires": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "magic-string": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.2.tgz",
+ "integrity": "sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg==",
+ "dev": true,
+ "requires": {
+ "sourcemap-codec": "^1.4.4"
+ }
+ },
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "requires": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ }
+ }
+ },
+ "make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
+ "make-fetch-happen": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-4.0.2.tgz",
+ "integrity": "sha512-YMJrAjHSb/BordlsDEcVcPyTbiJKkzqMf48N8dAJZT9Zjctrkb6Yg4TY9Sq2AwSIQJFn5qBBKVTYt3vP5FMIHA==",
+ "dev": true,
+ "requires": {
+ "agentkeepalive": "^3.4.1",
+ "cacache": "^11.3.3",
+ "http-cache-semantics": "^3.8.1",
+ "http-proxy-agent": "^2.1.0",
+ "https-proxy-agent": "^2.2.1",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "node-fetch-npm": "^2.0.2",
+ "promise-retry": "^1.1.1",
+ "socks-proxy-agent": "^4.0.0",
+ "ssri": "^6.0.0"
+ }
+ },
+ "mamacro": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz",
+ "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA=="
+ },
+ "map-age-cleaner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
+ "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
+ "requires": {
+ "p-defer": "^1.0.0"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "mat-table-exporter": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/mat-table-exporter/-/mat-table-exporter-9.0.0.tgz",
+ "integrity": "sha512-xqvitbmC2dhABjVov0GACG8Nr0NmK83MB6nant4kuMIAVGc3yMZI+Q4F/hC/FHtVELwZuD+H8NFR9V/dqCAWdw==",
+ "requires": {
+ "cdk-table-exporter": "^9.0.0"
+ }
+ },
+ "md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "mem": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
+ "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
+ "requires": {
+ "map-age-cleaner": "^0.1.1",
+ "mimic-fn": "^2.0.0",
+ "p-is-promise": "^2.0.0"
+ }
+ },
+ "memory-fs": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
+ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
+ "requires": {
+ "errno": "^0.1.3",
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "merge-source-map": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
+ "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
+ "requires": {
+ "source-map": "^0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "miller-rabin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+ "requires": {
+ "bn.js": "^4.0.0",
+ "brorand": "^1.0.1"
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "mime-db": {
+ "version": "1.43.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
+ "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
+ },
+ "mime-types": {
+ "version": "2.1.26",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
+ "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
+ "requires": {
+ "mime-db": "1.43.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
+ },
+ "mini-css-extract-plugin": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz",
+ "integrity": "sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw==",
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "normalize-url": "1.9.1",
+ "schema-utils": "^1.0.0",
+ "webpack-sources": "^1.1.0"
+ }
+ },
+ "minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
+ },
+ "minimalistic-crypto-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ },
+ "minipass": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
+ "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
+ "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
+ "dev": true,
+ "requires": {
+ "minipass": "^2.9.0"
+ }
+ },
+ "mississippi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
+ "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
+ "requires": {
+ "concat-stream": "^1.5.0",
+ "duplexify": "^3.4.2",
+ "end-of-stream": "^1.1.0",
+ "flush-write-stream": "^1.0.0",
+ "from2": "^2.1.0",
+ "parallel-transform": "^1.1.0",
+ "pump": "^3.0.0",
+ "pumpify": "^1.3.3",
+ "stream-each": "^1.1.0",
+ "through2": "^2.0.0"
+ }
+ },
+ "mixin-deep": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ }
+ }
+ },
+ "move-concurrently": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
+ "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
+ "requires": {
+ "aproba": "^1.1.1",
+ "copy-concurrently": "^1.0.0",
+ "fs-write-stream-atomic": "^1.0.8",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.4",
+ "run-queue": "^1.0.3"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "multicast-dns": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
+ "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
+ "requires": {
+ "dns-packet": "^1.3.1",
+ "thunky": "^1.0.2"
+ }
+ },
+ "multicast-dns-service-types": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
+ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+ "dev": true
+ },
+ "nan": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
+ "optional": true
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+ },
+ "neo-async": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
+ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw=="
+ },
+ "ng4-loading-spinner": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/ng4-loading-spinner/-/ng4-loading-spinner-1.2.3.tgz",
+ "integrity": "sha512-AxokaWmIMSv4YeZcwzSCs0f1PBnn/lgOVpaXuR5PdnNqGkpDema6b2KwONLtdzmL5YqKOpQo8DoyTRhlzGoohQ=="
+ },
+ "nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
+ },
+ "node-fetch-npm": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz",
+ "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==",
+ "dev": true,
+ "requires": {
+ "encoding": "^0.1.11",
+ "json-parse-better-errors": "^1.0.0",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "node-forge": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
+ "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ=="
+ },
+ "node-libs-browser": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
+ "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
+ "requires": {
+ "assert": "^1.1.1",
+ "browserify-zlib": "^0.2.0",
+ "buffer": "^4.3.0",
+ "console-browserify": "^1.1.0",
+ "constants-browserify": "^1.0.0",
+ "crypto-browserify": "^3.11.0",
+ "domain-browser": "^1.1.1",
+ "events": "^3.0.0",
+ "https-browserify": "^1.0.0",
+ "os-browserify": "^0.3.0",
+ "path-browserify": "0.0.1",
+ "process": "^0.11.10",
+ "punycode": "^1.2.4",
+ "querystring-es3": "^0.2.0",
+ "readable-stream": "^2.3.3",
+ "stream-browserify": "^2.0.1",
+ "stream-http": "^2.7.2",
+ "string_decoder": "^1.0.0",
+ "timers-browserify": "^2.0.4",
+ "tty-browserify": "0.0.0",
+ "url": "^0.11.0",
+ "util": "^0.11.0",
+ "vm-browserify": "^1.0.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ }
+ }
+ },
+ "node-releases": {
+ "version": "1.1.53",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz",
+ "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ=="
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+ },
+ "normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI="
+ },
+ "normalize-url": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
+ "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
+ "requires": {
+ "object-assign": "^4.0.1",
+ "prepend-http": "^1.0.0",
+ "query-string": "^4.1.0",
+ "sort-keys": "^1.0.0"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
+ "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
+ "dev": true,
+ "requires": {
+ "npm-normalize-package-bin": "^1.0.1"
+ }
+ },
+ "npm-normalize-package-bin": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
+ "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==",
+ "dev": true
+ },
+ "npm-package-arg": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz",
+ "integrity": "sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "^2.6.0",
+ "osenv": "^0.1.5",
+ "semver": "^5.5.0",
+ "validate-npm-package-name": "^3.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "npm-packlist": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
+ "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
+ "dev": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1",
+ "npm-normalize-package-bin": "^1.0.1"
+ }
+ },
+ "npm-pick-manifest": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz",
+ "integrity": "sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA==",
+ "dev": true,
+ "requires": {
+ "figgy-pudding": "^3.5.1",
+ "npm-package-arg": "^6.0.0",
+ "semver": "^5.4.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "npm-registry-fetch": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.9.1.tgz",
+ "integrity": "sha512-VQCEZlydXw4AwLROAXWUR7QDfe2Y8Id/vpAgp6TI1/H78a4SiQ1kQrKZALm5/zxM5n4HIi+aYb+idUAV/RuY0Q==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "^1.3.4",
+ "bluebird": "^3.5.1",
+ "figgy-pudding": "^3.4.1",
+ "lru-cache": "^5.1.1",
+ "make-fetch-happen": "^4.0.2",
+ "npm-package-arg": "^6.1.0"
+ }
+ },
+ "npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "requires": {
+ "path-key": "^2.0.0"
+ }
+ },
+ "null-check": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz",
+ "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=",
+ "dev": true
+ },
+ "num2fraction": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+ "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4="
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "object-component": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
+ "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
+ "dev": true
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-inspect": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
+ "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw=="
+ },
+ "object-is": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz",
+ "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==",
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ }
+ },
+ "object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.assign": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+ "requires": {
+ "define-properties": "^1.1.2",
+ "function-bind": "^1.1.1",
+ "has-symbols": "^1.0.0",
+ "object-keys": "^1.0.11"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "obuf": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
+ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "on-headers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ },
+ "dependencies": {
+ "mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+ "dev": true
+ }
+ }
+ },
+ "open": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-6.2.0.tgz",
+ "integrity": "sha512-Vxf6HJkwrqmvh9UAID3MnMYXntbTxKLOSfOnO7LJdzPf3NE3KQYFNV0/Lcz2VAndbRFil58XVCyh8tiX11fiYw==",
+ "dev": true,
+ "requires": {
+ "is-wsl": "^1.1.0"
+ }
+ },
+ "opn": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
+ "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
+ "requires": {
+ "is-wsl": "^1.1.0"
+ }
+ },
+ "optimist": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "dev": true,
+ "requires": {
+ "minimist": "~0.0.1",
+ "wordwrap": "~0.0.2"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
+ "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
+ "dev": true
+ }
+ }
+ },
+ "original": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
+ "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
+ "requires": {
+ "url-parse": "^1.4.3"
+ }
+ },
+ "os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "dev": true
+ },
+ "os-locale": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
+ "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
+ "requires": {
+ "execa": "^1.0.0",
+ "lcid": "^2.0.0",
+ "mem": "^4.0.0"
+ }
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+ "dev": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "p-defer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
+ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+ },
+ "p-is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
+ "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg=="
+ },
+ "p-limit": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
+ "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "p-map": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
+ "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="
+ },
+ "p-retry": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz",
+ "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==",
+ "requires": {
+ "retry": "^0.12.0"
+ },
+ "dependencies": {
+ "retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs="
+ }
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+ },
+ "pacote": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.0.tgz",
+ "integrity": "sha512-aUplXozRbzhaJO48FaaeClmN+2Mwt741MC6M3bevIGZwdCaP7frXzbUOfOWa91FPHoLITzG0hYaKY363lxO3bg==",
+ "dev": true,
+ "requires": {
+ "bluebird": "^3.5.3",
+ "cacache": "^11.3.2",
+ "figgy-pudding": "^3.5.1",
+ "get-stream": "^4.1.0",
+ "glob": "^7.1.3",
+ "lru-cache": "^5.1.1",
+ "make-fetch-happen": "^4.0.1",
+ "minimatch": "^3.0.4",
+ "minipass": "^2.3.5",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "normalize-package-data": "^2.4.0",
+ "npm-package-arg": "^6.1.0",
+ "npm-packlist": "^1.1.12",
+ "npm-pick-manifest": "^2.2.3",
+ "npm-registry-fetch": "^3.8.0",
+ "osenv": "^0.1.5",
+ "promise-inflight": "^1.0.1",
+ "promise-retry": "^1.1.1",
+ "protoduck": "^5.0.1",
+ "rimraf": "^2.6.2",
+ "safe-buffer": "^5.1.2",
+ "semver": "^5.6.0",
+ "ssri": "^6.0.1",
+ "tar": "^4.4.8",
+ "unique-filename": "^1.1.1",
+ "which": "^1.3.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+ },
+ "parallel-transform": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
+ "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
+ "requires": {
+ "cyclist": "^1.0.1",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.1.5"
+ }
+ },
+ "parse-asn1": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz",
+ "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==",
+ "requires": {
+ "asn1.js": "^4.0.0",
+ "browserify-aes": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.0",
+ "pbkdf2": "^3.0.3",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "requires": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ }
+ },
+ "parse5": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
+ "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
+ },
+ "parseqs": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
+ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
+ "dev": true,
+ "requires": {
+ "better-assert": "~1.0.0"
+ }
+ },
+ "parseuri": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
+ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
+ "dev": true,
+ "requires": {
+ "better-assert": "~1.0.0"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
+ },
+ "path-browserify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
+ "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ=="
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "path-type": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+ "requires": {
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+ }
+ }
+ },
+ "pbkdf2": {
+ "version": "3.0.17",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
+ "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
+ "requires": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "pkg-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
+ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+ "requires": {
+ "find-up": "^3.0.0"
+ }
+ },
+ "pkg-up": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
+ "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
+ "requires": {
+ "find-up": "^2.1.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
+ }
+ }
+ },
+ "portfinder": {
+ "version": "1.0.25",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz",
+ "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==",
+ "requires": {
+ "async": "^2.6.2",
+ "debug": "^3.1.1",
+ "mkdirp": "^0.5.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
+ },
+ "postcss": {
+ "version": "7.0.17",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz",
+ "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==",
+ "requires": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "postcss-import": {
+ "version": "12.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz",
+ "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==",
+ "requires": {
+ "postcss": "^7.0.1",
+ "postcss-value-parser": "^3.2.3",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
+ }
+ }
+ },
+ "postcss-load-config": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz",
+ "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==",
+ "requires": {
+ "cosmiconfig": "^5.0.0",
+ "import-cwd": "^2.0.0"
+ }
+ },
+ "postcss-loader": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz",
+ "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==",
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "postcss": "^7.0.0",
+ "postcss-load-config": "^2.0.0",
+ "schema-utils": "^1.0.0"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz",
+ "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg=="
+ },
+ "prepend-http": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
+ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
+ },
+ "primeicons": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-2.0.0.tgz",
+ "integrity": "sha512-GJTCeMSQU8UU1GqbsaDrg/IH+b/vSinJQl52NVpdJ7sShYLZA8Eq6jLF48Ye3N/dQloGrE07i7XsZvxQ9pNbqg=="
+ },
+ "primeng": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/primeng/-/primeng-8.1.1.tgz",
+ "integrity": "sha512-8dP8A3qkmOvDTe97kCeFvoCk6oPNDdgMTdT4UBzhC4ua5wM7i7pjYXuKzAXm3oEFf+iSEB6WqzzfSqyZdbEA+w=="
+ },
+ "printj": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
+ "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ=="
+ },
+ "private": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+ "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
+ },
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
+ "promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "optional": true,
+ "requires": {
+ "asap": "~2.0.3"
+ }
+ },
+ "promise-inflight": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
+ },
+ "promise-retry": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz",
+ "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=",
+ "dev": true,
+ "requires": {
+ "err-code": "^1.0.0",
+ "retry": "^0.10.0"
+ }
+ },
+ "protoduck": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz",
+ "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==",
+ "dev": true,
+ "requires": {
+ "genfun": "^5.0.0"
+ }
+ },
+ "protractor": {
+ "version": "5.4.3",
+ "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.3.tgz",
+ "integrity": "sha512-7pMAolv8Ah1yJIqaorDTzACtn3gk7BamVKPTeO5lqIGOrfosjPgXFx/z1dqSI+m5EeZc2GMJHPr5DYlodujDNA==",
+ "dev": true,
+ "requires": {
+ "@types/q": "^0.0.32",
+ "@types/selenium-webdriver": "^3.0.0",
+ "blocking-proxy": "^1.0.0",
+ "browserstack": "^1.5.1",
+ "chalk": "^1.1.3",
+ "glob": "^7.0.3",
+ "jasmine": "2.8.0",
+ "jasminewd2": "^2.1.0",
+ "optimist": "~0.6.0",
+ "q": "1.4.1",
+ "saucelabs": "^1.5.0",
+ "selenium-webdriver": "3.6.0",
+ "source-map-support": "~0.4.0",
+ "webdriver-js-extender": "2.1.0",
+ "webdriver-manager": "^12.0.6"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "del": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+ "dev": true,
+ "requires": {
+ "globby": "^5.0.0",
+ "is-path-cwd": "^1.0.0",
+ "is-path-in-cwd": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "rimraf": "^2.2.8"
+ }
+ },
+ "globby": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+ "dev": true,
+ "requires": {
+ "array-union": "^1.0.1",
+ "arrify": "^1.0.0",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "is-path-cwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+ "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+ "dev": true
+ },
+ "is-path-in-cwd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+ "dev": true,
+ "requires": {
+ "is-path-inside": "^1.0.0"
+ }
+ },
+ "is-path-inside": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+ "dev": true,
+ "requires": {
+ "path-is-inside": "^1.0.1"
+ }
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "source-map-support": {
+ "version": "0.4.18",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+ "dev": true,
+ "requires": {
+ "source-map": "^0.5.6"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ },
+ "webdriver-manager": {
+ "version": "12.1.7",
+ "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.7.tgz",
+ "integrity": "sha512-XINj6b8CYuUYC93SG3xPkxlyUc3IJbD6Vvo75CVGuG9uzsefDzWQrhz0Lq8vbPxtb4d63CZdYophF8k8Or/YiA==",
+ "dev": true,
+ "requires": {
+ "adm-zip": "^0.4.9",
+ "chalk": "^1.1.1",
+ "del": "^2.2.0",
+ "glob": "^7.0.3",
+ "ini": "^1.3.4",
+ "minimist": "^1.2.0",
+ "q": "^1.4.1",
+ "request": "^2.87.0",
+ "rimraf": "^2.5.2",
+ "semver": "^5.3.0",
+ "xml2js": "^0.4.17"
+ }
+ }
+ }
+ },
+ "proxy-addr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+ "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
+ },
+ "pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+ "dev": true
+ },
+ "psl": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
+ "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ=="
+ },
+ "public-encrypt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "parse-asn1": "^5.0.0",
+ "randombytes": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "pumpify": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+ "requires": {
+ "duplexify": "^3.6.0",
+ "inherits": "^2.0.3",
+ "pump": "^2.0.0"
+ },
+ "dependencies": {
+ "pump": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ }
+ }
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ },
+ "q": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz",
+ "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=",
+ "dev": true
+ },
+ "qjobs": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
+ "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ },
+ "query-string": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+ "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+ "requires": {
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ }
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
+ },
+ "querystring-es3": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
+ },
+ "querystringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
+ "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "randomfill": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+ "requires": {
+ "randombytes": "^2.0.5",
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "requires": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+ }
+ }
+ },
+ "raw-loader": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-3.1.0.tgz",
+ "integrity": "sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA==",
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "schema-utils": "^2.0.1"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.12.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
+ "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
+ },
+ "schema-utils": {
+ "version": "2.6.6",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz",
+ "integrity": "sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA==",
+ "requires": {
+ "ajv": "^6.12.0",
+ "ajv-keywords": "^3.4.1"
+ }
+ }
+ }
+ },
+ "read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=",
+ "requires": {
+ "pify": "^2.3.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ }
+ }
+ },
+ "read-package-json": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz",
+ "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.1",
+ "graceful-fs": "^4.1.2",
+ "json-parse-better-errors": "^1.0.1",
+ "normalize-package-data": "^2.0.0",
+ "npm-normalize-package-bin": "^1.0.0"
+ }
+ },
+ "read-package-tree": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.2.2.tgz",
+ "integrity": "sha512-rW3XWUUkhdKmN2JKB4FL563YAgtINifso5KShykufR03nJ5loGFlkUMe1g/yxmqX073SoYYTsgXu7XdDinKZuA==",
+ "dev": true,
+ "requires": {
+ "debuglog": "^1.0.1",
+ "dezalgo": "^1.0.0",
+ "once": "^1.3.0",
+ "read-package-json": "^2.0.0",
+ "readdir-scoped-modules": "^1.0.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdir-scoped-modules": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz",
+ "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==",
+ "dev": true,
+ "requires": {
+ "debuglog": "^1.0.1",
+ "dezalgo": "^1.0.0",
+ "graceful-fs": "^4.1.2",
+ "once": "^1.3.0"
+ }
+ },
+ "readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "rechoir": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+ "dev": true,
+ "requires": {
+ "resolve": "^1.1.6"
+ }
+ },
+ "reflect-metadata": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
+ "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
+ "dev": true
+ },
+ "regenerate": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
+ "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg=="
+ },
+ "regenerate-unicode-properties": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz",
+ "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==",
+ "requires": {
+ "regenerate": "^1.4.0"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.13.3",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
+ "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
+ },
+ "regenerator-transform": {
+ "version": "0.14.4",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.4.tgz",
+ "integrity": "sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw==",
+ "requires": {
+ "@babel/runtime": "^7.8.4",
+ "private": "^0.1.8"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "regexp.prototype.flags": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
+ "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.0-next.1"
+ }
+ },
+ "regexpu-core": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
+ "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
+ "dev": true,
+ "requires": {
+ "regenerate": "^1.2.1",
+ "regjsgen": "^0.2.0",
+ "regjsparser": "^0.1.4"
+ }
+ },
+ "regjsgen": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
+ "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
+ "dev": true
+ },
+ "regjsparser": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
+ "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
+ "dev": true,
+ "requires": {
+ "jsesc": "~0.5.0"
+ },
+ "dependencies": {
+ "jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+ "dev": true
+ }
+ }
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g=="
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
+ },
+ "request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
+ },
+ "resolve": {
+ "version": "1.15.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz",
+ "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==",
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ },
+ "resolve-cwd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
+ "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
+ "requires": {
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "dev": true,
+ "requires": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
+ },
+ "retry": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz",
+ "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=",
+ "dev": true
+ },
+ "rfdc": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz",
+ "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "run-async": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz",
+ "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==",
+ "dev": true,
+ "requires": {
+ "is-promise": "^2.1.0"
+ }
+ },
+ "run-queue": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
+ "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
+ "requires": {
+ "aproba": "^1.1.1"
+ }
+ },
+ "rxjs": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+ "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "sass": {
+ "version": "1.22.9",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.22.9.tgz",
+ "integrity": "sha512-FzU1X2V8DlnqabrL4u7OBwD2vcOzNMongEJEx3xMEhWY/v26FFR3aG0hyeu2T965sfR0E9ufJwmG+Qjz78vFPQ==",
+ "requires": {
+ "chokidar": ">=2.0.0 <4.0.0"
+ }
+ },
+ "sass-loader": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.2.0.tgz",
+ "integrity": "sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA==",
+ "requires": {
+ "clone-deep": "^4.0.1",
+ "loader-utils": "^1.0.1",
+ "neo-async": "^2.5.0",
+ "pify": "^4.0.1",
+ "semver": "^5.5.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ }
+ }
+ },
+ "saucelabs": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz",
+ "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==",
+ "dev": true,
+ "requires": {
+ "https-proxy-agent": "^2.2.1"
+ }
+ },
+ "sax": {
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
+ "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE="
+ },
+ "schema-utils": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "requires": {
+ "ajv": "^6.1.0",
+ "ajv-errors": "^1.0.0",
+ "ajv-keywords": "^3.1.0"
+ }
+ },
+ "select-hose": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
+ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo="
+ },
+ "selenium-webdriver": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz",
+ "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==",
+ "dev": true,
+ "requires": {
+ "jszip": "^3.1.3",
+ "rimraf": "^2.5.4",
+ "tmp": "0.0.30",
+ "xml2js": "^0.4.17"
+ },
+ "dependencies": {
+ "tmp": {
+ "version": "0.0.30",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",
+ "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.1"
+ }
+ }
+ }
+ },
+ "selfsigned": {
+ "version": "1.10.7",
+ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz",
+ "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==",
+ "requires": {
+ "node-forge": "0.9.0"
+ }
+ },
+ "semver": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz",
+ "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ=="
+ },
+ "semver-dsl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
+ "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=",
+ "dev": true,
+ "requires": {
+ "semver": "^5.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "semver-intersect": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz",
+ "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==",
+ "dev": true,
+ "requires": {
+ "semver": "^5.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "send": {
+ "version": "0.17.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ }
+ }
+ },
+ "serialize-javascript": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
+ "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ=="
+ },
+ "serve-index": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+ "requires": {
+ "accepts": "~1.3.4",
+ "batch": "0.6.1",
+ "debug": "2.6.9",
+ "escape-html": "~1.0.3",
+ "http-errors": "~1.6.2",
+ "mime-types": "~2.1.17",
+ "parseurl": "~1.3.2"
+ },
+ "dependencies": {
+ "http-errors": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.0",
+ "statuses": ">= 1.4.0 < 2"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "setprototypeof": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
+ "set-immediate-shim": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
+ },
+ "set-value": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
+ },
+ "setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "shallow-clone": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
+ "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
+ "requires": {
+ "kind-of": "^6.0.2"
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+ },
+ "shelljs": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz",
+ "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.0.0",
+ "interpret": "^1.0.0",
+ "rechoir": "^0.6.2"
+ }
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ },
+ "slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU="
+ },
+ "smart-buffer": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz",
+ "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==",
+ "dev": true
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "socket.io": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz",
+ "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==",
+ "dev": true,
+ "requires": {
+ "debug": "~3.1.0",
+ "engine.io": "~3.2.0",
+ "has-binary2": "~1.0.2",
+ "socket.io-adapter": "~1.1.0",
+ "socket.io-client": "2.1.1",
+ "socket.io-parser": "~3.2.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
+ "socket.io-adapter": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
+ "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==",
+ "dev": true
+ },
+ "socket.io-client": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz",
+ "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==",
+ "dev": true,
+ "requires": {
+ "backo2": "1.0.2",
+ "base64-arraybuffer": "0.1.5",
+ "component-bind": "1.0.0",
+ "component-emitter": "1.2.1",
+ "debug": "~3.1.0",
+ "engine.io-client": "~3.2.0",
+ "has-binary2": "~1.0.2",
+ "has-cors": "1.1.0",
+ "indexof": "0.0.1",
+ "object-component": "0.0.3",
+ "parseqs": "0.0.5",
+ "parseuri": "0.0.5",
+ "socket.io-parser": "~3.2.0",
+ "to-array": "0.1.4"
+ },
+ "dependencies": {
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
+ "socket.io-parser": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
+ "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==",
+ "dev": true,
+ "requires": {
+ "component-emitter": "1.2.1",
+ "debug": "~3.1.0",
+ "isarray": "2.0.1"
+ },
+ "dependencies": {
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "isarray": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+ "dev": true
+ }
+ }
+ },
+ "sockjs": {
+ "version": "0.3.19",
+ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
+ "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==",
+ "requires": {
+ "faye-websocket": "^0.10.0",
+ "uuid": "^3.0.1"
+ }
+ },
+ "sockjs-client": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz",
+ "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==",
+ "requires": {
+ "debug": "^3.2.5",
+ "eventsource": "^1.0.7",
+ "faye-websocket": "~0.11.1",
+ "inherits": "^2.0.3",
+ "json3": "^3.3.2",
+ "url-parse": "^1.4.3"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "faye-websocket": {
+ "version": "0.11.3",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
+ "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
+ "requires": {
+ "websocket-driver": ">=0.5.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
+ "socks": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz",
+ "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==",
+ "dev": true,
+ "requires": {
+ "ip": "1.1.5",
+ "smart-buffer": "^4.1.0"
+ }
+ },
+ "socks-proxy-agent": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz",
+ "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==",
+ "dev": true,
+ "requires": {
+ "agent-base": "~4.2.1",
+ "socks": "~2.3.2"
+ },
+ "dependencies": {
+ "agent-base": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
+ "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
+ "dev": true,
+ "requires": {
+ "es6-promisify": "^5.0.0"
+ }
+ }
+ }
+ },
+ "sort-keys": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
+ "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
+ "requires": {
+ "is-plain-obj": "^1.0.0"
+ }
+ },
+ "source-list-map": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
+ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="
+ },
+ "source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
+ },
+ "source-map-loader": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.4.tgz",
+ "integrity": "sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ==",
+ "requires": {
+ "async": "^2.5.0",
+ "loader-utils": "^1.1.0"
+ }
+ },
+ "source-map-resolve": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+ "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+ "requires": {
+ "atob": "^2.1.2",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-support": {
+ "version": "0.5.12",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz",
+ "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==",
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
+ },
+ "sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
+ },
+ "spdx-correct": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+ "dev": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+ "dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+ "dev": true
+ },
+ "spdy": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
+ "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==",
+ "requires": {
+ "debug": "^4.1.0",
+ "handle-thing": "^2.0.0",
+ "http-deceiver": "^1.2.7",
+ "select-hose": "^2.0.0",
+ "spdy-transport": "^3.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
+ "spdy-transport": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
+ "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
+ "requires": {
+ "debug": "^4.1.0",
+ "detect-node": "^2.0.4",
+ "hpack.js": "^2.1.6",
+ "obuf": "^1.1.2",
+ "readable-stream": "^3.0.6",
+ "wbuf": "^1.7.3"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "speed-measure-webpack-plugin": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.1.tgz",
+ "integrity": "sha512-qVIkJvbtS9j/UeZumbdfz0vg+QfG/zxonAjzefZrqzkr7xOncLVXkeGbTpzd1gjCBM4PmVNkWlkeTVhgskAGSQ==",
+ "requires": {
+ "chalk": "^2.0.1"
+ }
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ },
+ "ssf": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.3.tgz",
+ "integrity": "sha512-pRuUdW0WwyB2doSqqjWyzwCD6PkfxpHAHdZp39K3dp/Hq7f+xfMwNAWIi16DyrRg4gg9c/RvLYkJTSawTPTm1w==",
+ "requires": {
+ "frac": "~1.1.2"
+ }
+ },
+ "sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "ssri": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
+ "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
+ "requires": {
+ "figgy-pudding": "^3.5.1"
+ }
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ },
+ "stream-browserify": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+ "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
+ "requires": {
+ "inherits": "~2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "stream-each": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
+ "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==",
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "stream-http": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+ "requires": {
+ "builtin-status-codes": "^3.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.3.6",
+ "to-arraybuffer": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "stream-shift": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
+ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
+ },
+ "streamroller": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz",
+ "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==",
+ "dev": true,
+ "requires": {
+ "async": "^2.6.2",
+ "date-format": "^2.0.0",
+ "debug": "^3.2.6",
+ "fs-extra": "^7.0.1",
+ "lodash": "^4.17.14"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "strict-uri-encode": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
+ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "string.prototype.trimend": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
+ "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ }
+ },
+ "string.prototype.trimleft": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
+ "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5",
+ "string.prototype.trimstart": "^1.0.0"
+ }
+ },
+ "string.prototype.trimright": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
+ "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5",
+ "string.prototype.trimend": "^1.0.0"
+ }
+ },
+ "string.prototype.trimstart": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
+ "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true
+ },
+ "strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
+ },
+ "style-loader": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.0.0.tgz",
+ "integrity": "sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw==",
+ "requires": {
+ "loader-utils": "^1.2.3",
+ "schema-utils": "^2.0.1"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.12.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
+ "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
+ },
+ "schema-utils": {
+ "version": "2.6.6",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz",
+ "integrity": "sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA==",
+ "requires": {
+ "ajv": "^6.12.0",
+ "ajv-keywords": "^3.4.1"
+ }
+ }
+ }
+ },
+ "stylus": {
+ "version": "0.54.5",
+ "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz",
+ "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=",
+ "requires": {
+ "css-parse": "1.7.x",
+ "debug": "*",
+ "glob": "7.0.x",
+ "mkdirp": "0.5.x",
+ "sax": "0.5.x",
+ "source-map": "0.1.x"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
+ "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.2",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "source-map": {
+ "version": "0.1.43",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
+ "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
+ "requires": {
+ "amdefine": ">=0.0.4"
+ }
+ }
+ }
+ },
+ "stylus-loader": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz",
+ "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==",
+ "requires": {
+ "loader-utils": "^1.0.2",
+ "lodash.clonedeep": "^4.5.0",
+ "when": "~3.6.x"
+ }
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "symbol-observable": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
+ "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
+ "dev": true
+ },
+ "tapable": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
+ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="
+ },
+ "tar": {
+ "version": "4.4.13",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
+ "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
+ "dev": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.8.6",
+ "minizlib": "^1.2.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.3"
+ }
+ },
+ "terser": {
+ "version": "4.6.3",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.3.tgz",
+ "integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==",
+ "requires": {
+ "commander": "^2.20.0",
+ "source-map": "~0.6.1",
+ "source-map-support": "~0.5.12"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "terser-webpack-plugin": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
+ "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
+ "requires": {
+ "cacache": "^12.0.2",
+ "find-cache-dir": "^2.1.0",
+ "is-wsl": "^1.1.0",
+ "schema-utils": "^1.0.0",
+ "serialize-javascript": "^2.1.2",
+ "source-map": "^0.6.1",
+ "terser": "^4.1.2",
+ "webpack-sources": "^1.4.0",
+ "worker-farm": "^1.7.0"
+ },
+ "dependencies": {
+ "cacache": {
+ "version": "12.0.4",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
+ "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==",
+ "requires": {
+ "bluebird": "^3.5.5",
+ "chownr": "^1.1.1",
+ "figgy-pudding": "^3.5.1",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.1.15",
+ "infer-owner": "^1.0.3",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "move-concurrently": "^1.0.1",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^2.6.3",
+ "ssri": "^6.0.1",
+ "unique-filename": "^1.1.1",
+ "y18n": "^4.0.0"
+ }
+ },
+ "find-cache-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
+ "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^2.0.0",
+ "pkg-dir": "^3.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "requires": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "thunky": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
+ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="
+ },
+ "timers-browserify": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz",
+ "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==",
+ "requires": {
+ "setimmediate": "^1.0.4"
+ }
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "to-array": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
+ "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
+ "dev": true
+ },
+ "to-arraybuffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="
+ },
+ "to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+ },
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ },
+ "tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="
+ },
+ "ts-node": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz",
+ "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==",
+ "dev": true,
+ "requires": {
+ "arrify": "^1.0.0",
+ "buffer-from": "^1.1.0",
+ "diff": "^3.1.0",
+ "make-error": "^1.1.1",
+ "minimist": "^1.2.0",
+ "mkdirp": "^0.5.1",
+ "source-map-support": "^0.5.6",
+ "yn": "^2.0.0"
+ }
+ },
+ "tslib": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz",
+ "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg=="
+ },
+ "tslint": {
+ "version": "5.15.0",
+ "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.15.0.tgz",
+ "integrity": "sha512-6bIEujKR21/3nyeoX2uBnE8s+tMXCQXhqMmaIPJpHmXJoBJPTLcI7/VHRtUwMhnLVdwLqqY3zmd8Dxqa5CVdJA==",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "^6.22.0",
+ "builtin-modules": "^1.1.1",
+ "chalk": "^2.3.0",
+ "commander": "^2.12.1",
+ "diff": "^3.2.0",
+ "glob": "^7.1.1",
+ "js-yaml": "^3.13.0",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "resolve": "^1.3.2",
+ "semver": "^5.3.0",
+ "tslib": "^1.8.0",
+ "tsutils": "^2.29.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "tsutils": {
+ "version": "2.29.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
+ "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.8.1"
+ }
+ },
+ "tty-browserify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+ "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ },
+ "typescript": {
+ "version": "3.4.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz",
+ "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==",
+ "dev": true
+ },
+ "ultron": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
+ "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
+ "dev": true
+ },
+ "unicode-canonical-property-names-ecmascript": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
+ "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ=="
+ },
+ "unicode-match-property-ecmascript": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz",
+ "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==",
+ "requires": {
+ "unicode-canonical-property-names-ecmascript": "^1.0.4",
+ "unicode-property-aliases-ecmascript": "^1.0.4"
+ }
+ },
+ "unicode-match-property-value-ecmascript": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz",
+ "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ=="
+ },
+ "unicode-property-aliases-ecmascript": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz",
+ "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg=="
+ },
+ "union-value": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^2.0.1"
+ }
+ },
+ "unique-filename": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
+ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+ "requires": {
+ "unique-slug": "^2.0.0"
+ }
+ },
+ "unique-slug": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
+ "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
+ "requires": {
+ "imurmurhash": "^0.1.4"
+ }
+ },
+ "universal-analytics": {
+ "version": "0.4.20",
+ "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.20.tgz",
+ "integrity": "sha512-gE91dtMvNkjO+kWsPstHRtSwHXz0l2axqptGYp5ceg4MsuurloM0PU3pdOfpb5zBXUvyjT4PwhWK2m39uczZuw==",
+ "dev": true,
+ "requires": {
+ "debug": "^3.0.0",
+ "request": "^2.88.0",
+ "uuid": "^3.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
+ }
+ }
+ },
+ "upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
+ },
+ "url": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
+ }
+ }
+ },
+ "url-parse": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
+ "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
+ "requires": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
+ },
+ "useragent": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz",
+ "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "4.1.x",
+ "tmp": "0.0.x"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+ "dev": true,
+ "requires": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+ "dev": true
+ }
+ }
+ },
+ "util": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
+ "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
+ "requires": {
+ "inherits": "2.0.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ }
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "validate-npm-package-name": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
+ "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=",
+ "dev": true,
+ "requires": {
+ "builtins": "^1.0.3"
+ }
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "vm-browserify": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
+ "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
+ },
+ "void-elements": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
+ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
+ "dev": true
+ },
+ "watchpack": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz",
+ "integrity": "sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==",
+ "requires": {
+ "chokidar": "^2.1.8",
+ "graceful-fs": "^4.1.2",
+ "neo-async": "^2.5.0"
+ }
+ },
+ "wbuf": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
+ "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
+ "requires": {
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "webdriver-js-extender": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz",
+ "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==",
+ "dev": true,
+ "requires": {
+ "@types/selenium-webdriver": "^3.0.0",
+ "selenium-webdriver": "^3.0.1"
+ }
+ },
+ "webpack": {
+ "version": "4.39.2",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.2.tgz",
+ "integrity": "sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==",
+ "requires": {
+ "@webassemblyjs/ast": "1.8.5",
+ "@webassemblyjs/helper-module-context": "1.8.5",
+ "@webassemblyjs/wasm-edit": "1.8.5",
+ "@webassemblyjs/wasm-parser": "1.8.5",
+ "acorn": "^6.2.1",
+ "ajv": "^6.10.2",
+ "ajv-keywords": "^3.4.1",
+ "chrome-trace-event": "^1.0.2",
+ "enhanced-resolve": "^4.1.0",
+ "eslint-scope": "^4.0.3",
+ "json-parse-better-errors": "^1.0.2",
+ "loader-runner": "^2.4.0",
+ "loader-utils": "^1.2.3",
+ "memory-fs": "^0.4.1",
+ "micromatch": "^3.1.10",
+ "mkdirp": "^0.5.1",
+ "neo-async": "^2.6.1",
+ "node-libs-browser": "^2.2.1",
+ "schema-utils": "^1.0.0",
+ "tapable": "^1.1.3",
+ "terser-webpack-plugin": "^1.4.1",
+ "watchpack": "^1.6.0",
+ "webpack-sources": "^1.4.1"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.12.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
+ "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
+ }
+ }
+ },
+ "webpack-core": {
+ "version": "0.6.9",
+ "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz",
+ "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=",
+ "requires": {
+ "source-list-map": "~0.1.7",
+ "source-map": "~0.4.1"
+ },
+ "dependencies": {
+ "source-list-map": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz",
+ "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY="
+ },
+ "source-map": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+ "requires": {
+ "amdefine": ">=0.0.4"
+ }
+ }
+ }
+ },
+ "webpack-dev-middleware": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz",
+ "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==",
+ "requires": {
+ "memory-fs": "^0.4.1",
+ "mime": "^2.4.4",
+ "mkdirp": "^0.5.1",
+ "range-parser": "^1.2.1",
+ "webpack-log": "^2.0.0"
+ },
+ "dependencies": {
+ "mime": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
+ "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA=="
+ }
+ }
+ },
+ "webpack-dev-server": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz",
+ "integrity": "sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw==",
+ "requires": {
+ "ansi-html": "0.0.7",
+ "bonjour": "^3.5.0",
+ "chokidar": "^2.1.8",
+ "compression": "^1.7.4",
+ "connect-history-api-fallback": "^1.6.0",
+ "debug": "^4.1.1",
+ "del": "^4.1.1",
+ "express": "^4.17.1",
+ "html-entities": "^1.2.1",
+ "http-proxy-middleware": "0.19.1",
+ "import-local": "^2.0.0",
+ "internal-ip": "^4.3.0",
+ "ip": "^1.1.5",
+ "is-absolute-url": "^3.0.3",
+ "killable": "^1.0.1",
+ "loglevel": "^1.6.4",
+ "opn": "^5.5.0",
+ "p-retry": "^3.0.1",
+ "portfinder": "^1.0.25",
+ "schema-utils": "^1.0.0",
+ "selfsigned": "^1.10.7",
+ "semver": "^6.3.0",
+ "serve-index": "^1.9.1",
+ "sockjs": "0.3.19",
+ "sockjs-client": "1.4.0",
+ "spdy": "^4.0.1",
+ "strip-ansi": "^3.0.1",
+ "supports-color": "^6.1.0",
+ "url": "^0.11.0",
+ "webpack-dev-middleware": "^3.7.2",
+ "webpack-log": "^2.0.0",
+ "ws": "^6.2.1",
+ "yargs": "12.0.5"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ },
+ "ws": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
+ "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ }
+ }
+ },
+ "webpack-log": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
+ "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
+ "requires": {
+ "ansi-colors": "^3.0.0",
+ "uuid": "^3.3.2"
+ }
+ },
+ "webpack-merge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
+ "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.15"
+ }
+ },
+ "webpack-sources": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
+ "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
+ "requires": {
+ "source-list-map": "^2.0.0",
+ "source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
+ "webpack-subresource-integrity": {
+ "version": "1.1.0-rc.6",
+ "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz",
+ "integrity": "sha512-Az7y8xTniNhaA0620AV1KPwWOqawurVVDzQSpPAeR5RwNbL91GoBSJAAo9cfd+GiFHwsS5bbHepBw1e6Hzxy4w==",
+ "requires": {
+ "webpack-core": "^0.6.8"
+ }
+ },
+ "websocket-driver": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
+ "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==",
+ "requires": {
+ "http-parser-js": ">=0.4.0 <0.4.11",
+ "safe-buffer": ">=5.1.0",
+ "websocket-extensions": ">=0.1.1"
+ }
+ },
+ "websocket-extensions": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
+ "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg=="
+ },
+ "when": {
+ "version": "3.6.4",
+ "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz",
+ "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404="
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+ },
+ "wmf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
+ "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw=="
+ },
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+ "dev": true
+ },
+ "worker-farm": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
+ "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
+ "requires": {
+ "errno": "~0.1.7"
+ }
+ },
+ "worker-plugin": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/worker-plugin/-/worker-plugin-3.2.0.tgz",
+ "integrity": "sha512-W5nRkw7+HlbsEt3qRP6MczwDDISjiRj2GYt9+bpe8A2La00TmJdwzG5bpdMXhRt1qcWmwAvl1TiKaHRa+XDS9Q==",
+ "requires": {
+ "loader-utils": "^1.1.0"
+ }
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ },
+ "dependencies": {
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "ws": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
+ "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
+ "dev": true,
+ "requires": {
+ "async-limiter": "~1.0.0",
+ "safe-buffer": "~5.1.0",
+ "ultron": "~1.1.0"
+ }
+ },
+ "xlsx": {
+ "version": "0.15.6",
+ "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.15.6.tgz",
+ "integrity": "sha512-7vD9eutyLs65iDjNFimVN+gk/oDkfkCgpQUjdE82QgzJCrBHC4bGPH7fzKVyy0UPp3gyFVQTQEFJaWaAvZCShQ==",
+ "requires": {
+ "adler-32": "~1.2.0",
+ "cfb": "^1.1.4",
+ "codepage": "~1.14.0",
+ "commander": "~2.17.1",
+ "crc-32": "~1.2.0",
+ "exit-on-epipe": "~1.0.1",
+ "ssf": "~0.10.3",
+ "wmf": "~1.0.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.17.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
+ "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
+ }
+ }
+ },
+ "xml2js": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+ "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+ "dev": true,
+ "requires": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "dependencies": {
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+ "dev": true
+ }
+ }
+ },
+ "xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "dev": true
+ },
+ "xmlhttprequest-ssl": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
+ "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
+ },
+ "yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
+ },
+ "yargs": {
+ "version": "12.0.5",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
+ "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
+ "requires": {
+ "cliui": "^4.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^3.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1 || ^4.0.0",
+ "yargs-parser": "^11.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "11.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
+ "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
+ "yeast": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
+ "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
+ "dev": true
+ },
+ "yn": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz",
+ "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=",
+ "dev": true
+ },
+ "zone.js": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.9.1.tgz",
+ "integrity": "sha512-GkPiJL8jifSrKReKaTZ5jkhrMEgXbXYC+IPo1iquBjayRa0q86w3Dipjn8b415jpitMExe9lV8iTsv8tk3DGag=="
+ }
+ }
+}
diff --git a/mod2/ui/package.json b/mod2/ui/package.json
new file mode 100644
index 0000000..315ac39
--- /dev/null
+++ b/mod2/ui/package.json
@@ -0,0 +1,64 @@
+{
+ "name": "dcae-mod-fe",
+ "version": "0.0.0",
+ "scripts": {
+ "ng": "ng",
+ "start": "ng serve --proxy-config proxy.conf.json",
+ "build": "ng build",
+ "test": "ng test",
+ "lint": "ng lint",
+ "e2e": "ng e2e"
+ },
+ "private": true,
+ "dependencies": {
+ "@angular-devkit/build-angular": "^0.803.24",
+ "@angular/animations": "~8.0.0",
+ "@angular/cdk": "~8.2.3",
+ "@angular/common": "~8.0.0",
+ "@angular/compiler": "~8.0.0",
+ "@angular/core": "~8.0.0",
+ "@angular/forms": "~8.0.0",
+ "@angular/material": "^8.2.3",
+ "@angular/platform-browser": "~8.0.0",
+ "@angular/platform-browser-dynamic": "~8.0.0",
+ "@angular/router": "~8.0.0",
+ "@auth0/angular-jwt": "^4.0.0",
+ "@fortawesome/fontawesome-free": "^5.13.0",
+ "bootstrap": "^4.4.1",
+ "font-awesome": "^4.7.0",
+ "hammerjs": "^2.0.8",
+ "jszip": "^3.4.0",
+ "mat-table-exporter": "^9.0.0",
+ "ng4-loading-spinner": "^1.2.3",
+ "primeicons": "^2.0.0",
+ "primeng": "^8.0.0-rc.1",
+ "rxjs": "~6.4.0",
+ "tslib": "^1.9.0",
+ "xlsx": "^0.15.6",
+ "zone.js": "~0.9.1"
+ },
+ "devDependencies": {
+ "@angular-builders/custom-webpack": "^8.4.1",
+ "@angular-builders/dev-server": "^7.3.1",
+ "@angular/cli": "~8.0.1",
+ "@angular/compiler-cli": "~8.0.0",
+ "@angular/language-service": "~8.0.0",
+ "@babel/compat-data": "7.8.0",
+ "@types/jasmine": "~3.3.8",
+ "@types/jasminewd2": "~2.0.3",
+ "@types/node": "^8.9.5",
+ "codelyzer": "^5.0.0",
+ "dotenv": "^8.2.0",
+ "jasmine-core": "~3.4.0",
+ "jasmine-spec-reporter": "~4.2.1",
+ "karma": "~4.1.0",
+ "karma-chrome-launcher": "~2.2.0",
+ "karma-coverage-istanbul-reporter": "~2.0.1",
+ "karma-jasmine": "~2.0.1",
+ "karma-jasmine-html-reporter": "^1.4.0",
+ "protractor": "~5.4.0",
+ "ts-node": "~7.0.0",
+ "tslint": "~5.15.0",
+ "typescript": "~3.4.3"
+ }
+}
diff --git a/mod2/ui/pipelineConfig.json b/mod2/ui/pipelineConfig.json
new file mode 100644
index 0000000..2a1b18b
--- /dev/null
+++ b/mod2/ui/pipelineConfig.json
@@ -0,0 +1,21 @@
+{
+ "release": "3.1.3",
+ "blueprintRepo": "codecloud.web.att.com/scm/st_dcaecntr/platform_onboarding.git",
+ "featureBranch": "feature/cdptest",
+ "featureBranchDir": "DCAE-EOM-K8S/dcae-onboarding-dcae-mod-fe",
+ "jiraTag": "REPLACE-999",
+ "serviceInfo": [
+ {
+ "isKubernetes": true,
+ "serviceName": "dcae-mod-fe",
+ "compSpecFilePath": "public/dpo/comp_spec_toolbox_fe.json",
+ "inputsFilePath": "public/dpo/inputs_ftl3g_k8s.json",
+ "directory": ".",
+ "docker": {
+ "installDir": "/opt/app/dcae-onboarding-dcae-mod-fe",
+ "registry": "dockercentral.it.att.com:5100/com.att.dcae.dcaemod",
+ "filePath": "./Dockerfile"
+ }
+ }
+ ]
+}
diff --git a/mod2/ui/pom.xml b/mod2/ui/pom.xml
new file mode 100644
index 0000000..50122de
--- /dev/null
+++ b/mod2/ui/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ org.onap.dcae
+ ~ ================================================================================
+ ~ Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ ~ ================================================================================
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ============LICENSE_END=========================================================
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.oparent</groupId>
+ <artifactId>oparent</artifactId>
+ <version>2.0.0</version>
+ </parent>
+ <groupId>org.onap.dcaegen2.platform.mod</groupId>
+ <artifactId>ui</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.eirslett</groupId>
+ <artifactId>frontend-maven-plugin</artifactId>
+ <version>1.7.6</version>
+ <configuration>
+ <workingDirectory>./</workingDirectory>
+ <nodeVersion>v12.16.1</nodeVersion>
+ <npmVersion>6.13.4</npmVersion>
+ </configuration>
+ <executions>
+ <execution>
+ <id>install node and npm</id>
+ <goals>
+ <goal>install-node-and-npm</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>npm install</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>npm run build</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <configuration>
+ <arguments>run build</arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project> \ No newline at end of file
diff --git a/mod2/ui/proxy.conf.json b/mod2/ui/proxy.conf.json
new file mode 100644
index 0000000..e730329
--- /dev/null
+++ b/mod2/ui/proxy.conf.json
@@ -0,0 +1,11 @@
+{
+ "/api": {
+ "target": "http://zlecdyh2bdcc1s2dokr05.ec53e7.dyh2b.tci.att.com:32705/",
+ "secure": false,
+ "logLevel": "debug",
+ "pathRewrite": {
+ "^/api": ""
+ },
+ "changeOrigin": true
+ }
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/app-routing.module.ts b/mod2/ui/src/app/app-routing.module.ts
new file mode 100644
index 0000000..0ffe503
--- /dev/null
+++ b/mod2/ui/src/app/app-routing.module.ts
@@ -0,0 +1,55 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule, NavigationStart, NavigationEnd, Route} from '@angular/router';
+import { HomeComponent } from './home/home.component';
+import { OnboardingToolsComponent } from './onboarding-tools/onboarding-tools.component';
+import { CompSpecsComponent } from './comp-specs/comp-specs.component';
+import { MsInstancesComponent } from './msInstances/msInstances.component';
+import { LoginComponent } from './login/login.component';
+import { RegisterComponent } from './register/register.component';
+import { ResetPasswordComponent } from './reset-password/reset-password.component';
+import { AuthGuard } from './guards/auth.guard';
+import { RoleGuard } from './guards/role.guard';
+import { UserManagementComponent } from './user-management/user-management.component';
+import { LoginGuard } from './guards/login.guard';
+import { MicroservicesComponent } from './microservices/microservices.component';
+import { BlueprintsComponent } from './blueprints/blueprints.component';
+import { CompSpecValidationComponent } from './comp-spec-validation/comp-spec-validation.component';
+
+const routes: Routes = [
+ { path: '', component: HomeComponent, canActivate:[LoginGuard]},
+ { path: 'home', component: HomeComponent, canActivate:[AuthGuard] },
+ { path: 'login', component: LoginComponent, canActivate:[LoginGuard]},
+ { path: 'register', component: RegisterComponent, canActivate:[AuthGuard, RoleGuard] },
+ { path: 'reset-password', component: ResetPasswordComponent, canActivate:[AuthGuard]},
+ { path: 'users', component: UserManagementComponent, canActivate:[AuthGuard, RoleGuard]},
+ { path: 'OnboardingTools', component: OnboardingToolsComponent, canActivate:[AuthGuard] },
+ { path: 'CompSpecs', component: CompSpecsComponent, canActivate:[AuthGuard]},
+ { path: 'ms-instances', component: MsInstancesComponent, canActivate:[AuthGuard] },
+ { path: 'base-microservices', component: MicroservicesComponent, canActivate: [AuthGuard] },
+ { path: 'blueprints', component: BlueprintsComponent, canActivate: [AuthGuard] },
+ { path: 'spec-validator', component: CompSpecValidationComponent, canActivate: [AuthGuard] }
+];
+
+@NgModule({
+ imports: [RouterModule.forRoot(routes)],
+ exports: [RouterModule]
+})
+export class AppRoutingModule { }
diff --git a/mod2/ui/src/app/app.component.css b/mod2/ui/src/app/app.component.css
new file mode 100644
index 0000000..0b9779a
--- /dev/null
+++ b/mod2/ui/src/app/app.component.css
@@ -0,0 +1,173 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+.sidenav-container {
+ height: 100%;
+}
+
+.sidenav {
+ width: 190px;
+ background: linear-gradient(to bottom, #1D2329 0%, #454B52 8%)
+}
+
+.sidenav .mat-toolbar {
+ background: inherit;
+ color:rgb(225, 241, 247);
+}
+
+.subMenuItem{
+ color: white;
+ font-size: 14px;
+ font-weight: 400;
+ height: 6vh !important;
+ min-height: 35px !important;
+}
+
+.mat-toolbar.mat-primary {
+ display: block;
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ height: 33px;
+ position: fixed;
+ border-radius: 0%;
+ background: linear-gradient(to bottom, #1D2329 0%, #454B52 135%)
+}
+
+.nav {
+ font-size: 16px;
+ font-weight: 500;
+ background-color: #454B52;
+ color:white;
+ height: 7vh !important;
+ min-height: 40px !important;
+}
+
+*:focus {
+ outline: none !important;
+ border: 0 !important;
+}
+
+.is-active{
+ background-color: #EA712F !important;
+}
+
+label {
+ cursor: pointer;
+}
+
+.input{
+ padding-top: 20px;
+}
+
+.inputLabel {
+ font-weight: 600;
+ margin-left: 25px;
+ width: 160px;
+}
+
+.inputFieldSm {
+ width: 200px;
+ height: 35px;
+ padding-left: 8px;
+}
+.inputFieldMed {
+ width: 300px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldLg {
+ width: 400px;
+ height: 35px;
+ padding-left: 6px;
+}
+
+/* B R E A D C R U M B S . . . . . . . . */
+.breadcrumb {
+ list-style: none;
+ overflow: hidden;
+ font: 12px Helvetica, Arial, Sans-Serif;
+ background: transparent;
+ margin-left: 5px;
+ margin-top: -3px;
+ padding: 0;
+}
+.breadcrumb li {
+ float: left;
+}
+.breadcrumb li a {
+ color: #1D2329;
+ font-weight: 700;
+ text-decoration: none;
+ padding: 6px 0 6px 45px;
+ background: brown; /* fallback color */
+ background: hsla(21,82%,55%,1);
+ position: relative;
+ display: block;
+ float: left;
+}
+.breadcrumb li a:after {
+ content: " ";
+ display: block;
+ width: 0;
+ height: 0;
+ border-top: 50px solid transparent; /* Go big on the size, and let overflow hide */
+ border-bottom: 50px solid transparent;
+ border-left: 30px solid hsla(21,82%,55%,1);
+ position: absolute;
+ top: 50%;
+ margin-top: -50px;
+ left: 100%;
+ z-index: 2;
+}
+.breadcrumb li a:before {
+ content: " ";
+ display: block;
+ width: 0;
+ height: 0;
+ border-top: 50px solid transparent; /* Go big on the size, and let overflow hide */
+ border-bottom: 50px solid transparent;
+ border-left: 30px solid #b9bec4;
+ position: absolute;
+ top: 50%;
+ margin-top: -50px;
+ margin-left: 3px;
+ left: 100%;
+ z-index: 1;
+}
+.breadcrumb li:first-child a {
+ padding-left: 14px;
+}
+.breadcrumb li:nth-child(2) a { background: hsla(30,100%,50%,.95); }
+.breadcrumb li:nth-child(2) a:after { border-left-color: hsla(30,100%,50%,.95); }
+.breadcrumb li:nth-child(3) a { background: hsla(38,100%,50%,.90); }
+.breadcrumb li:nth-child(3) a:after { border-left-color: hsla(38,100%,50%,.90); }
+.breadcrumb li:nth-child(4) a { background: hsla(45,100%,50%,.85); }
+.breadcrumb li:nth-child(4) a:after { border-left-color: hsla(45,100%,50%,.85); }
+.breadcrumb li:nth-child(5) a { background: hsla(52,100%,50%,.80); }
+.breadcrumb li:nth-child(5) a:after { border-left-color: hsla(52,100%,50%,.80); }
+.breadcrumb li:last-child a {
+ background: transparent !important;
+ color: black;
+ pointer-events: none;
+ cursor: default;
+ margin-left: -10px;
+}
+.breadcrumb li:last-child a:after { border: 0; }
+.breadcrumb li a:hover { background: rgba(102, 102, 102, 0.993); color: #e9fffd; cursor: pointer}
+.breadcrumb li a:hover:after { border-left-color: hsla(0,0%,40%,1); color: #bbc9d8 !important; cursor: pointer}
diff --git a/mod2/ui/src/app/app.component.html b/mod2/ui/src/app/app.component.html
new file mode 100644
index 0000000..e214dc1
--- /dev/null
+++ b/mod2/ui/src/app/app.component.html
@@ -0,0 +1,136 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<ng4-loading-spinner></ng4-loading-spinner>
+<mat-sidenav-container style="background: linear-gradient(to top, #878C94 0%, #DCDFE3 10%, #F2F2F2 40%, #DCDFE3 80%, #878C94 110%);" class="sidenav-container" *ngIf="authService.authPass">
+ <mat-sidenav [class.mat-elevation-z2]="!isActive" [class.mat-elevation-z8]="isActive" #sideMenu class="sidenav"
+ fixedInViewport="true" [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
+ [mode]="(isHandset$ | async) ? 'over' : 'side'" [opened]="(isHandset$ | async) === true">
+ <mat-toolbar></mat-toolbar>
+ <hr width=90%>
+ <mat-action-list style="margin-top: -10px;">
+ <button class="nav" mat-list-item (click)="setCrumbs('', 'reset')" [routerLink]="'/home'" [routerLinkActive]="'is-active'">Home</button>
+ <button class="nav" mat-list-item (click)="setCrumbs('User Management', 'reset')" *ngIf="authService.isAdmin" [routerLink]="'/users'" [routerLinkActive]="'is-active'">User Management</button>
+ <button class="nav" mat-list-item (click)="setCrumbs('Onboarding Tools', 'reset')" [routerLink]="'/OnboardingTools'" [skipLocationChange]="false" [routerLinkActive]="'is-active'">Onboarding Tools</button>
+ <button class="nav" mat-list-item (click)="msMenu()">
+ <i *ngIf="msMenuIconRight" class="pi pi-chevron-right"></i>
+ <i *ngIf="!msMenuIconRight" class="pi pi-chevron-down"></i>
+ &nbsp;&nbsp;Microservices</button>
+ <div *ngIf="showMsMenu" style="margin-left: 20px;">
+ <button class="subMenuItem" mat-list-item (click)="setCrumbs('Microservices', 'reset')" [routerLink]="'/base-microservices'" [routerLinkActive]="'is-active'">Microservices</button>
+ <button class="subMenuItem" mat-list-item (click)="setCrumbs('MS Instances', 'reset')" [routerLink]="'/ms-instances'" [routerLinkActive]="'is-active'">MS Instances</button>
+ <button class="subMenuItem" mat-list-item (click)="setCrumbs('Blueprints', 'reset')" [routerLink]="'/blueprints'" [routerLinkActive]="'is-active'">Blueprints</button>
+
+ <button class="nav" mat-list-item (click)="utilitiesMenu()">
+ <i *ngIf="utilitiesMenuIconRight" class="pi pi-chevron-right"></i>
+ <i *ngIf="!utilitiesMenuIconRight" class="pi pi-chevron-down"></i>
+ &nbsp;&nbsp;Utilites</button>
+
+ <div *ngIf="showUtilitiesMenu" style="margin-left: 20px;">
+ <button class="subMenuItem" mat-list-item (click)="setCrumbs('Spec Validator', 'reset')"
+ [routerLink]="'/spec-validator'" [routerLinkActive]="'is-active'">Spec Validator</button>
+ <button class="subMenuItem" mat-list-item (click)="redirectToAPIs()">MOD APIs</button>
+ </div>
+ </div>
+ <button class="nav" mat-list-item (click)='redirectTo("https://wiki.web.att.com/pages/viewpage.action?spaceKey=DPD&title=DCAE+MOD+User+Guide")'>User Guide</button>
+
+ </mat-action-list>
+ </mat-sidenav>
+ <mat-sidenav-content style="margin-top: 70px; max-height: 90%">
+ <!-- Top bar when Logged in -->
+ <mat-toolbar [class.mat-elevation-z2]="!isActive" [class.mat-elevation-z8]="isActive" color="primary"
+ fixedInViewport="true" style="background-color: #1D2329; color:#F2F2F2">
+ <button type="button" aria-label="Toggle sidenav" mat-icon-button (click)="sideMenu.toggle()" style="color:#F2F2F2">
+ <i *ngIf="!sideMenu.opened" class="pi pi-angle-double-right" style="font-size: 25px; margin-left: -30px; margin-bottom: 8px;"></i>
+ <i *ngIf="sideMenu.opened" class="pi pi-angle-double-left" style="font-size: 25px; margin-left: -30px; margin-bottom: 8px;"></i>
+ </button>
+ <span style="font-size: 22px; font-weight: 500; margin-left: 35px">MOD</span>
+ <button type="button" *ngIf="authService.authPass" (click)="handleLogout()"
+ style="float:right; margin-right: 18%; height: 32px; border: none; color:#F2F2F2; background: linear-gradient(to bottom, #1D2329 0%, #454B52 135%);
+ font-size: 16px; font-weight: 400">
+ <i class="pi pi-sign-out" style="vertical-align:text-top"></i>
+ Logout
+ </button>
+ <button type="button" *ngIf="authService.authPass" (click)="handleProfile()"
+ style="float:right; margin-right: 4%; height: 32px; border: none; color:#F2F2F2; background: linear-gradient(to bottom, #1D2329 0%, #454B52 135%);
+ font-size: 16px; font-weight: 400">
+ <i class="pi pi-user-edit" style="vertical-align:text-top"></i>
+ {{authService.getUser().username}}
+ </button>
+ <!-- BREADCRUMBS . . . . . -->
+ <ul class="breadcrumb">
+ <li *ngFor="let crumb of breadcrumbs" [routerLink]="crumb.link" (click)="setCrumbs(crumb.page, 'crumbClicked')"><a>{{crumb.page}}</a></li>
+ </ul>
+ </mat-toolbar>
+ <main [@routeAnimations]="prepareRoute(outlet)" class="content">
+ <router-outlet #outlet="outlet"></router-outlet>
+ </main>
+ </mat-sidenav-content>
+</mat-sidenav-container>
+
+<!-- Top bar when Logging in -->
+<mat-toolbar *ngIf="!authService.authPass" [class.mat-elevation-z2]="!isActive" [class.mat-elevation-z8]="isActive" color="primary"
+ fixedInViewport="true" style="background-color: #1D2329">
+ <span style="font-size: 22px; font-weight: 500">MOD</span>
+ <app-login></app-login>
+</mat-toolbar>
+
+<!-- Login Expired dialog -->
+<p-dialog header="Login Expired" [(visible)]="authService.reLoginMsg" [modal]="true" [style]="{width:'25vw'}" [baseZIndex]="10000"
+ [draggable]="false" [resizable]="false">
+ <p>Your login has expired. Please log in again.</p>
+ <p-footer>
+ <button type="button" pButton icon="pi pi-check" (click)="onConfirm()" label="OK"></button>
+ </p-footer>
+</p-dialog>
+
+<!--reset User Password dialog-->
+<p-dialog [(visible)]="resetPasswordFlag" appendTo="body" [modal]="true" [transitionOptions]="'300ms'" [style]="{width: '630px'}" [baseZIndex]="10000"
+[closable]="true" (onHide)="closeResetDialog()">
+<p-header style="display: inline-flex;">
+ Reset User Password
+</p-header>
+<form [formGroup]="resetPasswordForm">
+ <!-- * * * New Password * * * -->
+ <div class="input">
+ <div class="ui-inputgroup" >
+ <label class="inputLabel">New Password</label>
+ <span class="ui-inputgroup-addon" (click)="hidePassword=!hidePassword">
+ <i [ngClass]="hidePassword? 'pi pi-eye-slash':'pi pi-eye'"></i></span>
+ <input class="inputFieldSm" [type]="hidePassword? 'password':'text'" pInputText formControlName="password" />
+ </div>
+ </div>
+ <i *ngIf="resetPasswordForm.get('password').errors && resetPasswordForm.get('password').errors.minlength" style="width: 140px;margin-left: 20px;font-size: small;color: red;">password should be more than 5 characters</i>
+ <!-- * * * Confirm New Password * * * -->
+ <div class="input">
+ <div class="ui-inputgroup" >
+ <label class="inputLabel">Confirm Password</label>
+ <span class="ui-inputgroup-addon" (click)="hideConfirmPassword=!hideConfirmPassword">
+ <i [ngClass]="hideConfirmPassword? 'pi pi-eye-slash':'pi pi-eye'"></i></span>
+ <input class="inputFieldSm" [type]="hideConfirmPassword? 'password':'text'" pInputText formControlName="confirm_password" />
+ </div>
+ </div>
+ <i *ngIf="resetPasswordForm.errors && resetPasswordForm.errors.errMsg" style="width: 140px;margin-left: 20px;font-size: small;color: red;">{{resetPasswordForm.errors.errMsg}}</i>
+ <!-- * * * Submit and Cancel buttons * * * -->
+ <div style="margin-top: 2em; margin-left: 1.3em; margin-bottom: 2em;">
+ <button pButton type="button" (click)="closeResetDialog()" label="Cancel"></button>&nbsp;
+ <button pButton type="submit" (click)="resetPasswordForm.valid && submitReset()" class="ui-button-success" label="Submit" style="width: 70px"></button>
+ </div>
+</form>
+
+</p-dialog> \ No newline at end of file
diff --git a/mod2/ui/src/app/app.component.spec.ts b/mod2/ui/src/app/app.component.spec.ts
new file mode 100644
index 0000000..d6eb43c
--- /dev/null
+++ b/mod2/ui/src/app/app.component.spec.ts
@@ -0,0 +1,90 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { TestBed, async } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { AppComponent } from './app.component';
+import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
+import { MatSidenavModule } from '@angular/material/sidenav';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { MatCardModule } from '@angular/material/card';
+import { MatTreeModule } from '@angular/material/tree';
+import { DialogModule } from 'primeng/dialog';
+import { MatListModule } from '@angular/material/list';
+import { LoginComponent } from './login/login.component';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { CardModule } from 'primeng/card';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { JwtHelperService, JwtModule, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+describe('AppComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ RouterTestingModule,
+ Ng4LoadingSpinnerModule,
+ MatSidenavModule,
+ MatToolbarModule,
+ MatCardModule,
+ MatTreeModule,
+ DialogModule,
+ MatListModule,
+ FormsModule,
+ ReactiveFormsModule,
+ CardModule,
+ HttpClientTestingModule,
+ JwtModule,
+ ],
+ declarations: [
+ AppComponent,
+ LoginComponent
+ ], providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+
+ it('should create the app', () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app).toBeTruthy();
+ });
+
+ it(`should have as title 'mod-fe'`, () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app.title).toEqual('mod-fe');
+ });
+
+ it(`should have menu item variables as 'false'`, () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app.showUtilitiesMenu).toEqual(false);
+ expect(app.utilitiesMenuIconRight).toEqual(true);
+ });
+
+ it(`should change utilites menu arrow`, () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ app.utilitiesMenu()
+ expect(app.showUtilitiesMenu).toEqual(true);
+ expect(app.utilitiesMenuIconRight).toEqual(false);
+ });
+}); \ No newline at end of file
diff --git a/mod2/ui/src/app/app.component.ts b/mod2/ui/src/app/app.component.ts
new file mode 100644
index 0000000..87d29b4
--- /dev/null
+++ b/mod2/ui/src/app/app.component.ts
@@ -0,0 +1,218 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, HostBinding, OnInit } from '@angular/core';
+import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
+import { Observable } from 'rxjs';
+import { map, shareReplay } from 'rxjs/operators';
+import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';
+import { FlatTreeControl } from '@angular/cdk/tree';
+import { Event, Router, RouterOutlet, NavigationStart, NavigationEnd, RouterEvent } from '@angular/router';
+import { AuthService } from './services/auth.service';
+import { BreadcrumbService } from './services/breadcrumb.service';
+import { environment } from '../environments/environment';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { UserService } from './services/user.service';
+import { User } from './models/User';
+import { Authority } from './models/Authority.enum';
+
+interface TreeNode {
+ name: string;
+ children?: TreeNode[];
+}
+
+const TREE_DATA: TreeNode[] = [
+ {
+ name: 'Microservices',
+ children: [
+ { name: 'Microservices' },
+ { name: 'MS Instances' },
+ { name: 'Blueprints' },
+ { name: 'MOD APIs' }
+ ]
+ }
+];
+
+interface ExampleFlatNode {
+ expandable: boolean;
+ name: string;
+ level: number;
+}
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.css']
+})
+export class AppComponent implements OnInit{
+
+ @HostBinding('@.disabled')
+ public animationsDisabled = true;
+ activeNode: any;
+ resetPasswordFlag: boolean = false;
+ resetPasswordForm: FormGroup;
+ hidePassword: boolean = true;
+ hideConfirmPassword: boolean = true;
+ breadcrumbs: any[] = [];
+
+ prepareRoute(outlet: RouterOutlet) {
+ return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animation'];
+ }
+
+ title = 'mod-fe';
+ right: boolean = true;
+ down: boolean = false;
+
+ menu_tree(){
+ this.right = !this.right;
+ this.down = !this.down;
+ }
+
+ isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
+ .pipe(
+ map(result => result.matches),
+ shareReplay()
+ );
+
+ redirectTo(link){
+ window.open(link, "_blank");
+ }
+
+ redirectToAPIs() {
+ window.open(`http://${environment.api_baseURL}:31001/swagger-ui.html#/`, "_blank");
+ }
+
+ constructor(private breakpointObserver: BreakpointObserver, private router: Router, public authService: AuthService,
+ private bread: BreadcrumbService, private fb: FormBuilder, private userService: UserService) {
+ this.dataSource.data = TREE_DATA;
+ }
+
+ ngOnInit() {
+ this.resetPasswordForm = this.fb.group(
+ {
+ password: ['', [Validators.minLength(6)]],
+ confirm_password: ''
+ },
+ {validators: [this.passwordValidator]}
+ );
+
+ // Subscribe to breadcrumb changes
+ this.bread.breadcrumbs$.subscribe( (crumbArray) => {this.breadcrumbs = crumbArray});
+ }
+
+ setCrumbs(component, action) {
+ this.bread.setBreadcrumbs(component, action)
+ }
+
+ passwordValidator(group: FormGroup) {
+ if(group.value.password === group.value.confirm_password){
+ return null;
+ } else {
+ return {errMsg: 'Passwords do not match!'};
+ }
+ }
+
+ private _transformer = (node: TreeNode, level: number) => {
+ return {
+ expandable: !!node.children && node.children.length > 0,
+ name: node.name,
+ level: level,
+ };
+ }
+
+ tree_handler(name, treenode) {
+ if (name == "MOD APIs") {
+ window.open(`http://${environment.api_baseURL}:31001/swagger-ui.html#/`, "_blank");
+ } else if (name == "MS Instances") {
+ this.router.navigate(["ms-instances"]);
+ this.activeNode = treenode;
+ } else if(name == "Microservices") {
+ this.router.navigate(["base-microservices"]);
+ this.activeNode = treenode;
+ } else if(name == "Blueprints") {
+ this.router.navigate(["blueprints"]);
+ this.activeNode = treenode;
+ }
+
+ }
+
+ treeControl = new FlatTreeControl<ExampleFlatNode>(
+ node => node.level, node => node.expandable);
+
+ treeFlattener = new MatTreeFlattener(
+ this._transformer, node => node.level, node => node.expandable, node => node.children);
+
+ dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
+
+ hasChild = (_: number, node: ExampleFlatNode) => node.expandable;
+
+ showMsMenu = false;
+ msMenuIconRight = true;
+ msMenu() {
+ this.showMsMenu = !this.showMsMenu
+ this.msMenuIconRight = !this.msMenuIconRight
+ }
+
+ showUtilitiesMenu = false;
+ utilitiesMenuIconRight = true;
+ utilitiesMenu(){
+ this.showUtilitiesMenu = !this.showUtilitiesMenu
+ this.utilitiesMenuIconRight = !this.utilitiesMenuIconRight
+ }
+
+ onConfirm() {
+ this.authService.reLoginMsg = false;
+ }
+
+ handleLogout() {
+ this.showMsMenu = false
+ this.authService.logout()
+ }
+
+ handleProfile() {
+ console.log(this.authService.getUser().roles);
+ this.resetPasswordFlag = true;
+ }
+
+ closeResetDialog() {
+ this.resetPasswordForm.reset();
+ this.resetPasswordFlag = false;
+ }
+
+ submitReset() {
+ if(this.authService.getUser().roles.includes(Authority.ADMIN)){
+ this.userService.editUser(this.authService.getUser().username, this.resetPasswordForm.value as User).subscribe(res=>{
+ alert("Password reset successful. Please login in using the new credentials.");
+ this.authService.logout();
+ }, (err)=>{
+ alert(err.error.message);
+
+ });
+ } else {
+ this.userService.editProfile(this.authService.getUser().username, this.resetPasswordForm.value as User).subscribe(res=>{
+ alert("Password reset successful. Please login in using the new credentials.");
+ this.authService.logout();
+ }, (err)=>{
+ alert(err.error.message);
+ });
+ }
+ this.resetPasswordForm.reset();
+ this.resetPasswordFlag = false;
+ }
+
+}
diff --git a/mod2/ui/src/app/app.module.ts b/mod2/ui/src/app/app.module.ts
new file mode 100644
index 0000000..1e1da59
--- /dev/null
+++ b/mod2/ui/src/app/app.module.ts
@@ -0,0 +1,172 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+
+import { AppRoutingModule } from './app-routing.module';
+import { AppComponent } from './app.component';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { PathLocationStrategy, LocationStrategy} from '@angular/common';
+
+import { SharedModule } from './shared/shared-module';
+import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
+import { HomeComponent } from './home/home.component';
+import { LayoutModule } from '@angular/cdk/layout';
+import { MatToolbarModule } from '@angular/material/toolbar';
+import { MatButtonModule } from '@angular/material/button';
+import { MatSidenavModule } from '@angular/material/sidenav';
+import { MatIconModule } from '@angular/material/icon';
+import { MatListModule } from '@angular/material/list';
+import { MatTableModule } from '@angular/material/table';
+import { MatPaginatorModule } from '@angular/material/paginator';
+import { MatSortModule } from '@angular/material/sort';
+import { MatTreeModule } from '@angular/material/tree';
+import { MatCardModule } from '@angular/material/card';
+import { MaterialElevationDirective } from './material-elevation.directive';
+import { MatProgressSpinnerModule, MatTooltipModule, MatMenuModule } from '@angular/material';
+import { OnboardingToolsComponent, SafePipe } from './onboarding-tools/onboarding-tools.component';
+import { CompSpecsComponent } from './comp-specs/comp-specs.component';
+import { MatTableExporterModule } from 'mat-table-exporter';
+import { TableModule } from 'primeng/table';
+import { MsInstancesComponent } from './msInstances/msInstances.component';
+import { ButtonModule } from 'primeng/button';
+import { SidebarModule } from 'primeng/sidebar';
+import { MenuModule } from 'primeng/menu';
+import { ToolbarModule } from 'primeng/toolbar';
+import { PanelMenuModule } from 'primeng/panelmenu';
+import { CardModule } from 'primeng/card';
+import { LoginComponent } from './login/login.component';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RegisterComponent } from './register/register.component';
+import { ResetPasswordComponent } from './reset-password/reset-password.component';
+import { AuthGuard } from './guards/auth.guard';
+import { RoleGuard } from './guards/role.guard';
+import { JwtInterceptorService } from './services/jwt-interceptor.service';
+import { JwtModule } from '@auth0/angular-jwt';
+import { UserManagementComponent } from './user-management/user-management.component';
+import { DialogModule } from 'primeng/dialog';
+import { ToastModule } from 'primeng/toast';
+import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
+import { PasswordModule } from 'primeng/password';
+import { TooltipModule } from 'primeng/tooltip';
+import { AccordionModule } from 'primeng/accordion';
+import { SplitButtonModule } from 'primeng/splitbutton';
+import { DropdownModule } from 'primeng/dropdown';
+import { FileUploadModule } from 'primeng/fileupload';
+import { InputTextareaModule } from 'primeng/inputtextarea';
+import { MatExpansionModule } from '@angular/material/expansion';
+import { RadioButtonModule } from 'primeng/radiobutton';
+import { SelectButtonModule } from 'primeng/selectbutton';
+import { MessageService } from 'primeng/api';
+import { MsAddChangeComponent } from './ms-add-change/ms-add-change.component';
+import { MicroservicesComponent } from './microservices/microservices.component';
+import { PaginatorModule } from 'primeng/paginator';
+import { ScrollPanelModule } from 'primeng/scrollpanel';
+import { CalendarModule } from 'primeng/calendar';
+import { BlueprintsComponent } from './blueprints/blueprints.component';
+import { CompSpecAddComponent } from './comp-spec-add/comp-spec-add.component';
+import { MsInstanceAddComponent } from './ms-instance-add/ms-instance-add.component';
+import {MultiSelectModule} from 'primeng/multiselect';
+import {CheckboxModule} from 'primeng/checkbox';
+import { InputSwitchModule } from 'primeng/inputswitch';
+import { CompSpecValidationComponent } from './comp-spec-validation/comp-spec-validation.component';
+
+@NgModule({
+ declarations: [
+ AppComponent,
+ HomeComponent,
+ MaterialElevationDirective,
+ SafePipe,
+ OnboardingToolsComponent,
+ CompSpecsComponent,
+ MsInstancesComponent,
+ LoginComponent,
+ RegisterComponent,
+ ResetPasswordComponent,
+ UserManagementComponent,
+ MsAddChangeComponent,
+ MicroservicesComponent,
+ BlueprintsComponent,
+ CompSpecAddComponent,
+ MsInstanceAddComponent,
+ CompSpecValidationComponent
+ ],
+ imports: [
+ BrowserModule,
+ AppRoutingModule,
+ BrowserAnimationsModule,
+ SharedModule,
+ HttpClientModule,
+ LayoutModule,
+ MatToolbarModule,
+ MatButtonModule,
+ MatSidenavModule,
+ MatIconModule,
+ MatListModule,
+ MatTableModule,
+ MatPaginatorModule,
+ MatSortModule,
+ MatTreeModule,
+ MatCardModule,
+ MatProgressSpinnerModule,
+ MatTableExporterModule,
+ TableModule,
+ ButtonModule,
+ SidebarModule,
+ MenuModule,
+ ToolbarModule,
+ PanelMenuModule,
+ FormsModule,
+ ReactiveFormsModule,
+ CardModule,
+ JwtModule.forRoot({
+ config: {
+ tokenGetter: ()=>localStorage.getItem('jwt')
+ }
+ }),
+ DialogModule,
+ ToastModule,
+ Ng4LoadingSpinnerModule,
+ TooltipModule,
+ AccordionModule,
+ SplitButtonModule,
+ DropdownModule,
+ FileUploadModule,
+ InputTextareaModule,
+ MatExpansionModule,
+ PasswordModule,
+ RadioButtonModule,
+ SelectButtonModule,
+ MatTooltipModule,
+ PaginatorModule,
+ ScrollPanelModule,
+ MatMenuModule,
+ CalendarModule,
+ MultiSelectModule,
+ CheckboxModule,
+ InputSwitchModule
+ ],
+ providers: [AuthGuard, RoleGuard, {
+ provide: HTTP_INTERCEPTORS,
+ useClass: JwtInterceptorService,
+ multi: true
+ }, Location, { provide: LocationStrategy, useClass: PathLocationStrategy }, MessageService],
+ bootstrap: [AppComponent]
+})
+export class AppModule { }
diff --git a/mod2/ui/src/app/blueprints/blueprints.component.css b/mod2/ui/src/app/blueprints/blueprints.component.css
new file mode 100644
index 0000000..ccc03d9
--- /dev/null
+++ b/mod2/ui/src/app/blueprints/blueprints.component.css
@@ -0,0 +1,142 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+td{
+ word-break:break-all;
+ font-size: 12px;
+}
+
+th{
+ font-size: 12px;
+}
+
+.table_column_filter{
+ width: 100%;
+ height: 20px;
+ font-size: 10px;
+}
+
+.table_div{
+ margin: 0px 50px 10px 20px;
+ min-width: 900px;
+ width: 98%;
+ border: 1px solid darkslategray;
+}
+
+.fa-refresh{
+ cursor: pointer;
+}
+
+textarea
+{
+ font-size: 12px;
+}
+
+.row-expand-layout{
+ display: grid;
+ width: 100%;
+ grid-template-columns: 20% 30% auto 25%;
+ grid-gap: 10px;
+ grid-auto-rows: minmax(100px, auto);
+}
+
+.row-expand-card{
+ font-size: 12px;
+ border-radius: 5px;
+ border: 1px solid slategray;
+ padding: 10px 5px 5px 10px;
+ /* This height prevents vertical scroll bars in Notes and Failure Reason */
+ height: 92px;
+ overflow: hidden;
+}
+
+.table_export_buttons_alignment{
+ margin-left: 5px;
+ margin-top: -32px;
+ float: left;
+}
+
+.table_export_button{
+ border-radius: 5px;
+ height: 22px;
+ font-size: 14px;
+ border: none;
+ margin-top: 4px;
+ margin-right: 7px;
+ display: inline-flex;
+}
+
+.table_caption_header{
+ margin-left: -18%;
+ width: 82%;
+ max-height: 25px;
+ display: inline-flex;
+}
+
+.table_global_filter{
+ width: 250px;
+ height:25px;
+ margin-bottom: -5px;
+ font-size: 12px;
+ margin-left: 15px;
+}
+
+.table_title{
+ width: 40%;
+ margin-left: 10%;
+}
+
+.table_action_item{
+ outline: none;
+ font-size: 12px;
+}
+
+::ng-deep .mat-menu-content {
+padding-top: 0px !important;
+padding-bottom: 0px !important;
+}
+.mat-menu-item{
+line-height:30px;
+height:30px;
+}
+
+.greenStatus{
+ background-color: rgba(80, 233, 105, 0.616)
+}
+
+.redStatus{
+ background-color: rgba(255, 29, 29, 0.527)
+}
+
+.blueStatus{
+ background-color: rgba(0, 183, 255, 0.384)
+}
+
+.greyStatus{
+ background-color: rgba(150, 150, 150, 0.432)
+}
+
+.ui-toast-detail{
+ white-space: pre-wrap;
+ font-size: 12px;
+}
+
+.ui-state-highlight {
+ background-color: #878C94 !important;
+ color: black !important;
+}
diff --git a/mod2/ui/src/app/blueprints/blueprints.component.html b/mod2/ui/src/app/blueprints/blueprints.component.html
new file mode 100644
index 0000000..53fed09
--- /dev/null
+++ b/mod2/ui/src/app/blueprints/blueprints.component.html
@@ -0,0 +1,283 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<ng4-loading-spinner [timeout]="1000000"></ng4-loading-spinner>
+<div class="table_div" [style.visibility]="visible">
+ <!-- * * * * Table of Blueprints * * * * -->
+ <p-table #dt [columns]="cols" [(selection)]="selectedBPs" [value]="bpElements" sortMode="multiple" [paginator]="true"
+ [rows]="18" [rowsPerPageOptions]="[10,12,14,16,18,20,25,50]" (onFilter)="onTableFiltered(dt.filteredValue, $event)" dataKey="id" editMode="row">
+
+ <!-- * * * * Top caption row * * * * -->
+ <ng-template pTemplate="caption">
+
+ <div class="table_caption_header">
+ <!--Blueprints Table Header-->
+ <div>
+ <!-- * * * * Refresh * * * * -->
+ <i class="fa fa-refresh" (click)="getAllBPs()"></i>
+ <!-- * * * * Global filter * * * * -->
+ <input class="table_global_filter" type="text" pInputText size="50" placeholder="Global Filter"
+ (input)="dt.filterGlobal($event.target.value, 'contains')">
+ <i class="fa fa-search" style="margin:4px 0 0 8px"></i>
+ </div>
+
+ <h4 class="table_title"><b>Deployment Artifacts</b></h4>
+
+ </div>
+ </ng-template>
+
+ <!-- * * * * Header row with dynamic column names. Columns include microservice Name, Release, Tag, Type, Version and Status * * * * -->
+ <ng-template pTemplate="header" let-columns>
+ <tr style="text-align: center; vertical-align: bottom;">
+ <th style="width: 3em"></th>
+ <th class="ui-state-highlight" *ngFor="let col of columns" style="outline: none;" [pSortableColumn]="col.field" style="font-size: 12px; outline: none;"
+ [ngStyle]="{'width': col.width}">
+ {{col.header}}<br>
+ <p-sortIcon [field]="col.field"></p-sortIcon>
+ </th>
+ <th style="width: 7%; vertical-align: middle;">
+ Actions
+ </th>
+ </tr>
+
+ <!-- * * * * Second header row for individual column filters * * * * -->
+ <tr>
+ <th style="width: 3em"></th>
+ <!-- * * * * column filters * * * * -->
+ <th *ngFor="let col of columns" style="text-align: center;" [ngSwitch]="col.field">
+ <input *ngSwitchCase="'instanceName'" [(ngModel)]="filteredName" pInputText type="text" (input)="dt.filter($event.target.value, col.field, 'contains')" class="table_column_filter" placeholder="Filter">
+ <input *ngSwitchCase="'instanceRelease'" [(ngModel)]="filteredRelease" pInputText type="text" (input)="dt.filter($event.target.value, col.field, 'contains')" class="table_column_filter" placeholder="Filter">
+ <input *ngSwitchCase="'tag'" [(ngModel)]="filteredTag" pInputText type="text" (input)="dt.filter($event.target.value, col.field, 'contains')" class="table_column_filter" placeholder="Filter">
+ <input *ngSwitchCase="'type'" [(ngModel)]="filteredType" pInputText type="text" (input)="dt.filter($event.target.value, col.field, 'contains')" class="table_column_filter" placeholder="Filter">
+ <input *ngSwitchCase="'version'" [(ngModel)]="filteredVersion" pInputText type="text" (input)="dt.filter($event.target.value, col.field, 'contains')" class="table_column_filter" placeholder="Filter">
+ <input *ngSwitchCase="'status'" [(ngModel)]="filteredStatus" pInputText type="text" (input)="dt.filter($event.target.value, col.field, 'contains')" class="table_column_filter" placeholder="Filter">
+ </th>
+ <th>
+ <div style="text-align: center;">
+ <p-tableHeaderCheckbox style="padding-right: 5px;"></p-tableHeaderCheckbox>
+ <button pButton type="button" class="ui-button-secondary" (click)="enableButtonCheck()" [matMenuTriggerFor]="menu" #menuTrigger="matMenuTrigger"
+ style="background-color: transparent; border: none; width: 20px; height: 20px; vertical-align: middle;">
+ <i class="pi pi-ellipsis-h" style="color: grey;"></i>
+ </button>
+ <mat-menu #menu="matMenu" xPosition="before">
+ <!--<div (mouseleave)="menuTrigger.closeMenu()">-->
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-download"></i> Download</span>
+ </div>
+
+ <!-- * * * * Download Blueprints * * * * -->
+ <div matTooltip="No Blueprints Selected" [matTooltipDisabled]="canDownload" matTooltipPosition="left">
+ <button mat-menu-item class="table_action_item" (click)="downloadSelectedBps()" [disabled]="!canDownload">Download Selected Blueprints</button>
+ </div>
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-times"></i> Delete</span>
+ </div>
+
+ <!-- * * * * Delete Selected Blueprints * * * -->
+ <div [matTooltip]="deleteTooltip" [matTooltipDisabled]="canDelete" matTooltipPosition="left">
+ <button mat-menu-item (click)="warnDeleteBlueprint(null)" class="table_action_item" [disabled]="!canDelete">Delete Selected Blueprints</button>
+ </div>
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-pencil"></i> Update</span>
+ </div>
+
+ <!-- * * * * State Changes * * * * -->
+ <div matTooltip="No Blueprints Selected" [matTooltipDisabled]="canUpdate" matTooltipPosition="left">
+ <button *ngFor="let state of states" mat-menu-item class="table_action_item" (click)="updateSelectedStatusesCheck(state)" [disabled]="!canUpdate">{{state.label}}</button>
+ </div>
+
+ <!--</div>-->
+ </mat-menu>
+ </div>
+ </th>
+ </tr>
+ </ng-template>
+
+ <!-- * * * * dynamic rows generated from columns object and msElems object * * * * -->
+ <ng-template pTemplate="body" let-rowData let-expanded="expanded" let-bpElem>
+ <tr>
+ <!-- * * * * Column for row expand buttons * * * * -->
+ <td>
+ <a href="#" [pRowToggler]="rowData">
+ <i [ngClass]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'"></i>
+ </a>
+ </td>
+
+ <td *ngFor="let col of cols">
+ <div *ngIf="col.field==='status'" style="width: -moz-max-content; width: fit-content; padding: 0px 5px 0px 5px; border-radius: 3px; font-weight: 600;"
+ [ngClass]="{
+ 'greenStatus' : bpElem[col.field] === 'DEV_COMPLETE' || bpElem[col.field] === 'PST_CERTIFIED' || bpElem[col.field] === 'ETE_CERTIFIED' || bpElem[col.field] === 'IN_PROD',
+ 'redStatus' : bpElem[col.field] === 'PST_FAILED' || bpElem[col.field] === 'ETE_FAILED' || bpElem[col.field] === 'PROD_FAILED',
+ 'blueStatus' : bpElem[col.field] === 'IN_DEV' || bpElem[col.field] === 'IN_PST' || bpElem[col.field] === 'IN_ETE',
+ 'greyStatus' : bpElem[col.field] === 'NOT_NEEDED'}">
+ {{bpElem[col.field]}}
+ </div>
+ <div *ngIf="col.field!=='status'">{{bpElem[col.field]}}</div>
+ </td>
+
+ <!-- * * * * Actions Column * * * * -->
+ <td>
+ <div style="text-align: center;">
+ <p-tableCheckbox [value]="rowData" style="padding-right: 5px;"></p-tableCheckbox>
+ <!-- * * * * Actions Button * * * * -->
+ <button #actionButton pButton type="button" #menuTrigger="matMenuTrigger" class="ui-button-secondary" style="background-color: transparent; border: none; width: 20px; height: 20px; vertical-align: middle;" [matMenuTriggerFor]="menu">
+ <i class="pi pi-ellipsis-h" style="color: grey;"></i>
+ </button>
+ <!-- * * * * Actions Menu Items * * * * -->
+ <mat-menu #menu="matMenu">
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i style="font-size: 12px;" class="pi pi-search"></i> View</span>
+ </div>
+
+ <button mat-menu-item class="table_action_item" (click)="viewBpContent(rowData)">View BP Content</button>
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-times"></i> Delete</span>
+ </div>
+
+ <div matTooltip='Only blueprints that are in a status of "In Dev", "Not Needed" or "Dev Complete" can be deleted' [matTooltipDisabled]="rowData.status === 'IN_DEV' || rowData.status === 'NOT_NEEDED' || rowData.status === 'DEV_COMPLETE'" matTooltipPosition="left">
+ <button mat-menu-item class="table_action_item" (click)="warnDeleteBlueprint(rowData)" [disabled]="rowData.status !== 'IN_DEV' && rowData.status !== 'NOT_NEEDED' && rowData.status !== 'DEV_COMPLETE'">Delete Blueprint</button>
+ </div>
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-pencil"></i> Update</span>
+ </div>
+
+ <div>
+ <div *ngFor="let state of states">
+ <button *ngIf="rowData.status !== state.field" mat-menu-item class="table_action_item" (click)="updateState(state, rowData, false)">{{state.label}}</button>
+ </div>
+ </div>
+ </mat-menu>
+ </div>
+ </td>
+ </tr>
+ </ng-template>
+
+
+ <!-- * * * * Row expand content * * * * -->
+ <ng-template pTemplate="rowexpansion" let-rowData let-columns="columns">
+ <tr>
+ <td [attr.colspan]="columns.length + 2">
+ <div class="row-expand-layout" [@rowExpansionTrigger]="'active'">
+ <!-- * * * * Audit Fields * * * * -->
+ <div class="row-expand-card" style="background-color: rgba(95, 158, 160, 0.295);">
+ <b>Created By:</b> {{rowData.metadata.createdBy}}<br>
+ <b>Created On:</b> {{rowData.metadata.createdOn}}<br>
+ <b>Updated By:</b> {{rowData.metadata.updatedBy}}<br>
+ <b>Updated On:</b> {{rowData.metadata.updatedOn}}<br>
+ </div>
+ <!-- * * * * Notes * * * * -->
+ <div class="row-expand-card" style="background-color: rgba(100, 148, 237, 0.295); white-space: pre-line;">
+ <b>Notes:</b><br>
+ <p-scrollPanel [style]="{width: '100%', height: '75px'}">
+ <div style="font-size: 12px; word-break: normal;">{{rowData.metadata.notes}}</div>
+ </p-scrollPanel>
+ </div>
+ <!-- * * * * Labels * * * * -->
+ <div class="row-expand-card" style="background-color: rgba(76, 65, 225, 0.295)">
+ <b style="padding-bottom: 5px;">Labels:</b><br>
+ <div *ngFor="let label of rowData['metadata']['labels']"
+ style="display: inline-flex; margin-top: 5px;">
+ <div style="padding: 2px 7px 3px 0px;">
+ <span style="background-color: rgba(80, 80, 80, 0.185); padding: 3px; border-radius: 3px;">{{label}}</span>
+ </div>
+ </div>
+ </div>
+ <!-- * * * * Failure Reason * * * * -->
+ <div class="row-expand-card" style="background-color: rgba(225, 65, 65, 0.295)">
+ <b>Failure Reason:</b><br>
+ <p-scrollPanel [style]="{width: '100%', height: '75px'}">
+ <div style="font-size: 12px; word-break: normal;">{{rowData.metadata.failureReason}}</div>
+ </p-scrollPanel>
+ </div>
+
+ </div>
+ </td>
+ </tr>
+ </ng-template>
+ </p-table>
+
+ <!-- * * * * download buttons for exporting table to either csv or excel file * * * * -->
+ <div class="table_export_buttons_alignment">
+ <button pButton type="button" (click)="exportTable('csv')" matTooltip="Export Table to CSV" matTooltipPosition="above" class="table_export_button" style="width: 55px;">
+ <i class="pi pi-file" style="margin-top: 3px; margin-left: 4px;"></i>
+ <label style="font-weight: 800; margin-top: 1px;">CSV</label>
+ </button>
+ <button pButton type="button" (click)="exportTable('excel')" matTooltip="Export Table to XLSX" class="table_export_button" matTooltipPosition="above" style="width: 65px; background-color: green;">
+ <i class="pi pi-file-excel" style="margin-top: 3px; margin-left: 4px;"></i>
+ <label style="font-weight: 800; margin-top: 1px">Excel</label>
+ </button>
+ </div>
+</div>
+
+<p-toast key="statusUpdate" class="ui-toast-detail" [style]="{width: '500px'}">
+ <ng-template let-message pTemplate="message">
+ <p><b>{{message.summary}}</b></p>
+ <p style="font-size: 12px;">{{message.detail}}</p>
+ </ng-template>
+</p-toast>
+<p-toast key="multipleBpReleasesSelected"></p-toast>
+
+<p-toast key="bpDeleteResponse"></p-toast>
+
+
+<!-- * * * * Confirm multiple statuses/releases update toast * * * * -->
+<p-toast position="center" key="confirmToast" (onClose)="onReject()" [baseZIndex]="5000" [style]="{width: '300px'}">
+ <ng-template let-message pTemplate="message">
+ <div style="text-align: center">
+ <i class="pi pi-exclamation-triangle" style="font-size: 3em"></i>
+ <h3>{{message.summary}}</h3>
+ <p>{{message.detail}}</p>
+ </div>
+ <div style="width: 100%; text-align: center;">
+ <button type="button" pButton (click)="onConfirm()" label="Confirm" class="ui-button-success"></button>
+ <button type="button" pButton (click)="onReject()" label="Cancel" class="ui-button-secondary" style="margin-left: 20px;"></button>
+ </div>
+ </ng-template>
+</p-toast>
+
+<!-- * * * * Confirm delete blueprint * * * * -->
+<p-toast position="center" key="confirmDeleteToast" class="ui-toast-detail" (onClose)="onReject()" [baseZIndex]="5000" [style]="{width: '300px'}">
+ <ng-template let-message pTemplate="message">
+ <div style="text-align: center">
+ <i class="pi pi-exclamation-triangle" style="font-size: 3em"></i>
+ <h3>{{message.summary}}</h3>
+ Confirm to delete blueprint(s):<br><br>
+ <p style="text-align: left; margin-left: 10%;">{{message.detail}}</p><br>
+ </div>
+ <div style="width: 100%; text-align: center;">
+ <button type="button" pButton (click)="onConfirmDelete()" label="Confirm" class="ui-button-success"></button>
+ <button type="button" pButton (click)="onRejectDelete()" label="Cancel" class="ui-button-secondary"
+ style="margin-left: 20px;"></button>
+ </div>
+ </ng-template>
+</p-toast>
+
+<!-- * * * * View BP Content Pop Up * * * * -->
+<p-dialog [(visible)]="showBpContentDialog" header="Blueprint Content" appendTo="body" [maximizable]="true" [modal]="true" [style]="{width: '80vw'}" [baseZIndex]="10000"
+ [closable]="false">
+ <pre>{{BpContentToView}}</pre>
+ <p-footer>
+ <button pButton label="Close" (click)="showBpContentDialog=false" type="button"></button>
+ <button pButton label="Download" (click)="download()" type="button"></button>
+ </p-footer>
+</p-dialog> \ No newline at end of file
diff --git a/mod2/ui/src/app/blueprints/blueprints.component.spec.ts b/mod2/ui/src/app/blueprints/blueprints.component.spec.ts
new file mode 100644
index 0000000..caa5c38
--- /dev/null
+++ b/mod2/ui/src/app/blueprints/blueprints.component.spec.ts
@@ -0,0 +1,153 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatMenuModule, MatTooltipModule } from '@angular/material';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
+import { MessageService } from 'primeng/api';
+import { ButtonModule } from 'primeng/button';
+import { DialogModule } from 'primeng/dialog';
+import { DropdownModule } from 'primeng/dropdown';
+import { ScrollPanelModule } from 'primeng/scrollpanel';
+import { TableModule } from 'primeng/table';
+import { ToastModule } from 'primeng/toast';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { BlueprintsComponent } from './blueprints.component';
+
+describe('BlueprintsComponent', () => {
+ let component: BlueprintsComponent;
+ let fixture: ComponentFixture<BlueprintsComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [BlueprintsComponent],
+ imports: [
+ Ng4LoadingSpinnerModule,
+ TableModule,
+ MatMenuModule,
+ ScrollPanelModule,
+ ToastModule,
+ DialogModule,
+ DropdownModule,
+ FormsModule,
+ ReactiveFormsModule,
+ ButtonModule,
+ HttpClientTestingModule,
+ ToastModule,
+ RouterTestingModule,
+ MatTooltipModule,
+ BrowserAnimationsModule
+ ],
+ providers: [
+ MessageService,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BlueprintsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it(`should set states`, async(() => {
+ const fixture = TestBed.createComponent(BlueprintsComponent);
+ const app = fixture.debugElement.componentInstance;
+ let mockStates = [
+ 'state1',
+ 'state2'
+ ]
+ app.setMenuStates(mockStates)
+ fixture.detectChanges();
+ expect(app.states).toEqual([ ]);
+ }));
+
+ it(`should not enable action buttons`, async(() => {
+ const fixture = TestBed.createComponent(BlueprintsComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ app.selectedBPs = []
+ app.enableButtonCheck()
+ fixture.detectChanges();
+
+ expect(app.canDownload).toEqual(false);
+ expect(app.canUpdate).toEqual(false);
+ expect(app.canDelete).toEqual(false);
+ }));
+
+ it(`should enable download/update buttons but not delete`, async(() => {
+ const fixture = TestBed.createComponent(BlueprintsComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ app.selectedBPs = [{status: 'TEST'}]
+ app.enableButtonCheck()
+ fixture.detectChanges();
+
+ expect(app.canDownload).toEqual(true);
+ expect(app.canUpdate).toEqual(true);
+ expect(app.canDelete).toEqual(false);
+ }));
+
+ it(`should enable download/update buttons but not delete`, async(() => {
+ const fixture = TestBed.createComponent(BlueprintsComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ app.selectedBPs = [{ status: 'IN_DEV' }]
+ app.enableButtonCheck()
+ fixture.detectChanges();
+
+ expect(app.canDownload).toEqual(true);
+ expect(app.canUpdate).toEqual(true);
+ expect(app.canDelete).toEqual(true);
+ }));
+
+ it(`should enable download/update buttons but not delete`, async(() => {
+ const fixture = TestBed.createComponent(BlueprintsComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ let mockBpToView = {
+ tag: 'test-tag',
+ type: 'k8s',
+ instanceRelease: '2008',
+ version: '1',
+ content: 'test'
+ }
+
+ app.viewBpContent(mockBpToView)
+ fixture.detectChanges();
+
+ expect(app.BpFileNameForDownload).toEqual('test-tag_k8s_2008_1');
+ expect(app.BpContentToView).toEqual('test');
+ expect(app.showBpContentDialog).toEqual(true);
+ }));
+
+});
+
+
diff --git a/mod2/ui/src/app/blueprints/blueprints.component.ts b/mod2/ui/src/app/blueprints/blueprints.component.ts
new file mode 100644
index 0000000..b4a7e73
--- /dev/null
+++ b/mod2/ui/src/app/blueprints/blueprints.component.ts
@@ -0,0 +1,602 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, ViewChild, ElementRef, Input, EventEmitter, Output, ChangeDetectorRef } from '@angular/core';
+import { Table } from 'primeng/table';
+import { MessageService } from 'primeng/api';
+import { trigger, state, style, transition, animate } from '@angular/animations';
+import * as saveAs from 'file-saver';
+import * as JSZip from 'jszip';
+import { AuthService } from '../services/auth.service';
+import { DatePipe } from '@angular/common';
+import { DeploymentArtifactService } from '../services/deployment-artifact.service';
+import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner';
+import { Toast } from 'primeng/toast'
+import { ActivatedRoute } from '@angular/router';
+import { DownloadService } from '../services/download.service';
+
+@Component({
+ selector: 'app-blueprints',
+ templateUrl: './blueprints.component.html',
+ styleUrls: ['./blueprints.component.css'],
+ animations: [
+ trigger('rowExpansionTrigger', [
+ state('void', style({
+ transform: 'translateX(-10%)',
+ opacity: 0
+ })),
+ state('active', style({
+ transform: 'translateX(0)',
+ opacity: 1
+ })),
+ transition('* <=> *', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)'))
+ ])
+ ],
+ providers: [DatePipe, MessageService]
+})
+export class BlueprintsComponent implements OnInit {
+ @ViewChild(Table, { static: false }) dt: Table;
+ @ViewChild(Toast, { static: false }) toast: Toast;
+
+ /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. **/
+ bpElements: BlueprintElement[] = [];
+ cols: any[] = [
+ { field: 'instanceName', header: 'Instance Name' },
+ { field: 'instanceRelease', header: 'Instance Release', width: '7%' },
+ { field: 'tag', header: 'Tag' },
+ { field: 'type', header: 'Type', width: '7%' },
+ { field: 'version', header: 'Version', width: '6%' },
+ { field: 'status', header: 'Status', width: '125px' }];
+ states: {field: string, label: string}[] = [];
+ columns: any[];
+ filteredRows: any;
+ downloadItems: { label: string; command: () => void; }[];
+ username: string;
+ showBpContentDialog: boolean = false;
+ selectedBPs: BlueprintElement[] = [];
+ // Hides the BP list until the rows are retrieved and filtered
+ visible = "hidden";
+ // These 2 fields are passed from MS Instance to filter the BP list
+ tag: string;
+ release: string;
+
+ filteredName: string;
+ filteredRelease: string;
+ filteredTag: string;
+ filteredType: string;
+ filteredVersion: string;
+ filteredStatus: string;
+
+ constructor(private change: ChangeDetectorRef, private messageService: MessageService, private authService: AuthService,
+ private datePipe: DatePipe, private bpApis: DeploymentArtifactService, private spinnerService: Ng4LoadingSpinnerService,
+ private route: ActivatedRoute, private downloadService: DownloadService) { }
+
+ ngOnInit() {
+
+ this.username = this.authService.getUser().username;
+
+ this.getStates();
+ this.getAllBPs();
+
+ this.change.markForCheck();
+
+ this.route.queryParams.subscribe((params) => {
+ this.filteredTag = params['tag'];
+ this.filteredRelease = params['release']});
+ }
+
+ //gets statuses for status updates
+ getStates(){
+ this.states = []
+ this.bpApis.getStatuses().subscribe((response) => {this.setMenuStates(response)})
+ }
+
+ //fills actions menu with states
+ setMenuStates(states){
+ for(let item of states){
+ this.states.push({
+ field: item,
+ label: 'To ' + item
+ })
+ }
+ }
+
+ canDelete: boolean = false;
+ canDownload: boolean = false;
+ canUpdate: boolean = false;
+ deleteTooltip: string;
+ enableButtonCheck(){
+ if(this.selectedBPs.length > 0){
+ this.canDownload = true;
+ this.canUpdate = true;
+
+ for(let item of this.selectedBPs){
+ if (item.status !== 'IN_DEV' && item.status !== 'NOT_NEEDED' && item.status !== 'DEV_COMPLETE'){
+ this.canDelete = false;
+ this.deleteTooltip = 'Only blueprints that are in a status of "In Dev", "Not Needed" or "Dev Complete" can be deleted'
+ break
+ } else {
+ this.canDelete = true;
+ }
+ }
+
+ } else {
+ this.canDownload = false;
+ this.canUpdate = false;
+ this.canDelete = false;
+ this.deleteTooltip = 'No Blueprints Selected'
+ }
+ }
+
+ updateStateTo: string = ''; //selected state to update blueprint to
+ //checks if there are different releases/statuses selected
+ updateSelectedStatusesCheck(state){
+ this.updateStateTo = state.field
+ let multipleStates: boolean = false
+ let multipleReleases: boolean = false
+ let firstStatus = this.selectedBPs[0]['status']
+ let firstRelease = this.selectedBPs[0]['instanceRelease']
+
+ for(let bp of this.selectedBPs){
+ if(bp.instanceRelease !== firstRelease){
+ multipleReleases = true
+ }
+ if (bp.status !== firstStatus) {
+ multipleStates = true
+ }
+ }
+
+ if(multipleReleases && multipleStates){
+ this.messageService.add({ key: 'confirmToast', sticky: true, severity: 'warn', summary: 'Are you sure?', detail: 'You are about to update blueprints for different releases and statuses. Confirm to proceed.' });
+ } else if (multipleReleases && !multipleStates) {
+ this.messageService.add({ key: 'confirmToast', sticky: true, severity: 'warn', summary: 'Are you sure?', detail: 'You are about to update blueprints for different releases. Confirm to proceed.' });
+ } else if (!multipleReleases && multipleStates) {
+ this.messageService.add({ key: 'confirmToast', sticky: true, severity: 'warn', summary: 'Are you sure?', detail: 'You are about to update blueprints for different statuses. Confirm to proceed.' });
+ } else if (!multipleReleases && !multipleStates){
+ this.updateSelectedStatuses()
+ }
+ }
+ onConfirm() {
+ this.messageService.clear('confirmToast')
+ this.updateSelectedStatuses()
+ }
+ onReject() {
+ this.messageService.clear('confirmToast')
+ }
+
+ /* * * * Update status for multiple blueprints * * * */
+ successfulStatusUpdates: number = 0 //keeps track of how many status updates were successful
+ selectionLength: number = 0 //length of array of blueprints with different statuses than update choice
+ statusUpdateCount: number = 0 //keeps track of how many api calls have been made throughout a loop
+ statusUpdateErrors: string[] = [] //keeps list of errors
+ updateSelectedStatuses(){
+ this.successfulStatusUpdates = 0
+ this.statusUpdateErrors = []
+ this.statusUpdateCount = 0
+
+ let bpsToUpdate = this.selectedBPs.filter(bp => bp.status !== this.updateStateTo) //array of blueprints with different statuses than update choice
+ this.selectionLength = bpsToUpdate.length;
+
+ if (this.selectionLength === 0) { this.selectedBPs = [] } else {
+ this.spinnerService.show();
+ this.updateState(this.updateStateTo, bpsToUpdate, true)
+ }
+ }
+
+ /* * * * Update Statuses * * * */
+ //state is the state to update to
+ //data is the bp data from selection
+ //multiple is whether updates were called for single blueprint or multiple selected blueprints
+ updateState(state, data, multiple){
+ //single status update
+ if(!multiple){
+ this.bpApis.patchBlueprintStatus(state.field, data['id']).subscribe(
+ (response: string) => {
+ data.status = state.field
+ this.messageService.add({ key: 'statusUpdate', severity: 'success', summary: 'Status Updated' });
+ }, errResponse => {
+ this.statusUpdatesResponseHandler(errResponse, false)
+ }
+ )
+ }
+
+ //multiple status updates
+ if(multiple){
+ (async () => {
+ for (let bp of data) {
+ this.bpApis.patchBlueprintStatus(this.updateStateTo, bp.id).subscribe(
+ (response: string) => {
+ bp.status = this.updateStateTo
+ this.statusUpdatesResponseHandler(null, true)
+ }, errResponse => {
+ this.statusUpdatesResponseHandler(errResponse, true)
+ }
+ )
+ await timeout(1500);
+ }
+ })();
+
+ function timeout(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ }
+ }
+ }
+
+ /* * * * Handles errors and messages for status updates * * * */
+ statusUpdatesResponseHandler(response, multiple){
+ if(!multiple){
+ if(response !== null){
+ if (response.error.message.includes('Only 1 blueprint can be in the DEV_COMPLETE state.')) {
+ let message = response.error.message.replace('Only 1 blueprint can be in the DEV_COMPLETE state. ', '\n\nOnly 1 blueprint can be in the DEV_COMPLETE state.\n')
+ this.messageService.add({ key: 'statusUpdate', severity: 'error', summary: 'Status Not Updated', detail: message, sticky: true });
+ } else {
+ this.messageService.add({ key: 'statusUpdate', severity: 'error', summary: 'Error Message', detail: response.error.message, sticky: true });
+ }
+ }
+ }
+
+ if(multiple){
+ this.statusUpdateCount++
+ if (response === null) {
+ this.successfulStatusUpdates++
+ } else {
+ if (response.error.message.includes('Only 1 blueprint can be in the DEV_COMPLETE state.')) {
+ let error = response.error.message.split('Only 1 blueprint can be in the DEV_COMPLETE state.')[0]
+ this.statusUpdateErrors.push(error)
+ } else {
+ this.messageService.add({ key: 'statusUpdate', severity: 'error', summary: 'Error Message', detail: response.error.message, sticky: true });
+ }
+ }
+
+ if (this.statusUpdateCount === this.selectionLength) {
+ if (this.successfulStatusUpdates > 0) {
+ this.messageService.add({ key: 'statusUpdate', severity: 'success', summary: `(${this.successfulStatusUpdates} of ${this.selectionLength}) Statuses Updated`, life: 5000 });
+ }
+ if (this.statusUpdateErrors.length > 0) {
+ let message: string = ''
+ for (let elem of this.statusUpdateErrors) {
+ message += '- ' + elem + '\n'
+ }
+ message += '\nOnly 1 blueprint can be in the DEV_COMPLETE state.\nChange the current DEV_COMPLETE blueprint to NOT_NEEDED or IN_DEV before changing another to DEV_COMPLETE.'
+ this.messageService.add({ key: 'statusUpdate', severity: 'error', summary: 'Statuses Not Updated', detail: message, sticky: true });
+ }
+ this.spinnerService.hide()
+ this.selectedBPs = []
+ }
+ }
+ }
+
+ bpToDelete: any;
+ deleteSingle: boolean = false;
+ rowIndexToDelete;
+ rowIndexToDeleteFiltered;
+ warnDeleteBlueprint(data){
+ if(data !== null){
+ this.deleteSingle = true;
+ this.rowIndexToDeleteFiltered = this.filteredRows.map(function (x) { return x.id; }).indexOf(data['id']);
+ this.rowIndexToDelete = this.bpElements.map(function (x) { return x.id; }).indexOf(data['id']);
+ this.bpToDelete = data;
+ this.messageService.add({ key: 'confirmDeleteToast', sticky: true, severity: 'warn', summary: 'Are you sure?', detail: `- ${data.instanceName} (v${data.version}) for ${data.instanceRelease}` });
+ } else {
+ this.deleteSingle = false;
+ this.selectionLength = this.selectedBPs.length;
+ let warnMessage: string = ''
+ for(let item of this.selectedBPs){
+ warnMessage += `- ${item.instanceName} (v${item.version}) for ${item.instanceRelease}\n`
+ }
+ this.messageService.add({ key: 'confirmDeleteToast', sticky: true, severity: 'warn', summary: 'Are you sure?', detail: warnMessage });
+ }
+ }
+
+ resetFilter = false;
+ onConfirmDelete() {
+ this.messageService.clear('confirmDeleteToast')
+
+ if (this.filteredName !== '' || this.filteredRelease !== '' || this.filteredTag !== '' || this.filteredType !== '' || this.filteredVersion !== '' || this.filteredStatus !== ''){
+ this.resetFilter = true;
+ } else {this.resetFilter = false}
+
+ if(this.deleteSingle){
+ this.bpApis.deleteBlueprint(this.bpToDelete['id']).subscribe(response => {
+ this.checkBpWasSelected(this.bpToDelete['id'])
+ this.bpElements.splice(this.rowIndexToDelete, 1)
+ if (this.resetFilter) {
+ this.resetFilters()
+ }
+ this.messageService.add({ key: 'bpDeleteResponse', severity: 'success', summary: 'Success Message', detail: 'Deployment Artifact Deleted' });
+ }, error => {
+ this.messageService.add({ key: 'bpDeleteResponse', severity: 'error', summary: 'Error Message', detail: error.error.message });
+ })
+ } else {
+ for(let item of this.selectedBPs){
+ this.bpApis.deleteBlueprint(item.id).subscribe(response => {
+ this.deleteResponseHandler(true, item.id)
+ }, error => {
+ this.messageService.add({ key: 'bpDeleteResponse', severity: 'error', summary: 'Error Message', detail: error.error.message });
+ })
+ }
+ }
+ }
+ onRejectDelete() {
+ this.messageService.clear('confirmDeleteToast')
+ }
+
+ checkBpWasSelected(id){
+ if(this.selectedBPs.length > 0){
+ for(let item of this.selectedBPs){
+ if(item.id === id){
+ let indexToDelete = this.selectedBPs.map(function (x) { return x.id; }).indexOf(item['id']);
+ this.selectedBPs.splice(indexToDelete, 1)
+ }
+ }
+ }
+ }
+
+ bpsToDelete: string[] = [];
+ deleteBpCount = 0;
+ deleteResponseHandler(success, bpToDeleteId){
+ this.deleteBpCount++
+ if(success){
+ this.bpsToDelete.push(bpToDeleteId)
+ }
+ if(this.deleteBpCount === this.selectionLength){
+ for(let item of this.bpsToDelete){
+
+ let indexToDelete = this.bpElements.map(function (x) { return x.id; }).indexOf(item);
+ this.bpElements.splice(indexToDelete, 1)
+ }
+
+ if(this.resetFilter){
+ this.resetFilters()
+ }
+
+ this.selectedBPs = [];
+ this.bpsToDelete = [];
+ this.deleteBpCount = 0;
+ this.messageService.add({ key: 'bpDeleteResponse', severity: 'success', summary: 'Success Message', detail: 'Deployment Artifacts Deleted' });
+ }
+ }
+
+ resetFilters(){
+ let filters: {field: string, value: string}[] = [];
+ filters.push({field: 'instanceName', value: this.filteredName})
+ filters.push({ field: 'instanceRelease', value: this.filteredRelease })
+ filters.push({ field: 'tag', value: this.filteredTag })
+ filters.push({ field: 'type', value: this.filteredType })
+ filters.push({ field: 'version', value: this.filteredVersion })
+ filters.push({ field: 'status', value: this.filteredStatus })
+
+ for(let item of filters){
+ this.dt.filter(item.value, item.field, 'contains')
+ }
+ }
+
+ /* * * * Gets all blueprints * * * */
+ getAllBPs() {
+ this.spinnerService.show();
+ this.bpElements = [];
+ this.columns = this.cols.map(col => ({ title: col.header, dataKey: col.field }));
+
+ this.visible = "hidden";
+
+ this.bpApis.getAllBlueprints()
+ .subscribe((data: any[]) => {
+ this.fillTable(data)
+ })
+
+ }
+
+ /* * * * Checks when table is filtered and stores filtered data in new object to be downloaded when download button is clicked * * * */
+ onTableFiltered(values) {
+ if (values) {
+ this.filteredRows = values;
+ } else {
+ this.filteredRows = this.bpElements
+ }
+ }
+
+ /* * * * Download table as excel file * * * */
+ exportTable(exportTo) {
+ let downloadElements: any[] = []
+
+ for (let row of this.filteredRows) {
+ let labels;
+ let notes;
+ if (exportTo === "excel") {
+ if (row.metadata.labels !== undefined && row.metadata.labels !== null ) {
+ labels = row.metadata.labels.join(",")
+ }
+ } else {
+ labels = row.metadata.labels
+ }
+
+ if (row.metadata.notes !== null && row.metadata.notes !== undefined && row.metadata.notes !== '') {
+ notes = encodeURI(row.metadata.notes).replace(/%20/g, " ").replace(/%0A/g, "\\n")
+ }
+
+ downloadElements.push({
+ Instance_Name: row.instanceName,
+ Instance_Release: row.instanceRelease,
+ Tag: row.tag,
+ Type: row.type,
+ Version: row.version,
+ Status: row.status,
+ Created_By: row.metadata.createdBy,
+ Created_On: row.metadata.createdOn,
+ Updated_By: row.metadata.updatedBy,
+ Updated_On: row.metadata.updatedOn,
+ Failure_Reason: row.metadata.failureReason,
+ Notes: notes,
+ Labels: labels
+ })
+ }
+
+ let csvHeaders = []
+
+ if (exportTo === "csv") {
+ csvHeaders = [
+ "Instance_Name",
+ "Instance_Release",
+ "Tag",
+ "Type",
+ "Version",
+ "Status",
+ "Created_By",
+ "Created_On",
+ "Updated_By",
+ "Updated_On",
+ "Failure_Reason",
+ "Notes",
+ "Labels"];
+
+ }
+
+ this.downloadService.exportTableData(exportTo, downloadElements, csvHeaders)
+ }
+
+ /* * * * Fills object with blueprint data to be used to fill table * * * */
+ fillTable(data) {
+ let fileName: string;
+ let tag: string;
+ let type: string;
+
+ for (let elem of data) {
+ fileName = elem.fileName;
+ if(fileName.includes('docker')){
+ type = 'docker'
+ if(fileName.includes('-docker')){
+ tag = fileName.split('-docker')[0]
+ } else if (fileName.includes('_docker')){
+ tag = fileName.split('_docker')[0]
+ }
+ } else if (fileName.includes('k8s')){
+ type = 'k8s'
+ if (fileName.includes('-k8s')) {
+ tag = fileName.split('-k8s')[0]
+ } else if (fileName.includes('_k8s')) {
+ tag = fileName.split('_k8s')[0]
+ }
+ }
+
+ //create temporary bp element to push to array of blueprints
+ var tempBpElement: BlueprintElement = {
+ instanceId: elem.msInstanceInfo.id,
+ instanceName: elem.msInstanceInfo.name,
+ instanceRelease: elem.msInstanceInfo.release,
+ id: elem.id,
+ version: elem.version,
+ content: elem.content,
+ status: elem.status,
+ fileName: fileName,
+ tag: tag,
+ type: type,
+ metadata: {
+ failureReason: elem.metadata.failureReason,
+ notes: elem.metadata.notes,
+ labels: elem.metadata.labels,
+ createdBy: elem.metadata.createdBy,
+ createdOn: this.datePipe.transform(elem.metadata.createdOn, 'MM-dd-yyyy HH:mm'),
+ updatedBy: elem.metadata.updatedBy,
+ updatedOn: this.datePipe.transform(elem.metadata.updatedOn, 'MM-dd-yyyy HH:mm')
+ },
+ specification: {
+ id: elem.specificationInfo.id
+ }
+ }
+
+ this.bpElements.push(tempBpElement)
+ }
+ this.bpElements.reverse();
+ this.filteredRows = this.bpElements;
+
+ this.resetFilters();
+
+ this.visible = "visible";
+ this.spinnerService.hide();
+ }
+
+ /* * * * Define content to show in bp view dialog pop up * * * */
+ BpContentToView: string;
+ viewBpContent(data){
+ this.BpFileNameForDownload = `${data['tag']}_${data['type']}_${data['instanceRelease']}_${data['version']}`
+ this.BpContentToView = data['content']
+ this.showBpContentDialog = true
+ }
+
+ /* * * * Download single blueprint * * * */
+ BpFileNameForDownload: string;
+ download() {
+ let file = new Blob([this.BpContentToView], { type: 'text;charset=utf-8' });
+ let name: string = this.BpFileNameForDownload + '.yaml'
+ saveAs(file, name)
+ }
+
+/* * * * Download selected blueprints * * * */
+ downloadSelectedBps() {
+ let canDownloadBps: boolean = true;
+
+ //checks if blueprints for multiple releases are selected
+ let selectedBpRelease: string = this.selectedBPs[0]['instanceRelease'];
+ for (let bp in this.selectedBPs) {
+ if (this.selectedBPs[bp]['instanceRelease'] !== selectedBpRelease) {
+ canDownloadBps = false
+ break
+ }
+ }
+
+ //downloads blueprints to zip file if all selected blueprints are for one release
+ if (canDownloadBps) {
+ var zip = new JSZip();
+ for (var i in this.selectedBPs) {
+ zip.file(`${this.selectedBPs[i]['tag']}_${this.selectedBPs[i]['type']}_${this.selectedBPs[i]['instanceRelease']}_${this.selectedBPs[i]['version']}.yaml`, this.selectedBPs[i]['content'])
+ }
+ zip.generateAsync({ type: "blob" }).then(function (content) {
+ saveAs(content, 'Blueprints.zip');
+ });
+ } else {
+ this.messageService.add({ key: 'multipleBpReleasesSelected', severity: 'error', summary: 'Error Message', detail: "Cannot download blueprints for different releases" });
+ }
+
+ this.selectedBPs = []
+ }
+}
+
+export interface BlueprintElement{
+ instanceId: string
+ instanceName: string
+ instanceRelease: string
+ id: string
+ version: string
+ content: string
+ status: string
+ fileName: string
+ tag: string
+ type: string
+ metadata: {
+ failureReason: string
+ notes: string
+ labels: string[]
+ createdBy: string
+ createdOn: string
+ updatedBy: string
+ updatedOn: string
+ },
+ specification: {
+ id: string
+ }
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.css b/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.css
new file mode 100644
index 0000000..54806ab
--- /dev/null
+++ b/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.css
@@ -0,0 +1,43 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+.input {
+ padding-top: 10px;
+}
+
+.inputLabel {
+ font-weight: 600;
+ margin-left: 20px;
+ width: 135px;
+}
+
+.inputFieldSm {
+ width: 200px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldMed {
+ width: 300px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldLg {
+ width: 400px;
+ height: 35px;
+ padding-left: 6px;
+}
diff --git a/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.html b/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.html
new file mode 100644
index 0000000..f15f19b
--- /dev/null
+++ b/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.html
@@ -0,0 +1,64 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<p-dialog *ngIf="visible" header="Component Spec ADD" [(visible)]="visible" appendTo="body" [modal]="true" [transitionOptions]="'300ms'"
+ [closeOnEscape]="false" [closable]="false" [style]="{width: '650px'}" (onHide)="closeDialog()">
+
+ <!-- * * * * * Input fields * * * * * -->
+ <form [formGroup]="csAddForm" (ngSubmit)="saveCs()" class="bg-faded">
+ <!-- * * * Type * * * -->
+ <div class="input">
+ <label class="inputLabel">Type<span style="color:red">*</span></label>
+ <p-dropdown [options]="types" placeholder="Select Type" optionLabel="type" formControlName="type"></p-dropdown>
+ </div>
+ <!-- * * * Labels * * * -->
+ <div class="input">
+ <label class="inputLabel">Labels</label>
+ <input class="inputFieldLg" type="text" pInputText formControlName="labels" />
+ </div>
+ <span style="padding: 9px 0px 0px 158px; font-size: 13px;">(Separate labels with a space)</span>
+ <!-- * * * Notes * * * -->
+ <div class="input">
+ <label class="inputLabel" style="vertical-align: top">Notes</label>
+ <textarea class="inputFieldLg" [rows]="1" [cols]="30" pInputTextarea autoResize="autoResize" formControlName="notes"></textarea>
+ </div>
+ <!-- * * * Comp Spec File Select * * * -->
+ <div class="input">
+ <label class="inputLabel">Component Spec<span style="color:red">*</span></label>
+
+ <input type="file" style="width: 460px; color:blue; font-style: italic;" (input)="onCompSpecUpload($event)" name="myfile" id="myfile" accept=".json">
+ </div>
+
+ <!-- * * * Policy File Select * * * -->
+ <div class="input">
+ <label class="inputLabel">Policy</label>
+
+ <input type="file" style="width: 460px; color:blue; font-style: italic;" (input)="onPolicyUpload($event)"
+ name="myPolicyFile" id="myPolicyFile" accept=".json">
+ </div>
+
+ <!-- * * * ADD and Cancel buttons * * * -->
+ <div style="float: right; padding: 20px 45px">
+ <button pButton type="button" (click)="closeDialog()" label="Cancel"></button>&nbsp;
+ <button pButton type="submit" class="ui-button-success" label="Add" [disabled]="!csAddForm.valid || !compSpecSelected" style="width: 70px"></button>
+ </div>
+ </form>
+
+ <p-toast key="jsonError" [style]="{width: '430px'}"></p-toast>
+
+</p-dialog>
diff --git a/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.spec.ts b/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.spec.ts
new file mode 100644
index 0000000..e29a110
--- /dev/null
+++ b/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.spec.ts
@@ -0,0 +1,77 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { MessageService } from 'primeng/api';
+import { ButtonModule } from 'primeng/button';
+import { DialogModule } from 'primeng/dialog';
+import { DropdownModule } from 'primeng/dropdown';
+import { ToastModule } from 'primeng/toast';
+
+
+import { CompSpecAddComponent } from './comp-spec-add.component';
+
+describe('CompSpecAddComponent', () => {
+ let component: CompSpecAddComponent;
+ let fixture: ComponentFixture<CompSpecAddComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [CompSpecAddComponent],
+ imports: [
+ DialogModule,
+ DropdownModule,
+ ToastModule,
+ FormsModule,
+ ReactiveFormsModule,
+ ButtonModule,
+ HttpClientTestingModule,
+ RouterTestingModule
+ ],
+ providers: [
+ MessageService,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CompSpecAddComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it(`should invalidate spec JSON structure`, async(() => {
+ const fixture = TestBed.createComponent(CompSpecAddComponent);
+ const app = fixture.debugElement.componentInstance;
+ let mockErrorJson = "test: 'test}"
+ app.compSpecContent = mockErrorJson
+ expect(() => app.validateJsonStructure()).toThrowError('JSON Structure error, quit!')
+ }));
+
+});
diff --git a/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.ts b/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.ts
new file mode 100644
index 0000000..7564852
--- /dev/null
+++ b/mod2/ui/src/app/comp-spec-add/comp-spec-add.component.ts
@@ -0,0 +1,180 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { InputTextModule } from 'primeng/inputtext';
+import { DropdownModule } from 'primeng/dropdown';
+import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
+import { AuthService } from '../services/auth.service';
+import { MessageService } from 'primeng/api';
+
+interface Type {
+ type: string;
+}
+
+@Component({
+ selector: 'app-comp-spec-add',
+ templateUrl: './comp-spec-add.component.html',
+ styleUrls: ['./comp-spec-add.component.css']
+})
+
+export class CompSpecAddComponent implements OnInit {
+
+ compSpecSelected: any;
+ compSpecContent: any;
+
+ policySelected: any;
+ policyContent: any;
+
+ csAddForm: FormGroup;
+ // The loggged in user
+ username: string;
+
+ // Input form fields
+ type: string;
+ labels: string;
+ notes: string;
+ specFile: any;
+ policyJson: any;
+
+ // Dropdowns
+ types: Type[];
+
+ // Build JSON as a string
+ csAddString: any;
+ // Return JSON to parent component
+ csAddJson: any;
+
+ constructor(private fb: FormBuilder, private authService: AuthService, private messageService: MessageService) {
+ }
+
+ @Input() visible: boolean;
+ @Output() handler: EventEmitter<any> = new EventEmitter();
+
+ ngOnInit() {
+ // The logged in user
+ this.username = this.authService.getUser().username;
+
+ this.csAddForm = new FormGroup({
+ type: new FormControl(),
+ labels: new FormControl(),
+ notes: new FormControl(),
+ specFile: new FormControl(),
+ policyJson: new FormControl()
+ });
+
+ // FORM fields and validations
+ this.csAddForm = this.fb.group({
+ type: ['', [Validators.required]],
+ labels: ['', []],
+ notes: ['', []],
+ specFile: ['', []],
+ policyJson: ['', []]
+ });
+
+ // TYPE Dropdown
+ this.types = [
+ { type: 'DOCKER' },
+ { type: 'K8S' }
+ ];
+ }
+
+ saveCs() {
+ this.createOutputJson();
+ this.csAddJson = JSON.stringify(this.csAddString);
+ this.handler.emit(this.csAddJson);
+ this.closeDialog();
+ }
+
+ // Create the JSON to be sent to the parent component
+ // The "labels" functions below take into account leading/trailing spaces, multiple spaces between labels, and conversion into an array
+ createOutputJson() {
+ this.validateJsonStructure();
+
+ let policy;
+ if(this.policyContent !== undefined){
+ policy = JSON.parse(this.policyContent)
+ } else {
+ policy = null
+ }
+
+ this.csAddString = {
+ specContent: JSON.parse(this.compSpecContent),
+ policyJson: policy,
+ type: this.csAddForm.value['type'].type,
+ metadata: {
+ labels: this.csAddForm.value['labels'].trim().replace(/\s{2,}/g, ' ').split(" "),
+ notes: this.csAddForm.value['notes']
+ },
+ user: this.username
+ };
+ }
+
+ // Validate, catch, display JSON structure error, and quit!
+ validateJsonStructure() {
+ try {
+ JSON.parse(this.compSpecContent);
+ } catch (error) {
+ this.messageService.add({ key: 'jsonError', severity: 'error', summary: 'Invalid Component Spec JSON', detail: error, sticky: true });
+ throw new Error('JSON Structure error, quit!');
+ }
+
+ if(this.policyContent !== undefined){
+ try {
+ JSON.parse(this.policyContent);
+ } catch (error) {
+ this.messageService.add({ key: 'jsonError', severity: 'error', summary: 'Invalid Policy JSON', detail: error, sticky: true });
+ throw new Error('JSON Structure error, quit!');
+ }
+ }
+ }
+
+ // Read the selected Component Spec JSON file
+ onCompSpecUpload(event) {
+ this.compSpecSelected = event.target.files[0];
+ this.readCsFileContent(this.compSpecSelected);
+ }
+ //Read the selected Component Spec JSON file
+ onPolicyUpload(event) {
+ this.policySelected = event.target.files[0];
+ this.readPolicyFileContent(this.policySelected);
+ }
+
+ readCsFileContent(file) {
+ if (file) {
+ let fileReader = new FileReader();
+ fileReader.onload = (e) => { this.compSpecContent = fileReader.result; };
+ fileReader.readAsText(file);
+ }
+ }
+
+ readPolicyFileContent(file) {
+ if (file) {
+ let fileReader = new FileReader();
+ fileReader.onload = (e) => { this.policyContent = fileReader.result; };
+ fileReader.readAsText(file);
+ }
+ }
+
+ // The handler emits 'null' back to parent to close dialog and make it available again when clicked
+ closeDialog() {
+ this.visible = false;
+ this.handler.emit(null);
+ }
+
+}
diff --git a/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.css b/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.css
new file mode 100644
index 0000000..d76e0fa
--- /dev/null
+++ b/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.css
@@ -0,0 +1,73 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+.validator-input-card{
+ width: 40%;
+ min-width: 430px;
+ min-height: 100%;
+ border: 2px solid slategray;
+ border-radius: 5px;
+ background-color: white;
+ padding: 1%;
+}
+.validator-output-card{
+ width: 58%;
+ border: 2px solid slategray;
+ margin-left: 2%;
+ min-height: 100%;
+ border-radius: 5px;
+ background-color: white;
+ padding: 1%;
+}
+
+.input-section-card{
+ font-size: 14px;
+ border: solid slategray;
+ border-style: double;
+ margin-top: 7px
+}
+
+.validateSpec{
+ margin-top: 10px;
+}
+.downloadSchema{
+ margin-top: 80px;
+}
+
+.type-selection{
+ position: absolute;
+ background-color: rgba(128, 128, 128, 0.15);
+ width: 190px;
+ height: 40px;
+ display: inline-flex;
+ align-items: center;
+ margin-left: 150px;
+}
+
+.greenOutput{
+ background-color: rgba(0, 255, 0, 0.205);
+ height: 40px;
+ padding: 3px;
+ border: 2px solid rgba(0, 66, 0, 0.747);
+}
+.redOutput{
+ background-color: rgba(255, 0, 0, 0.267);
+ height: 87%;
+ padding: 10px;
+ border: 2px solid rgba(65, 0, 0, 0.712);
+}
diff --git a/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.html b/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.html
new file mode 100644
index 0000000..9867364
--- /dev/null
+++ b/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.html
@@ -0,0 +1,108 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<div style="margin-left: 2%; margin-right: 2%;">
+ <p style="font-size: 26px;">Component Specification Validation</p>
+ <div style="display: inline-flex; width: 100%; height: 100%; min-height: 450px;">
+ <div class="validator-input-card">
+ <div>
+ <mat-card class="input-section-card">
+ <span><b>Action</b></span><span style="color:red">*</span><br>
+ <div style="display: inline-flex;">
+ <div style="padding-right: 10%; width: 200px;">
+ <p-radioButton name="spec-validator-actions" value="validateSpec" [(ngModel)]="spec_validator_action" (click)="validateRadioButton()"></p-radioButton>&nbsp;&nbsp;Validate Spec File
+ </div>
+ <div>
+ <p-radioButton name="spec-validator-actions" value="downloadSchema" [(ngModel)]="spec_validator_action" (click)="downloadRadioButton()"></p-radioButton>&nbsp;&nbsp;Download Schema
+ </div>
+ </div>
+ </mat-card>
+
+ <mat-card class="input-section-card">
+ <span><b>Release</b></span><span style="color:red">*</span><br>
+ <div>
+ <div style="display: inline-flex; align-items: center;">
+ <p-radioButton name="spec-validator-release" value="2007" [(ngModel)]="release"></p-radioButton>&nbsp;&nbsp;2007+
+ </div>
+ </div>
+ </mat-card>
+
+ <mat-card class="input-section-card">
+ <span><b>Type</b></span><span style="color:red">*</span><br>
+ <div>
+ <div style="display: inline-flex; align-items: center;">
+ <p-radioButton name="spec-validator-type" value="k8s" [(ngModel)]="type"></p-radioButton>&nbsp;&nbsp;K8s
+ </div>
+ <br>
+ <div style="display: inline-flex; align-items: center;">
+ <p-radioButton name="spec-validator-type" value="docker" [(ngModel)]="type"></p-radioButton>&nbsp;&nbsp;Docker
+ </div>
+ </div>
+ </mat-card>
+
+ <mat-card *ngIf="spec_validator_action === 'validateSpec'" class="input-section-card">
+ <!-- * * * Comp Spec File Select * * * -->
+ <div>
+ <b>Component Spec File</b><span style="color:red">*</span><br>
+
+ <div style="display: inline-flex;">
+ <input #myFile type="file" style="color:blue; font-style: italic; width: fit-content"
+ (input)="onCompSpecUpload($event)" name="myfile" accept=".json">
+
+ <button pButton type="button" (click)="resetFile()"
+ style="background-color: transparent; border: none; height: 20px;"><i class="pi pi-times"
+ style="color: black;"></i></button>
+ </div>
+ </div>
+ </mat-card>
+
+ <div>
+ <div *ngIf="shouldValidate" style="background-color: rgba(128, 128, 128, 0.315); height: 2px; width: 100%; margin-top: 2%;"></div>
+ <div *ngIf="shouldDownload" style="background-color: rgba(128, 128, 128, 0.315); height: 2px; width: 100%; margin-top: 22%;"></div>
+
+ <div style="float: right; margin-top: 8px">
+ <div *ngIf="shouldValidate" matTooltip="Fill In Required Fields" [matTooltipDisabled]="!(release === '' || type === '' || compSpecContent === null)" matTooltipPosition="above">
+ <button [disabled]="release === '' || type === '' || compSpecContent === null" pButton label="Validate Spec" type="button" (click)="validateSpec()"></button>
+ </div>
+ <div *ngIf="shouldDownload" matTooltip="Fill In Required Fields" [matTooltipDisabled]="!(release === '' || type === '')" matTooltipPosition="above">
+ <button [disabled]="release === '' || type === ''" pButton label="Download Schema" type="button" (click)="downloadSchema()"></button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div *ngIf="shouldValidate" class="validator-output-card">
+ <span><b>Output:</b></span><br><br>
+ <div *ngIf="specValidated" style="width: 100%; padding: 1%; border-radius: 3px; overflow: hidden;" [ngClass]="{'greenOutput' : validCompSpec === true, 'redOutput' : validCompSpec === false}">
+ <div>
+ <span style="font-weight: 500;">{{specValidationOutputHeader}}</span>
+ <div *ngIf="specValidationOutputMessage !== ''" style="margin-top: 10px; width: 100%; height: 2px; background-color: rgba(128, 128, 128, 0.315); "></div>
+
+ <div *ngIf="specValidationOutputMessage !== ''" style="margin-top: 10px">
+ <p-scrollPanel [style]="{width: '100%', height: '50vh'}">
+ <pre style="white-space: pre-wrap;"><b>Summary:</b><br>{{specValidationOutputSummary}}</pre>
+ <pre style="white-space: pre-wrap;"><b>Message(s):</b><br>{{specValidationOutputMessage}}</pre>
+ </p-scrollPanel>
+ </div>
+
+ </div>
+ </div>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.spec.ts b/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.spec.ts
new file mode 100644
index 0000000..a9efe28
--- /dev/null
+++ b/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.spec.ts
@@ -0,0 +1,132 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { RadioButtonModule } from 'primeng/radiobutton';
+
+import { CompSpecValidationComponent } from './comp-spec-validation.component';
+import { FormsModule } from '@angular/forms';
+import { MatCardModule, MatTooltipModule } from '@angular/material';
+import { ScrollPanelModule } from 'primeng/scrollpanel';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { MessageService } from 'primeng/api';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
+
+describe('CompSpecValidationComponent', () => {
+ let component: CompSpecValidationComponent;
+ let fixture: ComponentFixture<CompSpecValidationComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CompSpecValidationComponent ],
+ imports: [
+ RadioButtonModule,
+ FormsModule,
+ MatCardModule,
+ MatTooltipModule,
+ ScrollPanelModule,
+ HttpClientTestingModule,
+ Ng4LoadingSpinnerModule
+ ],
+ providers: [
+ MessageService,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CompSpecValidationComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it(`should have as shouldValidate 'false'`, () => {
+ const fixture = TestBed.createComponent(CompSpecValidationComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app.shouldValidate).toEqual(false);
+ });
+
+ it(`should change shouldValidate to 'true'`, async(() => {
+ const fixture = TestBed.createComponent(CompSpecValidationComponent);
+ const app = fixture.debugElement.componentInstance;
+ app.validateRadioButton()
+ fixture.detectChanges();
+ expect(app.shouldValidate).toEqual(true);
+ }));
+
+ it(`should have as shouldDownload 'false'`, () => {
+ const fixture = TestBed.createComponent(CompSpecValidationComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app.shouldDownload).toEqual(false);
+ });
+
+ it(`should change shouldDownload to 'true'`, async(() => {
+ const fixture = TestBed.createComponent(CompSpecValidationComponent);
+ const app = fixture.debugElement.componentInstance;
+ app.downloadRadioButton()
+ fixture.detectChanges();
+ expect(app.shouldDownload).toEqual(true);
+ }));
+
+ it(`should set validation error message`, async(() => {
+ const fixture = TestBed.createComponent(CompSpecValidationComponent);
+ const app = fixture.debugElement.componentInstance;
+ let mockSuccess = {
+ status: 200
+ }
+ app.setSpecValidationMessage(mockSuccess)
+ fixture.detectChanges();
+ expect(app.validCompSpec).toEqual(true)
+ }));
+
+ it(`should set validation error message`, async(() => {
+ const fixture = TestBed.createComponent(CompSpecValidationComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ let mockError = {
+ status: 400,
+ error: {
+ summary: 'Test',
+ errors: [
+ 'error1',
+ 'error2'
+ ]
+ }
+ }
+ app.setSpecValidationMessage(mockError)
+ fixture.detectChanges();
+ expect(app.validCompSpec).toEqual(false)
+ }));
+
+ it(`should invalidate JSON structure`, async(() => {
+ const fixture = TestBed.createComponent(CompSpecValidationComponent);
+ const app = fixture.debugElement.componentInstance;
+ let mockErrorJson = "test: 'test}"
+ app.compSpecContent = mockErrorJson
+ expect(() => app.validateJsonStructure()).toThrowError('JSON Structure error, quit!')
+ }));
+
+});
diff --git a/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.ts b/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.ts
new file mode 100644
index 0000000..2ce8fef
--- /dev/null
+++ b/mod2/ui/src/app/comp-spec-validation/comp-spec-validation.component.ts
@@ -0,0 +1,145 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
+import { SpecValidationService } from '../services/spec-validation.service';
+import { DownloadService } from '../services/download.service';
+import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner';
+
+@Component({
+ selector: 'app-comp-spec-validation',
+ templateUrl: './comp-spec-validation.component.html',
+ styleUrls: ['./comp-spec-validation.component.css']
+})
+export class CompSpecValidationComponent implements OnInit {
+
+ @ViewChild('myFile', {static: false})
+ myInputVariable: ElementRef;
+
+ spec_validator_action;
+ release = '';
+ type = '';
+ shouldValidate = false;
+ shouldDownload = false;
+ validCompSpec = false;
+ specValidated = false;
+ specValidationOutputSummary: any;
+
+ constructor(private specValidator: SpecValidationService, private downloadService: DownloadService, private spinnerService: Ng4LoadingSpinnerService ) { }
+
+ ngOnInit() {
+
+ }
+
+ compSpecSelected: any;
+ onCompSpecUpload(event){
+ this.compSpecSelected = event.target.files[0];
+ this.readCsFileContent(this.compSpecSelected);
+ }
+
+ compSpecContent: any = null;
+ readCsFileContent(file) {
+ if (file) {
+ let fileReader = new FileReader();
+ fileReader.onload = (e) => { this.compSpecContent = fileReader.result; };
+ fileReader.readAsText(file);
+ }
+ }
+
+ validateRadioButton(){
+ this.shouldValidate = true;
+ this.shouldDownload = false;
+ }
+
+ downloadRadioButton(){
+ this.shouldValidate = false;
+ this.shouldDownload = true;
+ this.compSpecContent = null;
+ this.specValidated = false
+ }
+
+ resetFile(){
+ this.myInputVariable.nativeElement.value = "";
+ this.compSpecContent = null
+ this.compSpecSelected = null
+ this.specValidated = false
+ }
+
+ specValidationOutputHeader = ''
+ specValidationOutputMessage = '';
+ validateSpec(){
+ this.specValidationOutputHeader = ""
+ this.specValidationOutputMessage = ""
+ this.specValidationOutputSummary = ""
+
+ this.spinnerService.show()
+ this.validateJsonStructure()
+ this.specValidator.sendSpecFile(this.compSpecContent, this.type, this.release).subscribe(
+ res => {}, err => {
+ this.setSpecValidationMessage(err)
+ }
+ )
+ }
+
+ setSpecValidationMessage(res){
+ if(res.status === 200){
+ this.specValidationOutputHeader = "Success: Valid Component Spec"
+ this.specValidationOutputMessage = ""
+ this.validCompSpec = true
+ } else {
+ this.specValidationOutputHeader = `${res.status} Error: Invalid Component Spec`
+ this.specValidationOutputSummary = res.error.summary
+
+ for(let item of res.error.errors){
+ this.specValidationOutputMessage += `- ${item}\n\n`
+ }
+
+ this.validCompSpec = false
+ }
+
+ this.specValidated = true;
+ this.spinnerService.hide()
+ }
+
+ validateJsonStructure() {
+ try {
+ JSON.parse(this.compSpecContent);
+ } catch (error) {
+ this.specValidationOutputHeader = "Error: Invalid Component Spec"
+ this.specValidationOutputSummary = "JSON Structure Error"
+ this.specValidationOutputMessage = error
+ this.validCompSpec = false
+ this.specValidated = true
+ this.spinnerService.hide()
+ throw new Error('JSON Structure error, quit!');
+ }
+ }
+
+ downloadSchema(){
+ this.spinnerService.show()
+ this.specValidator.getSchema(this.type).subscribe(
+ res => {
+ this.downloadService.downloadJSON(res, `${this.release}+_${this.type}_Schema`)
+ this.spinnerService.hide()
+ }, err => {
+ console.log(err)
+ this.spinnerService.hide()
+ }
+ )
+ }
+}
diff --git a/mod2/ui/src/app/comp-specs/comp-specs.component.css b/mod2/ui/src/app/comp-specs/comp-specs.component.css
new file mode 100644
index 0000000..5f86e73
--- /dev/null
+++ b/mod2/ui/src/app/comp-specs/comp-specs.component.css
@@ -0,0 +1,121 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+td{
+ word-break:break-all
+}
+
+textarea
+{
+ font-size: 12px;
+}
+
+.table_actions_button{
+ background-color: transparent;
+ border: none;
+ width: 20px;
+ height: 20px;
+ vertical-align: middle;
+}
+
+.row-expand-layout{
+ display: grid;
+ grid-template-columns: 30% 40% auto;
+ grid-gap: 10px;
+ grid-auto-rows: minmax(100px, auto);
+}
+
+.row-expand-card{
+ font-size: 12px;
+ grid-row: 1;
+ border-radius: 5px;
+ border: 1px solid slategray;
+ padding: 10px;
+ /* This height prevents vertical scroll bar in Notes */
+ height: 92px;
+ overflow: hidden;
+}
+
+label {
+ cursor: pointer;
+}
+
+.fa-refresh{
+ cursor: pointer;
+}
+
+.input{
+ padding-top: 10px;
+}
+
+.inputLabel {
+ font-weight: 600;
+ margin-left: 20px;
+ width: 140px;
+}
+
+.inputFieldSm {
+ width: 200px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldMed {
+ width: 300px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldLg {
+ width: 400px;
+ height: 35px;
+ padding-left: 6px;
+}
+
+.table_action_item{
+ outline: none;
+ font-size: 12px;
+}
+
+::ng-deep .mat-menu-content {
+padding-top: 0px !important;
+padding-bottom: 0px !important;
+}
+.mat-menu-item{
+line-height:30px;
+height:30px;
+}
+
+.greenStatus{
+ background-color: rgba(80, 233, 105, 0.87)
+}
+
+.redStatus{
+ background-color: rgba(255, 29, 29, 0.733)
+}
+
+.blueStatus{
+ background-color: rgba(0, 183, 255, 0.432)
+}
+
+.greyStatus{
+ background-color: rgba(150, 150, 150, 0.432)
+}
+
+.ui-state-highlight {
+ background-color: #878C94 !important;
+ color: black !important;
+}
diff --git a/mod2/ui/src/app/comp-specs/comp-specs.component.html b/mod2/ui/src/app/comp-specs/comp-specs.component.html
new file mode 100644
index 0000000..3061cdf
--- /dev/null
+++ b/mod2/ui/src/app/comp-specs/comp-specs.component.html
@@ -0,0 +1,189 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<div style="margin: 0px 50px 10px 20px; border: 1px solid darkslategray; min-width: 980px">
+ <p-table #dt *ngIf="loadTable" [columns]="cols" [value]="csElements" sortMode="multiple" [paginator]="true"
+ [rows]="18" [rowsPerPageOptions]="[10,12,14,16,18,20,25,50]" (onFilter)="onTableFiltered(dt.filteredValue)" dataKey="id">
+ <ng-template pTemplate="caption">
+
+ <div style="margin-left: -18%; width: 82%; max-height: 25px; display: inline-flex;">
+ <!--CS Table Header-->
+ <div style="float: left;">
+ <!--Refresh-->
+ <i class="fa fa-refresh" (click)="getAllCs()"></i>
+ <!--Global Filter-->
+ <input type="text" pInputText size="50" placeholder="Global Filter"
+ (input)="dt.filterGlobal($event.target.value, 'contains')"
+ style="width: 250px; height:25px; font-size: 12px; margin-left: 15px">
+ <i class="fa fa-search" style="margin:4px 0px 0 8px"></i>
+ </div>
+
+ <h4 style="margin-left: 15%"><b>Component Specs</b></h4>
+
+ </div>
+ </ng-template>
+
+ <ng-template pTemplate="header" let-columns>
+ <tr>
+ <th style="width: 3em"></th>
+ <th class="ui-state-highlight" *ngFor="let col of columns" [pSortableColumn]="col.field"
+ style="font-size: 12px; outline: none; vertical-align: bottom; text-align: center;" [ngStyle]="{'width': col.width}">
+ {{col.header}}<br>
+ <p-sortIcon [field]="col.field"></p-sortIcon>
+ </th>
+ <th style="font-size: 13px; width: 8%; vertical-align: top; text-align: center;">
+ Actions
+ </th>
+ </tr>
+
+ <!--Second header row for individual column filters-->
+ <tr style="text-align: center;">
+ <th style="width: 3em"></th>
+ <th *ngFor="let col of columns" [ngSwitch]="col.field">
+ <input pInputText type="text" (input)="dt.filter($event.target.value, col.field, 'contains')"
+ style="width: 100%; height: 20px; font-size: 10px;" placeholder="Filter">
+ </th>
+ <th>
+
+ </th>
+ </tr>
+ </ng-template>
+
+ <ng-template pTemplate="body" let-rowData let-csElem>
+ <tr style="font-size: 12px;">
+ <!--Column for row expand buttons-->
+ <td>
+ <a href="#" [pRowToggler]="rowData">
+ <i [ngClass]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'"></i>
+ </a>
+ </td>
+
+ <td *ngFor="let col of cols">
+ <div *ngIf="col.field==='status'"
+ style="width: fit-content; width: -moz-max-content; padding: 0px 5px 0px 5px; border-radius: 3px; font-weight: 600;"
+ [ngClass]="{'greenStatus' : csElem[col.field] === 'ACTIVE', 'greyStatus' : csElem[col.field] === 'INACTIVE'}">
+ {{csElem[col.field]}}
+ </div>
+ <div *ngIf="col.field!=='status'">{{csElem[col.field]}}</div>
+ </td>
+
+ <!--Actions Column-->
+ <td>
+ <div style="text-align: center;">
+ <button pButton type="button"
+ style="background-color: transparent; border: none; width: 20px; height: 20px; vertical-align: middle;"
+ class="ui-button-secondary" [matMenuTriggerFor]="menu">
+ <i class="pi pi-ellipsis-h" style="color: grey;"></i>
+ </button>
+ <mat-menu #menu="matMenu" xPosition="before">
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-search" style="font-size: 10px;"></i> View</span>
+ </div>
+
+ <button mat-menu-item class="table_action_item" (click)="showViewCsDialog(rowData)">Component Spec</button>
+ <div matTooltip="Policy not included" [matTooltipDisabled]="rowData.policyJson" matTooltipPosition="left">
+ <button mat-menu-item [disabled]="!rowData.policyJson" class="table_action_item" (click)="showViewPolicyDialog(rowData)">Policy</button>
+ </div>
+ <!--
+ <div *ngIf="rowData.status !== 'ACTIVE'">
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-pencil"
+ style="font-size: 10px;"></i> Update</span>
+ </div>
+
+ <button mat-menu-item class="table_action_item" (click)="toActive(rowData)">To Active</button>
+ </div>-->
+ </mat-menu>
+ </div>
+ </td>
+ </tr>
+ </ng-template>
+
+ <!--Row expand content-->
+ <ng-template pTemplate="rowexpansion" let-rowData let-columns="columns">
+ <tr>
+ <td [attr.colspan]="columns.length + 2">
+ <div class="row-expand-layout" [@rowExpansionTrigger]="'active'">
+ <!-- Audit Fields -->
+ <div class="row-expand-card" style="background-color: rgba(95, 158, 160, 0.295)">
+ <b>Created By:</b> {{rowData.metadata.createdBy}}<br>
+ <b>Created On:</b> {{rowData.metadata.createdOn}}<br>
+ <b>Updated By:</b> {{rowData.metadata.updatedBy}}<br>
+ <b>Updated On:</b> {{rowData.metadata.updatedOn}}
+ </div>
+ <!-- Notes -->
+ <div class="row-expand-card" style="background-color: rgba(100, 148, 237, 0.219)">
+ <b>Notes:</b><br>
+ <p-scrollPanel [style]="{width: '100%', height: '62px'}">
+ <div style="font-size: 12px; word-break: normal;">{{rowData.metadata.notes}}</div>
+ </p-scrollPanel>
+ </div>
+ <!-- Labels -->
+ <div class="row-expand-card" style="background-color: rgba(76, 65, 225, 0.199)">
+ <b style="padding-bottom: 5px;">Labels:</b><br>
+ <div *ngFor="let label of rowData['metadata']['labels']"
+ style="display: inline-flex; margin-top: 5px;">
+ <div style="padding: 2px 7px 3px 0px;">
+ <span
+ style="background-color: rgba(80, 80, 80, 0.185); padding: 3px; border-radius: 3px;">{{label}}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </td>
+ </tr>
+ </ng-template>
+ </p-table>
+
+ <!--download buttons for exporting table to either csv or excel file-->
+ <div *ngIf="loadTable" style="margin-left: 10px; margin-top: -32px; float: left;">
+ <button pButton type="button" (click)="exportTable('csv')" matTooltip="Export Table to CSV"
+ matTooltipPosition="above"
+ style="border-radius: 5px; width: 65px; height: 22px; font-size: 14px; border: none; margin-top: 4px; display: inline-flex;">
+ <i class="pi pi-file" style="margin-top: 2px; margin-left: 8px;"></i>
+ <label style="font-weight: 800; vertical-align: middle;">CSV</label>
+ </button>
+ <button pButton type="button" (click)="exportTable('excel')" matTooltip="Export Table to XLSX"
+ matTooltipPosition="above"
+ style="border-radius: 5px; width: 65px; height: 22px; margin-left: 7px; font-size: 14px; background-color: green; border: none; display: inline-flex;">
+ <i class="pi pi-file-excel" style="margin-top: 2px; margin-left: 4px;"></i>
+ <label style="font-weight: 800; vertical-align: middle;">Excel</label>
+ </button>
+ </div>
+</div>
+
+<!-- * * * * View Spec Content Pop Up * * * * -->
+<p-dialog [(visible)]="showViewCs" header="Spec Content" appendTo="body" [maximizable]="true"
+ [modal]="true" [style]="{width: '80vw'}" [baseZIndex]="10000" [closable]="false">
+ <pre>{{specContentToView | json}}</pre>
+ <p-footer>
+ <button pButton label="Close" (click)="showViewCs=false" type="button"></button>
+ <button pButton label="Download" (click)="download(specContentToView, 'Component_Spec')" type="button"></button>
+ </p-footer>
+</p-dialog>
+
+<!-- * * * * View Policy JSON Pop Up * * * * -->
+<p-dialog [(visible)]="showViewPolicy" header="Policy Json" appendTo="body" [maximizable]="true" [modal]="true"
+ [style]="{width: '80vw'}" [baseZIndex]="10000" [closable]="false">
+ <pre>{{policyJsonToView | json}}</pre>
+ <p-footer>
+ <button pButton label="Close" (click)="showViewPolicy=false" type="button"></button>
+ <button pButton label="Download" (click)="download(policyJsonToView, 'Policy_Json')" type="button"></button>
+ </p-footer>
+</p-dialog>
diff --git a/mod2/ui/src/app/comp-specs/comp-specs.component.spec.ts b/mod2/ui/src/app/comp-specs/comp-specs.component.spec.ts
new file mode 100644
index 0000000..64405e3
--- /dev/null
+++ b/mod2/ui/src/app/comp-specs/comp-specs.component.spec.ts
@@ -0,0 +1,133 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientModule } from '@angular/common/http';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatMenuModule, MatTooltipModule } from '@angular/material';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
+import { MessageService } from 'primeng/api';
+import { ButtonModule } from 'primeng/button';
+import { DialogModule } from 'primeng/dialog';
+import { DropdownModule } from 'primeng/dropdown';
+import { ScrollPanelModule } from 'primeng/scrollpanel';
+import { TableModule } from 'primeng/table';
+import { ToastModule } from 'primeng/toast';
+
+import { CompSpecsComponent } from './comp-specs.component';
+
+describe('CompSpecsComponent', () => {
+ let component: CompSpecsComponent;
+ let fixture: ComponentFixture<CompSpecsComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ CompSpecsComponent
+ ],
+ imports: [
+ Ng4LoadingSpinnerModule,
+ TableModule,
+ MatMenuModule,
+ ScrollPanelModule,
+ ToastModule,
+ DialogModule,
+ DropdownModule,
+ FormsModule,
+ ReactiveFormsModule,
+ ButtonModule,
+ HttpClientModule,
+ ToastModule,
+ RouterTestingModule,
+ MatTooltipModule
+ ],
+ providers: [
+ MessageService,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CompSpecsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it(`should fill csElements Object`, () => {
+ const fixture = TestBed.createComponent(CompSpecsComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ let mockCsElement = [{
+ id: 'testId1234',
+ name: 'test-MS',
+ type: 'k8s',
+ specContent: '',
+ policyJson: 'test',
+ status: 'New',
+ msInstanceInfo: {
+ release: '2008',
+ name: 'test Ms',
+ },
+ metadata: {
+ createdBy: 'test',
+ createdOn: '01-01-2020 12:00',
+ updatedBy: 'test',
+ updatedOn: '01-01-2020 12:00',
+ notes: 'test',
+ labels: ['test'],
+ }
+ }]
+
+ app.fillTable(mockCsElement)
+
+ expect(app.loadTable).toEqual(true);
+ expect(app.csElements.length).toEqual(1);
+ });
+
+ it(`should set spec content to view`, () => {
+ const fixture = TestBed.createComponent(CompSpecsComponent);
+ const app = fixture.debugElement.componentInstance;
+ let mockData = {
+ specContent: 'test'
+ }
+ app.showViewCsDialog(mockData)
+ expect(app.showViewCs).toEqual(true);
+ expect(app.specContentToView).toEqual('test');
+ });
+
+ it(`should set policy json content to view`, () => {
+ const fixture = TestBed.createComponent(CompSpecsComponent);
+ const app = fixture.debugElement.componentInstance;
+ let mockData = {
+ policyJson: 'test'
+ }
+ app.showViewPolicyDialog(mockData)
+ expect(app.showViewPolicy).toEqual(true);
+ expect(app.policyJsonToView).toEqual('test');
+ });
+});
+
diff --git a/mod2/ui/src/app/comp-specs/comp-specs.component.ts b/mod2/ui/src/app/comp-specs/comp-specs.component.ts
new file mode 100644
index 0000000..4327c0b
--- /dev/null
+++ b/mod2/ui/src/app/comp-specs/comp-specs.component.ts
@@ -0,0 +1,211 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
+import { compSpecsService } from '../services/comp-specs-service.service';
+import { Table } from 'primeng/table';
+import { MessageService } from 'primeng/api';
+import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner';
+import { DatePipe } from '@angular/common';
+import { trigger, state, transition, style, animate } from '@angular/animations';
+import { ActivatedRoute } from '@angular/router';
+import { DownloadService } from '../services/download.service';
+
+@Component({
+ selector: 'app-comp-specs',
+ templateUrl: './comp-specs.component.html',
+ styleUrls: ['./comp-specs.component.css'],
+ animations: [
+ trigger('rowExpansionTrigger', [
+ state('void', style({
+ transform: 'translateX(-10%)',
+ opacity: 0
+ })),
+ state('active', style({
+ transform: 'translateX(0)',
+ opacity: 1
+ })),
+ transition('* <=> *', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)'))
+ ])
+ ],
+ providers: [DatePipe]
+})
+export class CompSpecsComponent implements OnInit {
+ @ViewChild(Table, { static: false }) dt: Table;
+
+ csElements: any[] = [];
+
+ cols: any[] = [
+ { field: 'instanceName', header: 'Instance Name' },
+ { field: 'release', header: 'Release', width: '15%' },
+ { field: 'type', header: 'Type', width: '15%' },
+ { field: 'policy', header: 'Policy', width: '15%' },
+ { field: 'status', header: 'Status', width: '15%' }
+ ];
+
+ columns: any[];
+ loadTable: boolean;
+ filteredRows: any;
+ summaryRows: any;
+ downloadItems: { label: string; command: () => void; }[];
+
+ msInstanceId: string;
+ msInstanceName: any;
+ msInstanceRelease: any;
+
+ constructor(private csApis: compSpecsService, private messageService: MessageService,
+ private spinnerService: Ng4LoadingSpinnerService, private datePipe: DatePipe,
+ private route: ActivatedRoute, private downloadService: DownloadService) { }
+
+ //create table of comp specs
+ ngOnInit() {
+ this.loadTable = false;
+
+ this.route.queryParams.subscribe((params) => {
+ this.msInstanceId = params['instanceId'];
+ });
+
+ this.getAllCs()
+ }
+
+ getAllCs() {
+
+ this.csElements = [];
+
+ this.csApis.getAllCompSpecs(this.msInstanceId)
+ .subscribe((data: any[]) => {
+ this.fillTable(data)
+ })
+
+ this.columns = this.cols.map(col => ({ title: col.header, dataKey: col.field }));
+ }
+
+ //filter table
+ onTableFiltered(values) {
+ if (values) { this.filteredRows = values; }
+ else { this.filteredRows = this.summaryRows; }
+ }
+
+ /* * * * Export ms instance table to excel or csv * * * */
+ exportTable(exportTo) {
+ let downloadElements: any[] = []
+
+ //labels array not handled well by excel download so converted them to a single string
+ for (let row of this.filteredRows) {
+ let labels;
+ let notes;
+ if (exportTo === "excel") {
+ if (row.metadata.labels !== undefined) {
+ labels = row.metadata.labels.join(",")
+ }
+ } else {
+ labels = row.metadata.labels
+ }
+
+ if (row.metadata.notes !== null && row.metadata.notes !== undefined && row.metadata.notes !== '') {
+ notes = encodeURI(row.metadata.notes).replace(/%20/g, " ").replace(/%0A/g, "\\n")
+ }
+
+ downloadElements.push({
+ Instance_Name: row.instanceName,
+ Release: row.release,
+ Type: row.type,
+ Status: row.status,
+ Created_By: row.metadata.createdBy,
+ Created_On: row.metadata.createdOn,
+ Updated_By: row.metadata.updatedBy,
+ Updated_On: row.metadata.updatedOn,
+ Notes: notes,
+ Labels: labels
+ })
+ }
+
+ let arrHeader = []
+
+ if (exportTo === "csv") {
+ arrHeader = [
+ "Instance_Name",
+ "Release",
+ "Type",
+ "Status",
+ "Created_By",
+ "Created_On",
+ "Updated_By",
+ "Updated_On",
+ "Notes",
+ "Labels"
+ ];
+ }
+
+ this.downloadService.exportTableData(exportTo, downloadElements, arrHeader)
+ }
+
+ //fill object with microservice data, to be used to fill table.
+ //checks if fields are empty and if they are, store 'N/A' as the values
+ fillTable(data) {
+ for (let elem of data) {
+ let policy = '';
+ if(elem.policyJson){policy = "Included"}
+
+ let tempCsElement: any = {
+ id: elem.id,
+ instanceName: elem.msInstanceInfo.name,
+ release: elem.msInstanceInfo.release,
+ type: elem.type,
+ policy: policy,
+ status: elem.status,
+ specContent: elem.specContent,
+ policyJson: elem.policyJson,
+ metadata: {
+ createdBy: elem.metadata.createdBy,
+ createdOn: this.datePipe.transform(elem.metadata.createdOn, 'MM-dd-yyyy HH:mm'),
+ updatedBy: elem.metadata.updatedBy,
+ updatedOn: this.datePipe.transform(elem.metadata.updatedOn, 'MM-dd-yyyy HH:mm'),
+ notes: elem.metadata.notes,
+ labels: elem.metadata.labels
+ }
+ }
+ this.csElements.unshift(tempCsElement)
+ }
+ this.msInstanceName = this.csElements[0]['instanceName']
+ this.msInstanceRelease = this.csElements[0]['release']
+ this.filteredRows = this.csElements
+ this.loadTable = true;
+ this.spinnerService.hide();
+ }
+
+ showViewCs: boolean = false;
+ specContentToView: string;
+ showViewCsDialog(data) {
+ this.showViewCs = true;
+ this.specContentToView = data.specContent;
+ }
+
+ showViewPolicy: boolean = false;
+ policyJsonToView: string;
+ showViewPolicyDialog(data) {
+ this.showViewPolicy = true;
+ this.policyJsonToView = data.policyJson;
+ }
+
+ /* * * * Download single spec file or policy * * * */
+ download(content, contentType) {
+ let fileName = `${this.msInstanceName}_${this.msInstanceRelease}_${contentType}`
+ this.downloadService.downloadJSON(content, fileName)
+ }
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/guards/auth.guard.spec.ts b/mod2/ui/src/app/guards/auth.guard.spec.ts
new file mode 100644
index 0000000..c82f8d6
--- /dev/null
+++ b/mod2/ui/src/app/guards/auth.guard.spec.ts
@@ -0,0 +1,44 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { TestBed, async, inject } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { AuthGuard } from './auth.guard';
+
+describe('AuthGuard', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [
+ AuthGuard,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ],
+ imports: [
+ HttpClientTestingModule,
+ RouterTestingModule
+ ]
+ });
+ });
+
+ it('should ...', inject([AuthGuard], (guard: AuthGuard) => {
+ expect(guard).toBeTruthy();
+ }));
+});
diff --git a/mod2/ui/src/app/guards/auth.guard.ts b/mod2/ui/src/app/guards/auth.guard.ts
new file mode 100644
index 0000000..cce544b
--- /dev/null
+++ b/mod2/ui/src/app/guards/auth.guard.ts
@@ -0,0 +1,62 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
+import { Observable, of } from 'rxjs';
+import { AuthService } from '../services/auth.service';
+import { catchError, map } from 'rxjs/operators';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthGuard implements CanActivate {
+
+ constructor(
+ private authService: AuthService,
+ private router: Router
+ ) {}
+
+ canActivate(
+ next: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
+
+ return this.authService.checkLogin().pipe(map((e:boolean)=>{
+ if(e){
+ this.authService.setUser();
+ if(this.authService.getUser().roles.includes("ROLE_ADMIN")){
+ this.authService.isAdmin = true;
+ }else{
+ this.authService.isAdmin = false;
+ }
+ this.authService.authPass=true;
+ return true;
+ }
+ }), catchError(err=>{
+ this.authService.reLoginMsg = true;
+ // window.alert("Your login has expired. Please log in again.");
+ this.authService.authPass=false;
+ this.router.navigate(['/login']);
+ return of(false);
+ }))
+ }
+
+
+
+
+}
diff --git a/mod2/ui/src/app/guards/login.guard.spec.ts b/mod2/ui/src/app/guards/login.guard.spec.ts
new file mode 100644
index 0000000..d58450c
--- /dev/null
+++ b/mod2/ui/src/app/guards/login.guard.spec.ts
@@ -0,0 +1,41 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { TestBed, async, inject } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { LoginGuard } from './login.guard';
+
+describe('LoginGuard', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [
+ LoginGuard,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ],
+ imports: [HttpClientTestingModule, RouterTestingModule]
+ });
+ });
+
+ it('should ...', inject([LoginGuard], (guard: LoginGuard) => {
+ expect(guard).toBeTruthy();
+ }));
+});
diff --git a/mod2/ui/src/app/guards/login.guard.ts b/mod2/ui/src/app/guards/login.guard.ts
new file mode 100644
index 0000000..851ef61
--- /dev/null
+++ b/mod2/ui/src/app/guards/login.guard.ts
@@ -0,0 +1,52 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
+import { Observable, of } from 'rxjs';
+import { AuthService } from '../services/auth.service';
+import { catchError, map } from 'rxjs/operators';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class LoginGuard implements CanActivate {
+ constructor(
+ private authService: AuthService,
+ private router: Router
+ ) {}
+
+ canActivate(
+ next: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
+
+ return this.authService.checkLogin().pipe(map((e:boolean)=>{
+ if(e){
+ console.log("Hi this is loginguard");
+ this.authService.authPass=true;
+ this.router.navigate(['/home']);
+ return true;
+ }
+ }), catchError(err=>{
+ console.log("Login guard out");
+ this.authService.authPass=false;
+ this.router.navigate(['/login']);
+ return of(false);
+ }))
+}
+}
diff --git a/mod2/ui/src/app/guards/role.guard.spec.ts b/mod2/ui/src/app/guards/role.guard.spec.ts
new file mode 100644
index 0000000..c57dfe6
--- /dev/null
+++ b/mod2/ui/src/app/guards/role.guard.spec.ts
@@ -0,0 +1,44 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { TestBed, async, inject } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { RoleGuard } from './role.guard';
+
+describe('RoleGuard', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [
+ RoleGuard,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ],
+ imports: [
+ HttpClientTestingModule,
+ RouterTestingModule
+ ]
+ });
+ });
+
+ it('should ...', inject([RoleGuard], (guard: RoleGuard) => {
+ expect(guard).toBeTruthy();
+ }));
+});
diff --git a/mod2/ui/src/app/guards/role.guard.ts b/mod2/ui/src/app/guards/role.guard.ts
new file mode 100644
index 0000000..7e5b7ae
--- /dev/null
+++ b/mod2/ui/src/app/guards/role.guard.ts
@@ -0,0 +1,61 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
+import { Observable, of } from 'rxjs';
+import { AuthService } from '../services/auth.service';
+import { catchError, map } from 'rxjs/operators';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class RoleGuard implements CanActivate {
+
+
+ constructor(
+ private authService: AuthService,
+ private router: Router
+ ) {}
+
+ canActivate(
+ next: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
+
+ return this.authService.checkLogin().pipe(map((e:boolean)=>{
+ if(e){
+ console.log("role guard in");
+ this.authService.setUser();
+ if(this.authService.getUser().roles.includes("ROLE_ADMIN")){
+ this.authService.isAdmin = true;
+ }else{
+ this.authService.isAdmin = false;
+ this.router.navigate(['/home']);
+ }
+ return this.authService.getUser().roles.includes("ROLE_ADMIN");
+ }
+ }), catchError(err=>{
+ this.authService.reLoginMsg = true;
+ // window.alert("Your login has expired. Please log in again.");
+ this.authService.authPass=false;
+ this.router.navigate(['/login']);
+ return of(false);
+ }))
+
+}
+}
diff --git a/mod2/ui/src/app/home/home.component.css b/mod2/ui/src/app/home/home.component.css
new file mode 100644
index 0000000..f345db2
--- /dev/null
+++ b/mod2/ui/src/app/home/home.component.css
@@ -0,0 +1,50 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+
+.card{
+ display: inline-block;
+ margin-top: 56px;
+ margin-left: 75px;
+ color: rgb(34, 32, 32);
+ font-family: Arial, Helvetica, sans-serif;
+ font-weight: 800;
+ text-align: center;
+ padding-top: 42px;
+ font-size: 20px;
+ border-width: 2px;
+ border-color: gray;
+ border-radius: 8px;
+ height: 112px;
+ width: 261px;
+ cursor: pointer
+}
+
+#subMenu{
+ height: 75px;
+ width: 229px;
+ padding-top: 24px;
+ margin-left: 61px;
+ font-size: 18px;
+ border-radius: 5px
+}
+
+
+.mat-form-field + .mat-form-field {
+ margin-left: 8px;
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/home/home.component.html b/mod2/ui/src/app/home/home.component.html
new file mode 100644
index 0000000..31fe720
--- /dev/null
+++ b/mod2/ui/src/app/home/home.component.html
@@ -0,0 +1,93 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<div style="margin: -50px 0px 0px -30px">
+ <mat-card
+ (click)="toggleMsMenu()"
+ appMaterialElevation
+ [defaultElevation]="defaultElevation"
+ raisedElevation="16"
+ class="card"
+ style="background-color: #60a4a5">
+ Microservices...
+ </mat-card>
+ <mat-card
+ (click)="navSelect('Onboarding Tools')"
+ appMaterialElevation
+ [defaultElevation]="defaultElevation"
+ raisedElevation="16"
+ class="card"
+ style="background-color: rgba(154, 135, 167, 0.904);"
+ [routerLink]="'/OnboardingTools'">
+ Onboarding Tools
+ </mat-card>
+ <mat-card *ngIf="authService.isAdmin"
+ (click)="navSelect('User Management')"
+ appMaterialElevation
+ [defaultElevation]="defaultElevation"
+ raisedElevation="16"
+ class="card"
+ style="background-color: rgba(160, 120, 83, 0.904);"
+ [routerLink]="'/users'">
+ User Management
+ </mat-card>
+</div>
+<br>
+<div *ngIf="displayMsMenu" style="margin-top: -60px">
+ <mat-card id="subMenu" (click)="navSelect('Microservices')"
+ appMaterialElevation
+ [defaultElevation]="defaultElevation"
+ raisedElevation="16"
+ class="card"
+ style="background-color: #70a7a9; position: absolute;">
+ Microservices
+ </mat-card>
+</div>
+<br>
+<div *ngIf="displayMsMenu" style="margin-top: 70px">
+ <mat-card id="subMenu" (click)="navSelect('MS Instances')"
+ appMaterialElevation
+ [defaultElevation]="defaultElevation"
+ raisedElevation="16"
+ class="card"
+ style="background-color: #8fbbbc; position: absolute;">
+ MS Instances
+ </mat-card>
+</div>
+<br>
+<div *ngIf="displayMsMenu" style="margin-top: 70px">
+ <mat-card id="subMenu" (click)="navSelect('Blueprints')"
+ appMaterialElevation
+ [defaultElevation]="defaultElevation"
+ raisedElevation="16"
+ class="card"
+ style="background-color: #afcecf; position: absolute;">
+ Blueprints
+ </mat-card>
+</div>
+<br>
+<div *ngIf="displayMsMenu" style="margin-top: 70px">
+ <mat-card id="subMenu" (click)="navSelect('MOD APIs')"
+ appMaterialElevation
+ [defaultElevation]="defaultElevation"
+ raisedElevation="16"
+ class="card"
+ style="background-color: #cfe2e2; position: absolute;">
+ MOD APIs
+ </mat-card>
+</div> \ No newline at end of file
diff --git a/mod2/ui/src/app/home/home.component.ts b/mod2/ui/src/app/home/home.component.ts
new file mode 100644
index 0000000..36f9ee1
--- /dev/null
+++ b/mod2/ui/src/app/home/home.component.ts
@@ -0,0 +1,64 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, HostBinding } from '@angular/core';
+import { AppComponent } from '../app.component';
+import { AuthService } from '../services/auth.service';
+import { BreadcrumbService } from '../services/breadcrumb.service';
+
+@Component({
+ selector: 'app-home',
+ templateUrl: './home.component.html',
+ styleUrls: ['./home.component.css']
+})
+export class HomeComponent implements OnInit {
+
+ defaultElevation = 2;
+ raisedElevation = 8;
+ panelOpenState = false;
+
+ name = 'Angular';
+
+ displayMsMenu = false;
+
+ constructor(private appComp: AppComponent, public authService: AuthService, private bread: BreadcrumbService) { }
+
+ ngOnInit() {
+ }
+
+ disableAnimation = true;
+ ngAfterViewInit(): void {
+ // timeout required to avoid the dreaded 'ExpressionChangedAfterItHasBeenCheckedError'
+ setTimeout(() => this.disableAnimation = false);
+ }
+
+ toggleMsMenu() {
+ if (this.displayMsMenu == false) {
+ this.displayMsMenu = true
+ } else {
+ this.displayMsMenu = false
+ }
+ }
+
+ navSelect(menuItem: any) {
+ this.appComp.tree_handler(menuItem, null);
+ // Set the breadcrumbs for the selected menu item (card)
+ this.bread.setBreadcrumbs(menuItem, "reset");
+ }
+
+}
diff --git a/mod2/ui/src/app/login/login.component.css b/mod2/ui/src/app/login/login.component.css
new file mode 100644
index 0000000..55e48a1
--- /dev/null
+++ b/mod2/ui/src/app/login/login.component.css
@@ -0,0 +1,25 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+.field-icon {
+ float:right;
+ left: -15px;
+ margin-top: 1px;
+ position: relative;
+ z-index: 2;
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/login/login.component.html b/mod2/ui/src/app/login/login.component.html
new file mode 100644
index 0000000..b98baff
--- /dev/null
+++ b/mod2/ui/src/app/login/login.component.html
@@ -0,0 +1,58 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<p-card header="Log in to MOD" [style]="{margin:'100px 300px 300px 300px'}">
+<hr class="line-break">
+<form [formGroup]="form" (ngSubmit)="submit()" class="p-5 bg-faded" style="margin-left: 220px;margin-bottom: 100px;">
+ <div class="ui-g ui-fluid" >
+ <div class="ui-g-12 ui-md-4">
+ <div class="ui-inputgroup" >
+ <span class="ui-inputgroup-addon"><i class="pi pi-user" style="line-height: 1.25;"></i></span>
+ <input type="text" placeholder="ATT UID" formControlName="username">
+ </div>
+ </div>
+ </div>
+ <!-- <div class="ui-g ui-fluid" >
+ <div class="ui-g-12 ui-md-4">
+ <div class="ui-inputgroup" >
+ <span class="ui-inputgroup-addon"><i class="pi pi-user" style="line-height: 1.25;"></i></span>
+ <input type="text" placeholder="ATT UID" formControlName="uid">
+ </div>
+ </div>
+ </div> -->
+ <div class="ui-g ui-fluid">
+ <div class="ui-g-12 ui-md-4">
+ <div class="ui-inputgroup" >
+ <span class="ui-inputgroup-addon" (click)="hide=!hide">
+ <i [ngClass]="hide? 'pi pi-eye-slash':'pi pi-eye'"></i></span>
+ <input [type]="hide? 'password':'text'" placeholder="password" formControlName="password" >
+ <!-- <a routerLink="/reset-password">Forget password?</a> -->
+ </div>
+ </div>
+ </div>
+
+ <p-footer class="text-left ui-g-12">
+ <!-- <button pButton type="button" class="ui-button-info" label="Cancel" (click)="cancel()" style="margin-right: .25em"></button> -->
+ <button pButton type="submit" class="ui-button-success" label="Login" [disabled]="!form.valid"></button>
+ </p-footer>
+ <div class="text-left ui-g-12">
+ <p>Not a registered user? Contact the DCAE-MOD team at <i>dcae-mod-team@att.com</i></p>
+ <a href="mailto:dcae-mod-team@att.com?subject=account application&body=Please help open a dcae account with username:">Cick here to contact now</a>
+ </div>
+ </form>
+</p-card>
diff --git a/mod2/ui/src/app/login/login.component.spec.ts b/mod2/ui/src/app/login/login.component.spec.ts
new file mode 100644
index 0000000..5656be4
--- /dev/null
+++ b/mod2/ui/src/app/login/login.component.spec.ts
@@ -0,0 +1,59 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { CardModule } from 'primeng/card';
+
+import { LoginComponent } from './login.component';
+
+describe('LoginComponent', () => {
+ let component: LoginComponent;
+ let fixture: ComponentFixture<LoginComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [LoginComponent],
+ imports: [
+ FormsModule,
+ ReactiveFormsModule,
+ CardModule,
+ HttpClientTestingModule,
+ RouterTestingModule
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LoginComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/login/login.component.ts b/mod2/ui/src/app/login/login.component.ts
new file mode 100644
index 0000000..16cafee
--- /dev/null
+++ b/mod2/ui/src/app/login/login.component.ts
@@ -0,0 +1,65 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { AuthService } from '../services/auth.service';
+import { User } from '../models/User';
+import { Router } from '@angular/router';
+
+@Component({
+ selector: 'app-login',
+ templateUrl: './login.component.html',
+ styleUrls: ['./login.component.css']
+})
+
+export class LoginComponent implements OnInit {
+
+ form: FormGroup;
+ hide: boolean=true;
+
+ constructor(private fb: FormBuilder, private authService: AuthService, private router: Router) { }
+
+ ngOnInit() {
+ this.form = this.fb.group({
+ username: ['', [Validators.required]],
+ // uid: ['', [Validators.required]],
+ password: ['', [Validators.required]]
+ });
+ }
+
+ submit() {
+ this.authService.login(this.form.value as User).subscribe(
+ res => {
+ // if (this.authService.getUser().roles && this.authService.getUser().roles.includes("ROLE_USER")) {
+ // this.authService.isAdmin = false;
+ // }
+ if(this.authService.getUser().roles &&this.authService.getUser().roles.includes("ROLE_ADMIN")) {
+ this.authService.isAdmin = true;
+ } else {
+ this.authService.isAdmin = false;
+ }
+ this.router.navigate(['/home']);
+ },
+ (err) => {
+ alert('User or Password is not correct, please re-enter');
+ this.form.reset();
+ }
+ );
+ }
+}
diff --git a/mod2/ui/src/app/material-elevation.directive.ts b/mod2/ui/src/app/material-elevation.directive.ts
new file mode 100644
index 0000000..8843d1e
--- /dev/null
+++ b/mod2/ui/src/app/material-elevation.directive.ts
@@ -0,0 +1,64 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Directive, ElementRef, HostListener, Input, Renderer2, OnChanges, SimpleChanges } from '@angular/core';
+
+@Directive({
+ selector: '[appMaterialElevation]'
+})
+export class MaterialElevationDirective implements OnChanges {
+
+ @Input()
+ defaultElevation = 2;
+
+ @Input()
+ raisedElevation = 8;
+
+ constructor(
+ private element: ElementRef,
+ private renderer: Renderer2
+ ) {
+ this.setElevation(this.defaultElevation);
+ }
+
+ ngOnChanges(_changes: SimpleChanges) {
+ this.setElevation(this.defaultElevation);
+ }
+
+ @HostListener('mouseenter')
+ onMouseEnter() {
+ this.setElevation(this.raisedElevation);
+ }
+
+ @HostListener('mouseleave')
+ onMouseLeave() {
+ this.setElevation(this.defaultElevation);
+ }
+
+ setElevation(amount: number) {
+ // remove all elevation classes
+ const classesToRemove = Array.from((<HTMLElement>this.element.nativeElement).classList).filter(c => c.startsWith('mat-elevation-z'));
+ classesToRemove.forEach((c) => {
+ this.renderer.removeClass(this.element.nativeElement, c);
+ });
+
+ // add the given elevation class
+ const newClass = `mat-elevation-z${amount}`;
+ this.renderer.addClass(this.element.nativeElement, newClass);
+ }
+}
diff --git a/mod2/ui/src/app/microservices/microservices.component.css b/mod2/ui/src/app/microservices/microservices.component.css
new file mode 100644
index 0000000..5f86e73
--- /dev/null
+++ b/mod2/ui/src/app/microservices/microservices.component.css
@@ -0,0 +1,121 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+td{
+ word-break:break-all
+}
+
+textarea
+{
+ font-size: 12px;
+}
+
+.table_actions_button{
+ background-color: transparent;
+ border: none;
+ width: 20px;
+ height: 20px;
+ vertical-align: middle;
+}
+
+.row-expand-layout{
+ display: grid;
+ grid-template-columns: 30% 40% auto;
+ grid-gap: 10px;
+ grid-auto-rows: minmax(100px, auto);
+}
+
+.row-expand-card{
+ font-size: 12px;
+ grid-row: 1;
+ border-radius: 5px;
+ border: 1px solid slategray;
+ padding: 10px;
+ /* This height prevents vertical scroll bar in Notes */
+ height: 92px;
+ overflow: hidden;
+}
+
+label {
+ cursor: pointer;
+}
+
+.fa-refresh{
+ cursor: pointer;
+}
+
+.input{
+ padding-top: 10px;
+}
+
+.inputLabel {
+ font-weight: 600;
+ margin-left: 20px;
+ width: 140px;
+}
+
+.inputFieldSm {
+ width: 200px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldMed {
+ width: 300px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldLg {
+ width: 400px;
+ height: 35px;
+ padding-left: 6px;
+}
+
+.table_action_item{
+ outline: none;
+ font-size: 12px;
+}
+
+::ng-deep .mat-menu-content {
+padding-top: 0px !important;
+padding-bottom: 0px !important;
+}
+.mat-menu-item{
+line-height:30px;
+height:30px;
+}
+
+.greenStatus{
+ background-color: rgba(80, 233, 105, 0.87)
+}
+
+.redStatus{
+ background-color: rgba(255, 29, 29, 0.733)
+}
+
+.blueStatus{
+ background-color: rgba(0, 183, 255, 0.432)
+}
+
+.greyStatus{
+ background-color: rgba(150, 150, 150, 0.432)
+}
+
+.ui-state-highlight {
+ background-color: #878C94 !important;
+ color: black !important;
+}
diff --git a/mod2/ui/src/app/microservices/microservices.component.html b/mod2/ui/src/app/microservices/microservices.component.html
new file mode 100644
index 0000000..95ec45c
--- /dev/null
+++ b/mod2/ui/src/app/microservices/microservices.component.html
@@ -0,0 +1,185 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<ng4-loading-spinner [timeout]="1000000"></ng4-loading-spinner>
+<div style="margin: 0px 0px 10px 20px; width: 97%; min-width: 900px; border: 1px solid darkslategray">
+ <!--Table of base microservices-->
+ <p-table #dt *ngIf="loadTable" [columns]="cols" [value]="msElements" sortMode="multiple" [paginator]="true"
+ [rows]="18" [rowsPerPageOptions]="[10,12,14,16,18,20,25,50]" (onFilter)="onTableFiltered(dt.filteredValue)" dataKey="id">
+
+ <!--Top caption row-->
+ <ng-template pTemplate="caption">
+
+ <div style="margin-left: -5%; width: 90%; max-height: 25px; display: inline-flex;">
+ <!--Microservices Table Header-->
+ <div style="float: left;">
+ <!--Refresh-->
+ <i class="fa fa-refresh" (click)="getAllMs()"></i>
+ <!--Global Filter-->
+ <input type="text" pInputText size="50" placeholder="Global Filter"
+ (input)="dt.filterGlobal($event.target.value, 'contains')"
+ style="width: 250px; height:25px; font-size: 12px; margin-left: 15px">
+ <i class="fa fa-search" style="margin:4px 0px 0 8px"></i>
+ </div>
+
+ <h4 style="margin-left: 15%"><b>Microservices</b></h4>
+
+ </div>
+
+ <div style="float: right;">
+ <button pButton type="button" (click)="showAddChangeDialog()" matTooltip="Add Microservice" matTooltipPosition="above"
+ style="border-radius: 5px; width: 65px; height: 27px; font-size: 14px; border: none; display: inline-flex;">
+ <i class="pi pi-plus" style="margin-top: 5px; margin-left: 10px;"></i>
+ <label style="font-weight: 800; margin-top: 3px">MS</label>
+ </button>
+ </div>
+
+ </ng-template>
+
+ <!--Header row with dynamic column names. Columns include microservice Name, Type, Location and Namespace-->
+ <ng-template pTemplate="header" let-columns>
+ <tr style="text-align: center">
+ <th style="width: 3em"></th>
+ <th class="ui-state-highlight" *ngFor="let col of columns" [pSortableColumn]="col.field" style="font-size: 12px; outline: none; vertical-align: bottom;" [ngStyle]="{'width': col.width}">
+ {{col.header}}<br>
+ <p-sortIcon [field]="col.field"></p-sortIcon>
+ </th>
+ <th style="font-size: 13px; width: 6.5%; vertical-align: top;">
+ Actions
+ </th>
+ </tr>
+
+ <!--Second header row for individual column filters-->
+ <tr style="text-align: center;">
+ <th style="width: 3em"></th>
+ <th *ngFor="let col of columns" [ngSwitch]="col.field">
+ <input pInputText type="text"
+ (input)="dt.filter($event.target.value, col.field, 'contains')" style="width: 100%; height: 20px; font-size: 10px;"
+ placeholder="Filter">
+ </th>
+ <th></th>
+ </tr>
+ </ng-template>
+
+ <!--dynamic rows generated from columns object and msElems object-->
+ <ng-template pTemplate="body" let-rowData let-expanded="expanded" let-msElem>
+ <tr style="font-size: 12px;">
+ <!--Column for row expand buttons-->
+ <td>
+ <a href="#" [pRowToggler]="rowData">
+ <i [ngClass]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'"></i>
+ </a>
+ </td>
+
+ <td *ngFor="let col of cols">
+ <div *ngIf="col.field==='status'"
+ style="width: fit-content; width: -moz-max-content; padding: 0px 5px 0px 5px; border-radius: 3px; font-weight: 600;"
+ [ngClass]="{'greenStatus' : msElem[col.field] === 'ACTIVE',
+ 'greyStatus' : msElem[col.field] === 'INACTIVE'}">
+ {{msElem[col.field]}}
+ </div>
+ <div *ngIf="col.field!=='status'">{{msElem[col.field]}}</div>
+ </td>
+
+ <!--Actions Column-->
+ <td>
+ <div style="text-align: center;">
+ <button pButton type="button" style="background-color: transparent; border: none; width: 20px; height: 20px; vertical-align: middle;" class="ui-button-secondary" [matMenuTriggerFor]="menu">
+ <i class="pi pi-ellipsis-h" style="color: grey;"></i>
+ </button>
+ <mat-menu #menu="matMenu" xPosition="before">
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-plus"
+ style="font-size: 10px;"></i> Add</span>
+ </div>
+
+ <button mat-menu-item class="table_action_item" (click)="showAddChangeMsInstanceDialog(rowData)">Add MS
+ Instance...</button>
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-pencil"></i> Update</span>
+ </div>
+
+ <button mat-menu-item class="table_action_item" (click)="showAddChangeDialog(rowData)">Update Microservice...</button>
+ </mat-menu>
+ </div>
+ </td>
+ </tr>
+ </ng-template>
+
+ <!--Row expand content-->
+ <ng-template pTemplate="rowexpansion" let-rowData let-columns="columns">
+ <tr>
+ <td [attr.colspan]="columns.length + 2">
+ <div class="row-expand-layout" [@rowExpansionTrigger]="'active'">
+ <!-- Audit Fields -->
+ <div class="row-expand-card" style="background-color: rgba(95, 158, 160, 0.295)">
+ <b>Created By:</b> {{rowData.metadata.createdBy}}<br>
+ <b>Created On:</b> {{rowData.metadata.createdOn}}<br>
+ <b>Updated By:</b> {{rowData.metadata.updatedBy}}<br>
+ <b>Updated On:</b> {{rowData.metadata.updatedOn}}
+ </div>
+ <!-- Notes -->
+ <div class="row-expand-card" style="background-color: rgba(100, 148, 237, 0.219)">
+ <b>Notes:</b><br>
+ <p-scrollPanel [style]="{width: '100%', height: '62px'}">
+ <div style="font-size: 12px; word-break: normal;">{{rowData.metadata.notes}}</div>
+ </p-scrollPanel>
+ </div>
+ <!-- Labels -->
+ <div class="row-expand-card" style="background-color: rgba(76, 65, 225, 0.199)">
+ <b style="padding-bottom: 5px;">Labels:</b><br>
+ <div *ngFor="let label of rowData['metadata']['labels']" style="display: inline-flex; margin-top: 5px;">
+ <div style="padding: 2px 7px 3px 0px;">
+ <span style="background-color: rgba(80, 80, 80, 0.185); padding: 3px; border-radius: 3px;">{{label}}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </td>
+ </tr>
+ </ng-template>
+ </p-table>
+
+ <!--download buttons for exporting table to either csv or excel file-->
+ <div *ngIf="loadTable" style="margin-left: 10px; margin-top: -32px; float: left;">
+ <button pButton type="button" (click)="exportTable('csv')"
+ matTooltip="Export Table to CSV" matTooltipPosition="above"
+ style="border-radius: 5px; width: 65px; height: 22px; font-size: 14px; border: none; margin-top: 4px; display: inline-flex;">
+ <i class="pi pi-file" style="margin-top: 2px; margin-left: 8px;"></i>
+ <label style="font-weight: 800; vertical-align: middle;">CSV</label>
+ </button>
+ <button pButton type="button" (click)="exportTable('excel')"
+ matTooltip="Export Table to XLSX" matTooltipPosition="above"
+ style="border-radius: 5px; width: 65px; height: 22px; margin-left: 7px; font-size: 14px; background-color: green; border: none; display: inline-flex;">
+ <i class="pi pi-file-excel" style="margin-top: 2px; margin-left: 4px;"></i>
+ <label style="font-weight: 800; vertical-align: middle;">Excel</label>
+ </button>
+ </div>
+
+ <!-- Dialog to Add or Change a MS -->
+ <app-ms-add-change *ngIf="showMsAddChangeDialog" [visible]="showMsAddChangeDialog" [currentRow]="currentRow" (handler)="addOrChangeMs($event)"></app-ms-add-change>
+
+ <!-- Dialog to Add (or Change) a MS Instance -->
+ <app-ms-instance-add *ngIf="showAddChangeMsInstance" [visible]="showAddChangeMsInstance" [msName]="addInstanceTo" [currentRow]="currentRow" (handler)="addMsInstance($event)"></app-ms-instance-add>
+
+ <!-- Shared success message -->
+ <p-toast key="addChangeSuccess"></p-toast>
+
+</div> \ No newline at end of file
diff --git a/mod2/ui/src/app/microservices/microservices.component.spec.ts b/mod2/ui/src/app/microservices/microservices.component.spec.ts
new file mode 100644
index 0000000..2d2e5f1
--- /dev/null
+++ b/mod2/ui/src/app/microservices/microservices.component.spec.ts
@@ -0,0 +1,134 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatMenuModule } from '@angular/material';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
+import { MessageService } from 'primeng/api';
+import { ButtonModule } from 'primeng/button';
+import { CalendarModule } from 'primeng/calendar';
+import { DialogModule } from 'primeng/dialog';
+import { DropdownModule } from 'primeng/dropdown';
+import { ScrollPanelModule } from 'primeng/scrollpanel';
+import { TableModule } from 'primeng/table';
+import { ToastModule } from 'primeng/toast';
+import { MsAddChangeComponent } from '../ms-add-change/ms-add-change.component';
+import { MsInstanceAddComponent } from '../ms-instance-add/ms-instance-add.component';
+
+import { MicroservicesComponent } from './microservices.component';
+
+describe('MicroservicesComponent', () => {
+ let component: MicroservicesComponent;
+ let fixture: ComponentFixture<MicroservicesComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ MicroservicesComponent,
+ MsAddChangeComponent,
+ MsInstanceAddComponent,
+ ],
+ imports: [
+ Ng4LoadingSpinnerModule,
+ TableModule,
+ MatMenuModule,
+ ScrollPanelModule,
+ ToastModule,
+ DialogModule,
+ DropdownModule,
+ FormsModule,
+ ReactiveFormsModule,
+ ButtonModule,
+ CalendarModule,
+ HttpClientTestingModule,
+ ToastModule,
+ RouterTestingModule
+ ],
+ providers: [
+ MessageService,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MicroservicesComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it(`should fill msInstances Object`, () => {
+ const fixture = TestBed.createComponent(MicroservicesComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ let mockMicroservice = [{
+ id: 'testId1234',
+ name: 'test-MS',
+ tag: 'test-MS-tag',
+ serviceName: 'testServiceName',
+ type: 'testType',
+ location: 'TestLocation',
+ namespace: 'testNameSpace',
+ status: 'testStatus',
+ metadata: {
+ createdBy: 'test',
+ createdOn: '01-01-2020 12:00',
+ updatedBy: 'test',
+ updatedOn: '01-01-2020 12:00',
+ notes: 'test',
+ labels: ['test'],
+ },
+ msInstances: 'test'
+ }]
+
+ app.fillTable(mockMicroservice)
+
+ expect(app.loadTable).toEqual(true);
+ expect(app.msElements.length).toEqual(1);
+ });
+
+ it(`should set addOrChange to "Add"`, () => {
+ const fixture = TestBed.createComponent(MicroservicesComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ let mockRowData = null
+ app.showAddChangeDialog(mockRowData)
+
+ expect(app.addOrChange).toEqual('Add');
+ });
+
+ it(`should set addOrChange to "Change"`, () => {
+ const fixture = TestBed.createComponent(MicroservicesComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ let mockRowData = {field: 'test'}
+ app.showAddChangeDialog(mockRowData)
+
+ expect(app.addOrChange).toEqual('Change');
+ });
+});
diff --git a/mod2/ui/src/app/microservices/microservices.component.ts b/mod2/ui/src/app/microservices/microservices.component.ts
new file mode 100644
index 0000000..640e750
--- /dev/null
+++ b/mod2/ui/src/app/microservices/microservices.component.ts
@@ -0,0 +1,311 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, ViewChild, ElementRef, Input, EventEmitter, Output } from '@angular/core';
+import { MatTableDataSource } from '@angular/material/table';
+import { Table } from 'primeng/table';
+import { MessageService } from 'primeng/api';
+import { trigger, state, style, transition, animate } from '@angular/animations';
+import { BaseMicroserviceService } from '../services/base-microservice.service';
+import { MsAddService } from '../services/ms-add.service';
+import { MicroserviceInstanceService } from '../services/microservice-instance.service';
+import { AuthService } from '../services/auth.service';
+import { DatePipe } from '@angular/common';
+import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner';
+import { DownloadService } from '../services/download.service';
+
+@Component({
+ selector: 'app-microservices',
+ templateUrl: './microservices.component.html',
+ styleUrls: ['./microservices.component.css'],
+ animations: [
+ trigger('rowExpansionTrigger', [
+ state('void', style({
+ transform: 'translateX(-10%)',
+ opacity: 0
+ })),
+ state('active', style({
+ transform: 'translateX(0)',
+ opacity: 1
+ })),
+ transition('* <=> *', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)'))
+ ])
+ ],
+ providers: [DatePipe]
+})
+export class MicroservicesComponent implements OnInit {
+ @ViewChild(Table, { static: false }) dt: Table;
+
+ /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
+ msElements: any[] = [];
+ dataSource = new MatTableDataSource<any>(this.msElements);
+ cols: any[] = [
+ { field: 'name', header: 'MS Name' },
+ { field: 'tag', header: 'MS Tag' },
+ { field: 'serviceName', header: 'Service Short Name'},
+ { field: 'type', header: 'Type', width: '11%' },
+ { field: 'namespace', header: 'Namespace', width: '15%' },
+ { field: 'status', header: 'Status', width: '90px' }
+ ];
+ columns: any[];
+ loadTable: boolean;
+ filteredRows: any;
+ downloadItems: { label: string; command: () => void; }[];
+ showAddChangeMsInstance: boolean;
+ addInstanceTo: string = "";
+ msInstanceStates: { label: string, value: string }[] = [
+ { label: 'New', value: 'new' },
+ { label: 'In Dev', value: 'in-dev' },
+ { label: 'Dev Complete', value: 'dev-complete' },
+ { label: 'In Test', value: 'in-test' },
+ { label: 'Certified', value: 'certified' },
+ { label: 'Prod Deployed', value: 'prod-deployed' }
+ ]
+
+ // Json to add MS to DB, returned from child
+ msAddChangeJson: any;
+
+ showMsAddChangeDialog: boolean = false;
+ currentRow: any;
+ currentMsRow: string = "";
+ addOrChange: string;
+ username: string;
+ errorMessage: any;
+ successMessage: string;
+
+ constructor(private spinnerService: Ng4LoadingSpinnerService, private baseMsService: BaseMicroserviceService,
+ private msInstanceApi: MicroserviceInstanceService, private messageService: MessageService,
+ private addChangeMsApi: MsAddService, private authService: AuthService, private datePipe: DatePipe,
+ private downloadService: DownloadService) { }
+
+ ngOnInit() {
+ this.username = this.authService.getUser().username;
+ this.getAllMs();
+ }
+
+ getAllMs() {
+ this.spinnerService.show();
+ this.msElements = [];
+ this.loadTable = false;
+
+ this.baseMsService.getAllBaseMs()
+ .subscribe((data: any[]) => {
+ this.fillTable(data)
+ })
+
+ this.columns = this.cols.map(col => ({ title: col.header, dataKey: col.field }));
+ }
+
+ /*checks when table is filtered and stores filtered data in new
+ object to be downloaded when download button is clicked*/
+ onTableFiltered(values) {
+ if (values !== null) {
+ this.filteredRows = values;
+ } else {
+ this.filteredRows = this.msElements;
+ }
+ }
+
+ //download table as excel file
+ exportTable(exportTo: string) {
+ let downloadElements: any[] = []
+
+ //labels array not handled well by excel download so converted them to a single string
+ for (let row of this.filteredRows) {
+ let labels;
+ let notes;
+ if (exportTo === "excel") {
+ if (row.metadata.labels !== undefined) {
+ labels = row.metadata.labels.join(",")
+ }
+ } else {
+ labels = row.metadata.labels
+ }
+
+ if (row.metadata.notes !== null && row.metadata.notes !== undefined && row.metadata.notes !== '') {
+ notes = encodeURI(row.metadata.notes).replace(/%20/g, " ").replace(/%0A/g, "\\n")
+ }
+
+ downloadElements.push({
+ MS_Name: row.name,
+ MS_Tag: row.tag,
+ Service_Short_Name: row.serviceName,
+ Type: row.type,
+ Location: row.location,
+ Namespace: row.namespace,
+ Status: row.status,
+ Created_By: row.metadata.createdBy,
+ Created_On: row.metadata.createdOn,
+ Updated_By: row.metadata.updatedBy,
+ Updated_On: row.metadata.updatedOn,
+ Notes: notes,
+ Labels: labels
+ })
+ }
+
+ let csvHeaders = []
+
+ if (exportTo === "csv") {
+ csvHeaders = [
+ "MS_Name",
+ "MS_Tag",
+ "Service_Short_Name",
+ "Type",
+ "Location",
+ "Namespace",
+ "Status",
+ "Created_By",
+ "Created_On",
+ "Updated_By",
+ "Updated_On",
+ "Notes",
+ "Labels"
+ ];
+ }
+
+ this.downloadService.exportTableData(exportTo, downloadElements, csvHeaders)
+ }
+
+ // * * * * * Show the Dialog to Add a MS (<app-ms-add-change> tag in the html) * * * * *
+ showAddChangeDialog(rowData) {
+ this.showMsAddChangeDialog = true;
+ this.currentRow = rowData;
+ if (this.currentRow) {
+ this.addOrChange = "Change";
+ } else {
+ this.addOrChange = "Add";
+ }
+ }
+
+ // * * * * * Add or Change a MS * * * * *
+ // The response includes the entire MS record that was Added or Changed, (along with ID and audit fields).
+ // When Added, the response is added directly to the table. When Changed, the current record is updated field-by-field.
+ addOrChangeMs(jsonFromChildDialog) {
+ if (jsonFromChildDialog) {
+ this.msAddChangeJson = jsonFromChildDialog;
+ if (this.addOrChange == "Change") {
+ this.currentMsRow = this.currentRow['id']
+ }
+ this.addChangeMsApi.addChangeMsToCatalog(this.addOrChange, this.currentMsRow, this.msAddChangeJson).subscribe(
+ (response: any) => {
+ if (this.addOrChange == "Add") {
+ this.msElements.unshift(response);
+ this.successMessage = "Microservice Added";
+ } else {
+ this.updateCurrentRow(jsonFromChildDialog);
+ this.successMessage = "Microservice Updated";
+ }
+ this.showMsAddChangeDialog = false;
+ this.messageService.add({ key: 'addChangeSuccess', severity: 'success', summary: 'Success', detail: this.successMessage, life: 5000 });
+ },
+ errResponse => {
+ // for testing only - this.updateCurrentRow(jsonFromChildDialog);
+ this.messageService.add({ key: 'msAddChangeError', severity: 'error', summary: 'Error', detail: errResponse.error.message, sticky: true });
+ }
+ )
+ }
+ else {
+ this.showMsAddChangeDialog = false;
+ };
+ }
+
+ updateCurrentRow(jsonFromChildDialog) {
+ const newRow = JSON.parse(jsonFromChildDialog);
+ this.currentRow['name'] = newRow['name'];
+ this.currentRow['serviceName'] = newRow['serviceName'];
+ this.currentRow['type'] = newRow['type'];
+ this.currentRow['location'] = newRow['location'];
+ this.currentRow['namespace'] = newRow['namespace'];
+ this.currentRow['metadata']['labels'] = newRow['metadata']['labels'];
+ this.currentRow['metadata']['notes'] = newRow['metadata']['notes'];
+ }
+
+ /* * * * Show pop up for Adding a new MS Instance * * * */
+ showAddChangeMsInstanceDialog(data) {
+ this.addInstanceTo = data['name']
+ this.showAddChangeMsInstance = true
+ }
+
+ /* * * * Call API to Add a new MS Instance * * * */
+ addMsInstance(body) {
+ if (body === null) {
+ this.showAddChangeMsInstance = false;
+ } else {
+ this.msInstanceApi.addChangeMsInstance("ADD", this.addInstanceTo, body).subscribe(
+ (data) => {
+ this.messageService.add({ key: 'addChangeSuccess', severity: 'success', summary: 'Success', detail: "MS Instance Added", life: 5000 });
+ this.showAddChangeMsInstance = false;
+ },
+ (errResponse) => {
+ console.log(errResponse)
+ this.messageService.add({ key: 'instanceAddChangeError', severity: 'error', summary: 'Error', detail: errResponse.error.message, sticky: true });
+ }
+ )
+ }
+ }
+
+ //fill object with microservice data, to be used to fill table.
+ //checks if fields are empty and if they are, store 'N/A' as the values
+ fillTable(data) {
+ for (let elem of data) {
+ var tempMsElement: any = {
+ id: elem.id,
+ name: elem.name,
+ tag: elem.tag,
+ serviceName: elem.serviceName,
+ type: elem.type,
+ location: elem.location,
+ namespace: elem.namespace,
+ status: elem.status,
+ metadata: {
+ createdBy: elem.metadata.createdBy,
+ createdOn: this.datePipe.transform(elem.metadata.createdOn, 'MM-dd-yyyy HH:mm'),
+ updatedBy: elem.metadata.updatedBy,
+ updatedOn: this.datePipe.transform(elem.metadata.updatedOn, 'MM-dd-yyyy HH:mm'),
+ notes: elem.metadata.notes,
+ labels: elem.metadata.labels
+ },
+ msInstances: elem.msInstances
+ }
+ this.msElements.push(tempMsElement)
+ }
+ this.filteredRows = this.msElements
+ this.loadTable = true;
+ this.spinnerService.hide();
+ }
+}
+
+export interface AddMsInstance{
+ name: string,
+ release: string,
+ metadata: {
+ scrumLead: string,
+ scrumLeadId: string,
+ systemsEngineer: string,
+ systemsEngineerId: string,
+ developer: string;
+ developerId: string;
+ pstDueDate: string,
+ pstDueIteration: string,
+ eteDueDate: string,
+ eteDueIteration: string,
+ labels: string[],
+ notes: string
+ }
+ user: string
+}
diff --git a/mod2/ui/src/app/models/AuthResponse.ts b/mod2/ui/src/app/models/AuthResponse.ts
new file mode 100644
index 0000000..f44104d
--- /dev/null
+++ b/mod2/ui/src/app/models/AuthResponse.ts
@@ -0,0 +1,28 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Authority } from './Authority.enum';
+
+export class AuthResponse {
+ token?: string;
+ type?: null;
+ id?: string;
+ username?:string;
+ roles?: Authority[];
+ message?:string;
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/models/Authority.enum.ts b/mod2/ui/src/app/models/Authority.enum.ts
new file mode 100644
index 0000000..cbac582
--- /dev/null
+++ b/mod2/ui/src/app/models/Authority.enum.ts
@@ -0,0 +1,22 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+export enum Authority {
+ ADMIN = 'ROLE_ADMIN',
+ USER = 'ROLE_USER'
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/models/User.ts b/mod2/ui/src/app/models/User.ts
new file mode 100644
index 0000000..3c662d9
--- /dev/null
+++ b/mod2/ui/src/app/models/User.ts
@@ -0,0 +1,25 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+export class User{
+ username: string;
+ fullName?: string;
+ password?: string;
+ active?: boolean;
+ roles?: any[];
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/ms-add-change/ms-add-change.component.css b/mod2/ui/src/app/ms-add-change/ms-add-change.component.css
new file mode 100644
index 0000000..f256b2f
--- /dev/null
+++ b/mod2/ui/src/app/ms-add-change/ms-add-change.component.css
@@ -0,0 +1,57 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+.input {
+ padding-top: 10px;
+}
+
+.inputLabel {
+ font-weight: 600;
+ margin-left: 20px;
+ width: 150px;
+}
+
+.inputFieldSm {
+ width: 200px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldMed {
+ width: 300px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldLg {
+ width: 400px;
+ height: 35px;
+ padding-left: 6px;
+}
+
+.validationMsg {
+ padding-left: 175px;
+ color: red;
+ font-size: 11px;
+ font-weight: 550;
+}
+
+.validationMsgWarning {
+ padding-left: 175px;
+ color: rgb(255, 81, 0);
+ font-size: 11px;
+ font-weight: 550;
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/ms-add-change/ms-add-change.component.html b/mod2/ui/src/app/ms-add-change/ms-add-change.component.html
new file mode 100644
index 0000000..2fd19d7
--- /dev/null
+++ b/mod2/ui/src/app/ms-add-change/ms-add-change.component.html
@@ -0,0 +1,109 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<p-dialog *ngIf="visible" [header]="guiHeader" [(visible)]="visible" appendTo="body" [modal]="true" [transitionOptions]="'300ms'"
+ [closeOnEscape]="false" [closable]="false" [style]="{width: '645px'}" (onHide)="closeDialog()">
+
+ <!-- "Add / Change MS" Error Message -->
+ <p-toast key="msAddChangeError" [style]="{width: '500px'}"></p-toast>
+
+ <!-- * * * * * Input fields * * * * * -->
+ <form [formGroup]="msAddForm" (ngSubmit)="saveMs()" class="bg-faded">
+ <!-- * * * MS Name * * * -->
+ <div class="input">
+ <label class="inputLabel">MS Name<span style="color:red">*</span></label>
+ <input class="inputFieldMed" type="text" pInputText formControlName="name">
+ </div>
+ <!-- * * * MS Tag * * * -->
+ <div class="input">
+ <label class="inputLabel">MS Tag<span style="color:red">*</span></label>
+ <input *ngIf="!currentRow" class="inputFieldMed" type="text" pInputText formControlName="tag">
+ <!-- If Updating (vs ADDing) the data, the "Tag" is Read-Only -->
+ <input *ngIf="currentRow" class="inputFieldMed" type="text" pInputText formControlName="tag" style="border:none" readonly>
+ <!-- * * * (Validation Rules Display) * * * -->
+ <div class="validationMsg" *ngIf="msAddForm.controls['tag'].invalid &&
+ !msAddForm.value['tag']=='' &&
+ msAddForm.controls['tag'].value.length < 51">
+ Format: lowercase alphanumeric with embedded dashes (5-50 characters)
+ </div>
+ <!-- * * * (Validation Rule - length > 50) * * * -->
+ <div class="validationMsg" *ngIf="msAddForm.controls['tag'].value.length > 50">
+ MS Tag cannot exceed 50 chars
+ </div>
+ </div>
+ <!-- * * * Service Short Name * * * -->
+ <div class="input">
+ <label class="inputLabel">Service Short Name</label>
+ <input class="inputFieldMed" type="text" pInputText formControlName="serviceName">
+ <!-- * * * (Validation Rules Display) * * * -->
+ <div class="validationMsg" *ngIf="msAddForm.controls['serviceName'].invalid &&
+ !msAddForm.value['serviceName']=='' &&
+ msAddForm.controls['serviceName'].value.length < 26">
+ Format: lowercase alpha with embedded dashes
+ </div>
+ <!-- * * * (Warning! Global vs Central/Edge Service Name length) * * * -->
+ <div class="validationMsgWarning" *ngIf="msAddForm.controls['serviceName'].valid &&
+ msAddForm.controls['serviceName'].value.length > 12 &&
+ msAddForm.controls['serviceName'].value.length < 26">
+ Warning! Only Global Site short names can exceed 12 chars (max 25)
+ </div>
+ <!-- * * * (Validation Rule - length > 25) * * * -->
+ <div class="validationMsg" *ngIf="msAddForm.controls['serviceName'].value.length > 25">
+ Global Site short names cannot exceed 25 chars
+ </div>
+ </div>
+ <!-- * * * Type * * * -->
+ <div class="input">
+ <label class="inputLabel">Type<span style="color:red">*</span></label>
+ <p-dropdown [options]="types" placeholder="Select Type" optionLabel="type" formControlName="type"></p-dropdown>
+ </div>
+ <!-- * * * Location
+ <div class="input">
+ <label class="inputLabel">Location<span style="color:red">*</span></label>
+ <p-dropdown [options]="locations" placeholder="Select Location" optionLabel="location" formControlName="location"></p-dropdown>
+ </div>
+ * * * -->
+ <!-- * * * Namespace * * * -->
+ <div class="input">
+ <label class="inputLabel">Namespace</label>
+ <input class="inputFieldMed" type="text" pInputText formControlName="namespace">
+ <!-- * * * (Validation Rules Display) * * * -->
+ <div class="validationMsg" *ngIf="msAddForm.controls['namespace'].invalid && !msAddForm.value['namespace']==''">
+ Format: lowercase alphanumeric with embedded dashes
+ </div>
+ </div>
+ <!-- * * * Labels * * * -->
+ <div class="input">
+ <label class="inputLabel">Labels</label>
+ <input class="inputFieldLg" type="text" pInputText formControlName="labels">
+ </div>
+ <span style="padding: 9px 0px 0px 172px; font-size: 13px;">(Separate labels with a space)</span>
+ <!-- * * * Notes * * * -->
+ <div class="input">
+ <label class="inputLabel" style="vertical-align: top">Notes</label>
+ <textarea class="inputFieldLg" [rows]="1" [cols]="30" pInputTextarea autoResize="autoResize" formControlName="notes"></textarea>
+ </div>
+ <!-- * * * ADD and CANCEL buttons * * * -->
+ <div style="float: right; padding: 20px 45px">
+ <button pButton type="button" (click)="closeDialog()" style="margin-right: 10px" label="Cancel"></button>
+ <button pButton type="submit" class="ui-button-success" style="width: 77px; text-align:center" [label]="addOrUpdate"
+ [disabled]="!msAddForm.valid || !msAddForm.value['name'].trim()"></button>
+ </div>
+ </form>
+
+</p-dialog>
diff --git a/mod2/ui/src/app/ms-add-change/ms-add-change.component.spec.ts b/mod2/ui/src/app/ms-add-change/ms-add-change.component.spec.ts
new file mode 100644
index 0000000..4ba7ae9
--- /dev/null
+++ b/mod2/ui/src/app/ms-add-change/ms-add-change.component.spec.ts
@@ -0,0 +1,67 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { MessageService } from 'primeng/api';
+import { ButtonModule } from 'primeng/button';
+import { DialogModule } from 'primeng/dialog';
+import { DropdownModule } from 'primeng/dropdown';
+import { ToastModule } from 'primeng/toast';
+
+import { MsAddChangeComponent } from './ms-add-change.component';
+
+describe('MsAddChangeComponent', () => {
+ let component: MsAddChangeComponent;
+ let fixture: ComponentFixture<MsAddChangeComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [MsAddChangeComponent],
+ imports: [
+ DialogModule,
+ DropdownModule,
+ ToastModule,
+ FormsModule,
+ ReactiveFormsModule,
+ ButtonModule,
+ HttpClientTestingModule,
+ RouterTestingModule
+ ],
+ providers: [
+ MessageService,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MsAddChangeComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/ms-add-change/ms-add-change.component.ts b/mod2/ui/src/app/ms-add-change/ms-add-change.component.ts
new file mode 100644
index 0000000..6991104
--- /dev/null
+++ b/mod2/ui/src/app/ms-add-change/ms-add-change.component.ts
@@ -0,0 +1,180 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { InputTextModule } from 'primeng/inputtext';
+import { DropdownModule } from 'primeng/dropdown';
+import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
+import { AuthService } from '../services/auth.service';
+
+interface Type {
+ type: string;
+}
+interface Location {
+ location: string;
+}
+
+@Component({
+ selector: 'app-ms-add-change',
+ templateUrl: './ms-add-change.component.html',
+ styleUrls: ['./ms-add-change.component.css']
+})
+
+export class MsAddChangeComponent implements OnInit {
+
+ guiHeader: string = "Microservice ADD"
+ // Used for the Add/Update button label
+ addOrUpdate: string = "Add";
+
+ msAddForm: FormGroup;
+ // The loggged in user
+ username: string;
+
+ // Input form fields
+ name: string;
+ tag: string;
+ serviceName: string = "";
+ type: string;
+ location: string;
+ namespace: string;
+ labels: string;
+ notes: string;
+
+ // Dropdowns
+ types: Type[];
+ locations: Location[];
+
+ // Return JSON to parent component
+ msAddChangeString: any;
+ msAddChangeJson: any;
+
+ constructor(private fb: FormBuilder, private authService: AuthService) {
+ }
+
+ @Input() visible: boolean;
+ @Input() currentRow: any;
+ @Output() handler: EventEmitter<any> = new EventEmitter();
+
+ ngOnInit() {
+ // The logged in user
+ this.username = this.authService.getUser().username;
+
+ this.msAddForm = new FormGroup({
+ name: new FormControl(),
+ tag: new FormControl(),
+ serviceName: new FormControl(),
+ type: new FormControl(),
+ //location: new FormControl(),
+ namespace: new FormControl(),
+ labels: new FormControl(),
+ notes: new FormControl()
+ });
+
+ // FORM fields and validations
+ this.msAddForm = this.fb.group({
+ name: ['', [Validators.required]],
+ tag: ['', [Validators.required, Validators.pattern('^([a-z0-9](-[a-z0-9])*)+$'), Validators.minLength(5), Validators.maxLength(50)]],
+ serviceName: ['', [Validators.pattern('^([a-z](-[a-z])*)+$'), Validators.maxLength(25)]],
+ type: ['', [Validators.required]],
+ //location: ['', [Validators.required]],
+ namespace: ['', [Validators.pattern('^([a-z0-9](-[a-z0-9])*)+$')]],
+ labels: ['', []],
+ notes: ['', []]
+ },
+ {updateOn: "blur"}
+ );
+
+ // TYPE Dropdown
+ this.types = [
+ { type: 'FM_COLLECTOR' },
+ { type: 'PM_COLLECTOR' },
+ { type: 'ANALYTIC' },
+ { type: 'TICK' },
+ { type: 'OTHER' }
+ ];
+ // LOCATION Dropdown
+ this.locations = [
+ { location: 'EDGE' },
+ { location: 'CENTRAL' },
+ { location: 'UNSPECIFIED' }
+ ];
+
+ // "Update" was selected, so populate the current row data in the GUI
+ if (this.currentRow) {
+ this.guiHeader = "Microservice Update";
+ this.addOrUpdate = "Update";
+ this.populateFields();
+ }
+
+ }
+
+ populateFields() {
+ let labelsStr: string;
+ if (this.currentRow['metadata']['labels']) {
+ labelsStr = this.currentRow['metadata']['labels'].join(' ')
+ }
+
+ // Prevent validation (length check) from failing in the html
+ if (this.currentRow['serviceName']) {
+ this.serviceName = this.currentRow['serviceName']
+ }
+
+ this.msAddForm.patchValue({
+ name: this.currentRow['name'],
+ tag: this.currentRow['tag'],
+ serviceName: this.serviceName,
+ type: {type: this.currentRow['type']},
+ //location: {location: this.currentRow['location']},
+ namespace: this.currentRow['namespace'],
+ labels: labelsStr,
+ notes: this.currentRow['metadata']['notes']
+ })
+ }
+
+ // The handler emits 'null' back to parent to close dialog and make it available again when clicked
+ closeDialog() {
+ this.visible = false;
+ this.handler.emit(null);
+ }
+
+ // Create the JSON to be sent to the parent component
+ // The "labels" functions below take into account leading/trailing spaces, multiple spaces between labels, and conversion into an array
+ createOutputJson() {
+ this.msAddChangeString = {
+ name: this.msAddForm.value['name'].trim(),
+ tag: this.msAddForm.value['tag'],
+ serviceName: this.msAddForm.value['serviceName'],
+ type: this.msAddForm.value['type'].type,
+ location: 'UNSPECIFIED',
+ //location: this.msAddForm.value['location'].location,
+ namespace: this.msAddForm.value['namespace'].trim(),
+ metadata: {
+ labels: this.msAddForm.value['labels'].trim().replace(/\s{2,}/g, ' ').split(" "),
+ notes: this.msAddForm.value['notes']
+ },
+ user: this.username
+ };
+ }
+
+ saveMs() {
+ this.createOutputJson();
+ this.msAddChangeJson = JSON.stringify(this.msAddChangeString);
+ this.handler.emit(this.msAddChangeJson);
+ }
+
+}
diff --git a/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.css b/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.css
new file mode 100644
index 0000000..8ecfc18
--- /dev/null
+++ b/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.css
@@ -0,0 +1,48 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+.input{
+ padding-top: 8px;
+}
+
+.inputLabel {
+ font-weight: 600;
+ margin-left: 20px;
+ width: 165px;
+}
+
+.inputFieldXSm {
+ width: 75px;
+ height: 30px;
+ padding-left: 6px;
+}
+.inputFieldSm {
+ width: 200px;
+ height: 30px;
+ padding-left: 6px;
+}
+.inputFieldMed {
+ width: 300px;
+ height: 30px;
+ padding-left: 6px;
+}
+.inputFieldLg {
+ width: 400px;
+ height: 30px;
+ padding-left: 6px;
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.html b/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.html
new file mode 100644
index 0000000..804de33
--- /dev/null
+++ b/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.html
@@ -0,0 +1,93 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<p-dialog [(visible)]="visible" [header]="guiHeader" appendTo="body" [modal]="true" [transitionOptions]="'300ms'" [style]="{width: '720px'}" [baseZIndex]="10000"
+ [closable]="false" (onHide)="closeDialog()">
+
+ <!-- "Add / Change MS Instance" Error Message -->
+ <p-toast key="instanceAddChangeError"></p-toast>
+
+ <form [formGroup]="msInstanceAddForm">
+ <!-- * * * Name * * * -->
+ <div class="input">
+ <label class="inputLabel">MS Name</label>
+ <b>{{msName}}</b>
+ </div>
+ <!-- * * * Release * * * -->
+ <div class="input">
+ <label class="inputLabel">Release<span style="color:red">*</span></label>
+ <p-dropdown [options]="msInstanceReleases" placeholder="Select Release" formControlName="release"></p-dropdown>
+ </div>
+ <!-- * * * Scrum Lead / UID * * * -->
+ <div class="input">
+ <label class="inputLabel">Scrum Lead/UID</label>
+ <input class="inputFieldLg" type="text" pInputText formControlName="scrumLead" /> / <input class="inputFieldXSm" type="text" pInputText formControlName="scrumLeadId" />
+ </div>
+ <!-- * * * Systems Engineer / UID * * * -->
+ <div class="input">
+ <label class="inputLabel">Systems Engineer/UID</label>
+ <input class="inputFieldLg" type="text" pInputText formControlName="systemsEngineer" /> / <input class="inputFieldXSm" type="text" pInputText formControlName="systemsEngineerId" />
+ </div>
+ <!-- * * * Developer / UID * * * -->
+ <div class="input">
+ <label class="inputLabel">Developer<span style="color:red">*</span>/UID<span style="color:red">*</span></label>
+ <input class="inputFieldLg" type="text" pInputText formControlName="developer" /> / <input class="inputFieldXSm" type="text" pInputText formControlName="developerId" />
+ </div>
+ <!-- * * * PST Due Date * * * -->
+ <div class="input">
+ <label class="inputLabel">PST Due Date</label>
+ <p-calendar appendTo="body" [baseZIndex]="10001" dateFormat="yy-mm-dd" formControlName="pstDueDate" [showIcon]="true"></p-calendar>
+ </div>
+ <!-- * * * PST Due Iteration * * * -->
+ <div class="input">
+ <label class="inputLabel">PST Due Iteration</label>
+ <input class="inputFieldSm" type="text" pInputText formControlName="pstDueIteration" />
+ </div>
+ <!-- * * * ETE Due Date * * * -->
+ <div class="input">
+ <label class="inputLabel">ETE Due Date</label>
+ <p-calendar appendTo="body" [baseZIndex]="10001" dateFormat="yy-mm-dd" formControlName="eteDueDate" [showIcon]="true"></p-calendar>
+ </div>
+ <!-- * * * ETE Due Iteration * * * -->
+ <div class="input">
+ <label class="inputLabel">ETE Due Iteration</label>
+ <input class="inputFieldSm" type="text" pInputText formControlName="eteDueIteration" />
+ </div>
+ <!-- * * * Labels * * * -->
+ <div class="input">
+ <label class="inputLabel">Labels</label>
+ <input class="inputFieldLg" type="text" pInputText formControlName="labels" />
+ </div>
+ <span style="padding: 0px 0px 0px 188px; font-size: 13px;">(Separate labels with a space)</span>
+ <!-- * * * Notes * * * -->
+ <div class="input">
+ <label class="inputLabel" style="vertical-align: top">Notes</label>
+ <textarea class="inputFieldLg" [rows]="1" [cols]="30" pInputTextarea autoResize="autoResize" formControlName="notes"></textarea>
+ </div>
+
+ <!-- * * * ADD and Cancel buttons * * * -->
+ <div style="float: right; padding: 10px 25px 5px;">
+ <button pButton type="button" (click)="closeDialog()" label="Cancel"></button>&nbsp;
+ <button pButton type="submit" (click)="submitMsInstance()" class="ui-button-success" [label]="addOrUpdate" style="width: 77px"
+ [disabled]="!msInstanceAddForm.valid ||
+ !msInstanceAddForm.value['developer'].trim() ||
+ !msInstanceAddForm.value['developerId'].trim()"></button>
+ </div>
+ </form>
+
+</p-dialog> \ No newline at end of file
diff --git a/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.spec.ts b/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.spec.ts
new file mode 100644
index 0000000..2318a2c
--- /dev/null
+++ b/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.spec.ts
@@ -0,0 +1,71 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { DatePipe } from '@angular/common';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { MessageService } from 'primeng/api';
+import { ButtonModule } from 'primeng/button';
+import { CalendarModule } from 'primeng/calendar';
+import { DialogModule } from 'primeng/dialog';
+import { DropdownModule } from 'primeng/dropdown';
+import { ToastModule } from 'primeng/toast';
+
+import { MsInstanceAddComponent } from './ms-instance-add.component';
+
+describe('MsInstanceAddComponent', () => {
+ let component: MsInstanceAddComponent;
+ let fixture: ComponentFixture<MsInstanceAddComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [MsInstanceAddComponent],
+ imports: [
+ DialogModule,
+ DropdownModule,
+ ToastModule,
+ FormsModule,
+ ReactiveFormsModule,
+ ButtonModule,
+ HttpClientTestingModule,
+ RouterTestingModule,
+ CalendarModule,
+ ],
+ providers: [
+ MessageService,
+ DatePipe,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MsInstanceAddComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.ts b/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.ts
new file mode 100644
index 0000000..228ddc1
--- /dev/null
+++ b/mod2/ui/src/app/ms-instance-add/ms-instance-add.component.ts
@@ -0,0 +1,189 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { MicroserviceInstanceService } from '../services/microservice-instance.service';
+import { MessageService } from 'primeng/api';
+import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms';
+import { AuthService } from '../services/auth.service';
+import { DatePipe } from '@angular/common';
+
+@Component({
+ selector: 'app-ms-instance-add',
+ templateUrl: './ms-instance-add.component.html',
+ styleUrls: ['./ms-instance-add.component.css']
+})
+export class MsInstanceAddComponent implements OnInit {
+
+ guiHeader: string = "Microservice Instance ADD";
+ // Used for the Add/Update button label
+ addOrUpdate: string = "Add";
+
+ msInstanceAddForm: FormGroup;
+ msInstanceToAdd: AddMsInstance;
+ addInstanceTo: string = "";
+ username: string;
+ msInstanceReleases: { label: string, value: string }[] = [
+ { label: '2004', value: '2004' },
+ { label: '2006', value: '2006' },
+ { label: '2008', value: '2008' },
+ { label: '2009', value: '2009' },
+ { label: '2010', value: '2010' },
+ { label: '2011', value: '2011' },
+ { label: '2012', value: '2012' }
+ ]
+
+ @Input() visible: boolean;
+ @Input() msName: string;
+ @Input() msInstanceChange: string; // Use to differentiate Add from Change, since currentRow can be problematic
+ @Input() currentRow: any;
+ @Output() handler: EventEmitter<any> = new EventEmitter();
+
+ constructor(private addChangeMsInstanceApi: MicroserviceInstanceService, private messageService: MessageService, private fb: FormBuilder, private authService: AuthService, private datePipe: DatePipe) { }
+
+ ngOnInit() {
+ this.username = this.authService.getUser().username;
+
+ this.msInstanceAddForm = new FormGroup({
+ name: new FormControl(),
+ release: new FormControl(),
+ scrumLead: new FormControl(),
+ scrumLeadId: new FormControl(),
+ systemsEngineer: new FormControl(),
+ systemsEngineerId: new FormControl(),
+ developer: new FormControl(),
+ developerId: new FormControl(),
+ status: new FormControl(),
+ pstDueDate: new FormControl(),
+ pstDueIteration: new FormControl(),
+ eteDueDate: new FormControl(),
+ eteDueIteration: new FormControl(),
+ labels: new FormControl(),
+ notes: new FormControl()
+ });
+
+ this.msInstanceAddForm = this.fb.group({
+ name: ['', []],
+ release: ['', [Validators.required]],
+ scrumLead: ['', []],
+ scrumLeadId: ['', []],
+ systemsEngineer: ['', []],
+ systemsEngineerId: ['', []],
+ developer: ['', [Validators.required]],
+ developerId: ['', [Validators.required]],
+ status: ['', []],
+ pstDueDate: ['', []],
+ pstDueIteration: ['', []],
+ eteDueDate: ['', []],
+ eteDueIteration: ['', []],
+ labels: ['', []],
+ notes: ['', []]
+ });
+
+ if (this.msInstanceChange) {
+ this.guiHeader = "Microservice Instance Update";
+ this.addOrUpdate = "Update";
+ this.populateFields();
+ }
+ }
+
+ populateFields() {
+ this.msName = this.currentRow['name'];
+
+ let labelsStr: string;
+ if (this.currentRow['metadata']['labels']) {
+ labelsStr = this.currentRow['metadata']['labels'].join(' ')
+ }
+
+ this.msInstanceAddForm.patchValue({
+ release: this.currentRow['release'],
+ scrumLead: this.currentRow['metadata']['scrumLead'],
+ scrumLeadId: this.currentRow['metadata']['scrumLeadId'],
+ systemsEngineer: this.currentRow['metadata']['systemsEngineer'],
+ systemsEngineerId: this.currentRow['metadata']['systemsEngineerId'],
+ developer: this.currentRow['metadata']['developer'],
+ developerId: this.currentRow['metadata']['developerId'],
+ pstDueDate: this.currentRow['pstDueDate'],
+ pstDueIteration: this.currentRow['pstDueIteration'],
+ eteDueDate: this.currentRow['eteDueDate'],
+ eteDueIteration: this.currentRow['eteDueIteration'],
+ labels: labelsStr,
+ notes: this.currentRow['metadata']['notes']
+ })
+}
+
+ /* * * * On click of cancel * * * */
+ closeDialog() {
+ this.visible = false;
+ this.handler.emit(null)
+ }
+
+ /* * * * On click of add * * * */
+ submitMsInstance() {
+ // Prevent error on "split" if record existed before "labels" were implemented
+ let labels: string[] = []
+ if (!this.msInstanceAddForm.value['labels']){
+ labels = []
+ } else {
+ labels = this.msInstanceAddForm.value['labels'].trim().replace(/\s{2,}/g, ' ').split(" ")
+ }
+
+ //build request body
+ this.msInstanceToAdd = {
+ name: this.msName,
+ release: this.msInstanceAddForm.value['release'],
+ metadata: {
+ scrumLead: this.msInstanceAddForm.value['scrumLead'],
+ scrumLeadId: this.msInstanceAddForm.value['scrumLeadId'],
+ systemsEngineer: this.msInstanceAddForm.value['systemsEngineer'],
+ systemsEngineerId: this.msInstanceAddForm.value['systemsEngineerId'],
+ developer: this.msInstanceAddForm.value['developer'],
+ developerId: this.msInstanceAddForm.value['developerId'],
+ pstDueDate: this.msInstanceAddForm.value['pstDueDate'],
+ pstDueIteration: this.msInstanceAddForm.value['pstDueIteration'],
+ eteDueDate: this.msInstanceAddForm.value['eteDueDate'],
+ eteDueIteration: this.msInstanceAddForm.value['eteDueIteration'],
+ labels: labels,
+ notes: this.msInstanceAddForm.value['notes']
+ },
+ user: this.username
+ }
+
+ this.handler.emit(this.msInstanceToAdd) //return request body back to parent
+ }
+}
+
+export interface AddMsInstance {
+ name: string,
+ release: string,
+ metadata: {
+ scrumLead: string,
+ scrumLeadId: string,
+ systemsEngineer: string,
+ systemsEngineerId: string,
+ developer: string,
+ developerId: string,
+ pstDueDate: any,
+ pstDueIteration: string,
+ eteDueDate: any,
+ eteDueIteration: string,
+ labels: string[],
+ notes: string
+ }
+ user: string
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/msInstances/msInstances.component.css b/mod2/ui/src/app/msInstances/msInstances.component.css
new file mode 100644
index 0000000..62c5ac8
--- /dev/null
+++ b/mod2/ui/src/app/msInstances/msInstances.component.css
@@ -0,0 +1,148 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+td{
+ word-break:break-all;
+ font-size: 12px;
+}
+
+th{
+ text-align: center;
+ font-size: 12px;
+}
+
+.table_column_filter{
+ width: 100%;
+ height: 20px;
+ font-size: 10px;
+}
+
+.table_div{
+ margin: 0px 50px 10px 20px;
+ min-width: 980px;
+ width: 98%;
+ border: 1px solid darkslategray;
+}
+
+.fa-refresh{
+ cursor: pointer;
+}
+
+textarea
+{
+ font-size: 12px;
+}
+
+.row-expand-layout{
+ display: grid;
+ grid-template-columns: 17% 30% 30% auto;
+ grid-gap: 10px;
+ grid-auto-rows: minmax(100px, auto);
+}
+
+.row-expand-card{
+ font-size: 12px;
+ border-radius: 5px;
+ border: 1px solid slategray;
+ padding: 10px;
+ /* This height prevents vertical scroll bar in Notes */
+ height: 92px;
+ overflow: hidden;
+ min-width: 195px;
+}
+
+.table_export_buttons_alignment{
+ margin-left: 5px;
+ margin-top: -32px;
+ float: left;
+}
+
+.table_export_button{
+ border-radius: 5px;
+ height: 22px;
+ font-size: 14px;
+ border: none;
+ margin-top: 4px;
+ margin-right: 7px;
+ display: inline-flex;
+}
+
+.table_caption_header{
+ margin-left: -18%;
+ width: 82%;
+ max-height: 25px;
+ display: inline-flex;
+}
+
+.table_global_filter{
+ width: 250px;
+ height: 25px;
+ margin-left: 15px;
+ font-size: 12px;
+}
+
+.table_title{
+ margin-left: 15%;
+}
+
+.table_actions_button{
+ background-color: transparent;
+ border: none;
+ width: 20px;
+ height: 20px;
+ vertical-align: middle;
+}
+
+.table_action_item{
+ outline: none;
+ font-size: 12px;
+}
+
+::ng-deep .mat-menu-content {
+ padding-top: 0px !important;
+ padding-bottom: 0px !important;
+}
+.mat-menu-item{
+ line-height:30px;
+ height:30px;
+}
+
+.greenStatus{
+ background-color: rgba(80, 233, 105, 0.87)
+}
+
+.redStatus{
+ background-color: rgba(255, 29, 29, 0.733)
+}
+
+.blueStatus{
+ background-color: rgba(0, 183, 255, 0.432)
+}
+
+.greyStatus{
+ background-color: rgba(150, 150, 150, 0.432)
+}
+
+.toast-newline {
+ white-space: pre-line;
+}
+
+.ui-state-highlight {
+ background-color: #878C94 !important;
+ color: black !important;
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/msInstances/msInstances.component.html b/mod2/ui/src/app/msInstances/msInstances.component.html
new file mode 100644
index 0000000..1545de3
--- /dev/null
+++ b/mod2/ui/src/app/msInstances/msInstances.component.html
@@ -0,0 +1,221 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<ng4-loading-spinner [timeout]="1000000"></ng4-loading-spinner>
+<div class="table_div">
+ <p-table #dt *ngIf="loadTable" [columns]="cols" [value]="msInstances" sortMode="multiple" [paginator]="true"
+ [rows]="18" [rowsPerPageOptions]="[10,12,14,16,18,20,25,50]" selectionMode="multiple"
+ [(selection)]="selectedMsInstances" (onFilter)="onTableFiltered(dt.filteredValue)" dataKey="id">
+ <ng-template pTemplate="caption">
+
+ <div class="table_caption_header">
+ <!--Microservices Table Header-->
+ <div style="float: left;">
+ <!--Refresh-->
+ <i class="fa fa-refresh" (click)="getAllInstances()"></i>
+ <!--Global Filter-->
+ <input type="text" pInputText size="50" placeholder="Global Filter"
+ (input)="dt.filterGlobal($event.target.value, 'contains')"
+ class="table_global_filter">
+ <i class="fa fa-search" style="margin:4px 0 0 8px"></i>
+ </div>
+
+ <div class="table_title">
+ <h4><b>Microservice Instances</b></h4>
+ </div>
+ </div>
+
+ </ng-template>
+
+ <!--column headers-->
+ <ng-template pTemplate="header" let-columns>
+ <tr>
+ <th style="width: 3em"></th>
+ <th class="ui-state-highlight" *ngFor="let col of columns" style="outline: none; vertical-align: bottom; text-align: center;" [pSortableColumn]="col.field" [ngStyle]="{'width': col.width}">
+ {{col.header}}<br>
+ <p-sortIcon [field]="col.field" style="font-size: 8px;"></p-sortIcon>
+ </th>
+ <!--actions column-->
+ <th style="width: 7%;">
+ Actions
+ </th>
+ </tr>
+ <!--Second header row for individual column filters-->
+ <tr>
+ <th style="width: 3em"></th>
+ <th *ngFor="let col of columns" [ngSwitch]="col.field">
+ <input pInputText type="text" (input)="dt.filter($event.target.value, col.field, 'contains')" class="table_column_filter" placeholder="Filter">
+ </th>
+ <th>
+ <div style="text-align: center;">
+ <p-tableHeaderCheckbox style="padding-right: 5px;"></p-tableHeaderCheckbox>
+ <button pButton type="button" class="ui-button-secondary" (click)="checkCanGenerateBp()" [matMenuTriggerFor]="menu"
+ style="background-color: transparent; border: none; width: 20px; height: 20px; vertical-align: middle;">
+ <i class="pi pi-ellipsis-h" style="color: grey;"></i>
+ </button>
+ <mat-menu #menu="matMenu" xPosition="before">
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-plus"
+ style="font-size: 10px;"></i> Add</span>
+ </div>
+
+ <div matTooltip="{{generateSelectedBPsTooltip}}" [matTooltipDisabled]="canGenerateSelectedBPs" matTooltipPosition="left">
+ <button mat-menu-item (click)="generateSelectedBlueprints()" class="table_action_item" [disabled]="!canGenerateSelectedBPs" style="margin-top: 5px;">Generate Selected Blueprints</button>
+ </div>
+ </mat-menu>
+ </div>
+ </th>
+ </tr>
+ </ng-template>
+
+ <!--row data-->
+ <ng-template pTemplate="body" let-rowData let-expanded="expanded" let-msElem>
+ <tr>
+ <!--Column for row expand buttons-->
+ <td>
+ <a href="#" [pRowToggler]="rowData">
+ <i [ngClass]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'"></i>
+ </a>
+ </td>
+
+ <td *ngFor="let col of cols">
+ <div *ngIf="col.field==='status'"
+ style="width: fit-content; width: -moz-max-content; padding: 0px 5px 0px 5px; border-radius: 3px; font-weight: 600;" [ngClass]="{
+ 'greenStatus' : msElem[col.field] === 'DEV_COMPLETE' || msElem[col.field] === 'CERTIFIED' || msElem[col.field] === 'PROD_DEPLOYED',
+ 'blueStatus' : msElem[col.field] === 'NEW' || msElem[col.field] === 'IN_DEV' || msElem[col.field] === 'IN_TEST'}">
+ {{msElem[col.field]}}
+ </div>
+ <div *ngIf="col.field!=='status'">{{msElem[col.field]}}</div>
+ </td>
+
+ <td>
+ <div style="text-align: center">
+ <p-tableCheckbox [value]="rowData" style="padding-right: 5px;"></p-tableCheckbox>
+ <button pButton type="button" class="ui-button-secondary" [matMenuTriggerFor]="menu"
+ style="background-color: transparent; border: none; width: 20px; height: 20px; vertical-align: middle;">
+ <i class="pi pi-ellipsis-h" style="color: grey;"></i>
+ </button>
+ <mat-menu #menu="matMenu" xPosition="before">
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-plus" style="font-size: 10px;"></i> Add</span>
+ </div>
+ <!-- * * * * Add component spec * * * * -->
+ <button mat-menu-item class="table_action_item" (click)="showAddCSDialog(rowData)">Component Spec...</button>
+ <!-- * * * * Generate Blueprint * * * * -->
+ <div matTooltip="No Active Component Spec" [matTooltipDisabled]="rowData.activeSpec!==null" matTooltipPosition="left">
+ <button mat-menu-item class="table_action_item" (click)="generateBlueprints(rowData)" [disabled]="rowData.activeSpec===null">Generate Blueprint</button>
+ </div>
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-search" style="font-size: 10px;"></i> View</span>
+ </div>
+ <!-- * * * * Go to spec files table * * * * -->
+ <div matTooltip="No Component Specs" [matTooltipDisabled]="rowData.activeSpec!==null" matTooltipPosition="left">
+ <button mat-menu-item class="table_action_item" (click)="viewCompSpecs(rowData)" [disabled]="rowData.activeSpec===null">Component Specs</button>
+ </div>
+ <!-- * * * * Go to blueprints table * * * * -->
+ <button mat-menu-item class="table_action_item" (click)="viewBlueprints(rowData)" [disabled]="rowData.activeSpec===null">Blueprints</button>
+
+ <div style="background-color: rgba(128, 128, 128, 0.25);">
+ <span style="font-size: 12px; margin-left: 10px; font-weight: 500;"><i class="pi pi-pencil"></i> Update</span>
+ </div>
+ <!-- * * * * Update ms instance record * * * * -->
+ <button mat-menu-item class="table_action_item" (click)="showAddChangeDialog(rowData)">Update MS Instance...</button>
+ </mat-menu>
+ </div>
+ </td>
+ </tr>
+ </ng-template>
+
+ <!--Row expand content-->
+ <ng-template pTemplate="rowexpansion" let-rowData let-columns="columns">
+ <tr>
+ <td [attr.colspan]="columns.length + 2">
+ <div class="row-expand-layout" [@rowExpansionTrigger]="'active'">
+ <!-- Audit Fields -->
+ <div class="row-expand-card" style="background-color: rgba(95, 158, 160, 0.295);">
+ <b>Created By:</b> {{rowData.metadata.createdBy}}<br>
+ <b>Created On:</b> {{rowData.metadata.createdOn}}<br>
+ <b>Updated By:</b> {{rowData.metadata.updatedBy}}<br>
+ <b>Updated On:</b> {{rowData.metadata.updatedOn}}
+ </div>
+ <!-- People -->
+ <div class="row-expand-card" style="background-color: rgba(160, 159, 95, 0.295)">
+ <b>Scrum Lead: </b>{{rowData.metadata.scrumLead}}
+ <span *ngIf="rowData.metadata.scrumLeadId"> ({{rowData.metadata.scrumLeadId}})</span><br/>
+ <b>Systems Engineer: </b>{{rowData.metadata.systemsEngineer}}
+ <span *ngIf="rowData.metadata.systemsEngineerId"> ({{rowData.metadata.systemsEngineerId}})</span><br/>
+ <b>Developer: </b>{{rowData.metadata.developer}}
+ <span *ngIf="rowData.metadata.developerId"> ({{rowData.metadata.developerId}})</span>
+ </div>
+ <!-- Notes -->
+ <div class="row-expand-card" style="background-color: rgba(100, 148, 237, 0.295); white-space: pre-line;">
+ <b>Notes:</b><br>
+ <p-scrollPanel [style]="{width: '100%', height: '62px'}">
+ <div style="font-size: 12px; word-break: normal;">{{rowData.metadata.notes}}</div>
+ </p-scrollPanel>
+ </div>
+ <!-- Labels -->
+ <div class="row-expand-card" style="background-color: rgba(76, 65, 225, 0.295)">
+ <b style="padding-bottom: 5px;">Labels:</b><br>
+ <div *ngFor="let label of rowData['metadata']['labels']"
+ style="display: inline-flex; margin-top: 5px;">
+ <div style="padding: 2px 7px 3px 0px;">
+ <span style="background-color: rgba(80, 80, 80, 0.185); padding: 5px; border-radius: 3px;">{{label}}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </td>
+ </tr>
+ </ng-template>
+
+ </p-table>
+
+ <!--download buttons for exporting table to either csv or excel file-->
+ <div *ngIf="loadTable" class="table_export_buttons_alignment">
+ <button pButton type="button" class="table_export_button" (click)="exportTable('csv')" matTooltip="Export Table to CSV" matTooltipPosition="above" style="width: 55px;">
+ <i class="pi pi-file" style="margin-top: 3px; margin-left: 4px;"></i>
+ <label style="font-weight: 800; margin-top: 1px;">CSV</label>
+ </button>
+ <button pButton type="button" class="table_export_button" (click)="exportTable('excel')" matTooltip="Export Table to XLSX" matTooltipPosition="above" style="width: 65px; background-color: green;">
+ <i class="pi pi-file-excel" style="margin-top: 3px; margin-left: 4px;"></i>
+ <label style="font-weight: 800; margin-top: 1px">Excel</label>
+ </button>
+ </div>
+
+ <!-- Dialog to Change an MS Instance -->
+ <app-ms-instance-add *ngIf="showAddChangeMsInstance" [visible]="showAddChangeMsInstance" [msName]="msName" [msInstanceChange]="msInstanceChange" [currentRow]="currentRow" (handler)="addChangeMsInstance($event)"></app-ms-instance-add>
+
+ <!-- Dialog to Add a Component Spec -->
+ <app-comp-spec-add *ngIf="showCsAddDialog" [visible]="showCsAddDialog" (handler)="addNewCs($event)"></app-comp-spec-add>
+
+ <!--Pop-up for "Success" changing MS Instance-->
+ <p-toast key="changeSuccess"></p-toast>
+ <!--Pop-up for "Success" adding Component Spec-->
+ <p-toast key="compSpecAdded" [style]="{width: '400px'}"></p-toast>
+ <!--Pop-up for "Error" adding Component Spec-->
+ <p-toast class="toast-newline" key="errorOnCsAdd" [style]="{width: '700px'}"></p-toast>
+
+ <p-toast class="toast-newline" key="csViewError" [style]="{width: '700px'}"></p-toast>
+
+ <p-toast key="bpGenMessage" [style]="{width: '450px'}"></p-toast>
+
+</div> \ No newline at end of file
diff --git a/mod2/ui/src/app/msInstances/msInstances.component.spec.ts b/mod2/ui/src/app/msInstances/msInstances.component.spec.ts
new file mode 100644
index 0000000..5a26b58
--- /dev/null
+++ b/mod2/ui/src/app/msInstances/msInstances.component.spec.ts
@@ -0,0 +1,127 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatMenuModule, MatTooltipModule } from '@angular/material';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
+import { MessageService } from 'primeng/api';
+import { ButtonModule } from 'primeng/button';
+import { CalendarModule } from 'primeng/calendar';
+import { DialogModule } from 'primeng/dialog';
+import { DropdownModule } from 'primeng/dropdown';
+import { ScrollPanelModule } from 'primeng/scrollpanel';
+import { TableModule } from 'primeng/table';
+import { ToastModule } from 'primeng/toast';
+import { CompSpecAddComponent } from '../comp-spec-add/comp-spec-add.component';
+import { MsInstanceAddComponent } from '../ms-instance-add/ms-instance-add.component';
+
+import { MsInstancesComponent } from './msInstances.component';
+
+describe('MsInstancesComponent', () => {
+ let component: MsInstancesComponent;
+ let fixture: ComponentFixture<MsInstancesComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ MsInstancesComponent,
+ CompSpecAddComponent,
+ MsInstanceAddComponent
+ ],
+ imports: [
+ Ng4LoadingSpinnerModule,
+ TableModule,
+ MatMenuModule,
+ ScrollPanelModule,
+ ToastModule,
+ DialogModule,
+ DropdownModule,
+ FormsModule,
+ ReactiveFormsModule,
+ ButtonModule,
+ CalendarModule,
+ HttpClientTestingModule,
+ ToastModule,
+ RouterTestingModule,
+ MatTooltipModule
+ ],
+ providers: [
+ MessageService,
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MsInstancesComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it(`should fill msInstances Object`, () => {
+ const fixture = TestBed.createComponent(MsInstancesComponent);
+ const app = fixture.debugElement.componentInstance;
+
+ let mockMsInstance = [{
+ id: 'testId1234',
+ name: 'test-MS',
+ release: '2008',
+ version: '1.0.0',
+ status: 'New',
+ msInfo: {
+ id: 'testBaseMsId1234',
+ name: 'test Base Ms',
+ tag: 'test-MS-tag',
+ },
+ metadata: {
+ scrumLead: 'test',
+ scrumLeadId: 'testId',
+ systemsEngineer: 'test',
+ systemsEngineerId: 'testId',
+ developer: 'test',
+ developerId: 'testId',
+ pstDueDate: '01-01-2020 12:00',
+ pstDueIteration: '1.1',
+ eteDueDate: '01-01-2020 12:00',
+ eteDueIteration: '1.1',
+ createdBy: 'test',
+ createdOn: '01-01-2020 12:00',
+ updatedBy: 'test',
+ updatedOn: '01-01-2020 12:00',
+ notes: 'test',
+ labels: ['test'],
+ },
+ activeSpec: 'test'
+ }]
+
+ app.fillTable(mockMsInstance)
+
+ expect(app.loadTable).toEqual(true);
+ expect(app.msInstances.length).toEqual(1);
+ });
+});
diff --git a/mod2/ui/src/app/msInstances/msInstances.component.ts b/mod2/ui/src/app/msInstances/msInstances.component.ts
new file mode 100644
index 0000000..e011cb9
--- /dev/null
+++ b/mod2/ui/src/app/msInstances/msInstances.component.ts
@@ -0,0 +1,511 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
+import { MatTableDataSource } from '@angular/material/table';
+import { Table } from 'primeng/table';
+import { MessageService } from 'primeng/api';
+import { trigger, state, style, transition, animate } from '@angular/animations';
+import { MicroserviceInstanceService } from '../services/microservice-instance.service';
+import { DatePipe } from '@angular/common';
+import { DeploymentArtifactService } from '../services/deployment-artifact.service';
+import { CompSpecAddService } from '../services/comp-spec-add.service';
+import { BreadcrumbService } from '../services/breadcrumb.service';
+import { Router } from '@angular/router';
+import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner';
+import { DownloadService } from '../services/download.service';
+
+@Component({
+ selector: 'app-msInstances',
+ templateUrl: './msInstances.component.html',
+ styleUrls: ['./msInstances.component.css'],
+ animations: [
+ trigger('rowExpansionTrigger', [
+ state('void', style({
+ transform: 'translateX(-10%)',
+ opacity: 0
+ })),
+ state('active', style({
+ transform: 'translateX(0)',
+ opacity: 1
+ })),
+ transition('* <=> *', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)'))
+ ])
+ ],
+ providers: [DatePipe]
+})
+export class MsInstancesComponent implements OnInit {
+ @ViewChild(Table, { static: false }) dt: Table;
+ @ViewChild('myInput', { static: false }) myInputVariable: ElementRef;
+
+
+ /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
+ msInstances: msInstance[] = [];
+ expandedItems: Array<any> = new Array<any>();
+ dataSource = new MatTableDataSource<msInstance>(this.msInstances);
+ cols: any[] = [
+ { field: 'baseMsName', header: 'MS Name' },
+ { field: 'tag', header: 'MS Tag' },
+ { field: 'release', header: 'Release', width: '7%' },
+ { field: 'pstDueDate', header: 'PST Date', width: '9%' },
+ { field: 'pstDueIteration', header: 'PST Iteration', width: '6.5%' },
+ { field: 'eteDueDate', header: 'ETE Date', width: '9%' },
+ { field: 'eteDueIteration', header: 'ETE Iteration', width: '6.5%' },
+ { field: 'status', header: 'Status', width: '125px' }
+ ];
+ selectedMsInstances: msInstance[] = [];
+ columns: any[];
+ loadTable: boolean;
+ filteredRows: any;
+ downloadItems: { label: string; command: () => void; }[];
+ showAddChangeMsInstance: boolean;
+ currentRow: any;
+ msInstanceChange: string = "change";
+ generatedBPs: any[] = [];
+ canGenerateSelectedBPs: boolean = false;
+ generateSelectedBPsTooltip: string = '';
+
+ // Json to add CS (Component Spec) to DB, returned from child
+ csAddJson: any;
+
+ showCsAddDialog: boolean = false;
+
+ showViewCs: boolean =false;
+ msInstanceId: string = '';
+ errorList: string[];
+
+ constructor(private spinnerService: Ng4LoadingSpinnerService, private msInstanceApi: MicroserviceInstanceService,
+ private bpApis: DeploymentArtifactService, private addCsApi: CompSpecAddService, private messageService: MessageService,
+ private datePipe: DatePipe, private router: Router, private downloadService: DownloadService, private bread: BreadcrumbService) { }
+
+ ngOnInit() {
+
+ this.getAllInstances();
+
+ }
+
+ getAllInstances() {
+ this.spinnerService.show();
+ this.msInstances = [];
+ this.loadTable = false;
+
+ this.msInstanceApi.getAllMsInstances()
+ .subscribe((data: any[]) => {
+ this.fillTable(data)
+ })
+
+ this.columns = this.cols.map(col => ({ title: col.header, dataKey: col.field }));
+ }
+
+
+ // * * * * * Show the Dialog to Change an MS Instance (<app-ms-instance-add> tag in the html) * * * * *
+ showAddChangeDialog(rowData) {
+ this.msInstanceId = rowData['id']
+ this.showAddChangeMsInstance = true;
+ this.currentRow = rowData;
+ }
+
+ /* * * * Call API to Change an MS Instance * * * */
+ addChangeMsInstance(jsonFromChildDialog) {
+ if (jsonFromChildDialog === null) {
+ this.showAddChangeMsInstance = false;
+ } else {
+ this.msInstanceApi.addChangeMsInstance("CHANGE", this.msInstanceId, jsonFromChildDialog).subscribe(
+ (data) => {
+ this.updateCurrentRow(data);
+ this.messageService.add({ key: 'changeSuccess', severity: 'success', summary: 'Success', detail: "MS Instance Updated", life: 5000 });
+ this.showAddChangeMsInstance = false;
+ },
+ (errResponse) => {
+ if (errResponse.error.message) {
+ this.messageService.add({ key: 'instanceAddChangeError', severity: 'error', summary: 'Error', detail: errResponse.error.message, sticky: true });
+ } else {
+ this.messageService.add({ key: 'instanceAddChangeError', severity: 'error', summary: 'Error', detail: errResponse.error.status, sticky: true });
+ }
+ }
+ )
+ }
+ }
+
+ updateCurrentRow(responseData) {
+ const newRow = responseData;
+ this.currentRow['release'] = newRow['release'];
+ this.currentRow['metadata']['scrumLead'] = newRow['metadata']['scrumLead'];
+ this.currentRow['metadata']['scrumLeadId'] = newRow['metadata']['scrumLeadId'];
+ this.currentRow['metadata']['systemsEngineer'] = newRow['metadata']['systemsEngineer'];
+ this.currentRow['metadata']['systemsEngineerId'] = newRow['metadata']['systemsEngineerId'];
+ this.currentRow['metadata']['developer'] = newRow['metadata']['developer'];
+ this.currentRow['metadata']['developerId'] = newRow['metadata']['developerId'];
+ this.currentRow['pstDueDate'] = this.datePipe.transform(newRow['metadata']['pstDueDate'], 'yyyy-MM-dd');
+ this.currentRow['pstDueIteration'] = newRow['metadata']['pstDueIteration'];
+ this.currentRow['eteDueDate'] = this.datePipe.transform(newRow['metadata']['eteDueDate'], 'yyyy-MM-dd');
+ this.currentRow['eteDueIteration'] = newRow['metadata']['eteDueIteration'];
+ this.currentRow['metadata']['labels'] = newRow['metadata']['labels'];
+ this.currentRow['metadata']['notes'] = newRow['metadata']['notes'];
+ this.currentRow['metadata']['updatedBy'] = newRow['metadata']['updatedBy'];
+ this.currentRow['metadata']['updatedOn'] = this.datePipe.transform(newRow['metadata']['updatedOn'], 'MM-dd-yyyy HH:mm');
+ }
+
+ // * * * * * Show the Dialog to Add a CS (in the html) * * * * *
+ // * * * * * Store the MS Instance ID for the URL and the "current row" to update when a CS is saved * * * * *
+ showAddCSDialog(rowData) {
+ this.showCsAddDialog = true;
+ this.msInstanceId = rowData['id'];
+ this.currentRow = rowData;
+ }
+
+ // * * * * * Add a CS * * * * *
+ addNewCs(jsonFromChildDialog) {
+ let compSpecAddMessage = '';
+ if (jsonFromChildDialog) {
+ this.csAddJson = jsonFromChildDialog;
+ if((JSON.parse(this.csAddJson)).policyJson === null){
+ compSpecAddMessage = 'Component Spec Added';
+ } else {
+ console.log("here")
+ compSpecAddMessage = 'Component Spec and Policy added '
+ }
+
+ this.addCsApi.addCsToCatalog(this.msInstanceId, this.csAddJson).subscribe(
+ (response: any) => {
+ this.messageService.add({ key: 'compSpecAdded', severity: 'success', summary: 'Success', detail: compSpecAddMessage, life: 5000 });
+ this.showCsAddDialog = false;
+ this.currentRow['activeSpec'] = true;
+ },
+ errResponse => {
+ if (errResponse.error.errors) {
+ this.messageService.add({ key: 'errorOnCsAdd', severity: 'error', summary: errResponse.error.message, detail: errResponse.error.errors.join('\n'), sticky: true});
+ } else {
+ let summary = errResponse.error.status + " - " + errResponse.error.error;
+ this.messageService.add({ key: 'errorOnCsAdd', severity: 'error', summary: summary, detail: errResponse.error.message, sticky: true});
+ }
+ });
+ } else {
+ this.showCsAddDialog = false
+ };
+ }
+
+/* * * * View Component Specs
+msName: string;
+msRelease: string;
+ showViewCsDialog(data){
+ this.msInstanceId = data['id']
+ this.msName = data['name']
+ this.msRelease = data['release']
+ this.showViewCs = true;
+ }
+ csView(data){
+ if(data===null){
+ this.showViewCs = false
+ } else {
+ this.showViewCs = false
+ this.messageService.add({ key: 'csViewError', severity: 'error', summary: 'Error Message', detail: data.error.message, sticky: true });
+ }
+ }
+ * * * */
+
+ /* * * * Generate single blueprint * * * */
+ generateBlueprints(data){
+ this.bpApis.postBlueprint(data['id']).subscribe((response) => {
+ this.messageService.add({ key: 'bpGenMessage', severity: 'success', summary: 'Success Message', detail: 'Blueprint Generated', life: 5000 });
+ }, (errResponse) => {
+ this.messageService.add({ key: 'bpGenMessage', severity: 'error', summary: 'Error Message', detail: errResponse.error.message, life: 15000 });
+ })
+ }
+
+ /* * * * Check if generate selected blueprints button should be disabled and set tooltip message * * * */
+ checkCanGenerateBp() {
+ if (this.selectedMsInstances.length > 0) {
+
+ let noActiveSpecs: string[] = [];
+ let checkReleases: boolean = true;
+ let firstRelease = this.selectedMsInstances[0]['release'];
+ for (let elem of this.selectedMsInstances) {
+ if (elem.release !== firstRelease){
+ checkReleases = false
+ this.canGenerateSelectedBPs = false
+ this.generateSelectedBPsTooltip = 'Cannot Generate Blueprints For Different Releases'
+ break
+ }
+ if (elem.activeSpec === null) {
+ noActiveSpecs.push(elem.name)
+ this.generateSelectedBPsTooltip += elem.name
+ }
+ }
+
+ if (noActiveSpecs.length < 1 && checkReleases) {
+ this.canGenerateSelectedBPs = true
+ } else if (noActiveSpecs.length > 0 && checkReleases){
+ this.canGenerateSelectedBPs = false
+ this.generateSelectedBPsTooltip = 'No Active Specs For : '
+ let i: number = 1;
+ for (let elem of noActiveSpecs) {
+ if (i === noActiveSpecs.length) {
+ this.generateSelectedBPsTooltip += '{' + elem + '}'
+ } else {
+ this.generateSelectedBPsTooltip += '{' + elem + '}, '
+ }
+ i++
+ }
+ }
+ } else {
+ this.canGenerateSelectedBPs = false
+ this.generateSelectedBPsTooltip = "No Instances Selected"
+ }
+ }
+
+ /* * * * Generate multiple blueprint * * * */
+ successfulBpGens: number;
+ generateSelectedBlueprints(){
+ this.successfulBpGens = 0;
+ this.count = 0;
+ this.selectionLength = this.selectedMsInstances.length;
+
+ this.spinnerService.show();
+
+ (async () => {
+ for (let instance of this.selectedMsInstances) {
+ this.bpApis.postBlueprint(instance.id).subscribe((response) => {
+ this.bpGenSuccess()
+ }, (errResponse) => {
+ this.bpGenError(errResponse.error.message)
+ })
+ await timeout(1500);
+ }
+ })();
+
+ function timeout(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ }
+
+ this.selectedMsInstances = []
+ }
+
+ /* * * * For BP Gen Successes * * * */
+ selectionLength: number;
+ count: number;
+ bpGenSuccess(){
+ this.successfulBpGens++;
+ this.count++;
+ if (this.count === this.selectionLength){
+ if(this.successfulBpGens > 0){
+ this.messageService.add({ key: 'bpGenMessage', severity: 'success', summary: 'Success Message', detail: 'Blueprints Generated', life: 5000 });
+ this.spinnerService.hide()
+ }
+ }
+ }
+
+ /* * * * For BP Gen Errors * * * */
+ bpGenError(err){
+ this.count++;
+ if (this.count === this.selectionLength) {
+ if (this.successfulBpGens > 0) {
+ this.messageService.add({ key: 'bpGenMessage', severity: 'success', summary: 'Success Message', detail: 'Blueprints Generated', life: 5000 });
+ this.spinnerService.hide()
+ }
+ }
+ this.messageService.add({ key: 'bpGenMessage', severity: 'error', summary: 'Error Message', detail: err, life: 15000 });
+ }
+
+ /* * * * View the Blueprints for the selected MS Instance * * * */
+ viewBlueprints(rowData) {
+ this.router.navigate(["blueprints"], {queryParams:{tag: rowData['tag'], release:rowData['release'] }});
+ this.bread.setBreadcrumbs("Blueprints", "add");
+ }
+
+ /* * * * View the Component Spec for the selected MS Instance * * * */
+ viewCompSpecs(rowData) {
+ this.router.navigate(["CompSpecs"], { queryParams: { instanceId: rowData['id'] }});
+ this.bread.setBreadcrumbs("Component Specs", "add");
+ }
+
+ /* * * * Stores filtered data in new array * * * */
+ onTableFiltered(values) {
+ if (values) { this.filteredRows = values; }
+ else { this.filteredRows = this.msInstances; }
+ }
+
+ /* * * * Export ms instance table to excel or csv * * * */
+ exportTable(exportTo) {
+ let downloadElements: any[] = []
+
+ //labels array not handled well by excel download so converted them to a single string
+ for(let row of this.filteredRows){
+ let labels;
+ let notes;
+ if(exportTo === "excel"){
+ if(row.metadata.labels !== undefined){
+ labels = row.metadata.labels.join(",")
+ }
+ } else {
+ labels = row.metadata.labels
+ }
+
+ if (row.metadata.notes !== null && row.metadata.notes !== undefined && row.metadata.notes !== '') {
+ notes = encodeURI(row.metadata.notes).replace(/%20/g, " ").replace(/%0A/g, "\\n")
+ }
+
+ downloadElements.push({
+ MS_Name: row.name,
+ MS_Tag: row.tag,
+ Release: row.release,
+ PST_Due_Date: row.pstDueDate,
+ PST_Due_Iteration: row.pstDueIteration,
+ ETE_Due_Date: row.eteDueDate,
+ ETE_Due_Iteration: row.eteDueIteration,
+ Status: row.status,
+ Created_By: row.metadata.createdBy,
+ Created_On: row.metadata.createdOn,
+ Updated_By: row.metadata.updatedBy,
+ Updated_On: row.metadata.updatedOn,
+ Scrum_Lead: row.metadata.scrumLead,
+ Scrum_Lead_Id: row.metadata.scrumLeadId,
+ Systems_Engineer: row.metadata.systemsEngineer,
+ Systems_Engineer_Id: row.metadata.systemsEngineerId,
+ Developer: row.metadata.developer,
+ Developer_Id: row.metadata.developerId,
+ Notes: notes,
+ Labels: labels
+ })
+ }
+
+ let csvHeaders = [];
+
+ if (exportTo === "csv") {
+ csvHeaders = [
+ "MS_Name",
+ "MS_Tag",
+ "Release",
+ "PST_Due_Date",
+ "PST_Due_Iteration",
+ "ETE_Due_Date",
+ "ETE_Due_Iteration",
+ "Status",
+ "Created_By",
+ "Created_On",
+ "Updated_By",
+ "Updated_On",
+ "Scrum_Lead",
+ "Scrum_Lead_Id",
+ "Systems_Engineer",
+ "Systems_Engineer_Id",
+ "Developer",
+ "Developer_Id",
+ "Notes",
+ "Labels"
+ ];
+ }
+
+ this.downloadService.exportTableData(exportTo, downloadElements, csvHeaders)
+ }
+
+ /* * * * Fill ms instance table * * * */
+ fillTable(data) {
+
+ for (let elem of data) {
+
+ /* * * Now storing as dates (not strings) on DB, so need to convert old data (mm-dd-yyyy and m-d-yyyy) * * */
+ let pstDueDate: any;
+ if (elem.metadata.pstDueDate && (elem.metadata.pstDueDate.length <= 11 &&
+ elem.metadata.pstDueDate.length > 7)) {
+ pstDueDate = new Date(elem.metadata.pstDueDate.replace(/-/g, '/')) // dash is invalid date format, FF fails
+ pstDueDate = this.datePipe.transform(pstDueDate, 'yyyy-MM-dd')
+ } else if (elem.metadata.pstDueDate) {
+ pstDueDate = this.datePipe.transform(elem.metadata.pstDueDate, 'yyyy-MM-dd')
+ } else {
+ pstDueDate = elem.metadata.pstDueDate
+ }
+
+ let eteDueDate: any;
+ if (elem.metadata.eteDueDate && (elem.metadata.eteDueDate.length <= 11 &&
+ elem.metadata.eteDueDate.length > 7)) {
+ eteDueDate = new Date(elem.metadata.eteDueDate.replace(/-/g, '/')) // dash is invalid date format, FF fails
+ eteDueDate = this.datePipe.transform(eteDueDate, 'yyyy-MM-dd')
+ } else if (elem.metadata.eteDueDate) {
+ eteDueDate = this.datePipe.transform(elem.metadata.eteDueDate, 'yyyy-MM-dd')
+ } else {
+ eteDueDate = elem.metadata.eteDueDate
+ }
+
+ var tempElem: msInstance = {
+ id: elem.id,
+ name: elem.name,
+ tag: elem.msInfo.tag,
+ release: elem.release,
+ version: elem.version,
+ status: elem.status,
+ baseMsId: elem.msInfo.id,
+ baseMsName: elem.msInfo.name,
+ metadata: {
+ scrumLead: elem.metadata.scrumLead,
+ scrumLeadId: elem.metadata.scrumLeadId,
+ systemsEngineer: elem.metadata.systemsEngineer,
+ systemsEngineerId: elem.metadata.systemsEngineerId,
+ developer: elem.metadata.developer,
+ developerId: elem.metadata.developerId,
+ createdBy: elem.metadata.createdBy,
+ createdOn: this.datePipe.transform(elem.metadata.createdOn, 'MM-dd-yyyy HH:mm'),
+ updatedBy: elem.metadata.updatedBy,
+ updatedOn: this.datePipe.transform(elem.metadata.updatedOn, 'MM-dd-yyyy HH:mm'),
+ notes: elem.metadata.notes,
+ labels: elem.metadata.labels,
+ },
+ pstDueDate: pstDueDate,
+ pstDueIteration: elem.metadata.pstDueIteration,
+ eteDueDate: eteDueDate,
+ eteDueIteration: elem.metadata.eteDueIteration,
+ activeSpec: elem.activeSpec
+ }
+ this.msInstances.push(tempElem)
+ }
+
+ this.filteredRows = this.msInstances
+ this.loadTable = true;
+ this.spinnerService.hide()
+ }
+}
+
+export interface msInstance{
+ id: string,
+ name: string,
+ tag: string,
+ release: string,
+ version: string,
+ status: string,
+ baseMsId: string,
+ baseMsName: string ,
+ metadata: {
+ scrumLead: string,
+ scrumLeadId: string,
+ systemsEngineer: string,
+ systemsEngineerId: string,
+ developer: string,
+ developerId: string,
+ createdBy: string,
+ createdOn: string,
+ updatedBy: string,
+ updatedOn: string,
+ notes: string,
+ labels: string[],
+ }
+ pstDueDate: string,
+ pstDueIteration: string,
+ eteDueDate: string,
+ eteDueIteration: string,
+ activeSpec: any
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.css b/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.css
new file mode 100644
index 0000000..1130851
--- /dev/null
+++ b/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.css
@@ -0,0 +1,27 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+iframe{
+ padding-top: 0px;
+ border: none;
+}
+
+#content{
+ position:absolute;
+ left: 0; right: 0; bottom: 0; top: 0px;
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.html b/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.html
new file mode 100644
index 0000000..417ee39
--- /dev/null
+++ b/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.html
@@ -0,0 +1,23 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<ng4-loading-spinner id=loadingSpinner [timeout]="60000"></ng4-loading-spinner>
+<div id="content">
+ <iframe width="100%" height="98.5%" [src]="video | safe" onload="document.getElementById('loadingSpinner').style.display='none';"></iframe>
+</div>
+
diff --git a/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.spec.ts b/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.spec.ts
new file mode 100644
index 0000000..d88c06d
--- /dev/null
+++ b/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.spec.ts
@@ -0,0 +1,48 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
+import { SafePipe } from '../onboarding-tools/onboarding-tools.component';
+
+import { OnboardingToolsComponent } from './onboarding-tools.component';
+
+describe('OnboardingToolsComponent', () => {
+ let component: OnboardingToolsComponent;
+ let fixture: ComponentFixture<OnboardingToolsComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [OnboardingToolsComponent, SafePipe],
+ imports: [
+ Ng4LoadingSpinnerModule,
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(OnboardingToolsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.ts b/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.ts
new file mode 100644
index 0000000..d400120
--- /dev/null
+++ b/mod2/ui/src/app/onboarding-tools/onboarding-tools.component.ts
@@ -0,0 +1,52 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, ViewEncapsulation, ViewChild, ElementRef, PipeTransform, Pipe, OnInit } from '@angular/core';
+import { DomSanitizer } from "@angular/platform-browser";
+import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner';
+import { environment } from '../../environments/environment';
+
+@Pipe({ name: 'safe' })
+export class SafePipe implements PipeTransform {
+ constructor(private sanitizer: DomSanitizer) { }
+ transform(url) {
+ return this.sanitizer.bypassSecurityTrustResourceUrl(url);
+ }
+}
+
+@Component({
+ selector: 'app-onboarding-tools',
+ templateUrl: './onboarding-tools.component.html',
+ styleUrls: ['./onboarding-tools.component.css']
+})
+
+export class OnboardingToolsComponent implements OnInit {
+
+ title = 'Onboarding Tools';
+
+ //video: string = `http://${environment.api_baseURL}:30991/onboarding-toolbox/blueprint-generator`
+ video: string = 'http://dcae-onboarding-toolbox-fe.ecomp.idns.cip.att.com:30991/onboarding-toolbox/blueprint-generator'
+
+ constructor(private spinnerService: Ng4LoadingSpinnerService) {
+ this.spinnerService.show();
+ }
+
+ ngOnInit() {
+ }
+
+}
diff --git a/mod2/ui/src/app/register/register.component.css b/mod2/ui/src/app/register/register.component.css
new file mode 100644
index 0000000..730a52d
--- /dev/null
+++ b/mod2/ui/src/app/register/register.component.css
@@ -0,0 +1,18 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
diff --git a/mod2/ui/src/app/register/register.component.html b/mod2/ui/src/app/register/register.component.html
new file mode 100644
index 0000000..74f9347
--- /dev/null
+++ b/mod2/ui/src/app/register/register.component.html
@@ -0,0 +1,62 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<p-card header="Register a New User" [style]="{margin:'100px 200px 100px 200px'}" class="ui-card">
+ <hr class="line-break">
+ <form [formGroup]="form" class="p-5 bg-faded" style="margin-left: 250px;margin-bottom: 100px;">
+ <div class="ui-g ui-fluid">
+ <div class="ui-g-12 ui-md-6">
+ <div class="ui-inputgroup" >
+ <span class="ui-inputgroup-addon"><i class="pi pi-user" style="line-height: 1.25;"></i></span>
+ <input type="text" pInputText placeholder="ATT UID" formControlName="username" class="ui-inputtext">
+ </div>
+ </div>
+ </div>
+ <i *ngIf="form.get('username').errors && form.get('username').errors.minlength" style="width: 140px;margin-left: 20px;font-size: small;color: red;">username should be at least 5 characters</i>
+ <i *ngIf="form.get('username').errors && form.get('username').errors.maxlength" style="width: 140px;margin-left: 20px;font-size: small;color: red;">username should be at most 10 characters</i>
+ <div class="ui-g ui-fluid" >
+ <div class="ui-g-12 ui-md-6">
+ <div class="ui-inputgroup" >
+ <span class="ui-inputgroup-addon"><i class="pi pi-user" style="line-height: 1.25;"></i></span>
+ <input type="text" pInputText placeholder="Full Name" formControlName="fullName" class="ui-inputtext">
+ </div>
+ </div>
+ </div>
+ <div class="ui-g ui-fluid" >
+ <div class="ui-g-12 ui-md-6">
+ <div class="ui-inputgroup">
+ <button pButton type="button" icon="pi pi-refresh" class="ui-button-warn" (click)="generateNewPassword()" ></button>
+ <input type="text" pInputText formControlName="password" placeholder="Generate password" class="ui-inputtext">
+ </div>
+ </div>
+ </div>
+ <i *ngIf="form.get('password').errors && form.get('password').errors.minlength" style="width: 140px;margin-left: 20px;font-size: small;color: red;">password should be at least 6 characters</i>
+ <div class="ui-g ui-fluid" >
+ <div class="ui-g-12 ui-md-6">
+ <div class="ui-inputgroup" >
+ <span class="ui-inputgroup-addon"><i class="pi pi-users" style="line-height: 1.25; height: 1em;"></i></span>
+ <p-multiSelect [options]="rolesFromBackend" formControlName="roles" [showToggleAll]="true" [virtualScroll]="true" [filter]="false" [style]="{height:'3em'}" class="ui-multiselect"></p-multiSelect>
+ </div>
+ </div>
+ </div>
+ <p-footer class="text-left ui-g-12">
+ <button pButton type="button" class="ui-button-info" label="Cancel" (click)="cancel()" style="margin-right: .25em"></button>
+ <button pButton type="submit" class="ui-button-success" label="Register" [disabled]="!form.valid" (click)="submit()"></button>
+ </p-footer>
+ </form>
+</p-card>
diff --git a/mod2/ui/src/app/register/register.component.spec.ts b/mod2/ui/src/app/register/register.component.spec.ts
new file mode 100644
index 0000000..d05fcd1
--- /dev/null
+++ b/mod2/ui/src/app/register/register.component.spec.ts
@@ -0,0 +1,61 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { CardModule } from 'primeng/card';
+import { MultiSelectModule } from 'primeng/multiselect';
+
+import { RegisterComponent } from './register.component';
+
+describe('RegisterComponent', () => {
+ let component: RegisterComponent;
+ let fixture: ComponentFixture<RegisterComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [RegisterComponent],
+ imports: [
+ FormsModule,
+ ReactiveFormsModule,
+ MultiSelectModule,
+ CardModule,
+ HttpClientTestingModule,
+ RouterTestingModule
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RegisterComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/register/register.component.ts b/mod2/ui/src/app/register/register.component.ts
new file mode 100644
index 0000000..28b0677
--- /dev/null
+++ b/mod2/ui/src/app/register/register.component.ts
@@ -0,0 +1,99 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { AuthService } from '../services/auth.service';
+import { Router } from '@angular/router';
+import { User } from '../models/User';
+import { AuthResponse } from '../models/AuthResponse';
+import {SelectItem} from 'primeng/api';
+import { UserService } from '../services/user.service';
+
+@Component({
+ selector: 'app-register',
+ templateUrl: './register.component.html',
+ styleUrls: ['./register.component.css']
+})
+export class RegisterComponent implements OnInit {
+
+ user: User = {
+ username:'',
+ fullName:'',
+ password:'',
+ roles: []
+ };
+ form: FormGroup;
+ roleOptions: SelectItem[];
+ rolesFromBackend = [];
+
+ constructor(private fb: FormBuilder, private authService: AuthService, private router: Router, private userService: UserService) { }
+
+ ngOnInit() {
+ this.form = this.fb.group({
+ username: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(10)]],
+ fullName: ['', [Validators.required]],
+ password: ['', [Validators.required, Validators.minLength(6)]],
+ roles:['', [Validators.required]]
+ });
+ // this.roleOptions = [{label:'Admin', value:{name:'ROLE_ADMIN'}}, {label:'User', value:{name:'ROLE_USER'}}, {label:'ScrumLead', value:{name:'ROLE_SCRUMLEAD'}}, {label:'Developer', value:{name:'ROLE_DEVELOPER'}}, {label:'PST', value:{name:'ROLE_PST'}}, {label:'ETE', value:{name:'ROLE_ETE'}}, {label:'Ops', value:{name:'ROLE_OPS'}}];
+ this.userService.getRoles().subscribe(res=>{
+ Object.values(res).forEach(ele=>{
+ this.rolesFromBackend.push({label:ele.substring(5), value:ele});
+ });
+ });
+ }
+
+ generateNewPassword() {
+ this.form.value.password = '';
+ const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&';
+ var array = new Uint32Array(32);
+ window.crypto.getRandomValues(array);
+ for(let i=0;i<32;i++) {
+ const index = Math.floor(array[i] % chars.length);
+ this.form.value.password += chars.charAt(index);
+ }
+ this.form.patchValue({password: this.form.value.password});
+ }
+
+ cancel() {
+ const result = window.confirm("Are you sure to quit registering current user and go back to user management?");
+ if(result === true){
+ this.router.navigate(['/users']);
+ }
+ }
+
+ submit() {
+ this.user.fullName = this. form.value.fullName;
+ this.user.username = this.form.value.username;
+ this.user.password = this.form.value.password;
+ this.user.roles = this.form.value.roles;
+ console.log(this.user.roles);
+ this.authService.register(this.user)
+ .subscribe( (res: AuthResponse) => {
+ alert(res.message);
+ this.router.navigate(['/users']);
+ }, (err) => {
+ console.log(err);
+ alert(err.error.message);
+ this.form.reset();
+ }
+ );
+ }
+
+}
diff --git a/mod2/ui/src/app/reset-password/reset-password.component.css b/mod2/ui/src/app/reset-password/reset-password.component.css
new file mode 100644
index 0000000..730a52d
--- /dev/null
+++ b/mod2/ui/src/app/reset-password/reset-password.component.css
@@ -0,0 +1,18 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
diff --git a/mod2/ui/src/app/reset-password/reset-password.component.html b/mod2/ui/src/app/reset-password/reset-password.component.html
new file mode 100644
index 0000000..748216a
--- /dev/null
+++ b/mod2/ui/src/app/reset-password/reset-password.component.html
@@ -0,0 +1,64 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<p-card header="Password Reset" [style]="{margin:'100px 300px 500px 300px'}">
+ <hr class="line-break">
+ <form [formGroup]="form" (ngSubmit)="submit()" class="p-5 bg-faded" style="margin-left: 200px;margin-bottom: 100px;">
+ <div class="ui-g ui-fluid" >
+ <div class="ui-g-12 ui-md-4">
+ <div class="ui-inputgroup" >
+ <span class="ui-inputgroup-addon"><i class="pi pi-user" style="line-height: 1.25;"></i></span>
+ <input type="text" pInputText placeholder="User id" formControlName="id" >
+ </div>
+ </div>
+ </div>
+ <div *ngIf="!authService.isAdmin; else admin">
+ <div class="ui-g ui-fluid">
+ <div class="ui-g-12 ui-md-4">
+ <div class="ui-inputgroup" >
+ <span class="ui-inputgroup-addon"><i class="pi pi-key" style="line-height: 1.25;"></i></span>
+ <input type="text" pInputText placeholder="New Password" formControlName="newPassword">
+ </div>
+ </div>
+ </div>
+ <div class="ui-g ui-fluid">
+ <div class="ui-g-12 ui-md-4">
+ <div class="ui-inputgroup" >
+ <span class="ui-inputgroup-addon"><i class="pi pi-key" style="line-height: 1.25;"></i></span>
+ <input type="text" pInputText placeholder="Confirm Password" formControlName="confirm_newPassword">
+ </div>
+ </div>
+ </div>
+ </div>
+ <ng-template class="ui-g ui-fluid" #admin>
+ <div class="ui-g-12 ui-md-4">
+ <div class="ui-inputgroup">
+ <input type="text" pInputText formControlName="password" placeholder="generate password">
+ <button pButton type="button" icon="pi pi-refresh" class="ui-button-warn" (click)="generateNewPassword()" ></button>
+ </div>
+ </div>
+ </ng-template>
+ <p-footer class="text-left ui-g-12">
+ <button pButton type="button" class="ui-button-info" label="Cancel" (click)="cancel()" style="margin-right: .25em"></button>
+ <button pButton type="submit" class="ui-button-success" label="Login" [disabled]="!form.valid"></button>
+ </p-footer>
+ <div class="text-left ui-g-12">
+ <a routerLink="/register">Not a registered user? Click here to register now!</a>
+ </div>
+ </form>
+ </p-card>
diff --git a/mod2/ui/src/app/reset-password/reset-password.component.spec.ts b/mod2/ui/src/app/reset-password/reset-password.component.spec.ts
new file mode 100644
index 0000000..a26d90b
--- /dev/null
+++ b/mod2/ui/src/app/reset-password/reset-password.component.spec.ts
@@ -0,0 +1,58 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { CardModule } from 'primeng/card';
+
+import { ResetPasswordComponent } from './reset-password.component';
+
+describe('ResetPasswordComponent', () => {
+ let component: ResetPasswordComponent;
+ let fixture: ComponentFixture<ResetPasswordComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ResetPasswordComponent],
+ imports: [
+ FormsModule,
+ ReactiveFormsModule,
+ CardModule,
+ HttpClientTestingModule,
+ RouterTestingModule
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ResetPasswordComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/reset-password/reset-password.component.ts b/mod2/ui/src/app/reset-password/reset-password.component.ts
new file mode 100644
index 0000000..b704b40
--- /dev/null
+++ b/mod2/ui/src/app/reset-password/reset-password.component.ts
@@ -0,0 +1,78 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { AuthService } from '../services/auth.service';
+import { Router } from '@angular/router';
+import { User } from '../models/User';
+
+@Component({
+ selector: 'app-reset-password',
+ templateUrl: './reset-password.component.html',
+ styleUrls: ['./reset-password.component.css']
+})
+export class ResetPasswordComponent implements OnInit {
+
+ form: FormGroup;
+
+ constructor(private fb: FormBuilder, public authService: AuthService, private router: Router) { }
+
+ ngOnInit() {
+ this.form = this.fb.group({
+ id: ['', [Validators.required]],
+ password: '',
+ newPassword: '',
+ confirm_newPassword: ''
+ });
+ }
+
+ cancel() {
+ this.form.reset();
+ }
+
+ generateNewPassword() {
+ this.form.value.password = '';
+ let p = '';
+ const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&';
+ for(let i=1;i<12;i++) {
+ const index = Math.floor(Math.random() * chars.length + 1);
+ this.form.value.password += chars.charAt(index);
+ }
+ this.form.patchValue({password: this.form.value.password});
+ }
+
+ submit() {
+ const id = this.form.value.id;
+ if(!this.authService.isAdmin){
+ if(this.form.value.newPassword === this.form.value.confirm_newPassword){
+ const password = this.form.value.newPassword;
+ console.log(id);
+ console.log(password); // toJane: need to call user API
+ } else {
+ alert('Your passwords do not match, please re-confirm!');
+ this.form.patchValue({newPassword: '', confirm_newPassword: ''});
+ }
+ } else {
+ const password = this.form.value.password;
+ console.log(id);
+ console.log(password);// toJane: need to call user API
+ }
+}
+
+}
diff --git a/mod2/ui/src/app/services/auth.service.spec.ts b/mod2/ui/src/app/services/auth.service.spec.ts
new file mode 100644
index 0000000..eecc055
--- /dev/null
+++ b/mod2/ui/src/app/services/auth.service.spec.ts
@@ -0,0 +1,43 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { AuthService } from './auth.service';
+
+describe('AuthService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ],
+ imports: [
+ HttpClientTestingModule,
+ RouterTestingModule
+ ]
+ });
+ });
+ it('should be created', () => {
+ const service: AuthService = TestBed.get(AuthService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/auth.service.ts b/mod2/ui/src/app/services/auth.service.ts
new file mode 100644
index 0000000..49bb5f1
--- /dev/null
+++ b/mod2/ui/src/app/services/auth.service.ts
@@ -0,0 +1,95 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient, HttpHandler, HttpHeaders } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { tap } from 'rxjs/internal/operators';
+import { User } from '../models/User';
+import { JwtHelperService } from '@auth0/angular-jwt';
+import { AuthResponse } from '../models/AuthResponse';
+import { Router } from '@angular/router';
+import { environment } from '../../environments/environment';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthService{
+
+ private user: User = {
+ username: '',
+ roles:[]
+ };
+ authPass=false;
+ isAdmin=false;
+ reLoginMsg = false;
+
+ constructor(
+ private http:HttpClient,
+ private jwtHelper: JwtHelperService,
+ private router: Router
+ ) {
+
+ }
+
+ register(user: User): Observable<AuthResponse> {
+ return this.http.post<AuthResponse>(`http://${environment.api_baseURL}:31003/api/auth/signup`, user);
+ // return this.http.post<AuthResponse>(`http://localhost:8082/api/auth/signup`, user);
+
+ }
+
+ login(user: User): Observable<AuthResponse> {
+ return this.http.post<AuthResponse>(`http://${environment.api_baseURL}:31003/api/auth/signin`, user)
+ .pipe(
+ tap((res: AuthResponse) => {
+ localStorage.setItem('token', res.token);
+ this.setUser();
+ this.authPass = true;
+ })
+ );
+ }
+
+ setUser() {
+ this.user.username = this.jwtHelper.decodeToken(localStorage.getItem('token')).sub;
+ this.user.roles = this.jwtHelper.decodeToken(localStorage.getItem('token')).roles;
+ this.user.fullName = this.jwtHelper.decodeToken(localStorage.getItem('token')).fullName;
+
+ }
+
+ checkLogin(): Observable<boolean>{
+ return this.http.post<boolean>(`http://${environment.api_baseURL}:31003/api/auth/validate-token`, null);
+ }
+
+ getJwt() {
+ if(localStorage.getItem('token')){
+ return localStorage.getItem('token');
+ }
+ return "";
+ }
+
+ logout() {
+ localStorage.removeItem('token');
+ this.authPass = false;
+ this.router.navigate(['/login']);
+ }
+
+ getUser(): User {
+ return this.user;
+ }
+
+}
diff --git a/mod2/ui/src/app/services/base-microservice.service.spec.ts b/mod2/ui/src/app/services/base-microservice.service.spec.ts
new file mode 100644
index 0000000..1cef5bd
--- /dev/null
+++ b/mod2/ui/src/app/services/base-microservice.service.spec.ts
@@ -0,0 +1,42 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, TestBed } from '@angular/core/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { BaseMicroserviceService } from './base-microservice.service';
+
+describe('BaseMicroserviceService', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ HttpClientTestingModule,
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+
+ it('should be created', () => {
+ const service: BaseMicroserviceService = TestBed.get(BaseMicroserviceService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/base-microservice.service.ts b/mod2/ui/src/app/services/base-microservice.service.ts
new file mode 100644
index 0000000..a5c64b1
--- /dev/null
+++ b/mod2/ui/src/app/services/base-microservice.service.ts
@@ -0,0 +1,35 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { environment } from '../../environments/environment';
+import { HttpClient } from '@angular/common/http';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class BaseMicroserviceService {
+
+ private url: string = `http://${environment.api_baseURL}:31001/api/`;
+
+ constructor(private http: HttpClient) { }
+
+ getAllBaseMs() {
+ return this.http.get(this.url + "base-microservice");
+ }
+}
diff --git a/mod2/ui/src/app/services/breadcrumb.service.ts b/mod2/ui/src/app/services/breadcrumb.service.ts
new file mode 100644
index 0000000..aa647aa
--- /dev/null
+++ b/mod2/ui/src/app/services/breadcrumb.service.ts
@@ -0,0 +1,73 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { Observable, of, Subject, BehaviorSubject } from 'rxjs';
+
+@Injectable({
+ providedIn: 'root'
+})
+
+export class BreadcrumbService {
+
+ breadcrumbs: any[] = [];
+
+ breadcrumbs$: Subject<any[]> = new BehaviorSubject([]);
+
+ constructor() {
+ this.setBreadcrumbs('', "reset");
+ }
+
+ setBreadcrumbs(component: string, action: string) {
+ if (action == "reset") {
+ this.breadcrumbs = [];
+ this.breadcrumbs.push({ page: 'Home', link: '/home' });
+ }
+
+ // If the breadcrumb item is clicked, remove evwrything to the right of the clicked item
+ if (action == "crumbClicked") {
+ const pos = this.breadcrumbs.map(function(crumb) { return crumb.page }).indexOf(component);
+ for (1; this.breadcrumbs.length -1 -pos; 1) {
+ this.breadcrumbs.pop()
+ }
+ } else { // Add the component that was selected
+ if (component == 'Microservices') {
+ this.breadcrumbs.push({ page: 'Microservices', link: '/base-microservices' });
+ } else if (component == 'MS Instances') {
+ this.breadcrumbs.push({ page: 'MS Instances', link: '/ms-instances' });
+ } else if (component == 'Blueprints') {
+ this.breadcrumbs.push({ page: 'Blueprints', link: '/blueprints' });
+ } else if (component == 'Component Specs') {
+ this.breadcrumbs.push({ page: 'Component Specs', link: '/CompSpecs' });
+ } else if (component == 'User Management') {
+ this.breadcrumbs.push({ page: 'User Management', link: '/users' });
+ } else if (component == 'Onboarding Tools') {
+ this.breadcrumbs.push({ page: 'Onboarding Tools', link: '/OnboardingTools' });
+ } else if (component == 'Spec Validator') {
+ this.breadcrumbs.push({ page: 'Spec Validator', link: '/spec-validator' });
+ }
+ }
+ this.notifySubscriber()
+ }
+
+
+ notifySubscriber() {
+ this.breadcrumbs$.next(this.breadcrumbs);
+ }
+}
+
diff --git a/mod2/ui/src/app/services/comp-spec-add.service.spec.ts b/mod2/ui/src/app/services/comp-spec-add.service.spec.ts
new file mode 100644
index 0000000..f7f5913
--- /dev/null
+++ b/mod2/ui/src/app/services/comp-spec-add.service.spec.ts
@@ -0,0 +1,42 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, TestBed } from '@angular/core/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { CompSpecAddService } from './comp-spec-add.service';
+
+describe('CompSpecAddService', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ HttpClientTestingModule,
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+
+ it('should be created', () => {
+ const service: CompSpecAddService = TestBed.get(CompSpecAddService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/comp-spec-add.service.ts b/mod2/ui/src/app/services/comp-spec-add.service.ts
new file mode 100644
index 0000000..d269ac4
--- /dev/null
+++ b/mod2/ui/src/app/services/comp-spec-add.service.ts
@@ -0,0 +1,45 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { environment } from '../../environments/environment';
+import { Observable } from 'rxjs';
+
+@Injectable({
+ providedIn: 'root'
+})
+
+export class CompSpecAddService {
+
+ private URL: string = `http://${environment.api_baseURL}:31001/api/specification/`;
+
+ constructor(private http: HttpClient) { }
+
+ addCsToCatalog(msInstanceId: string, addCsJson: any): Observable<any> {
+ let url = this.URL + msInstanceId;
+ let body = addCsJson;
+ let headers = new HttpHeaders({
+ 'Content-Type': 'application/json'
+ });
+
+ let options = {headers:headers}
+ return this.http.post<any>(url, body, options);
+ }
+
+}
diff --git a/mod2/ui/src/app/services/comp-specs-service.service.spec.ts b/mod2/ui/src/app/services/comp-specs-service.service.spec.ts
new file mode 100644
index 0000000..58cf0a2
--- /dev/null
+++ b/mod2/ui/src/app/services/comp-specs-service.service.spec.ts
@@ -0,0 +1,43 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { compSpecsService } from './comp-specs-service.service';
+
+describe('CompSpecsServiceService', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ HttpClientTestingModule,
+ RouterTestingModule
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+ it('should be created', () => {
+ const service: compSpecsService = TestBed.get(compSpecsService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/comp-specs-service.service.ts b/mod2/ui/src/app/services/comp-specs-service.service.ts
new file mode 100644
index 0000000..6fcd92c
--- /dev/null
+++ b/mod2/ui/src/app/services/comp-specs-service.service.ts
@@ -0,0 +1,43 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { environment } from '../../environments/environment';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class compSpecsService {
+
+ private baseUrl: string = `http://${environment.api_baseURL}:31001/api/specification/`;
+ constructor(private http: HttpClient) {
+ }
+
+ getAllCompSpecs(instanceId) {
+ let url = this.baseUrl + instanceId
+
+ return this.http.get(url);
+ }
+
+ post(msId, body){
+ let url: string = this.baseUrl + msId
+
+ return this.http.post<any>(url, body)
+ }
+}
diff --git a/mod2/ui/src/app/services/deployment-artifact.service.spec.ts b/mod2/ui/src/app/services/deployment-artifact.service.spec.ts
new file mode 100644
index 0000000..f392732
--- /dev/null
+++ b/mod2/ui/src/app/services/deployment-artifact.service.spec.ts
@@ -0,0 +1,43 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { DeploymentArtifactService } from './deployment-artifact.service';
+
+describe('DeploymentArtifactService', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ HttpClientTestingModule,
+ RouterTestingModule
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+ it('should be created', () => {
+ const service: DeploymentArtifactService = TestBed.get(DeploymentArtifactService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/deployment-artifact.service.ts b/mod2/ui/src/app/services/deployment-artifact.service.ts
new file mode 100644
index 0000000..e344bff
--- /dev/null
+++ b/mod2/ui/src/app/services/deployment-artifact.service.ts
@@ -0,0 +1,71 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { environment } from '../../environments/environment';
+import { AuthService } from './auth.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DeploymentArtifactService {
+
+ private URL: string = `http://${environment.api_baseURL}:31001/api/deployment-artifact/`;
+ private username = this.authService.getUser().username;
+ private url_User = "?user=" + this.username;
+
+ constructor(private http: HttpClient, private authService: AuthService) { }
+
+ getAllBlueprints() {
+ return this.http.get(this.URL);
+ }
+
+ getStatuses() {
+ let url = this.URL + 'statuses'
+
+ return this.http.get(url)
+ }
+
+ patchBlueprintStatus(update, bpId){
+ let url = this.URL + bpId + "?user=" + this.username
+ let status: string = update
+ let body = {
+ status: status
+ }
+
+ return this.http.patch(url, body)
+ }
+
+ postBlueprint(instanceID: string){
+ let url = ''
+
+ url = this.URL + instanceID + "?user=" + this.username
+ console.log(url)
+
+ return this.http.post<any>(url, '')
+ }
+
+ deleteBlueprint(instanceID: string){
+ console.log(instanceID)
+ let url = this.URL + instanceID + this.url_User
+
+ return this.http.delete(url)
+ }
+
+}
diff --git a/mod2/ui/src/app/services/download.service.spec.ts b/mod2/ui/src/app/services/download.service.spec.ts
new file mode 100644
index 0000000..1df7bfd
--- /dev/null
+++ b/mod2/ui/src/app/services/download.service.spec.ts
@@ -0,0 +1,41 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, TestBed } from '@angular/core/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { DownloadService } from './download.service';
+
+describe('DownloadService', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ HttpClientTestingModule,
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+ it('should be created', () => {
+ const service: DownloadService = TestBed.get(DownloadService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/download.service.ts b/mod2/ui/src/app/services/download.service.ts
new file mode 100644
index 0000000..619eff7
--- /dev/null
+++ b/mod2/ui/src/app/services/download.service.ts
@@ -0,0 +1,85 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import * as saveAs from 'file-saver';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DownloadService {
+
+ constructor() { }
+
+ /* * * * Download json file * * * */
+ downloadJSON(content, fileName){
+ let file = new Blob([JSON.stringify(content)], { type: 'text;charset=utf-8' });
+ let name: string = `${fileName}.json`
+ saveAs(file, name)
+ }
+
+ /* * * * Export ms instance table to excel or csv * * * */
+ exportTableData(exportTo, downloadElements, arrHeader) {
+ if (exportTo === "excel") {
+ import("xlsx").then(xlsx => {
+ const worksheet = xlsx.utils.json_to_sheet(downloadElements);
+ const workbook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] };
+ const excelBuffer: any = xlsx.write(workbook, { bookType: 'xlsx', type: 'array' });
+ this.saveAsExcelFile(excelBuffer, "Table_Data");
+ });
+ } else if (exportTo === "csv") {
+ let csvData = this.convertToCSV(downloadElements, arrHeader)
+ var blob = new Blob([csvData], { type: 'text/csv' })
+ saveAs(blob, "Table_Data.csv");
+ }
+ }
+ saveAsExcelFile(buffer: any, fileName: string): void {
+ import("file-saver").then(FileSaver => {
+ let EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8';
+ let EXCEL_EXTENSION = '.xlsx';
+ const data: Blob = new Blob([buffer], {
+ type: EXCEL_TYPE
+ });
+ FileSaver.saveAs(data, fileName + '_export_' + new Date().getTime() + EXCEL_EXTENSION);
+ });
+ }
+ convertToCSV(objArray, headerList) {
+ let array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
+ let str = '';
+ let row = '';
+ for (let index in headerList) {
+ row += headerList[index] + ',';
+ }
+ row = row.slice(0, -1);
+ str += row + '\r\n';
+ for (let i = 0; i < array.length; i++) {
+ let line = '';
+ for (let index in headerList) {
+ let head = headerList[index];
+ if (array[i][head] === null || array[i][head] === undefined) {
+ line += ','
+ } else {
+ if (head === "Labels" && array[i][head].length > 1) { line += '[' + array[i][head].join('] [') + '],'; }
+ else { line += array[i][head] + ','; }
+ }
+ }
+ str += line + '\r\n';
+ }
+ return str;
+ }
+}
diff --git a/mod2/ui/src/app/services/global-filters.service.spec.ts b/mod2/ui/src/app/services/global-filters.service.spec.ts
new file mode 100644
index 0000000..cadfd3f
--- /dev/null
+++ b/mod2/ui/src/app/services/global-filters.service.spec.ts
@@ -0,0 +1,30 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { TestBed } from '@angular/core/testing';
+
+import { GlobalFiltersService } from './global-filters.service';
+
+describe('GlobalFiltersService', () => {
+ beforeEach(() => TestBed.configureTestingModule({}));
+
+ it('should be created', () => {
+ const service: GlobalFiltersService = TestBed.get(GlobalFiltersService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/global-filters.service.ts b/mod2/ui/src/app/services/global-filters.service.ts
new file mode 100644
index 0000000..0937f92
--- /dev/null
+++ b/mod2/ui/src/app/services/global-filters.service.ts
@@ -0,0 +1,55 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class GlobalFiltersService {
+
+ //global filter values
+ instanceName: string;
+ instanceTag: string;
+ release: string;
+ status: string;
+
+ shouldFilter: boolean = false;
+
+ constructor() { }
+
+ setFilters(filters){
+ this.instanceName = filters.instanceName
+ this.instanceTag = filters.instanceTag
+ this.release = filters.release
+ this.status = filters.status
+ }
+
+ getFilters(){
+ let globalFilters = {instanceName: this.instanceName, instanceTag: this.instanceTag, release: this.release, status: this.status}
+ return globalFilters
+ }
+
+ checkShouldFilter(){
+ return this.shouldFilter
+ }
+
+ setShouldFilter(){
+ this.shouldFilter = !this.shouldFilter
+ }
+}
diff --git a/mod2/ui/src/app/services/jwt-interceptor.service.spec.ts b/mod2/ui/src/app/services/jwt-interceptor.service.spec.ts
new file mode 100644
index 0000000..6fea9ba
--- /dev/null
+++ b/mod2/ui/src/app/services/jwt-interceptor.service.spec.ts
@@ -0,0 +1,30 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { TestBed } from '@angular/core/testing';
+
+import { JwtInterceptorService } from './jwt-interceptor.service';
+
+describe('JwtInterceptorService', () => {
+ beforeEach(() => TestBed.configureTestingModule({}));
+
+ it('should be created', () => {
+ const service: JwtInterceptorService = TestBed.get(JwtInterceptorService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/jwt-interceptor.service.ts b/mod2/ui/src/app/services/jwt-interceptor.service.ts
new file mode 100644
index 0000000..2647583
--- /dev/null
+++ b/mod2/ui/src/app/services/jwt-interceptor.service.ts
@@ -0,0 +1,40 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable, Injector } from '@angular/core';
+import { HttpInterceptor } from '@angular/common/http';
+import { AuthService } from './auth.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class JwtInterceptorService implements HttpInterceptor{
+
+ constructor(private injector: Injector) { }
+
+ intercept(req: import("@angular/common/http").HttpRequest<any>, next: import("@angular/common/http").HttpHandler): import("rxjs").Observable<import("@angular/common/http").HttpEvent<any>> {
+ let authService = this.injector.get(AuthService);
+ let jwtReq = req.clone({
+ setHeaders: {
+ Authorization: `Bearer ${authService.getJwt()}`
+ }
+ })
+ return next.handle(jwtReq);
+ }
+
+}
diff --git a/mod2/ui/src/app/services/microservice-instance.service.spec.ts b/mod2/ui/src/app/services/microservice-instance.service.spec.ts
new file mode 100644
index 0000000..b3c4074
--- /dev/null
+++ b/mod2/ui/src/app/services/microservice-instance.service.spec.ts
@@ -0,0 +1,41 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, TestBed } from '@angular/core/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { MicroserviceInstanceService } from './microservice-instance.service';
+
+describe('MicroserviceInstanceService', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ HttpClientTestingModule,
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+ it('should be created', () => {
+ const service: MicroserviceInstanceService = TestBed.get(MicroserviceInstanceService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/microservice-instance.service.ts b/mod2/ui/src/app/services/microservice-instance.service.ts
new file mode 100644
index 0000000..96cce77
--- /dev/null
+++ b/mod2/ui/src/app/services/microservice-instance.service.ts
@@ -0,0 +1,46 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { environment } from '../../environments/environment';
+import { HttpClient } from '@angular/common/http';
+import { AddMsInstance } from '../microservices/microservices.component';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class MicroserviceInstanceService {
+
+ private url: string = `http://${environment.api_baseURL}:31001/api/microservice-instance/`;
+
+ constructor(private http: HttpClient) { }
+
+ getAllMsInstances() {
+ return this.http.get(this.url);
+ }
+
+ addChangeMsInstance(addOrChange: string, msNameOrId: string, body: AddMsInstance){
+ let URL = this.url + msNameOrId
+
+ if (addOrChange == "ADD") {
+ return this.http.post<any>(URL, body);
+ } else {
+ return this.http.patch<any>(URL, body);
+ }
+ }
+}
diff --git a/mod2/ui/src/app/services/ms-add.service.spec.ts b/mod2/ui/src/app/services/ms-add.service.spec.ts
new file mode 100644
index 0000000..dc53a56
--- /dev/null
+++ b/mod2/ui/src/app/services/ms-add.service.spec.ts
@@ -0,0 +1,42 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, TestBed } from '@angular/core/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { MsAddService } from './ms-add.service';
+
+describe('MsAddService', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ HttpClientTestingModule,
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+
+ it('should be created', () => {
+ const service: MsAddService = TestBed.get(MsAddService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/ms-add.service.ts b/mod2/ui/src/app/services/ms-add.service.ts
new file mode 100644
index 0000000..367799d
--- /dev/null
+++ b/mod2/ui/src/app/services/ms-add.service.ts
@@ -0,0 +1,52 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { environment } from '../../environments/environment';
+import { Observable } from 'rxjs';
+
+@Injectable({
+ providedIn: 'root'
+})
+
+
+
+export class MsAddService {
+
+ private URL: string = `http://${environment.api_baseURL}:31001/api/base-microservice`;
+
+ constructor(private http: HttpClient) { }
+
+ addChangeMsToCatalog(addOrChange, msID, addChangeMsJson): Observable<any> {
+ let url = this.URL;
+ let headers = new HttpHeaders({'Content-Type': 'application/json'});
+ let options = {headers:headers};
+ let body;
+
+ body = addChangeMsJson;
+
+ if (addOrChange == "Add") {
+ return this.http.post<any>(url, body, options);
+ } else {
+ url = url + "/" + msID;
+ return this.http.patch<any>(url, body, options);
+ }
+ }
+
+}
diff --git a/mod2/ui/src/app/services/spec-validation.service.spec.ts b/mod2/ui/src/app/services/spec-validation.service.spec.ts
new file mode 100644
index 0000000..e83f832
--- /dev/null
+++ b/mod2/ui/src/app/services/spec-validation.service.spec.ts
@@ -0,0 +1,41 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, TestBed } from '@angular/core/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { SpecValidationService } from './spec-validation.service';
+
+describe('SpecValidationService', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ HttpClientTestingModule,
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+ it('should be created', () => {
+ const service: SpecValidationService = TestBed.get(SpecValidationService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/spec-validation.service.ts b/mod2/ui/src/app/services/spec-validation.service.ts
new file mode 100644
index 0000000..2785efe
--- /dev/null
+++ b/mod2/ui/src/app/services/spec-validation.service.ts
@@ -0,0 +1,53 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { environment } from '../../environments/environment';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class SpecValidationService {
+
+ private URL: string = 'http://zlecdyh2adcc1s2dokr04.1463c9.dyh2a.tci.att.com:31002/';
+
+ constructor(private http: HttpClient) { }
+
+ sendSpecFile(specContent, type, release){
+
+ let url = ''
+
+ if(release === "2007"){
+ url = `${this.URL}v6/api/comp_spec_validator/`
+ }
+
+ let body = {
+ compspec_content: specContent,
+ type: type
+ }
+
+ return this.http.post(url, body)
+ }
+
+ getSchema(type){
+ let url = `${this.URL}v6/api/schema/${type}`
+
+ return this.http.get(url)
+ }
+}
diff --git a/mod2/ui/src/app/services/user.service.spec.ts b/mod2/ui/src/app/services/user.service.spec.ts
new file mode 100644
index 0000000..979e9fa
--- /dev/null
+++ b/mod2/ui/src/app/services/user.service.spec.ts
@@ -0,0 +1,44 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, TestBed } from '@angular/core/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+
+import { UserService } from './user.service';
+
+describe('UserService', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ HttpClientTestingModule
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => TestBed.configureTestingModule({}));
+
+ it('should be created', () => {
+ const service: UserService = TestBed.get(UserService);
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/services/user.service.ts b/mod2/ui/src/app/services/user.service.ts
new file mode 100644
index 0000000..ec1d503
--- /dev/null
+++ b/mod2/ui/src/app/services/user.service.ts
@@ -0,0 +1,53 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { User } from '../models/User';
+import { AuthResponse } from '../models/AuthResponse';
+import { environment } from '../../environments/environment';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class UserService {
+
+ constructor(private http: HttpClient) {}
+
+ getUsers(): Observable<User[]> {
+ return this.http.get<User[]>(`http://${environment.api_baseURL}:31003/api/users/getAll`);
+ }
+
+ editUser(username: string, user: User): Observable<any>{
+ return this.http.patch<any>(`http://${environment.api_baseURL}:31003/api/users/admin/${username}`, user);
+ }
+
+ editProfile(username: string, user: User): Observable<any>{
+ return this.http.patch<any>(`http://${environment.api_baseURL}:31003/api/users/user/${username}`, user);
+ }
+
+ deleteUser(username: string): Observable<{message:string}> {
+ return this.http.delete<{message: string}>(`http://${environment.api_baseURL}:31003/api/users/${username}`);
+ }
+
+ getRoles() {
+ return this.http.get(`http://${environment.api_baseURL}:31003/api/roles`);
+ }
+
+}
diff --git a/mod2/ui/src/app/shared/shared-module.ts b/mod2/ui/src/app/shared/shared-module.ts
new file mode 100644
index 0000000..7ab21b6
--- /dev/null
+++ b/mod2/ui/src/app/shared/shared-module.ts
@@ -0,0 +1,61 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { NgModule } from '@angular/core';
+import {MatSelectModule} from '@angular/material/select';
+import { FormsModule } from '@angular/forms';
+import {MatTableModule} from '@angular/material/table';
+import { MatFormFieldModule, MatInputModule } from '@angular/material';
+import { MatPaginatorModule } from '@angular/material';
+//import { MatSort } from '@angular/material';
+import { MatToolbarModule, MatIconModule, MatSidenavModule, MatListModule, MatButtonModule } from '@angular/material';
+
+@NgModule({
+ declarations: [
+ ],
+ imports: [
+ MatSelectModule,
+ FormsModule,
+ MatToolbarModule,
+ MatIconModule,
+ MatSidenavModule,
+ MatListModule,
+ MatButtonModule,
+ MatTableModule,
+ MatPaginatorModule,
+ MatFormFieldModule,
+ MatInputModule
+ //MatSort
+
+ ],
+ exports: [
+ MatSelectModule,
+ FormsModule,
+ MatToolbarModule,
+ MatIconModule,
+ MatSidenavModule,
+ MatListModule,
+ MatButtonModule,
+ MatTableModule,
+ MatPaginatorModule,
+ MatFormFieldModule,
+ MatInputModule
+ // MatSort
+ ]
+ })
+ export class SharedModule { } \ No newline at end of file
diff --git a/mod2/ui/src/app/user-management/user-management.component.css b/mod2/ui/src/app/user-management/user-management.component.css
new file mode 100644
index 0000000..495d0f8
--- /dev/null
+++ b/mod2/ui/src/app/user-management/user-management.component.css
@@ -0,0 +1,54 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+.pi-trash:hover {
+ color:red;
+}
+.pi-pencil:hover {
+ color:blue;
+}
+
+label {
+ cursor: pointer;
+}
+
+.input{
+ padding-top: 10px;
+}
+
+.inputLabel {
+ font-weight: 600;
+ margin-left: 20px;
+ width: 140px;
+}
+
+.inputFieldSm {
+ width: 200px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldMed {
+ width: 300px;
+ height: 35px;
+ padding-left: 6px;
+}
+.inputFieldLg {
+ width: 400px;
+ height: 35px;
+ padding-left: 6px;
+} \ No newline at end of file
diff --git a/mod2/ui/src/app/user-management/user-management.component.html b/mod2/ui/src/app/user-management/user-management.component.html
new file mode 100644
index 0000000..6885fe1
--- /dev/null
+++ b/mod2/ui/src/app/user-management/user-management.component.html
@@ -0,0 +1,89 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<div style="margin: 0px 20px 10px 20px">
+ <p-table #dt [value]="users" [rowHover]="true">
+ <ng-template pTemplate="caption">
+ <h5><strong>System User List and Management</strong><i style="font-size: smaller;"> ( for admin only )</i></h5>
+ <br/>
+ <a routerLink="/register">Want to register a new user? Click here!</a>
+ </ng-template>
+ <ng-template pTemplate="header">
+ <tr>
+ <th style="width: 15%">Username (ATT UID)</th>
+ <th>Full Name</th>
+ <th>Roles</th>
+ <!-- <th>Active Status</th> -->
+ <th style="width: 15%">Actions</th>
+ </tr>
+ </ng-template>
+ <ng-template pTemplate="body" let-user>
+ <tr>
+ <td>{{user.username}}</td>
+ <td>{{user.fullName}}</td>
+ <td>{{user.roles}}</td>
+ <!-- <td>true</td> -->
+ <td>
+ <i class="pi pi-trash" (click)="handleDelete(user.username)" pTooltip="delete user" tooltipPosition="right"></i>
+ <i class="pi pi-pencil" (click)="handleEdit(user)" pTooltip="edit user" tooltipPosition="right" style="margin-left: .5em;"></i>
+ </td>
+ </tr>
+ </ng-template>
+ </p-table>
+
+ <!--edit user information dialog-->
+ <p-dialog [(visible)]="editUserFlag" appendTo="body" [modal]="true" [transitionOptions]="'300ms'" [style]="{width: '635px'}" [baseZIndex]="10000"
+ [closable]="true" (onHide)="closeEditDialog()">
+ <p-header style="display: inline-flex;">
+ Edit User Information
+ </p-header>
+
+ <form [formGroup]="editUserForm">
+ <!-- * * * Username * * * -->
+ <div class="input">
+ <label class="inputLabel">ATT UID</label>&nbsp;
+ <b>{{editUser.username}}</b>
+ </div>
+ <!-- * * * User Full Name * * * -->
+ <div class="input">
+ <label class="inputLabel">Full Name</label>&nbsp;
+ <input class="inputFieldSm" type="text" pInputText formControlName="fullName"/>
+ </div>
+ <!-- * * * Roles * * * -->
+ <div class="input">
+ <label class="inputLabel">Roles</label>&nbsp;
+ <p-multiSelect [options]="rolesFromBackend" formControlName="roles" [showToggleAll]="true" [virtualScroll]="true" [filter]="false" [style]="{height:'3.6em', width:'200px'}"></p-multiSelect>
+ <!-- <b>{{editUser.roles}}</b> -->
+ </div>
+ <!-- * * * Re-Generate Password * * * -->
+ <div class="input">
+ <div class="ui-inputgroup">
+ <label class="inputLabel">New Password</label>&nbsp;
+ <button pButton type="button" icon="pi pi-refresh" class="ui-button-warn" (click)="generateNewPassword()" ></button>
+ <input type="text" pInputText formControlName="password" placeholder="Generate password" class="ui-inputtext" pTooltip="Password should be greater than 5 characters" tooltipPosition="right">
+ </div>
+ </div>
+ <i *ngIf="editUserForm.get('password').errors && editUserForm.get('password').errors.minlength" style="width: 140px;margin-left: 20px;font-size: small;color: red;">password should be at least 6 characters</i>
+ <!-- * * * Submit and Cancel buttons * * * -->
+ <div style="margin-top: 2em; margin-left: 1.3em; margin-bottom: 2em;">
+ <button pButton type="button" (click)="closeEditDialog()" label="Cancel"></button>&nbsp;
+ <button pButton type="submit" (click)="submitEdit(editUser)" class="ui-button-success" label="Submit" style="width: 70px"></button>
+ </div>
+ </form>
+</p-dialog>
+</div> \ No newline at end of file
diff --git a/mod2/ui/src/app/user-management/user-management.component.spec.ts b/mod2/ui/src/app/user-management/user-management.component.spec.ts
new file mode 100644
index 0000000..2cb6a6e
--- /dev/null
+++ b/mod2/ui/src/app/user-management/user-management.component.spec.ts
@@ -0,0 +1,63 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { RouterTestingModule } from '@angular/router/testing';
+import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
+import { DialogModule } from 'primeng/dialog';
+import { MultiSelectModule } from 'primeng/multiselect';
+import { TableModule } from 'primeng/table';
+
+import { UserManagementComponent } from './user-management.component';
+
+describe('UserManagementComponent', () => {
+ let component: UserManagementComponent;
+ let fixture: ComponentFixture<UserManagementComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [UserManagementComponent],
+ imports: [
+ TableModule,
+ DialogModule,
+ MultiSelectModule,
+ FormsModule,
+ ReactiveFormsModule,
+ HttpClientTestingModule,
+ RouterTestingModule
+ ],
+ providers: [
+ { provide: JWT_OPTIONS, useValue: JWT_OPTIONS },
+ JwtHelperService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(UserManagementComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/mod2/ui/src/app/user-management/user-management.component.ts b/mod2/ui/src/app/user-management/user-management.component.ts
new file mode 100644
index 0000000..b7ee6e7
--- /dev/null
+++ b/mod2/ui/src/app/user-management/user-management.component.ts
@@ -0,0 +1,149 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import { Component, OnInit, ViewChild, ChangeDetectionStrategy } from '@angular/core';
+import { User } from '../models/User';
+import { UserService } from '../services/user.service';
+import { Router } from '@angular/router';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { SelectItem } from 'primeng/api';
+import { AuthService } from '../services/auth.service';
+
+@Component({
+ selector: 'app-user-management',
+ templateUrl: './user-management.component.html',
+ styleUrls: ['./user-management.component.css']
+})
+export class UserManagementComponent implements OnInit {
+
+ users: User[] = [];
+ editUser: User = {
+ username:'',
+ fullName:'',
+ roles: []
+ };
+ editUserFlag: boolean = false;
+ editUserForm: FormGroup;
+ rolesFromBackend = [];
+ selectedRoles : Array<String>= [];
+
+ constructor(private userService: UserService, private router: Router, private fb: FormBuilder, private authService: AuthService) { }
+
+ ngOnInit() {
+ this.userService.getUsers().subscribe((res: User[]) => {
+ this.users = res;
+ this.users.map(user=>{
+ let tempRoles = [];
+ user.roles.map(role=>{
+ tempRoles.push(role.name.substring(5));
+ });
+ user.roles = tempRoles;
+ });
+
+ });
+ this.editUserForm = this.fb.group({
+ username: '',
+ fullName: '',
+ password: [null, [ Validators.minLength(6)]],
+ roles: [this.selectedRoles, [Validators.required]]
+ });
+ this.userService.getRoles().subscribe(res=>{
+ Object.values(res).forEach(ele=>{
+ this.rolesFromBackend.push({label:ele.substring(5), value:ele});
+ });
+ });
+ }
+
+ handleDelete(username) {
+ const result = window.confirm('Are you sure to delete this user?');
+ if(result === true) {
+ this.userService.deleteUser(username).subscribe(res=>{
+ alert(res.message);
+ this.userService.getUsers().subscribe( r => {
+ this.users = r;
+ this.users.map(user=>{
+ let tempRoles = [];
+ user.roles.map(role=>{
+ tempRoles.push(role.name.substring(5));
+ });
+ user.roles = tempRoles;
+ });
+ });
+ });
+ }
+ }
+
+ handleEdit(user) {
+ this.selectedRoles = [];
+ this.editUserFlag = true;
+ this.editUser = user;
+ this.editUserForm.get('username').setValue(user.username);
+ this.editUserForm.get('fullName').setValue(user.fullName);
+ user.roles.map(ele => {
+ let temp = "ROLE_" + ele;
+ this.selectedRoles.push(temp);
+ })
+
+ this.editUserForm.get('roles').setValue(this.selectedRoles);
+
+ }
+
+ closeEditDialog() {
+ this.editUserForm.reset();
+ this.editUserFlag = false;
+ }
+
+ generateNewPassword() {
+ this.editUserForm.value.password = '';
+ const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&';
+ var array = new Uint32Array(32);
+ window.crypto.getRandomValues(array);
+ for(let i=0;i<32;i++) {
+ const index = Math.floor(array[i] % chars.length);
+ this.editUserForm.value.password += chars.charAt(index);
+ }
+ this.editUserForm.patchValue({password: this.editUserForm.value.password});
+ }
+
+ submitEdit(user) {
+ this.editUserFlag = false;
+ console.log(this.editUserForm.value.fullName);
+ let tempUser = this.editUserForm.value as User;
+ console.log(tempUser);
+ this.userService.editUser(user.username, this.editUserForm.value as User).subscribe(res=>{
+ alert("User information updated successfully.");
+ this.userService.getUsers().subscribe( r => {
+ this.users = r;
+ this.users.map(user=>{
+ let tempRoles = [];
+ user.roles.map(role=>{
+ tempRoles.push(role.name.substring(5));
+ });
+ user.roles = tempRoles;
+ });
+ }, (err)=>{
+ // alert(err.error.message);
+ alert("Sorry but your credentials are out of date. Please log in again to resolve this.");
+ this.authService.logout();
+ });
+ }, (err)=>{
+ alert(err.error.message);
+ });
+ }
+
+}
diff --git a/mod2/ui/src/assets/.gitkeep b/mod2/ui/src/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mod2/ui/src/assets/.gitkeep
diff --git a/mod2/ui/src/assets/env.js b/mod2/ui/src/assets/env.js
new file mode 100644
index 0000000..144ee8b
--- /dev/null
+++ b/mod2/ui/src/assets/env.js
@@ -0,0 +1,17 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */ \ No newline at end of file
diff --git a/mod2/ui/src/environments/environment.prod.ts b/mod2/ui/src/environments/environment.prod.ts
new file mode 100644
index 0000000..7edd870
--- /dev/null
+++ b/mod2/ui/src/environments/environment.prod.ts
@@ -0,0 +1,22 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+export const environment = {
+ production: true,
+ //api_baseURL: process.env.DCAE_HOSTNAME
+};
diff --git a/mod2/ui/src/environments/environment.ts b/mod2/ui/src/environments/environment.ts
new file mode 100644
index 0000000..1907c5e
--- /dev/null
+++ b/mod2/ui/src/environments/environment.ts
@@ -0,0 +1,35 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+// This file can be replaced during build by using the `fileReplacements` array.
+// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
+// The list of file replacements can be found in `angular.json`.
+
+export const environment = {
+ production: false,
+ api_baseURL: `${process.env.DCAE_HOSTNAME}`
+};
+
+/*
+ * For easier debugging in development mode, you can import the following file
+ * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
+ *
+ * This import should be commented out in production mode because it will have a negative impact
+ * on performance if an error is thrown.
+ */
+// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
diff --git a/mod2/ui/src/favicon.ico b/mod2/ui/src/favicon.ico
new file mode 100644
index 0000000..8081c7c
--- /dev/null
+++ b/mod2/ui/src/favicon.ico
Binary files differ
diff --git a/mod2/ui/src/index.html b/mod2/ui/src/index.html
new file mode 100644
index 0000000..f2836a8
--- /dev/null
+++ b/mod2/ui/src/index.html
@@ -0,0 +1,36 @@
+<!--
+ # ============LICENSE_START=======================================================
+ # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ # ================================================================================
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ # ============LICENSE_END=========================================================
+ -->
+
+<!doctype html>
+<html lang="en">
+<head>
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
+ <meta charset="utf-8">
+ <title>ModFe</title>
+ <base href="/">
+
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="icon" type="image/x-icon" href="favicon.ico">
+ <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
+ <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel=“stylesheet”>
+</head>
+<body>
+ <app-root></app-root>
+</body>
+</html>
diff --git a/mod2/ui/src/main.ts b/mod2/ui/src/main.ts
new file mode 100644
index 0000000..54bf0d7
--- /dev/null
+++ b/mod2/ui/src/main.ts
@@ -0,0 +1,31 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+import 'hammerjs';
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+ enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule)
+ .catch(err => console.error(err));
diff --git a/mod2/ui/src/polyfills.ts b/mod2/ui/src/polyfills.ts
new file mode 100644
index 0000000..20fe70e
--- /dev/null
+++ b/mod2/ui/src/polyfills.ts
@@ -0,0 +1,81 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ * file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/guide/browser-support
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js'; // Run `npm install --save classlist.js`.
+
+/**
+ * Web Animations `@angular/platform-browser/animations`
+ * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
+ * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
+ */
+// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+/**
+ * By default, zone.js will patch all possible macroTask and DomEvents
+ * user can disable parts of macroTask/DomEvents patch by setting following flags
+ * because those flags need to be set before `zone.js` being loaded, and webpack
+ * will put import in the top of bundle, so user need to create a separate file
+ * in this directory (for example: zone-flags.ts), and put the following flags
+ * into that file, and then add the following code before importing zone.js.
+ * import './zone-flags.ts';
+ *
+ * The flags allowed in zone-flags.ts are listed here.
+ *
+ * The following flags will work for all browsers.
+ *
+ * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
+ * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
+ * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
+ *
+ * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
+ * with the following flag, it will bypass `zone.js` patch for IE/Edge
+ *
+ * (window as any).__Zone_enable_cross_context_check = true;
+ *
+ */
+
+/***************************************************************************************************
+ * Zone JS is required by default for Angular itself.
+ */
+import 'zone.js/dist/zone'; // Included with Angular CLI.
+
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
diff --git a/mod2/ui/src/styles.css b/mod2/ui/src/styles.css
new file mode 100644
index 0000000..6a392de
--- /dev/null
+++ b/mod2/ui/src/styles.css
@@ -0,0 +1,33 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+@import "~@angular/material/prebuilt-themes/indigo-pink.css";
+@import "~bootstrap/dist/css/bootstrap.css";
+
+html,
+body {
+ height: 100%;
+ overflow: hidden;
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ margin: 0;
+ font-family: Roboto, "Helvetica Neue", sans-serif;
+} \ No newline at end of file
diff --git a/mod2/ui/src/test.ts b/mod2/ui/src/test.ts
new file mode 100644
index 0000000..ccff8e7
--- /dev/null
+++ b/mod2/ui/src/test.ts
@@ -0,0 +1,38 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/zone-testing';
+import { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+declare const require: any;
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/mod2/ui/tsconfig.app.json b/mod2/ui/tsconfig.app.json
new file mode 100644
index 0000000..c85ee27
--- /dev/null
+++ b/mod2/ui/tsconfig.app.json
@@ -0,0 +1,14 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/app",
+ "types": ["node"]
+ },
+ "include": [
+ "src/**/*.ts"
+ ],
+ "exclude": [
+ "src/test.ts",
+ "src/**/*.spec.ts"
+ ]
+}
diff --git a/mod2/ui/tsconfig.json b/mod2/ui/tsconfig.json
new file mode 100644
index 0000000..e65fbae
--- /dev/null
+++ b/mod2/ui/tsconfig.json
@@ -0,0 +1,33 @@
+{
+ "compileOnSave": false,
+ "include": [
+ "typings.d.ts"
+ ],
+ "exclude": [
+ "node_modules/@types/nodes/index.d.ts"
+ ],
+ "compilerOptions": {
+ "baseUrl": "./",
+ "outDir": "./dist/out-tsc",
+ "sourceMap": true,
+ "declaration": false,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "importHelpers": true,
+ "target": "es2015",
+ "types": [
+ "node",
+ "lodash",
+ "typings.d.ts"
+ ],
+ "typeRoots": [
+ "node_modules/@types"
+ ],
+ "lib": [
+ "es2018",
+ "dom"
+ ]
+ }
+}
diff --git a/mod2/ui/tsconfig.spec.json b/mod2/ui/tsconfig.spec.json
new file mode 100644
index 0000000..6400fde
--- /dev/null
+++ b/mod2/ui/tsconfig.spec.json
@@ -0,0 +1,18 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/spec",
+ "types": [
+ "jasmine",
+ "node"
+ ]
+ },
+ "files": [
+ "src/test.ts",
+ "src/polyfills.ts"
+ ],
+ "include": [
+ "src/**/*.spec.ts",
+ "src/**/*.d.ts"
+ ]
+}
diff --git a/mod2/ui/tslint.json b/mod2/ui/tslint.json
new file mode 100644
index 0000000..188bd78
--- /dev/null
+++ b/mod2/ui/tslint.json
@@ -0,0 +1,92 @@
+{
+ "extends": "tslint:recommended",
+ "rules": {
+ "array-type": false,
+ "arrow-parens": false,
+ "deprecation": {
+ "severity": "warn"
+ },
+ "component-class-suffix": true,
+ "contextual-lifecycle": true,
+ "directive-class-suffix": true,
+ "directive-selector": [
+ true,
+ "attribute",
+ "app",
+ "camelCase"
+ ],
+ "component-selector": [
+ true,
+ "element",
+ "app",
+ "kebab-case"
+ ],
+ "import-blacklist": [
+ true,
+ "rxjs/Rx"
+ ],
+ "interface-name": false,
+ "max-classes-per-file": false,
+ "max-line-length": [
+ true,
+ 140
+ ],
+ "member-access": false,
+ "member-ordering": [
+ true,
+ {
+ "order": [
+ "static-field",
+ "instance-field",
+ "static-method",
+ "instance-method"
+ ]
+ }
+ ],
+ "no-consecutive-blank-lines": false,
+ "no-console": [
+ true,
+ "debug",
+ "info",
+ "time",
+ "timeEnd",
+ "trace"
+ ],
+ "no-empty": false,
+ "no-inferrable-types": [
+ true,
+ "ignore-params"
+ ],
+ "no-non-null-assertion": true,
+ "no-redundant-jsdoc": true,
+ "no-switch-case-fall-through": true,
+ "no-use-before-declare": true,
+ "no-var-requires": false,
+ "object-literal-key-quotes": [
+ true,
+ "as-needed"
+ ],
+ "object-literal-sort-keys": false,
+ "ordered-imports": false,
+ "quotemark": [
+ true,
+ "single"
+ ],
+ "trailing-comma": false,
+ "no-conflicting-lifecycle": true,
+ "no-host-metadata-property": true,
+ "no-input-rename": true,
+ "no-inputs-metadata-property": true,
+ "no-output-native": true,
+ "no-output-on-prefix": true,
+ "no-output-rename": true,
+ "no-outputs-metadata-property": true,
+ "template-banana-in-box": true,
+ "template-no-negated-async": true,
+ "use-lifecycle-interface": true,
+ "use-pipe-transform-interface": true
+ },
+ "rulesDirectory": [
+ "codelyzer"
+ ]
+} \ No newline at end of file
diff --git a/mod2/ui/typings.d.ts b/mod2/ui/typings.d.ts
new file mode 100644
index 0000000..125f045
--- /dev/null
+++ b/mod2/ui/typings.d.ts
@@ -0,0 +1,32 @@
+/*
+ * # ============LICENSE_START=======================================================
+ * # Copyright (c) 2020 AT&T Intellectual Property. All rights reserved.
+ * # ================================================================================
+ * # Licensed under the Apache License, Version 2.0 (the "License");
+ * # you may not use this file except in compliance with the License.
+ * # You may obtain a copy of the License at
+ * #
+ * # http://www.apache.org/licenses/LICENSE-2.0
+ * #
+ * # Unless required by applicable law or agreed to in writing, software
+ * # distributed under the License is distributed on an "AS IS" BASIS,
+ * # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * # See the License for the specific language governing permissions and
+ * # limitations under the License.
+ * # ============LICENSE_END=========================================================
+ */
+
+declare var process: Process;
+
+interface GlobalEnvironment {
+ process: Process
+}
+
+interface Process {
+ env: Env
+}
+
+interface Env{
+ DCAE_HOSTNAME: string
+}
+
diff --git a/releases/1.5.1-blueprint-generator.yaml b/releases/1.5.1-blueprint-generator.yaml
new file mode 100644
index 0000000..ce7fa45
--- /dev/null
+++ b/releases/1.5.1-blueprint-generator.yaml
@@ -0,0 +1,4 @@
+distribution_type: 'maven'
+version: '1.5.1'
+project: 'dcaegen2/platform'
+log_dir: 'dcaegen2-platform-mod-bpgenerator-maven-stage-master/229'