Repository: olingo-odata4
Updated Branches:
  refs/heads/master cadd64761 -> 210cf9b37


[OLINGO-317] Support for JSON variants in server serializer


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/210cf9b3
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/210cf9b3
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/210cf9b3

Branch: refs/heads/master
Commit: 210cf9b37d2d97848bb3ee4b27c60d33167021da
Parents: cadd647
Author: Michael Bolz <[email protected]>
Authored: Fri Jul 11 10:51:37 2014 +0200
Committer: Michael Bolz <[email protected]>
Committed: Fri Jul 11 10:51:37 2014 +0200

----------------------------------------------------------------------
 .../olingo/server/core/ContentNegotiator.java   | 17 +++--
 .../apache/olingo/server/core/ODataImpl.java    |  4 +-
 .../serializer/json/ODataJsonSerializer.java    | 65 +++++++++++---------
 .../tecsvc/processor/TechnicalProcessor.java    |  4 +-
 .../tecsvc/data/JsonDataProviderTest.java       |  7 +--
 .../json/ODataJsonSerializerTest.java           | 48 ++++++++++-----
 6 files changed, 82 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/210cf9b3/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
index ae932c3..793af7b 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
@@ -22,8 +22,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.olingo.commons.api.ODataRuntimeException;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
 import org.apache.olingo.commons.api.format.AcceptType;
 import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.server.api.ODataRequest;
 import 
org.apache.olingo.server.api.processor.CustomContentTypeSupportProcessor;
@@ -34,8 +36,6 @@ import 
org.apache.olingo.server.api.uri.queryoption.FormatOption;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.fasterxml.jackson.dataformat.xml.util.TypeUtil;
-
 public class ContentNegotiator {
 
   private final static Logger LOG = 
LoggerFactory.getLogger(ContentNegotiator.class);
@@ -49,9 +49,8 @@ public class ContentNegotiator {
     if (processorClass == MetadataProcessor.class) {
       defaults.add(new FormatContentTypeMapping("xml", 
ContentType.APPLICATION_XML.toContentTypeString()));
     } else {
-//      defaults.add(new FormatContentTypeMapping("json", 
ContentType.APPLICATION_JSON.toContentTypeString()));
-      defaults.add(new FormatContentTypeMapping("json", 
ContentType.APPLICATION_JSON.toContentTypeString()
-          + ";odata.metadata=minimal"));
+      defaults.add(new FormatContentTypeMapping("json",
+          
ODataFormat.JSON.getContentType(ODataServiceVersion.V40).toContentTypeString()));
     }
 
     return defaults;
@@ -84,7 +83,7 @@ public class ContentNegotiator {
     if (formatOption != null) {
 
       if ("json".equalsIgnoreCase(formatOption.getText().trim())) {
-        requestedContentType = 
ContentType.create(ContentType.APPLICATION_JSON, "odata.metadata=minimal");
+        requestedContentType = 
ODataFormat.JSON.getContentType(ODataServiceVersion.V40);
         for (FormatContentTypeMapping entry : supportedContentTypes) {
           if 
(requestedContentType.isCompatible(ContentType.create(entry.getContentType().trim())))
 {
             supported = true;
@@ -136,7 +135,7 @@ public class ContentNegotiator {
       }
 
       if (requestedContentType == null) {
-        throw new RuntimeException("unsupported accept content type: " + 
acceptedContentTypes + " != "
+        throw new ODataRuntimeException("unsupported accept content type: " + 
acceptedContentTypes + " != "
             + supportedContentTypes);
       }
     } else {
@@ -144,7 +143,7 @@ public class ContentNegotiator {
       if (processorClass == MetadataProcessor.class) {
         requestedContentType = ContentType.APPLICATION_XML;
       } else {
-        requestedContentType = 
ContentType.create(ContentType.APPLICATION_JSON, "odata.metadata=minimal");
+        requestedContentType = 
ODataFormat.JSON.getContentType(ODataServiceVersion.V40);
       }
 
       for (FormatContentTypeMapping entry : supportedContentTypes) {
@@ -156,7 +155,7 @@ public class ContentNegotiator {
     }
 
     if (!supported) {
-      throw new RuntimeException("unsupported accept content type: " + 
requestedContentType + " != "
+      throw new ODataRuntimeException("unsupported accept content type: " + 
requestedContentType + " != "
           + supportedContentTypes);
     }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/210cf9b3/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
index 1d1fdaf..c3eb43e 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
@@ -36,7 +36,9 @@ public class ODataImpl extends OData {
     ODataSerializer serializer;
     switch (format) {
     case JSON:
-      serializer = new ODataJsonSerializer();
+    case JSON_NO_METADATA:
+    case JSON_FULL_METADATA:
+      serializer = new ODataJsonSerializer(format);
       break;
     case XML:
       serializer = new ODataXmlSerializerImpl();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/210cf9b3/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
index 4870a5c..b2025eb 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
@@ -40,6 +40,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.format.ODataFormat;
 import 
org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
@@ -54,6 +55,12 @@ public class ODataJsonSerializer implements ODataSerializer {
 
   private static final Logger log = 
LoggerFactory.getLogger(ODataJsonSerializer.class);
 
+  private final ODataFormat format;
+
+  public ODataJsonSerializer(final ODataFormat format) {
+    this.format = format;
+  }
+
   @Override
   public InputStream serviceDocument(final Edm edm, final String serviceRoot) {
     CircleStreamBuffer buffer;
@@ -101,13 +108,26 @@ public class ODataJsonSerializer implements 
ODataSerializer {
   }
 
   @Override
+  public InputStream error(final ODataError error) {
+    CircleStreamBuffer buffer = new CircleStreamBuffer();
+    try {
+      JsonGenerator json = new 
JsonFactory().createGenerator(buffer.getOutputStream());
+      new ODataErrorSerializer().writeErrorDocument(json, error);
+      json.close();
+    } catch (final IOException e) {
+      throw new ODataRuntimeException(e);
+    }
+    return buffer.getInputStream();
+  }
+
+  @Override
   public InputStream entitySet(final EdmEntitySet edmEntitySet, final 
EntitySet entitySet,
       final ContextURL contextURL) {
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new 
JsonFactory().createGenerator(buffer.getOutputStream());
       json.writeStartObject();
-      if (contextURL != null) {
+      if (contextURL != null && format != ODataFormat.JSON_NO_METADATA) {
         json.writeStringField(Constants.JSON_CONTEXT, 
contextURL.getURI().toASCIIString());
       }
       if (entitySet.getCount() != null) {
@@ -149,17 +169,19 @@ public class ODataJsonSerializer implements 
ODataSerializer {
   protected void writeEntity(final EdmEntityType entityType, final Entity 
entity, final ContextURL contextURL,
       final JsonGenerator json) throws IOException, EdmPrimitiveTypeException {
     json.writeStartObject();
-    if (contextURL != null) {
-      json.writeStringField(Constants.JSON_CONTEXT, 
contextURL.getURI().toASCIIString());
-    }
-    if (entity.getETag() != null) {
-      json.writeStringField("@odata.etag", entity.getETag());
-    }
-    if (entity.getMediaETag() != null) {
-      json.writeStringField("@odata.mediaEtag", entity.getMediaETag());
-    }
-    if (entity.getMediaContentType() != null) {
-      json.writeStringField("@odata.mediaContentType", 
entity.getMediaContentType());
+    if (format != ODataFormat.JSON_NO_METADATA) {
+      if (contextURL != null) {
+        json.writeStringField(Constants.JSON_CONTEXT, 
contextURL.getURI().toASCIIString());
+      }
+      if (entity.getETag() != null) {
+        json.writeStringField("@odata.etag", entity.getETag());
+      }
+      if (entity.getMediaETag() != null) {
+        json.writeStringField("@odata.mediaEtag", entity.getMediaETag());
+      }
+      if (entity.getMediaContentType() != null) {
+        json.writeStringField("@odata.mediaContentType", 
entity.getMediaContentType());
+      }
     }
     for (final String propertyName : entityType.getPropertyNames()) {
       final EdmProperty edmProperty = (EdmProperty) 
entityType.getProperty(propertyName);
@@ -185,7 +207,7 @@ public class ODataJsonSerializer implements ODataSerializer 
{
         writePrimitive(edmProperty, property, json);
       } else if (property.isLinkedComplex()) {
         writeComplexValue(edmProperty, property.asLinkedComplex().getValue(), 
json);
-      } else if (property.isComplex()) {
+      } else if(property.isComplex()) {
         writeComplexValue(edmProperty, property.asComplex(), json);
       } else {
         throw new ODataRuntimeException("Property type not yet supported!");
@@ -193,7 +215,6 @@ public class ODataJsonSerializer implements ODataSerializer 
{
     }
   }
 
-
   private void writeCollection(EdmProperty edmProperty, Property property, 
JsonGenerator json)
           throws IOException, EdmPrimitiveTypeException {
     json.writeStartArray();
@@ -257,7 +278,7 @@ public class ODataJsonSerializer implements ODataSerializer 
{
   }
 
   private void writeComplexValue(final EdmProperty edmProperty, final 
List<Property> properties,
-      JsonGenerator json) throws IOException, EdmPrimitiveTypeException {
+                                       JsonGenerator json) throws IOException, 
EdmPrimitiveTypeException {
     final EdmComplexType type = (EdmComplexType) edmProperty.getType();
     json.writeStartObject();
     for (final String propertyName : type.getPropertyNames()) {
@@ -275,18 +296,4 @@ public class ODataJsonSerializer implements 
ODataSerializer {
     }
     return null;
   }
-
-  @Override
-  public InputStream error(ODataError error) {
-    CircleStreamBuffer buffer = new CircleStreamBuffer();
-    try {
-      JsonGenerator json = new 
JsonFactory().createGenerator(buffer.getOutputStream());
-      ODataErrorSerializer ser = new ODataErrorSerializer();
-      ser.writeErrorDocument(json, error);
-      json.close();
-    } catch (final IOException e) {
-      throw new ODataRuntimeException(e);
-    }
-    return buffer.getInputStream();
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/210cf9b3/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index 8e126b7..f9d1e55 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -66,7 +66,7 @@ public class TechnicalProcessor implements 
CollectionProcessor, EntityProcessor
       response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode());
       return;
     }
-    ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON);
+    ODataSerializer serializer = 
odata.createSerializer(ODataFormat.fromContentType(requestedContentType));
     final EdmEntitySet edmEntitySet = 
getEdmEntitySet(uriInfo.asUriInfoResource());
     try {
       final EntitySet entitySet = readEntitySetInternal(edmEntitySet, 
request.getRawBaseUri());
@@ -90,7 +90,7 @@ public class TechnicalProcessor implements 
CollectionProcessor, EntityProcessor
       response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode());
       return;
     }
-    ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON);
+    ODataSerializer serializer = 
odata.createSerializer(ODataFormat.fromContentType(requestedContentType));
     final EdmEntitySet edmEntitySet = 
getEdmEntitySet(uriInfo.asUriInfoResource());
     try {
       final Entity entity = readEntityInternal(uriInfo.asUriInfoResource(), 
edmEntitySet);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/210cf9b3/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java
 
b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java
index cc8ddce..462855c 100644
--- 
a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java
+++ 
b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/JsonDataProviderTest.java
@@ -35,6 +35,7 @@ import org.apache.olingo.commons.api.edm.EdmEntityType;
 import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.edm.EdmStructuredType;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.format.ODataFormat;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer;
 import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
@@ -184,16 +185,12 @@ public class JsonDataProviderTest {
     EntitySet outSet = jdp.readAll(entitySet);
 
 
-    ODataJsonSerializer serializer = new ODataJsonSerializer();
+    ODataJsonSerializer serializer = new ODataJsonSerializer(ODataFormat.JSON);
     ContextURL contextUrl = null;
     InputStream is = serializer.entitySet(entitySet, outSet, contextUrl);
 
     StringHelper.Stream stream = StringHelper.toStream(is);
 
-//    System.out.println("========== " + entitySet.getName() + " 
=================");
-//    stream.print();
-//    System.out.println("\n========== " + entitySet.getName() + " 
=================");
-
     Assert.assertEquals(expectedLength, stream.asString().length());
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/210cf9b3/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
index f1987fd..d3753b4 100644
--- 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
@@ -18,10 +18,10 @@
  */
 package org.apache.olingo.server.core.serializer.json;
 
-import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
@@ -29,6 +29,7 @@ import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntityContainer;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.format.ODataFormat;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
@@ -42,7 +43,7 @@ public class ODataJsonSerializerTest {
   private final EdmEntityContainer entityContainer = edm.getEntityContainer(
       new FullQualifiedName("com.sap.odata.test1", "Container"));
   private final DataProvider data = new DataProvider(edm);
-  private ODataSerializer serializer = new ODataJsonSerializer();
+  private ODataSerializer serializer = new 
ODataJsonSerializer(ODataFormat.JSON);
 
   @Test
   public void entitySimple() throws Exception {
@@ -50,7 +51,7 @@ public class ODataJsonSerializerTest {
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet.getEntityType(), 
entity,
         ContextURL.getInstance(URI.create("$metadata#ESAllPrim/$entity")));
-    final String resultString = streamToString(result);
+    final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
         + "\"PropertyInt16\":32767,"
@@ -81,7 +82,7 @@ public class ODataJsonSerializerTest {
     entitySet.setNext(URI.create("/next"));
     InputStream result = serializer.entitySet(edmEntitySet, entitySet,
         ContextURL.getInstance(URI.create("$metadata#ESAllPrim")));
-    final String resultString = streamToString(result);
+    final String resultString = IOUtils.toString(result);
 
     Assert.assertTrue(resultString.matches("\\{"
         + "\"@odata\\.context\":\"\\$metadata#ESAllPrim\","
@@ -104,7 +105,7 @@ public class ODataJsonSerializerTest {
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet.getEntityType(), 
entity,
         ContextURL.getInstance(URI.create("$metadata#ESCollAllPrim/$entity")));
-    final String resultString = streamToString(result);
+    final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESCollAllPrim/$entity\","
         + "\"PropertyInt16\":1,"
@@ -136,7 +137,7 @@ public class ODataJsonSerializerTest {
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet.getEntityType(), 
entity,
         ContextURL.getInstance(URI.create("$metadata#ESCompAllPrim/$entity")));
-    final String resultString = streamToString(result);
+    final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESCompAllPrim/$entity\","
         + "\"PropertyInt16\":32767,"
@@ -167,7 +168,7 @@ public class ODataJsonSerializerTest {
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet.getEntityType(), 
entity,
         
ContextURL.getInstance(URI.create("$metadata#ESMixPrimCollComp/$entity")));
-    final String resultString = streamToString(result);
+    final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\","
         + "\"PropertyInt16\":32767,"
@@ -180,16 +181,29 @@ public class ODataJsonSerializerTest {
     Assert.assertEquals(expectedResult, resultString);
   }
 
-  private String streamToString(InputStream input) throws IOException {
-    byte[] buffer = new byte[8192];
-    StringBuilder result = new StringBuilder();
-
-    int count = input.read(buffer);
-    while (count >= 0) {
-      result.append(new String(buffer, 0, count, "UTF-8"));
-      count = input.read(buffer);
-    }
+  @Test
+  public void entityTwoPrimNoMetadata() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESTwoPrim");
+    final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA)
+        .entity(edmEntitySet.getEntityType(), entity, 
ContextURL.getInstance(URI.create("contextURL")));
+    final String resultString = IOUtils.toString(result);
+    final String expectedResult = 
"{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}";
+    Assert.assertEquals(expectedResult, resultString);
+  }
 
-    return result.toString();
+  @Test
+  public void entitySetTwoPrimNoMetadata() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESTwoPrim");
+    final EntitySet entitySet = data.readAll(edmEntitySet);
+    InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA)
+        .entitySet(edmEntitySet, entitySet, 
ContextURL.getInstance(URI.create("contextURL")));
+    final String resultString = IOUtils.toString(result);
+    final String expectedResult = "{\"value\":["
+        + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"},"
+        + "{\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\"},"
+        + "{\"PropertyInt16\":-32766,\"PropertyString\":\"Test String3\"},"
+        + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}";
+    Assert.assertEquals(expectedResult, resultString);
   }
 }

Reply via email to