Commit 900c1a91 authored by David Lam's avatar David Lam Committed by Greg Messner
Browse files

Health Check Api (#159)

* Added Health Check API support
parent 4c8b29ab
...@@ -139,6 +139,7 @@ The API has been broken up into sub APIs classes to make it easier to learn and ...@@ -139,6 +139,7 @@ The API has been broken up into sub APIs classes to make it easier to learn and
&nbsp;&nbsp;[DeployKeysApi](#deploykeysapi)<br/> &nbsp;&nbsp;[DeployKeysApi](#deploykeysapi)<br/>
&nbsp;&nbsp;[EventsApi](#eventsapi)<br/> &nbsp;&nbsp;[EventsApi](#eventsapi)<br/>
&nbsp;&nbsp;[GroupApi](#groupapi)<br/> &nbsp;&nbsp;[GroupApi](#groupapi)<br/>
&nbsp;&nbsp;[HealthCheckApi](#healthcheckapi)<br/>
&nbsp;&nbsp;[IssuesApi](#issuesapi)<br/> &nbsp;&nbsp;[IssuesApi](#issuesapi)<br/>
&nbsp;&nbsp;[JobApi](#jobapi)<br/> &nbsp;&nbsp;[JobApi](#jobapi)<br/>
&nbsp;&nbsp;[LabelsApi](#labelsapi)<br/> &nbsp;&nbsp;[LabelsApi](#labelsapi)<br/>
...@@ -191,6 +192,13 @@ List<Event> events = gitLabApi.getEventsApi().getAuthenticatedUserEvents(null, n ...@@ -191,6 +192,13 @@ List<Event> events = gitLabApi.getEventsApi().getAuthenticatedUserEvents(null, n
List<Group> groups = gitLabApi.getGroupApi().getGroups(); List<Group> groups = gitLabApi.getGroupApi().getGroups();
``` ```
#### HealthCheckApi
```java
// Get the liveness endpoint health check results.
// Assumes ip_whitelisted
LivenessHealthCheck healthCheck = gitLabApi.getHealthCheckApi().getLiveness();
```
#### IssuesApi #### IssuesApi
```java ```java
// Get a list of issues for the specified project ID // Get a list of issues for the specified project ID
......
...@@ -51,6 +51,7 @@ public class GitLabApi { ...@@ -51,6 +51,7 @@ public class GitLabApi {
private CommitsApi commitsApi; private CommitsApi commitsApi;
private DeployKeysApi deployKeysApi; private DeployKeysApi deployKeysApi;
private GroupApi groupApi; private GroupApi groupApi;
private HealthCheckApi healthCheckApi;
private IssuesApi issuesApi; private IssuesApi issuesApi;
private MergeRequestApi mergeRequestApi; private MergeRequestApi mergeRequestApi;
private MilestonesApi milestonesApi; private MilestonesApi milestonesApi;
...@@ -878,6 +879,25 @@ public class GitLabApi { ...@@ -878,6 +879,25 @@ public class GitLabApi {
return (groupApi); return (groupApi);
} }
/**
* Gets the HealthCheckApi instance owned by this GitLabApi instance. The HealthCheckApi is used
* to perform all admin level gitlab health monitoring.
*
* @return the HealthCheckApi instance owned by this GitLabApi instance
*/
public HealthCheckApi getHealthCheckApi() {
if (healthCheckApi == null) {
synchronized (this) {
if (healthCheckApi == null) {
healthCheckApi = new HealthCheckApi(this);
}
}
}
return (healthCheckApi);
}
/** /**
* Gets the IssuesApi instance owned by this GitLabApi instance. The IssuesApi is used * Gets the IssuesApi instance owned by this GitLabApi instance. The IssuesApi is used
* to perform all iossue related API calls. * to perform all iossue related API calls.
......
...@@ -54,6 +54,7 @@ public class GitLabApiClient { ...@@ -54,6 +54,7 @@ public class GitLabApiClient {
private ClientConfig clientConfig; private ClientConfig clientConfig;
private Client apiClient; private Client apiClient;
private String baseUrl;
private String hostUrl; private String hostUrl;
private TokenType tokenType = TokenType.PRIVATE; private TokenType tokenType = TokenType.PRIVATE;
private String authToken; private String authToken;
...@@ -91,7 +92,7 @@ public class GitLabApiClient { ...@@ -91,7 +92,7 @@ public class GitLabApiClient {
/** /**
* Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified * Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified
* server URL, private token, and secret token. * server URL, private token, and secret token.
* *
* @param hostUrl the URL to the GitLab API server * @param hostUrl the URL to the GitLab API server
* @param privateToken the private token to authenticate with * @param privateToken the private token to authenticate with
*/ */
...@@ -102,7 +103,7 @@ public class GitLabApiClient { ...@@ -102,7 +103,7 @@ public class GitLabApiClient {
/** /**
* Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified * Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified
* server URL, private token, and secret token. * server URL, private token, and secret token.
* *
* @param hostUrl the URL to the GitLab API server * @param hostUrl the URL to the GitLab API server
* @param tokenType the type of auth the token is for, PRIVATE or ACCESS * @param tokenType the type of auth the token is for, PRIVATE or ACCESS
* @param authToken the token to authenticate with * @param authToken the token to authenticate with
...@@ -141,7 +142,7 @@ public class GitLabApiClient { ...@@ -141,7 +142,7 @@ public class GitLabApiClient {
/** /**
* Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified * Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified
* server URL, private token, and secret token. * server URL, private token, and secret token.
* *
* @param hostUrl the URL to the GitLab API server * @param hostUrl the URL to the GitLab API server
* @param privateToken the private token to authenticate with * @param privateToken the private token to authenticate with
* @param secretToken use this token to validate received payloads * @param secretToken use this token to validate received payloads
...@@ -153,7 +154,7 @@ public class GitLabApiClient { ...@@ -153,7 +154,7 @@ public class GitLabApiClient {
/** /**
* Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified * Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified
* server URL, private token, and secret token. * server URL, private token, and secret token.
* *
* @param hostUrl the URL to the GitLab API server * @param hostUrl the URL to the GitLab API server
* @param tokenType the type of auth the token is for, PRIVATE or ACCESS * @param tokenType the type of auth the token is for, PRIVATE or ACCESS
* @param authToken the token to authenticate with * @param authToken the token to authenticate with
...@@ -166,7 +167,7 @@ public class GitLabApiClient { ...@@ -166,7 +167,7 @@ public class GitLabApiClient {
/** /**
* Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified * Construct an instance to communicate with a GitLab API server using GitLab API version 4, and the specified
* server URL and private token. * server URL and private token.
* *
* @param hostUrl the URL to the GitLab API server * @param hostUrl the URL to the GitLab API server
* @param privateToken the private token to authenticate with * @param privateToken the private token to authenticate with
* @param secretToken use this token to validate received payloads * @param secretToken use this token to validate received payloads
...@@ -177,7 +178,7 @@ public class GitLabApiClient { ...@@ -177,7 +178,7 @@ public class GitLabApiClient {
} }
/** /**
* Construct an instance to communicate with a GitLab API server using the specified GitLab API version, * Construct an instance to communicate with a GitLab API server using the specified GitLab API version,
* server URL and private token. * server URL and private token.
* *
* @param apiVersion the ApiVersion specifying which version of the API to use * @param apiVersion the ApiVersion specifying which version of the API to use
...@@ -191,7 +192,7 @@ public class GitLabApiClient { ...@@ -191,7 +192,7 @@ public class GitLabApiClient {
} }
/** /**
* Construct an instance to communicate with a GitLab API server using the specified GitLab API version, * Construct an instance to communicate with a GitLab API server using the specified GitLab API version,
* server URL and private token. * server URL and private token.
* *
* @param apiVersion the ApiVersion specifying which version of the API to use * @param apiVersion the ApiVersion specifying which version of the API to use
...@@ -205,6 +206,7 @@ public class GitLabApiClient { ...@@ -205,6 +206,7 @@ public class GitLabApiClient {
// Remove the trailing "/" from the hostUrl if present // Remove the trailing "/" from the hostUrl if present
this.hostUrl = (hostUrl.endsWith("/") ? hostUrl.replaceAll("/$", "") : hostUrl); this.hostUrl = (hostUrl.endsWith("/") ? hostUrl.replaceAll("/$", "") : hostUrl);
this.baseUrl = this.hostUrl;
if (ApiVersion.OAUTH2_CLIENT != apiVersion) { if (ApiVersion.OAUTH2_CLIENT != apiVersion) {
this.hostUrl += apiVersion.getApiNamespace(); this.hostUrl += apiVersion.getApiNamespace();
} }
...@@ -265,7 +267,6 @@ public class GitLabApiClient { ...@@ -265,7 +267,6 @@ public class GitLabApiClient {
/** /**
* Set the ID of the user to sudo as. * Set the ID of the user to sudo as.
* *
* @param sudoAsId the ID of the user to sudo as
*/ */
Integer getSudoAsId() { Integer getSudoAsId() {
return (sudoAsId); return (sudoAsId);
...@@ -282,29 +283,44 @@ public class GitLabApiClient { ...@@ -282,29 +283,44 @@ public class GitLabApiClient {
/** /**
* Construct a REST URL with the specified path arguments. * Construct a REST URL with the specified path arguments.
* *
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
* @return a REST URL with the specified path arguments * @return a REST URL with the specified path arguments
* @throws IOException if an error occurs while constructing the URL * @throws IOException if an error occurs while constructing the URL
*/ */
protected URL getApiUrl(Object... pathArgs) throws IOException { protected URL getApiUrl(Object... pathArgs) throws IOException {
String url = appendPathArgs(this.hostUrl, pathArgs);
return (new URL(url));
}
/**
* Construct a REST URL with the specified path arguments using
* Gitlab base url.
*
* @param pathArgs variable list of arguments used to build the URI
* @return a REST URL with the specified path arguments
* @throws IOException if an error occurs while constructing the URL
*/
protected URL getUrlWithBase(Object... pathArgs) throws IOException {
String url = appendPathArgs(this.baseUrl, pathArgs);
return (new URL(url));
}
StringBuilder url = new StringBuilder(); private String appendPathArgs(String url, Object... pathArgs) {
url.append(hostUrl); StringBuilder urlBuilder = new StringBuilder(url);
for (Object pathArg : pathArgs) { for (Object pathArg : pathArgs) {
if (pathArg != null) { if (pathArg != null) {
url.append("/"); urlBuilder.append("/");
url.append(pathArg.toString()); urlBuilder.append(pathArg.toString());
} }
} }
return urlBuilder.toString();
return (new URL(url.toString()));
} }
/** /**
* Validates the secret token (X-GitLab-Token) header against the expected secret token, returns true if valid, * Validates the secret token (X-GitLab-Token) header against the expected secret token, returns true if valid,
* otherwise returns false. * otherwise returns false.
* *
* @param response the Response instance sent from the GitLab server * @param response the Response instance sent from the GitLab server
* @return true if the response's secret token is valid, otherwise returns false * @return true if the response's secret token is valid, otherwise returns false
*/ */
...@@ -323,7 +339,7 @@ public class GitLabApiClient { ...@@ -323,7 +339,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP GET call with the specified query parameters and path objects, returning * Perform an HTTP GET call with the specified query parameters and path objects, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
* *
* @param queryParams multivalue map of request parameters * @param queryParams multivalue map of request parameters
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
...@@ -337,7 +353,7 @@ public class GitLabApiClient { ...@@ -337,7 +353,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP GET call with the specified query parameters and URL, returning * Perform an HTTP GET call with the specified query parameters and URL, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
* *
* @param queryParams multivalue map of request parameters * @param queryParams multivalue map of request parameters
* @param url the fully formed path to the GitLab API endpoint * @param url the fully formed path to the GitLab API endpoint
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
...@@ -349,7 +365,7 @@ public class GitLabApiClient { ...@@ -349,7 +365,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP GET call with the specified query parameters and path objects, returning * Perform an HTTP GET call with the specified query parameters and path objects, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
* *
* @param queryParams multivalue map of request parameters * @param queryParams multivalue map of request parameters
* @param accepts if non-empty will set the Accepts header to this value * @param accepts if non-empty will set the Accepts header to this value
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
...@@ -364,7 +380,7 @@ public class GitLabApiClient { ...@@ -364,7 +380,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP GET call with the specified query parameters and URL, returning * Perform an HTTP GET call with the specified query parameters and URL, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
* *
* @param queryParams multivalue map of request parameters * @param queryParams multivalue map of request parameters
* @param url the fully formed path to the GitLab API endpoint * @param url the fully formed path to the GitLab API endpoint
* @param accepts if non-empty will set the Accepts header to this value * @param accepts if non-empty will set the Accepts header to this value
...@@ -377,7 +393,7 @@ public class GitLabApiClient { ...@@ -377,7 +393,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP POST call with the specified form data and path objects, returning * Perform an HTTP POST call with the specified form data and path objects, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
* *
* @param formData the Form containing the name/value pairs * @param formData the Form containing the name/value pairs
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
...@@ -391,7 +407,7 @@ public class GitLabApiClient { ...@@ -391,7 +407,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP POST call with the specified form data and path objects, returning * Perform an HTTP POST call with the specified form data and path objects, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
* *
* @param queryParams multivalue map of request parameters * @param queryParams multivalue map of request parameters
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
* @return a Response instance with the data returned from the endpoint * @return a Response instance with the data returned from the endpoint
...@@ -405,7 +421,7 @@ public class GitLabApiClient { ...@@ -405,7 +421,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP POST call with the specified form data and URL, returning * Perform an HTTP POST call with the specified form data and URL, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
* *
* @param formData the Form containing the name/value pairs * @param formData the Form containing the name/value pairs
* @param url the fully formed path to the GitLab API endpoint * @param url the fully formed path to the GitLab API endpoint
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
...@@ -501,7 +517,7 @@ public class GitLabApiClient { ...@@ -501,7 +517,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP PUT call with the specified form data and path objects, returning * Perform an HTTP PUT call with the specified form data and path objects, returning
* a ClientResponse instance with the data returned from the endpoint. * a ClientResponse instance with the data returned from the endpoint.
* *
* @param queryParams multivalue map of request parameters * @param queryParams multivalue map of request parameters
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
* @return a ClientResponse instance with the data returned from the endpoint * @return a ClientResponse instance with the data returned from the endpoint
...@@ -561,7 +577,7 @@ public class GitLabApiClient { ...@@ -561,7 +577,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP DELETE call with the specified form data and path objects, returning * Perform an HTTP DELETE call with the specified form data and path objects, returning
* a Response instance with the data returned from the endpoint. * a Response instance with the data returned from the endpoint.
* *
* @param queryParams multivalue map of request parameters * @param queryParams multivalue map of request parameters
* @param pathArgs variable list of arguments used to build the URI * @param pathArgs variable list of arguments used to build the URI
* @return a Response instance with the data returned from the endpoint * @return a Response instance with the data returned from the endpoint
...@@ -574,7 +590,7 @@ public class GitLabApiClient { ...@@ -574,7 +590,7 @@ public class GitLabApiClient {
/** /**
* Perform an HTTP DELETE call with the specified form data and URL, returning * Perform an HTTP DELETE call with the specified form data and URL, returning
* a Response instance with the data returned from the endpoint. * a Response instance with the data returned from the endpoint.
* *
* @param queryParams multivalue map of request parameters * @param queryParams multivalue map of request parameters
* @param url the fully formed path to the GitLab API endpoint * @param url the fully formed path to the GitLab API endpoint
* @return a Response instance with the data returned from the endpoint * @return a Response instance with the data returned from the endpoint
......
package org.gitlab4j.api;
import org.gitlab4j.api.models.HealthCheckInfo;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.net.URL;
public class HealthCheckApi extends AbstractApi {
public HealthCheckApi(GitLabApi gitLabApi) {
super(gitLabApi);
}
/**
* Get Health Checks from the liveness endpoint.
*
* Requires ip_whitelist
* https://docs.gitlab.com/ee/administration/monitoring/ip_whitelist.html
*
* GET /-/liveness
*
* @return HealthCheckInfo instance
* @throws GitLabApiException if any exception occurs
*/
public HealthCheckInfo getLiveness() throws GitLabApiException, IOException {
URL livenessUrl = getApiClient().getUrlWithBase("-", "liveness");
Response response = get(Response.Status.OK, null, livenessUrl);
return (response.readEntity(HealthCheckInfo.class));
}
/**
* Get Health Checks from the liveness endpoint.
*
* Requires ip_whitelist
* https://docs.gitlab.com/ee/administration/monitoring/ip_whitelist.html
*
* GET /-/liveness
*
* @param token Health Status token
* @return HealthCheckInfo instance
* @throws GitLabApiException if any exception occurs
* @deprecated
*/
public HealthCheckInfo getLiveness(String token) throws GitLabApiException, IOException {
URL livenessUrl = getApiClient().getUrlWithBase("-", "liveness");
GitLabApiForm formData = new GitLabApiForm()
.withParam("token", token, false);
Response response = get(Response.Status.OK, formData.asMap(), livenessUrl);
return (response.readEntity(HealthCheckInfo.class));
}
/**
* Get Health Checks from the readiness endpoint.
*
* Requires ip_whitelist
* https://docs.gitlab.com/ee/administration/monitoring/ip_whitelist.html
*
* GET /-/readiness
*
* @return HealthCheckInfo instance
* @throws GitLabApiException if any exception occurs
*/
public HealthCheckInfo getReadiness() throws GitLabApiException, IOException {
URL readinessUrl = getApiClient().getUrlWithBase("-", "readiness");
Response response = get(Response.Status.OK, null, readinessUrl);
return (response.readEntity(HealthCheckInfo.class));
}
/**
* Get Health Checks from the readiness endpoint.
*
* Requires ip_whitelist
* https://docs.gitlab.com/ee/administration/monitoring/ip_whitelist.html
*
* GET /-/readiness
*
* @param token Health Status token
* @return HealthCheckInfo instance
* @throws GitLabApiException if any exception occurs
* @deprecated
*/
public HealthCheckInfo getReadiness(String token) throws GitLabApiException, IOException {
URL readinessUrl = getApiClient().getUrlWithBase("-", "readiness");
GitLabApiForm formData = new GitLabApiForm()
.withParam("token", token, false);
Response response = get(Response.Status.OK, formData.asMap(), readinessUrl);
return (response.readEntity(HealthCheckInfo.class));
}
}
package org.gitlab4j.api.models;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class HealthCheckInfo {
private HealthCheckItem dbCheck;
private HealthCheckItem redisCheck;
private HealthCheckItem cacheCheck;
private HealthCheckItem queuesCheck;
private HealthCheckItem sharedStateCheck;
private HealthCheckItem fsShardsCheck;
private HealthCheckItem gitalyCheck;
public HealthCheckItem getDbCheck() {
return this.dbCheck;
}
public void setDbCheck(HealthCheckItem dbCheck) {
this.dbCheck = dbCheck;
}
public HealthCheckItem getRedisCheck() {
return this.redisCheck;
}
public void setRedisCheck(HealthCheckItem redisCheck) {
this.redisCheck = redisCheck;
}
public HealthCheckItem getCacheCheck() {
return this.cacheCheck;
}
public void setCacheCheck(HealthCheckItem cacheCheck) {
this.cacheCheck = cacheCheck;
}
public HealthCheckItem getQueuesCheck() {
return this.queuesCheck;
}
public void setQueuesCheck(HealthCheckItem queuesCheck) {
this.queuesCheck = queuesCheck;
}
public HealthCheckItem getSharedStateCheck() {
return this.sharedStateCheck;
}
public void setSharedStateCheck(HealthCheckItem sharedStateCheck) {
this.sharedStateCheck = sharedStateCheck;
}
public HealthCheckItem getFsShardsCheck() {
return this.fsShardsCheck;
}
public void setFsShardsCheck(HealthCheckItem fsShardsCheck) {
this.fsShardsCheck = fsShardsCheck;
}
public HealthCheckItem getGitalyCheck() {
return this.gitalyCheck;
}
public void setGitalyCheck(HealthCheckItem gitalyCheck) {
this.gitalyCheck = gitalyCheck;
}
}
package org.gitlab4j.api.models;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import java.util.Map;
@XmlAccessorType(XmlAccessType.FIELD)
public class HealthCheckItem {
private HealthCheckStatus status;
private Map<String, String> labels;
private String message;
public HealthCheckStatus getStatus() {
return this.status;
}
public void setStatus(HealthCheckStatus status) {
this.status = status;
}
public Map<String, String> getLabels() {
return labels;
}
public void setLabels(Map<String, String> labels) {
this.labels = labels;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
package org.gitlab4j.api.models;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import org.gitlab4j.api.utils.JacksonJsonEnumHelper;
public enum HealthCheckStatus {
OK, FAILED;
private static JacksonJsonEnumHelper<HealthCheckStatus> enumHelper = new JacksonJsonEnumHelper<>(HealthCheckStatus.class);
@JsonCreator
public static HealthCheckStatus forValue(String value) {
return enumHelper.forValue(value);
}
@JsonValue
public String toValue() {
return enumHelper.toString(this);
}
@Override
public String toString() {
return enumHelper.toString(this);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment