diff options
author | st782s <statta@research.att.com> | 2017-05-04 07:48:42 -0400 |
---|---|---|
committer | st782s <statta@research.att.com> | 2017-05-04 12:28:17 -0400 |
commit | b54df0ddd0c6a0372327c5aa3668e5a6458fcd64 (patch) | |
tree | e69cfa9b314a801bd187cf0145d1d4306436229c /ecomp-portal-BE-os/src/test/java | |
parent | 39d1e62c84041831bfc52cca73b5ed5efaf57d27 (diff) |
[PORTAL-7] Rebase
This rebasing includes common libraries and common overlays projects
abstraction of components
Change-Id: I9a24a338665c7cd058978e8636bc412d9e2fdce8
Signed-off-by: st782s <statta@research.att.com>
Diffstat (limited to 'ecomp-portal-BE-os/src/test/java')
6 files changed, 583 insertions, 0 deletions
diff --git a/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/SharedContextRestClient.java b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/SharedContextRestClient.java new file mode 100644 index 00000000..49686c80 --- /dev/null +++ b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/SharedContextRestClient.java @@ -0,0 +1,280 @@ +/*-
+ * ================================================================================
+ * ECOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * 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.
+ * ================================================================================
+ */
+package org.openecomp.portalapp.portal.controller;
+
+import java.net.URI;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLContext;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.Consts;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContexts;
+import org.apache.http.ssl.TrustStrategy;
+import org.apache.http.util.EntityUtils;
+/**
+ * Provides reusable features for test cases to get or post from an REST
+ * endpoint, allowing use of HTTPS connections to servers that use self-signed
+ * certificates.
+ */
+public class SharedContextRestClient {
+
+ private static final Log logger = LogFactory.getLog(SharedContextRestClient.class);
+
+ /**
+ * Convenience method that builds and sends a GET request using properties
+ * to build the URI and populate header with credentials.
+ *
+ * @param task
+ * last component(s) of REST endpoint name; e.g., "get".
+ * @param contextId
+ * @param contextKey
+ * @return JSON string fetched
+ * @throws Exception
+ * if the HTTP response code is anything other than OK.
+ */
+ public static String getJson(final SharedContextTestProperties properties, final String task,
+ final String contextId, final String contextKey) throws Exception {
+ String requestPath = '/' + properties.getProperty(SharedContextTestProperties.APPNAME) //
+ + '/' + properties.getProperty(SharedContextTestProperties.RESTPATH) //
+ + '/' + task;
+ return getJson(properties.getProperty(SharedContextTestProperties.HOSTNAME), //
+ properties.getProperty(SharedContextTestProperties.PORT, -1), //
+ properties.getProperty(SharedContextTestProperties.SECURE, true), //
+ properties.getProperty(SharedContextTestProperties.UEBKEY), //
+ properties.getProperty(SharedContextTestProperties.USERNAME), //
+ properties.getProperty(SharedContextTestProperties.PASSWORD), requestPath, //
+ contextId, //
+ contextKey);
+ }
+
+ /**
+ * Constructs and sends a GET request using the specified values.
+ *
+ * @param hostname
+ * @param port
+ * ignored if negative
+ * @param secure
+ * If true, uses https; else http.
+ * @param headerUebkey
+ * @param headerUsername
+ * @param headerPassword
+ * @param requestPath
+ * full path of the REST endpoint
+ * @param contextId
+ * @param contextKey
+ * Ignored if null
+ * @return JSON result
+ */
+ public static String getJson(final String hostname, final int port, boolean secure, final String headerUebkey,
+ final String headerUsername, final String headerPassword, final String requestPath, final String contextId,
+ final String contextKey) throws Exception {
+
+ URIBuilder uriBuilder = new URIBuilder();
+ if (secure)
+ uriBuilder.setScheme("https");
+ else
+ uriBuilder.setScheme("http");
+ uriBuilder.setHost(hostname);
+ if (port > 0)
+ uriBuilder.setPort(port);
+ uriBuilder.setPath(requestPath);
+ uriBuilder.addParameter("context_id", contextId);
+ if (contextKey != null)
+ uriBuilder.addParameter("ckey", contextKey);
+ final URI uri = uriBuilder.build();
+
+ CloseableHttpClient httpClient;
+ if (secure) {
+ // Tell HttpClient to accept any server certificate for HTTPS.
+ // http://stackoverflow.com/questions/24720013/apache-http-client-ssl-certificate-error
+ SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
+ @Override
+ public boolean isTrusted(final X509Certificate[] chain, final String authType)
+ throws CertificateException {
+ return true;
+ }
+ }).build();
+ SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
+ NoopHostnameVerifier.INSTANCE);
+ httpClient = HttpClientBuilder.create().setSSLSocketFactory(sslsf).build();
+ } else {
+ httpClient = HttpClients.createDefault();
+ }
+
+ HttpGet httpGet = new HttpGet(uri);
+ httpGet.setHeader("uebkey", headerUebkey);
+ httpGet.setHeader("username", headerUsername);
+ httpGet.setHeader("password", headerPassword);
+
+ String json = null;
+ CloseableHttpResponse response = null;
+ try {
+ logger.debug("GET from " + uri);
+ response = httpClient.execute(httpGet);
+ logger.info("Status is " + response.getStatusLine());
+ if (response.getStatusLine().getStatusCode() != HttpServletResponse.SC_OK)
+ throw new Exception("Status is " + response.getStatusLine().toString());
+ HttpEntity entity = response.getEntity();
+ if (entity == null) {
+ logger.warn("Entity is null!");
+ } else {
+ // entity content length is never set.
+ // this naively tries to read everything.
+ json = EntityUtils.toString(entity);
+ EntityUtils.consume(entity);
+ }
+ } finally {
+ if (response != null)
+ response.close();
+ }
+ return json;
+ }
+
+ /**
+ * Convenience method that builds and sends a POST request using properties
+ * to build the URI and populate header with credentials.
+ *
+ * @param path
+ * last component(s) of REST endpoint name; e.g., "users" or
+ * "user/{userid}/roles".
+ * @return JSON string fetched
+ * @throws Exception
+ * if the HTTP response code is anything other than OK.
+ */
+ public static String postJson(final SharedContextTestProperties properties, final String path, final String json)
+ throws Exception {
+ String requestPath = '/' + properties.getProperty(SharedContextTestProperties.APPNAME) //
+ + '/' + properties.getProperty(SharedContextTestProperties.RESTPATH) //
+ + '/' + path;
+ return postJson(properties.getProperty(SharedContextTestProperties.HOSTNAME), //
+ properties.getProperty(SharedContextTestProperties.PORT, -1), //
+ properties.getProperty(SharedContextTestProperties.SECURE, true), //
+ properties.getProperty(SharedContextTestProperties.UEBKEY), //
+ properties.getProperty(SharedContextTestProperties.USERNAME), //
+ properties.getProperty(SharedContextTestProperties.PASSWORD), //
+ requestPath, //
+ json);
+ }
+
+ /**
+ * Constructs and sends a POST request using the specified values.
+ *
+ * @param hostname
+ * @param port
+ * @param secure
+ * If true, uses https; else http.
+ * @param requestPath
+ * full path of the REST endpoint
+ * @param headerUebkey
+ * @param headerUsername
+ * @param headerPassword
+ * @param json
+ * Content to post
+ * @return JSON result
+ * @throws Exception
+ */
+ public static String postJson(final String hostname, final int port, boolean secure, final String headerUebkey,
+ final String headerUsername, final String headerPassword, final String requestPath, final String json)
+ throws Exception {
+
+ URIBuilder builder = new URIBuilder();
+ if (secure)
+ builder.setScheme("https");
+ else
+ builder.setScheme("http");
+ builder.setHost(hostname);
+ if (port > 0)
+ builder.setPort(port);
+ builder.setPath(requestPath);
+ final URI uri = builder.build();
+
+ CloseableHttpClient httpClient;
+ if (secure) {
+ // Tell HttpClient to accept any server certificate for HTTPS.
+ // http://stackoverflow.com/questions/24720013/apache-http-client-ssl-certificate-error
+ SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
+ @Override
+ public boolean isTrusted(final X509Certificate[] chain, final String authType)
+ throws CertificateException {
+ return true;
+ }
+ }).build();
+ SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
+ NoopHostnameVerifier.INSTANCE);
+ httpClient = HttpClientBuilder.create().setSSLSocketFactory(sslsf).build();
+ } else {
+ httpClient = HttpClients.createDefault();
+ }
+ HttpPost httpPost = new HttpPost(uri);
+ httpPost.setHeader("uebkey", headerUebkey);
+ httpPost.setHeader("username", headerUsername);
+ httpPost.setHeader("password", headerPassword);
+
+ StringEntity postEntity = new StringEntity(json, ContentType.create("application/json", Consts.UTF_8));
+ httpPost.setEntity(postEntity);
+
+ String responseJson = null;
+ CloseableHttpResponse response = null;
+ try {
+ logger.debug("POST to " + uri);
+ response = httpClient.execute(httpPost);
+ logger.info("Status is " + response.getStatusLine());
+ if (response.getStatusLine().getStatusCode() != HttpServletResponse.SC_OK)
+ throw new Exception("Status is " + response.getStatusLine().toString());
+
+ HttpEntity entity = response.getEntity();
+ if (entity == null) {
+ logger.warn("Entity is null!");
+ } else {
+ long len = entity.getContentLength();
+ if (len < 0)
+ logger.warn("Content length is -1");
+ if (len < 2048) {
+ responseJson = EntityUtils.toString(entity);
+ logger.debug(responseJson);
+ } else {
+ logger.warn("Not implemented - stream content");
+ }
+ EntityUtils.consume(entity);
+ }
+ } finally {
+ if (response != null)
+ response.close();
+ }
+ return responseJson;
+ }
+
+}
diff --git a/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/SharedContextRestControllerTest.java b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/SharedContextRestControllerTest.java new file mode 100644 index 00000000..a7a86e8c --- /dev/null +++ b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/SharedContextRestControllerTest.java @@ -0,0 +1,125 @@ +/*-
+ * ================================================================================
+ * ECOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * 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.
+ * ================================================================================
+ */
+package org.openecomp.portalapp.portal.controller;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.Assert;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Tests the endpoints exposed by the Shared Context REST controller in Portal
+ * Core.
+ *
+ * @author clott
+ */
+public class SharedContextRestControllerTest {
+
+ private final Log logger = LogFactory.getLog(getClass());
+
+ private final SharedContextTestProperties properties;
+
+ private final String ckey = "ckey";
+ private final String cvalue = "cvalue";
+
+ // Supposed to be a Portal session ID
+ private final String cxid = UUID.randomUUID().toString();
+
+ private final String key = "key123";
+ private final String value1 = "first value";
+ private final String value2 = "second value";
+
+ public SharedContextRestControllerTest() throws IOException {
+ properties = new SharedContextTestProperties();
+ }
+
+ @SuppressWarnings("unchecked")
+ //@Test
+ public void test() throws Exception {
+ String response = null, val = null;
+ ObjectMapper mapper = new ObjectMapper();
+ Map<String, Object> responseMap, jsonMap;
+
+ logger.info("Get on empty context");
+ response = SharedContextRestClient.getJson(properties, "get", cxid, key);
+ // Should not exist - just generated the UUID
+ Map<String, Object> responseMap1 = mapper.readValue(response, Map.class);
+ response = (String) responseMap1.get("response");
+ Assert.assertNull(response);
+
+ logger.info("Set a new context");
+ response = setContext(cxid, key, value1);
+ Assert.assertNotNull(response);
+ responseMap = mapper.readValue(response, Map.class);
+ String responseValue = (String) responseMap.get("response");
+ Assert.assertNotNull(responseValue);
+ Assert.assertEquals("added", responseValue);
+
+ logger.info("Get existing context");
+ response = SharedContextRestClient.getJson(properties, "get", cxid, key);
+ responseMap = mapper.readValue(response, Map.class);
+ jsonMap = (Map<String,Object>) responseMap.get("response");
+ Assert.assertNotNull(jsonMap);
+ val = (String) jsonMap.get(cvalue);
+ Assert.assertEquals(val, value1);
+
+ logger.info("Overwrite exiting context");
+ response = setContext(cxid, key, value2);
+ Assert.assertNotNull(response);
+ responseMap = mapper.readValue(response, Map.class);
+ response = (String) responseMap.get("response");
+ Assert.assertNotNull(responseValue);
+ // Assert.assertEquals("replaced", responseValue);
+
+ logger.info("Get existing context to verify overwrite");
+ response = SharedContextRestClient.getJson(properties, "get", cxid, key);
+ responseMap = mapper.readValue(response, Map.class);
+ jsonMap = (Map<String,Object>) responseMap.get("response");
+ Assert.assertNotNull(jsonMap);
+ val = (String) jsonMap.get(cvalue);
+ Assert.assertEquals(val, value2);
+
+ logger.info("Delete one context");
+ response = SharedContextRestClient.getJson(properties, "remove", cxid, key);
+ responseMap = mapper.readValue(response, Map.class);
+ response = (String) responseMap.get("response");
+ Assert.assertEquals(response, "removed");
+
+ logger.info("Clear the context");
+ response = SharedContextRestClient.getJson(properties, "clear", cxid, null);
+ Assert.assertEquals("", response);
+ }
+
+ private String setContext(String context, String id, String value) throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ HashMap<String,String> stringMap = new HashMap<String,String>();
+ stringMap.put("context_id", cxid);
+ stringMap.put(ckey, key);
+ stringMap.put(cvalue, value2);
+ String json = mapper.writeValueAsString(stringMap);
+ String response = SharedContextRestClient.postJson(properties, "set", json);
+ return response;
+ }
+}
diff --git a/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/SharedContextTestProperties.java b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/SharedContextTestProperties.java new file mode 100644 index 00000000..baed554b --- /dev/null +++ b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/SharedContextTestProperties.java @@ -0,0 +1,81 @@ +/*-
+ * ================================================================================
+ * ECOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * 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.
+ * ================================================================================
+ */
+package org.openecomp.portalapp.portal.controller;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Trivial extension of Properties that populates itself from a known source.
+ */
+public class SharedContextTestProperties extends Properties {
+
+ private static final long serialVersionUID = -4064100267979036550L;
+
+ // property names
+ public static final String HOSTNAME = "hostname";
+ public static final String PORT = "port";
+ public static final String SECURE = "secure";
+ public static final String APPNAME = "appname";
+ public static final String RESTPATH = "restpath";
+ public static final String UEBKEY = "uebkey";
+ public static final String USERNAME = "username";
+ public static final String PASSWORD = "password";
+
+ /**
+ * Expected on the classpath
+ */
+ private static final String propertiesFileName = "shared-context-test.properties";
+
+ /**
+ * Constructor populates itself from properties file found in same package.
+ *
+ * @throws Exception
+ */
+ public SharedContextTestProperties() throws IOException {
+ InputStream inStream = getClass().getResourceAsStream(propertiesFileName);
+ if (inStream == null)
+ throw new IOException("Failed to find file on classpath: " + propertiesFileName);
+ super.load(inStream);
+ inStream.close();
+ }
+
+ public int getProperty(final String name, final int defVal) throws NumberFormatException {
+ String prop = getProperty(name);
+ if (prop == null)
+ return defVal;
+ return Integer.parseInt(prop);
+ }
+
+ public boolean getProperty(final String name, final boolean defVal) {
+ String prop = getProperty(name);
+ if (prop == null)
+ return false;
+ return Boolean.parseBoolean(prop);
+ }
+
+ // Test this class
+ public static void main(String[] args) throws Exception {
+ SharedContextTestProperties p = new SharedContextTestProperties();
+ System.out.println("Property " + SharedContextTestProperties.HOSTNAME + " = "
+ + p.getProperty(SharedContextTestProperties.HOSTNAME));
+ }
+}
diff --git a/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/shared-context-test.properties b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/shared-context-test.properties new file mode 100644 index 00000000..3e44a781 --- /dev/null +++ b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/controller/shared-context-test.properties @@ -0,0 +1,28 @@ +###
+# ================================================================================
+# ECOMP Portal
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property
+# ================================================================================
+# 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.
+# ================================================================================
+###
+
+hostname= localhost
+# port = 80
+secure = true
+appname = ecompportal
+restpath = context
+uebkey = xgnLrmNmkfCRnIwa
+username = Default
+password = AppPassword!1
diff --git a/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/listener/HealthMonitorTest.java b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/listener/HealthMonitorTest.java new file mode 100644 index 00000000..6d01f2c9 --- /dev/null +++ b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/listener/HealthMonitorTest.java @@ -0,0 +1,36 @@ +/*-
+ * ================================================================================
+ * ECOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * 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.
+ * ================================================================================
+ */
+package org.openecomp.portalapp.portal.listener;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class HealthMonitorTest {
+
+ @Test
+ public void initialFlagsTest() {
+ assertEquals(false, HealthMonitor.isBackEndUp());
+ assertEquals(false, HealthMonitor.isFrontEndUp());
+ assertEquals(false, HealthMonitor.isDatabaseUp());
+ assertEquals(false, HealthMonitor.isUebUp());
+ }
+
+}
diff --git a/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/utils/EcompPortalUtilsTest.java b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/utils/EcompPortalUtilsTest.java new file mode 100644 index 00000000..4df4f761 --- /dev/null +++ b/ecomp-portal-BE-os/src/test/java/org/openecomp/portalapp/portal/utils/EcompPortalUtilsTest.java @@ -0,0 +1,33 @@ +/*-
+ * ================================================================================
+ * ECOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * 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.
+ * ================================================================================
+ */
+package org.openecomp.portalapp.portal.utils;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class EcompPortalUtilsTest {
+
+
+ @Test
+ public void legitimateUserIdFailureTest() {
+ assertEquals(false, EcompPortalUtils.legitimateUserId("1#@23456"));
+ }
+}
|