Skip to content
Snippets Groups Projects
Commit 9b94e0cc authored by Riabokon Stanislav(EPAM)[GCP]'s avatar Riabokon Stanislav(EPAM)[GCP]
Browse files

Merge branch 'master' into integration-master

parents 7707790a 587925b2
No related branches found
No related tags found
1 merge request!68Integration tests for Google Cloud Run (GONRG-1016)
Showing
with 273 additions and 130 deletions
......@@ -38,3 +38,4 @@ build/
# Environment configuration
*.env
.envrc
......@@ -243,6 +243,7 @@ The following software have components provided under the terms of this license:
- Apache Groovy (from http://groovy-lang.org)
- Apache HttpAsyncClient (from http://hc.apache.org/httpcomponents-asyncclient)
- Apache HttpClient (from http://hc.apache.org/httpcomponents-client)
- Apache HttpClient Cache (from http://hc.apache.org/httpcomponents-client)
- Apache HttpCore (from http://hc.apache.org/httpcomponents-core-ga)
- Apache HttpCore NIO (from http://hc.apache.org/httpcomponents-core-ga)
- Apache Log4j API (from )
......@@ -897,8 +898,8 @@ The following software have components provided under the terms of this license:
- Microsoft Azure client library for KeyVault Secrets (from https://github.com/Azure/azure-sdk-for-java)
- Microsoft Azure common module for Storage (from https://github.com/Azure/azure-sdk-for-java)
- Mockito (from http://mockito.org)
- Mockito (from http://www.mockito.org)
- Mockito (from http://mockito.org)
- Mockito (from http://www.mockito.org)
- Netty/Codec/HTTP (from )
- Netty/Common (from )
- Plexus :: Default Container (from )
......
# This file contains the essential configs for the osdu on azure helm chart
global:
# Service(s) Replica Count
replicaCount: 2
################################################################################
# Specify the Gitlab branch being used for image creation
# ie: community.opengroup.org:5555/osdu/platform/security-and-compliance/legal/{{ .Values.global.branch }}/legal:latest
#
image:
repository: #{container-registry}#.azurecr.io
branch: #{ENVIRONMENT_NAME}#
tag: #{Build.SourceVersion}#
......@@ -66,42 +66,28 @@ spec:
- name: AZURE_CLIENT_ID
valueFrom:
secretKeyRef:
name: clientid
key: clientid
name: active-directory
key: principal-clientid
- name: AZURE_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: clientpassword
key: clientpassword
name: active-directory
key: principal-clientpassword
- name: AZURE_TENANT_ID
valueFrom:
configMapKeyRef:
name: osdu-svc-properties
key: ENV_TENANT_ID
secretKeyRef:
name: active-directory
key: tenantid
- name: aad_client_id
valueFrom:
secretKeyRef:
name: appid
key: appid
name: active-directory
key: application-appid
- name: appinsights_key
valueFrom:
secretKeyRef:
name: appinsights
name: central-logging
key: appinsights
- name: servicebus_namespace_name
valueFrom:
configMapKeyRef:
name: osdu-svc-properties
key: ENV_SERVICEBUS_NAMESPACE
- name: storage_account
valueFrom:
configMapKeyRef:
name: osdu-svc-properties
key: ENV_STORAGE_ACCOUNT
- name: azure_activedirectory_session_stateless
value: "true"
- name: azure_activedirectory_AppIdUri
value: "api://$(aad_client_id)"
- name: cosmosdb_database
value: osdu-db
- name: LOG_PREFIX
......@@ -118,5 +104,9 @@ spec:
value: http://entitlements-azure/entitlements/v1
- name: entitlements_service_api_key
value: "OBSOLETE"
- name: partition_service_endpoint
value: http://partition/api/partition/v1
- name: azure_istioauth_enabled
value: "true"
- name: azure_activedirectory_AppIdUri
value: "api://$(aad_client_id)"
# Copyright © Microsoft Corporation
#
# 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.
trigger:
batch: true
branches:
include:
- master
paths:
exclude:
- /**/*.md
- .gitignore
- /docs
- /provider/legal-aws
- /provider/legal-byoc
- /provider/legal-gcp
- /provider/legal-ibm
resources:
repositories:
- repository: FluxRepo
type: git
name: k8-gitops-manifests
- repository: TemplateRepo
type: git
name: infra-azure-provisioning
variables:
- group: 'Azure - OSDU'
- group: 'Azure - OSDU Secrets'
- name: serviceName
value: "legal"
- name: chartPath
value: "devops/azure/chart"
- name: valuesFile
value: "devops/azure/chart/helm-config.yaml"
- name: 'MANIFEST_REPO'
value: $[ resources.repositories['FluxRepo'].name ]
- name: SKIP_TESTS
value: 'false'
stages:
- template: /devops/build-stage.yml@TemplateRepo
parameters:
mavenGoal: 'package'
mavenPublishJUnitResults: true
serviceCoreMavenOptions: '-P legal-core'
mavenOptions: '-P legal-azure'
copyFileContents: |
pom.xml
provider/legal-azure/maven/settings.xml
provider/legal-azure/pom.xml
provider/legal-azure/target/*-spring-boot.jar
copyFileContentsToFlatten: ''
mavenSettingsFile: './maven/settings.xml'
serviceBase: ${{ variables.serviceName }}
testingRootFolder: 'testing'
chartPath: ${{ variables.chartPath }}
- template: /devops/deploy-stages.yml@TemplateRepo
parameters:
serviceName: ${{ variables.serviceName }}
chartPath: ${{ variables.chartPath }}
valuesFile: ${{ variables.valuesFile }}
testCoreMavenPomFile: 'testing/legal-test-core/pom.xml'
testCoreMavenOptions: '--settings $(System.DefaultWorkingDirectory)/drop/deploy/testing/maven/settings.xml'
skipDeploy: ${{ variables.SKIP_DEPLOY }}
skipTest: ${{ variables.SKIP_TESTS }}
providers:
- name: Azure
environments: ['dev']
# Copyright © Microsoft Corporation
#
# 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.
trigger:
batch: true
branches:
include:
- master
paths:
exclude:
- /**/*.md
- .gitignore
- /docs
- /provider/legal-aws
- /provider/legal-byoc
- /provider/legal-gcp
- /provider/legal-ibm
resources:
repositories:
- repository: FluxRepo
type: git
name: k8-gitops-manifests
- repository: TemplateRepo
type: git
name: infra-azure-provisioning
variables:
- group: 'Azure - OSDU'
- group: 'Azure - OSDU Secrets'
- name: serviceName
value: "legal"
- name: chartPath
value: "devops/azure/chart"
- name: valuesFile
value: "devops/azure/chart/helm-config.yaml"
- name: 'MANIFEST_REPO'
value: $[ resources.repositories['FluxRepo'].name ]
- name: SKIP_TESTS
value: 'false'
stages:
- template: /devops/build-stage.yml@TemplateRepo
parameters:
mavenGoal: 'package'
mavenPublishJUnitResults: true
serviceCoreMavenOptions: '-P legal-core'
mavenOptions: '-P legal-azure'
copyFileContents: |
pom.xml
provider/legal-azure/maven/settings.xml
provider/legal-azure/pom.xml
provider/legal-azure/target/*-spring-boot.jar
copyFileContentsToFlatten: ''
mavenSettingsFile: './maven/settings.xml'
serviceBase: ${{ variables.serviceName }}
testingRootFolder: 'testing'
chartPath: ${{ variables.chartPath }}
- template: /devops/deploy-stages.yml@TemplateRepo
parameters:
serviceName: ${{ variables.serviceName }}
chartPath: ${{ variables.chartPath }}
valuesFile: ${{ variables.valuesFile }}
testCoreMavenPomFile: 'testing/legal-test-core/pom.xml'
testCoreMavenOptions: '--settings $(System.DefaultWorkingDirectory)/drop/deploy/testing/maven/settings.xml'
skipDeploy: ${{ variables.SKIP_DEPLOY }}
skipTest: ${{ variables.SKIP_TESTS }}
providers:
- name: Azure
environments: ['demo']
......@@ -17,7 +17,7 @@
apiVersion: v1
kind: Service
metadata:
name: osdu-gitlab-legal
name: legal
namespace: osdu
spec:
type: ClusterIP
......@@ -26,7 +26,7 @@ spec:
port: 80
targetPort: 80
selector:
app: osdu-gitlab-legal
app: legal
---
# Source: legal/templates/deployment.yaml
# Copyright © Microsoft Corporation
......@@ -49,14 +49,14 @@ metadata:
name: osdu-gitlab-legal
namespace: osdu
spec:
replicas: 1
replicas: 2
selector:
matchLabels:
app: osdu-gitlab-legal
app: legal
template:
metadata:
labels:
app: osdu-gitlab-legal
app: legal
aadpodidbinding: osdu-identity
spec:
volumes:
......@@ -67,14 +67,14 @@ spec:
volumeAttributes:
secretProviderClass: azure-keyvault
containers:
- name: osdu-gitlab-legal
image: community.opengroup.org:5555/osdu/platform/security-and-compliance/legal/legal-master:latest
- name: legal
image: community.opengroup.org:5555/osdu/platform/security-and-compliance/legal/legal-trusted-partition-svc
imagePullPolicy: Always
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /entitlements/v1/swagger-ui.html
path: /api/legal/v1/swagger-ui.html
port: 80
volumeMounts:
- name: azure-keyvault
......@@ -97,42 +97,28 @@ spec:
- name: AZURE_CLIENT_ID
valueFrom:
secretKeyRef:
name: clientid
key: clientid
name: active-directory
key: principal-clientid
- name: AZURE_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: clientpassword
key: clientpassword
name: active-directory
key: principal-clientpassword
- name: AZURE_TENANT_ID
valueFrom:
configMapKeyRef:
name: osdu-svc-properties
key: ENV_TENANT_ID
secretKeyRef:
name: active-directory
key: tenantid
- name: aad_client_id
valueFrom:
secretKeyRef:
name: appid
key: appid
name: active-directory
key: application-appid
- name: appinsights_key
valueFrom:
secretKeyRef:
name: appinsights
name: central-logging
key: appinsights
- name: servicebus_namespace_name
valueFrom:
configMapKeyRef:
name: osdu-svc-properties
key: ENV_SERVICEBUS_NAMESPACE
- name: storage_account
valueFrom:
configMapKeyRef:
name: osdu-svc-properties
key: ENV_STORAGE_ACCOUNT
- name: azure_activedirectory_session_stateless
value: "true"
- name: azure_activedirectory_AppIdUri
value: "api://$(aad_client_id)"
- name: cosmosdb_database
value: osdu-db
- name: LOG_PREFIX
......@@ -149,3 +135,12 @@ spec:
value: http://entitlements-azure/entitlements/v1
- name: entitlements_service_api_key
value: "OBSOLETE"
- name: partition_service_endpoint
value: http://partition/api/partition/v1
# If Istio is enabled L#126 is true and L# 127-130 removed
- name: azure_istioauth_enabled
value: "false"
- name: azure_activedirectory_session_stateless
value: "true"
- name: azure_activedirectory_AppIdUri
value: "api://$(aad_client_id)"
......@@ -44,17 +44,17 @@ az keyvault secret show --vault-name $KEY_VAULT_NAME --name $KEY_VAULT_SECRET_NA
| `legal_service_region` | `us` | Legal service region | no | - |
| `entitlements_service_endpoint` | ex `https://foo-entitlements.azurewebsites.net` | Entitlements API endpoint | no | output of infrastructure deployment |
| `entitlements_service_api_key` | `********` | The API key clients will need to use when calling the service | yes | -- |
| `partition_service_endpoint` | ex `https://foo-partition.azurewebsites.net` | Partition Service API endpoint | no | output of infrastructure deployment |
| `azure.activedirectory.app-resource-id` | `********` | AAD client application ID | yes | output of infrastructure deployment |
| `LEGAL_HOSTNAME` | `notused` | Possibly unused | no | - |
| `CRON_JOB_IP` | `10.0.0.1` | Possibly unused | no | - |
| `azure.activedirectory.session-stateless` | `true` | Flag run in stateless mode (needed by AAD dependency) | no | -- |
| `aad_client_id` | `********` | AAD client application ID | yes | output of infrastructure deployment |
| `azure.activedirectory.AppIdUri` | `api://${azure.activedirectory.client-id}` | URI for AAD Application | no | -- |
| `cosmosdb_database` | ex `dev-osdu-r2-db` | Cosmos database for legal documents | no | output of infrastructure deployment |
| `storage_account` | ex `devintosdur2storage` | Storage account for legal documents | no | output of infrastructure deployment |
| `azure.storage.container-name` | ex `legal-service-azure-configuration` | Storage container for legal documents | no | output of infrastructure deployment |
| `azure.storage.enable-https` | `true` | Spring configuration for Azure Storage | no | - |
| `servicebus_topic_name` | `legaltags` | Topic for async messaging | no | output of infrastructure deployment |
| `servicebus_namespace_name` | ex `foo-sb-namespace` | Namespace for async messaging | no | output of infrastructure deployment |
| `KEYVAULT_URI` | ex `https://foo-keyvault.vault.azure.net/` | URI of KeyVault that holds application secrets | no | output of infrastructure deployment |
| `AZURE_CLIENT_ID` | `********` | Identity to run the service locally. This enables access to Azure resources. You only need this if running locally | yes | keyvault secret: `$KEYVAULT_URI/secrets/app-dev-sp-username` |
| `AZURE_TENANT_ID` | `********` | AD tenant to authenticate users from | yes | keyvault secret: `$KEYVAULT_URI/secrets/app-dev-sp-tenant-id` |
......@@ -90,27 +90,6 @@ Java version: 1.8.0_212, vendor: AdoptOpenJDK, runtime: /usr/lib/jvm/jdk8u212-b0
...
```
You may need to configure access to the remote maven repository that holds the OSDU dependencies. This file should live within `~/.m2/settings.xml`:
```bash
$ cat ~/.m2/settings.xml
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>os-core</id>
<username>mvn-pat</username>
<!-- Treat this auth token like a password. Do not share it with anyone, including Microsoft support. -->
<!-- The generated token expires on or before 11/14/2019 -->
<password>$PERSONAL_ACCESS_TOKEN_GOES_HERE</password>
</server>
</servers>
</settings>
```
_A settings file is also conveniently located in ./.mvn/community-maven.settings.xml which is also used for CI/CD processes._
### Build and run the application
After configuring your environment as specified above, you can follow these steps to build and run the application. These steps should be invoked from the *repository root.*
......
......@@ -40,6 +40,21 @@
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-core-common</artifactId>
<version>0.3.12</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</exclusion>
<exclusion>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</exclusion>
<exclusion>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.opengroup.osdu.legal</groupId>
......@@ -88,7 +103,7 @@
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>core-lib-azure</artifactId>
<version>0.0.29</version>
<version>0.0.33</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
......
......@@ -15,8 +15,10 @@
package org.opengroup.osdu.legal.azure.countries;
import javax.inject.Inject;
import javax.inject.Named;
import com.azure.storage.blob.BlobContainerClient;
import org.opengroup.osdu.azure.blobstorage.IBlobContainerClientFactory;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.legal.provider.interfaces.IStorageReader;
......@@ -27,13 +29,20 @@ import org.springframework.stereotype.Component;
public class StorageReaderFactoryImpl implements IStorageReaderFactory {
@Inject
private BlobContainerClient blobContainerClient;
private IBlobContainerClientFactory blobContainerClientFactory;
@Inject
private DpsHeaders headers;
@Inject
@Named("STORAGE_CONTAINER_NAME")
private String containerName;
@Inject
private JaxRsDpsLog logger;
@Override
public IStorageReader getReader(TenantInfo tenant, String projectRegion) {
return new StorageReaderImpl(tenant, projectRegion, blobContainerClient, logger);
return new StorageReaderImpl(tenant, projectRegion, blobContainerClientFactory.getClient(headers.getPartitionId(), containerName), logger);
}
}
......@@ -14,8 +14,6 @@
package org.opengroup.osdu.legal.azure.di;
import com.azure.security.keyvault.secrets.SecretClient;
import org.opengroup.osdu.azure.KeyVaultFacade;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
......@@ -25,18 +23,12 @@ import javax.inject.Named;
@Component
public class AzureBootstrapConfig {
@Value("${azure.storage.account-name}")
private String storageAccount;
@Value("${azure.storage.container-name}")
private String storageContainer;
@Value("${azure.servicebus.topic-name}")
private String serviceBusTopic;
@Value("${azure.servicebus.namespace-name}")
private String serviceBusNamespace;
@Value("${azure.cosmosdb.legal.collection}")
private String legalCollectionName;
......@@ -46,24 +38,12 @@ public class AzureBootstrapConfig {
@Value("${azure.cosmosdb.database}")
private String cosmosDBName;
@Bean
@Named("STORAGE_ACCOUNT_NAME")
public String storageAccount() {
return storageAccount;
}
@Bean
@Named("STORAGE_CONTAINER_NAME")
public String containerName() {
return storageContainer;
}
@Bean
@Named("SERVICE_BUS_NAMESPACE")
public String serviceBusNamespace() {
return serviceBusNamespace;
}
@Bean
@Named("SERVICE_BUS_TOPIC")
public String serviceBusTopic() {
......@@ -76,25 +56,13 @@ public class AzureBootstrapConfig {
return keyVaultURL;
}
@Bean
@Named("COSMOS_ENDPOINT")
public String cosmosEndpoint(SecretClient kv) {
return KeyVaultFacade.getSecretWithValidation(kv, "cosmos-endpoint");
}
@Bean
@Named("COSMOS_KEY")
public String cosmosKey(SecretClient kv) {
return KeyVaultFacade.getSecretWithValidation(kv, "cosmos-primary-key");
}
@Bean
public String cosmosDBName() {
return cosmosDBName;
}
@Bean
public String legalTagsContainer(){
public String legalTagsContainer() {
return legalCollectionName;
}
}
\ No newline at end of file
......@@ -17,27 +17,32 @@ package org.opengroup.osdu.legal.azure.jobs;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.microsoft.azure.servicebus.Message;
import com.microsoft.azure.servicebus.TopicClient;
import org.opengroup.osdu.azure.servicebus.ITopicClientFactory;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.model.legal.StatusChangedTags;
import org.opengroup.osdu.legal.provider.interfaces.ILegalTagPublisher;
import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import javax.inject.Named;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
@Component
public class LegalTagPublisherImpl implements ILegalTagPublisher {
@Inject
private TopicClient topicClient;
private ITopicClientFactory topicClientFactory;
@Inject
private JaxRsDpsLog logger;
@Inject
@Named("SERVICE_BUS_TOPIC")
private String serviceBusTopic;
@Override
public void publish(String projectId, DpsHeaders headers, StatusChangedTags tags) throws Exception {
Gson gson = new Gson();
......@@ -68,10 +73,8 @@ public class LegalTagPublisherImpl implements ILegalTagPublisher {
try {
logger.info("Storage publishes message " + headers.getCorrelationId());
topicClient.send(message);
}
catch (Exception e)
{
topicClientFactory.getClient(headers.getPartitionId(), serviceBusTopic).send(message);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
......
......@@ -18,7 +18,7 @@ import com.azure.cosmos.FeedOptions;
import com.azure.cosmos.SqlParameter;
import com.azure.cosmos.SqlParameterList;
import com.azure.cosmos.SqlQuerySpec;
import org.opengroup.osdu.azure.CosmosStore;
import org.opengroup.osdu.azure.cosmosdb.CosmosStore;
import org.opengroup.osdu.common.Validators;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.model.legal.ListLegalTagArgs;
......
......@@ -18,14 +18,19 @@ server.servlet.contextPath=/api/legal/v1/
REGION=${legal_service_region}
AUTHORIZE_API=${entitlements_service_endpoint}
AUTHORIZE_API_KEY=${entitlements_service_api_key}
# Partition Service configuration
PARTITION_API=${partition_service_endpoint}
azure.activedirectory.app-resource-id=${aad_client_id}
LEGAL_HOSTNAME=notused
CRON_JOB_IP=10.0.0.1
# Azure AD configuration for OpenIDConnect, commented below settings to disable AAD AuthN ,
# Uncomment it In the Istio AUTHN disabled Scenario
#azure.activedirectory.session-stateless=true
#azure.activedirectory.client-id=${aad_client_id}
#azure.activedirectory.AppIdUri=api://${azure.activedirectory.client-id}
#azure.activedirectory.session-stateless=true
# Istio Auth Enabled
azure.istio.auth.enabled=${azure_istioauth_enabled}
......@@ -35,13 +40,11 @@ azure.cosmosdb.database=${cosmosdb_database}
azure.cosmosdb.legal.collection=LegalTag
# Azure Blob Storage configuration
azure.storage.account-name=${storage_account}
azure.storage.container-name=legal-service-azure-configuration
azure.storage.enable-https=true
# Azure Service Bus configuration
azure.servicebus.topic-name=${servicebus_topic_name}
azure.servicebus.namespace-name=${servicebus_namespace_name}
# Azure KeyVault configuration
azure.keyvault.url=${KEYVAULT_URI}
......@@ -57,3 +60,4 @@ logging.slf4jlogger.enabled=true
#TenantFactory Configuration
tenantFactoryImpl.required=true
tenantInfo.container.name=TenantInfo
......@@ -31,7 +31,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.main.basedir>${project.basedir}</project.main.basedir>
<jackson.version>2.10.1</jackson.version>
<corelib.version>0.0.28</corelib.version>
<corelib.version>0.0.33</corelib.version>
</properties>
<dependencies>
<dependency>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment