aboutsummaryrefslogtreecommitdiffstats
path: root/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle
diff options
context:
space:
mode:
authorMarcus G K Williams <marcus.williams@intel.com>2017-09-07 17:17:07 -0700
committerMarcus G K Williams <marcus.williams@intel.com>2017-09-15 15:06:23 -0700
commit6475b40bcbb943aa52beec12fc8b54d671d9e429 (patch)
tree468ff4f4144c3eae69e205bc0e08aa9d75a7c337 /appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle
parent3aa02022732ca26c7c586026926674e88ab0bb2e (diff)
Fix/Add unit tests for appc-rest-adapter
Refactored RestAdapterImpl.java and added RequestFactory.java to enable cleaner unit tests. Added unit tests. Issue-Id: APPC-182 Change-Id: I129a9145ac028eda3257ef8c26f67b87f12c683f Signed-off-by: Marcus G K Williams <marcus.williams@intel.com>
Diffstat (limited to 'appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle')
-rw-r--r--appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/main/java/org/openecomp/appc/adapter/rest/RequestFactory.java60
-rw-r--r--appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/main/java/org/openecomp/appc/adapter/rest/impl/RestAdapterImpl.java186
-rw-r--r--appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/test/java/org/openecomp/appc/adapter/rest/impl/TestRestAdapterImpl.java150
3 files changed, 193 insertions, 203 deletions
diff --git a/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/main/java/org/openecomp/appc/adapter/rest/RequestFactory.java b/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/main/java/org/openecomp/appc/adapter/rest/RequestFactory.java
new file mode 100644
index 000000000..b273a5de4
--- /dev/null
+++ b/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/main/java/org/openecomp/appc/adapter/rest/RequestFactory.java
@@ -0,0 +1,60 @@
+/*
+ * ============LICENSE_START=============================================================================================================
+ * Copyright (c) 2017 Intel Corp. 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.openecomp.appc.adapter.rest;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.utils.URIBuilder;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
+public class RequestFactory {
+ private final EELFLogger logger = EELFManager.getInstance().getLogger(RequestFactory.class);
+
+ final static Map<String, Supplier<HttpRequestBase>> map = new HashMap<>();
+
+ static {
+ map.put("GET", HttpGet::new);
+ map.put("POST", HttpPost::new);
+ map.put("PUT", HttpPut::new);
+ map.put("DELETE", HttpDelete::new);
+ }
+
+ public HttpRequestBase getHttpRequest(String method, String tUrl) {
+ Supplier<HttpRequestBase> httpRequestSupplier = map.get(method.toUpperCase());
+ URI uri = null;
+ if (httpRequestSupplier != null ) {
+ try {
+ uri = new URIBuilder(tUrl).build();
+ } catch (URISyntaxException ex) {
+ logger.error("URI Syntax Incorrect: " + tUrl, ex);
+ }
+ HttpRequestBase httpRequest = httpRequestSupplier.get();
+ httpRequest.setURI(uri);
+ return httpRequest;
+
+ }
+ throw new IllegalArgumentException("No method named: " + method.toUpperCase());
+ }
+}
diff --git a/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/main/java/org/openecomp/appc/adapter/rest/impl/RestAdapterImpl.java b/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/main/java/org/openecomp/appc/adapter/rest/impl/RestAdapterImpl.java
index 772000518..fae0bd955 100644
--- a/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/main/java/org/openecomp/appc/adapter/rest/impl/RestAdapterImpl.java
+++ b/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/main/java/org/openecomp/appc/adapter/rest/impl/RestAdapterImpl.java
@@ -33,6 +33,7 @@ import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
@@ -40,12 +41,14 @@ import org.glassfish.grizzly.http.util.HttpStatus;
import org.json.JSONObject;
import org.openecomp.appc.Constants;
import org.openecomp.appc.adapter.rest.RestAdapter;
+import org.openecomp.appc.adapter.rest.RequestFactory;
import org.openecomp.appc.configuration.Configuration;
import org.openecomp.appc.configuration.ConfigurationFactory;
import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
import java.util.Iterator;
import java.util.Map;
+import java.util.function.Supplier;
/**
* This class implements the {@link RestAdapter} interface. This interface
@@ -97,146 +100,42 @@ public class RestAdapterImpl implements RestAdapter {
public void commonGet(Map<String, String> params, SvcLogicContext ctx) {
logger.info("Run get method");
- String haveHeader;
- String tUrl=params.get("org.openecomp.appc.instance.URI");
- haveHeader=params.get("org.openecomp.appc.instance.haveHeader");
- String headers=params.get("org.openecomp.appc.instance.headers");
+
RequestContext rc = new RequestContext(ctx);
rc.isAlive();
- try {
- HttpGet httpGet = new HttpGet(tUrl);
-
- if(haveHeader.equals("true"))
- {
- JSONObject JsonHeaders= new JSONObject(headers);
- Iterator keys = JsonHeaders.keys();
- while(keys.hasNext()) {
- String String1 = (String)keys.next();
- String String2 = JsonHeaders.getString(String1);
- httpGet.addHeader(String1,String2);
- }
-
- }
-
- HttpClient httpClient = HttpClients.createDefault();
- HttpResponse response;
- response = httpClient.execute(httpGet);
- int responseCode=response.getStatusLine().getStatusCode();
- HttpEntity entity = response.getEntity();
- String responseOutput=EntityUtils.toString(entity);
- doSuccess(rc,responseCode,responseOutput);
- } catch (Exception ex) {
- doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, ex.toString());
- }
+ HttpGet httpGet = (HttpGet) createHttpRequest("GET", params, rc);
+ executeHttpRequest(httpGet, rc);
}
public void commonDelete(Map<String, String> params, SvcLogicContext ctx) {
logger.info("Run Delete method");
- String haveHeader;
- String tUrl=params.get("org.openecomp.appc.instance.URI");
- haveHeader=params.get("org.openecomp.appc.instance.haveHeader");
- String headers=params.get("org.openecomp.appc.instance.headers");
+
RequestContext rc = new RequestContext(ctx);
rc.isAlive();
- try {
- HttpDelete httpDelete = new HttpDelete(tUrl);
- if(haveHeader.equals("true"))
- {
- JSONObject JsonHeaders= new JSONObject(headers);
- Iterator keys = JsonHeaders.keys();
- while(keys.hasNext()) {
- String String1 = (String)keys.next();
- String String2 = JsonHeaders.getString(String1);
- httpDelete.addHeader(String1,String2);
- }
-
- }
- HttpClient httpClient = HttpClients.createDefault();
- HttpResponse response = httpClient.execute(httpDelete);
- int responseCode=response.getStatusLine().getStatusCode();
- HttpEntity entity = response.getEntity();
- String responseOutput=EntityUtils.toString(entity);
- doSuccess(rc,responseCode,responseOutput);
- } catch (Exception ex) {
- doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, ex.toString());
- }
+ HttpDelete httpDelete = (HttpDelete) createHttpRequest("DELETE", params, rc);
+ executeHttpRequest(httpDelete, rc);
}
public void commonPost(Map<String, String> params, SvcLogicContext ctx) {
logger.info("Run post method");
- String tUrl=params.get("org.openecomp.appc.instance.URI");
- String body=params.get("org.openecomp.appc.instance.requestBody");
- String haveHeader=params.get("org.openecomp.appc.instance.haveHeader");
- String headers=params.get("org.openecomp.appc.instance.headers");
+
RequestContext rc = new RequestContext(ctx);
rc.isAlive();
- try {
- HttpPost httpPost = new HttpPost(tUrl);
- if(haveHeader.equals("true"))
- {
- JSONObject JsonHeaders= new JSONObject(headers);
- Iterator keys = JsonHeaders.keys();
- while(keys.hasNext()) {
- String String1 = (String)keys.next();
- String String2 = JsonHeaders.getString(String1);
- httpPost.addHeader(String1,String2);
- }
-
- }
- StringEntity bodyParams =new StringEntity (body,"UTF-8");
- httpPost.setEntity(bodyParams);
- HttpClient httpClient = HttpClients.createDefault();
- HttpResponse response = httpClient.execute(httpPost);
- int responseCode=response.getStatusLine().getStatusCode();
- HttpEntity entity = response.getEntity();
- String responseOutput=EntityUtils.toString(entity);
- doSuccess(rc,responseCode,responseOutput);
- } catch (Exception ex) {
- doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, ex.toString());
- }
+ HttpPost httpPost = (HttpPost) createHttpRequest("POST", params, rc);
+ executeHttpRequest(httpPost, rc);
}
public void commonPut(Map<String, String> params, SvcLogicContext ctx) {
logger.info("Run put method");
- String tUrl=params.get("org.openecomp.appc.instance.URI");
- String body=params.get("org.openecomp.appc.instance.requestBody");
- String haveHeader=params.get("org.openecomp.appc.instance.haveHeader");
- String headers=params.get("org.openecomp.appc.instance.headers");
+
RequestContext rc = new RequestContext(ctx);
rc.isAlive();
- try {
- HttpPut httpPut = new HttpPut(tUrl);
- if(haveHeader.equals("true"))
- {
- JSONObject JsonHeaders= new JSONObject(headers);
- Iterator keys = JsonHeaders.keys();
- while(keys.hasNext()) {
- String String1 = (String)keys.next();
- String String2 = JsonHeaders.getString(String1);
- httpPut.addHeader(String1,String2);
- }
-
- }
- StringEntity bodyParams =new StringEntity (body,"UTF-8");
- httpPut.setEntity(bodyParams);
- HttpClient httpClient = HttpClients.createDefault();
- HttpResponse response = httpClient.execute(httpPut);
- int responseCode=response.getStatusLine().getStatusCode();
- HttpEntity entity = response.getEntity();
- String responseOutput=EntityUtils.toString(entity);
- if(responseCode == 200){
- doSuccess(rc,responseCode,responseOutput);
- } else {
- doFailure(rc, HttpStatus.getHttpStatus(responseCode), response.getStatusLine().getReasonPhrase());
- }
- }
- catch (Exception ex) {
- doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, ex.toString());
- }
+ HttpPut httpPut = (HttpPut) createHttpRequest("PUT", params, rc);
+ executeHttpRequest(httpPut, rc);
}
@SuppressWarnings("static-method")
@@ -277,6 +176,61 @@ public class RestAdapterImpl implements RestAdapter {
svcLogic.setAttribute("org.openecomp.rest.result.code",Integer.toString(HttpStatus.OK_200.getStatusCode()));
}
+ public void executeHttpRequest(HttpRequestBase httpRequest, RequestContext rc){
+ try {
+ HttpClient httpClient = HttpClients.createDefault();
+ HttpResponse response = httpClient.execute(httpRequest);
+ int responseCode = response.getStatusLine().getStatusCode();
+ HttpEntity entity = response.getEntity();
+ String responseOutput = EntityUtils.toString(entity);
+ if(responseCode == 200){
+ doSuccess(rc,responseCode,responseOutput);
+ } else {
+ doFailure(rc, HttpStatus.getHttpStatus(responseCode), response.getStatusLine().getReasonPhrase());
+ }
+ }
+ catch (Exception ex) {
+ doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, ex.toString());
+ }
+ }
+
+ public HttpRequestBase createHttpRequest(String method, Map<String, String> params, RequestContext rc){
+ HttpRequestBase httpRequest = null;
+ try {
+ String tUrl = params.get("org.openecomp.appc.instance.URI");
+ String haveHeader = params.get("org.openecomp.appc.instance.haveHeader");
+ String headers = params.get("org.openecomp.appc.instance.headers");
+
+ Supplier<RequestFactory> requestFactory = RequestFactory::new;
+ httpRequest = requestFactory.get().getHttpRequest(method, tUrl);
+
+ if (haveHeader.equals("true")) {
+ JSONObject JsonHeaders = new JSONObject(headers);
+ Iterator keys = JsonHeaders.keys();
+ while (keys.hasNext()) {
+ String String1 = (String) keys.next();
+ String String2 = JsonHeaders.getString(String1);
+ httpRequest.addHeader(String1, String2);
+ }
+ }
+ if (params.containsKey("org.openecomp.appc.instance.requestBody")) {
+ String body = params.get("org.openecomp.appc.instance.requestBody");
+ StringEntity bodyParams = new StringEntity (body,"UTF-8");
+ if (method.equals("PUT")){
+ HttpPut httpPut = (HttpPut) httpRequest;
+ httpPut.setEntity(bodyParams);
+ }
+ if (method.equals("POST")){
+ HttpPost httpPost = (HttpPost) httpRequest;
+ httpPost.setEntity(bodyParams);
+ }
+ }
+ } catch (Exception ex) {
+ doFailure(rc, HttpStatus.INTERNAL_SERVER_ERROR_500, ex.toString());
+ }
+ return httpRequest;
+ }
+
/**
* initialize the provider adapter by building the context cache
diff --git a/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/test/java/org/openecomp/appc/adapter/rest/impl/TestRestAdapterImpl.java b/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/test/java/org/openecomp/appc/adapter/rest/impl/TestRestAdapterImpl.java
index 205e772d1..5c027f5bf 100644
--- a/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/test/java/org/openecomp/appc/adapter/rest/impl/TestRestAdapterImpl.java
+++ b/appc-adapters/appc-rest-adapter/appc-rest-adapter-bundle/src/test/java/org/openecomp/appc/adapter/rest/impl/TestRestAdapterImpl.java
@@ -6,6 +6,8 @@
* ================================================================================
* Copyright (C) 2017 Amdocs
* =============================================================================
+ * Copyright (C) 2017 Intel Corp.
+ * =============================================================================
* 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
@@ -25,72 +27,30 @@
package org.openecomp.appc.adapter.rest.impl;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import java.io.IOException;
-import java.lang.reflect.Field;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.util.EntityUtils;
import org.junit.Before;
import org.junit.BeforeClass;
-import org.junit.Ignore;
import org.junit.Test;
-import org.slf4j.MDC;
-import org.openecomp.appc.Constants;
-import org.openecomp.appc.adapter.rest.RestAdapter;
-import org.openecomp.appc.configuration.ConfigurationFactory;
import org.openecomp.appc.exceptions.APPCException;
-import org.openecomp.appc.exceptions.UnknownProviderException;
import com.att.cdp.exceptions.ZoneException;
-import com.att.cdp.zones.ComputeService;
-import com.att.cdp.zones.Context;
-import com.att.cdp.zones.ContextFactory;
-import com.att.cdp.zones.model.Server;
-import com.att.cdp.zones.model.Server.Status;
import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
/**
* Test the ProviderAdapter implementation.
*/
-
-@Ignore
public class TestRestAdapterImpl {
-
- @SuppressWarnings("nls")
- private static final String PROVIDER_NAME = "APPC";
-
- @SuppressWarnings("nls")
- private static final String PROVIDER_TYPE = "OpenStackProvider";
-
- private static String IDENTITY_URL;
-
- private static String PRINCIPAL;
-
- private static String CREDENTIAL;
-
- private static String TENANT_NAME;
-
- private static String TENANT_ID;
-
- private static String USER_ID;
-
- private static String REGION_NAME;
-
- private static String SERVER_URL;
-
- private static Class<?> providerAdapterImplClass;
- private static Class<?> configurationFactoryClass;
- private static Field providerCacheField;
- private static Field configField;
-
private RestAdapterImpl adapter;
@@ -107,57 +67,73 @@ public class TestRestAdapterImpl {
}
@Test
- public void testCommonGet() throws IOException, IllegalStateException, IllegalArgumentException,
- ZoneException, APPCException {
-
- Map<String, String> params = new HashMap<>();
- params.put("org.openecomp.appc.instance.URI", "http://example.com:8080/about/health");
- params.put("org.openecomp.appc.instance.haveHeader","false");
- SvcLogicContext svcContext = new SvcLogicContext();
- adapter.commonGet(params, svcContext);
- String statusCode=svcContext.getAttribute("org.openecomp.rest.agent.result.code");
- assertEquals("200",statusCode);
+ public void testCreateHttpRequestGet() throws IOException, IllegalStateException, IllegalArgumentException,
+ ZoneException, APPCException {
+
+ Map<String, String> params = new HashMap<>();
+ params.put("org.openecomp.appc.instance.URI", "http://example.com:8080/about/health");
+ params.put("org.openecomp.appc.instance.haveHeader","false");
+
+ HttpGet httpGet = ((HttpGet) givenParams(params, "GET"));
+
+ assertEquals("GET", httpGet.getMethod());
+ assertEquals("http://example.com:8080/about/health", httpGet.getURI().toURL().toString());
}
@Test
- public void testCommonPost() throws IOException, IllegalStateException, IllegalArgumentException,
+ public void testCreateHttpRequestPost() throws IOException, IllegalStateException, IllegalArgumentException,
ZoneException, APPCException {
-
- Map<String, String> params = new HashMap<>();
- params.put("org.openecomp.appc.instance.URI", "http://example.com:8081/posttest");
- params.put("org.openecomp.appc.instance.haveHeader","false");
- params.put("org.openecomp.appc.instance.requestBody", "{\"name\":\"MyNode\", \"width\":200, \"height\":100}");
- SvcLogicContext svcContext = new SvcLogicContext();
- adapter.commonPost(params, svcContext);
- String statusCode=svcContext.getAttribute("org.openecomp.rest.agent.result.code");
- assertEquals("200",statusCode);
+
+ Map<String, String> params = new HashMap<>();
+ params.put("org.openecomp.appc.instance.URI", "http://example.com:8081/posttest");
+ params.put("org.openecomp.appc.instance.haveHeader","false");
+ params.put("org.openecomp.appc.instance.requestBody", "{\"name\":\"MyNode\", \"width\":200, \"height\":100}");
+
+ HttpPost httpPost = ((HttpPost) givenParams(params, "POST"));
+
+ assertEquals("POST", httpPost.getMethod());
+ assertEquals("http://example.com:8081/posttest", httpPost.getURI().toURL().toString());
+ assertEquals("{\"name\":\"MyNode\", \"width\":200, \"height\":100}", EntityUtils.toString(httpPost.getEntity()));
}
@Test
- public void testCommonPut() throws IOException, IllegalStateException, IllegalArgumentException,
+ public void testCreateHttpRequestPut() throws IOException, IllegalStateException, IllegalArgumentException,
ZoneException, APPCException {
-
- Map<String, String> params = new HashMap<>();
- params.put("org.openecomp.appc.instance.URI", "http://example.com:8081/puttest");
- params.put("org.openecomp.appc.instance.haveHeader","false");
- params.put("org.openecomp.appc.instance.requestBody", "{\"name\":\"MyNode2\", \"width\":300, \"height\":300}");
- SvcLogicContext svcContext = new SvcLogicContext();
- adapter.commonPut(params, svcContext);
- String statusCode=svcContext.getAttribute("org.openecomp.rest.agent.result.code");
- assertEquals("200",statusCode);
+
+ Map<String, String> params = new HashMap<>();
+ params.put("org.openecomp.appc.instance.URI", "http://example.com:8081/puttest");
+ params.put("org.openecomp.appc.instance.haveHeader","false");
+ params.put("org.openecomp.appc.instance.requestBody", "{\"name\":\"MyNode2\", \"width\":300, \"height\":300}");
+
+ HttpPut httpPut = ((HttpPut) givenParams(params, "PUT"));
+ //Header headers[] = httpPut.getAllHeaders();
+
+ assertEquals("PUT", httpPut.getMethod());
+ assertEquals("http://example.com:8081/puttest", httpPut.getURI().toURL().toString());
+ assertEquals("{\"name\":\"MyNode2\", \"width\":300, \"height\":300}", EntityUtils.toString(httpPut.getEntity()));
}
@Test
- public void testCommonDelete() throws IOException, IllegalStateException, IllegalArgumentException,
+ public void testCreateHttpRequestDelete() throws IOException, IllegalStateException, IllegalArgumentException,
ZoneException, APPCException {
-
- Map<String, String> params = new HashMap<>();
- params.put("org.openecomp.appc.instance.URI", "http://example.com:8081/deletetest");
- params.put("org.openecomp.appc.instance.haveHeader","false");
- SvcLogicContext svcContext = new SvcLogicContext();
- adapter.commonDelete(params, svcContext);
- String statusCode=svcContext.getAttribute("org.openecomp.rest.agent.result.code");
- assertEquals("200",statusCode);
+
+ Map<String, String> params = new HashMap<>();
+ params.put("org.openecomp.appc.instance.URI", "http://example.com:8081/deletetest");
+ params.put("org.openecomp.appc.instance.haveHeader","false");
+
+ HttpDelete httpDelete = ((HttpDelete) givenParams(params, "DELETE"));
+
+ assertEquals("DELETE", httpDelete.getMethod());
+ assertEquals("http://example.com:8081/deletetest", httpDelete.getURI().toURL().toString());
+ }
+
+ private HttpRequestBase givenParams(Map<String, String> params, String method){
+ SvcLogicContext ctx = new SvcLogicContext();
+ RequestContext rc = new RequestContext(ctx);
+ rc.isAlive();
+
+ adapter = new RestAdapterImpl();
+ return adapter.createHttpRequest(method, params, rc);
}