You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2013/06/27 10:36:01 UTC

git commit: CAMEL-6494: Allow for skipping fields and trailing characters in Bindy fixed-length records. Thanks to Rich Newcomb for the patch.

Updated Branches:
  refs/heads/master 5bb1b4d3e -> b7e0a366f


CAMEL-6494: Allow for skipping fields and trailing characters in Bindy fixed-length records. Thanks to Rich Newcomb for the patch.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/b7e0a366
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/b7e0a366
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/b7e0a366

Branch: refs/heads/master
Commit: b7e0a366f9af09c7343c30b752ab668e2eee6dc3
Parents: 5bb1b4d
Author: Claus Ibsen <da...@apache.org>
Authored: Thu Jun 27 10:35:50 2013 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Jun 27 10:35:50 2013 +0200

----------------------------------------------------------------------
 .../bindy/BindyFixedLengthFactory.java          |  28 ++-
 .../bindy/annotation/FixedLengthRecord.java     |   5 +
 .../BindySimpleIgnoreTrailingCharsTest.java     | 249 ++++++++++++++++++
 .../skipfields/BindySimpleSkipFieldsTest.java   | 252 +++++++++++++++++++
 4 files changed, 528 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/b7e0a366/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java
index 57836eb..da522e9 100644
--- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java
+++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java
@@ -48,9 +48,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin
 
     boolean isOneToMany;
 
-    //private Map<Integer, DataField> dataFields = new LinkedHashMap<Integer, DataField>();
     private Map<Integer, DataField> dataFields = new TreeMap<Integer, DataField>();
-    //private Map<Integer, Field> annotatedFields = new LinkedHashMap<Integer, Field>();
     private Map<Integer, Field> annotatedFields = new TreeMap<Integer, Field>();
    
     private int numberOptionalFields;
@@ -65,6 +63,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin
     private boolean isFooter;
     private char paddingChar;
     private int recordLength;
+    private boolean ignoreTrailingChars;
 
     public BindyFixedLengthFactory(PackageScanClassResolver resolver, String... packageNames) throws Exception {
         super(resolver, packageNames);
@@ -204,6 +203,12 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin
                 throw new IllegalArgumentException("Offset/Position of the field " + dataField.toString()
                                                    + " cannot be negative");
             }
+
+            // skip ahead if the expected position is greater than the offset
+            if (dataField.pos() > offset) {
+                LOG.debug("skipping ahead [" + (dataField.pos() - offset) + "] chars.");
+                offset = dataField.pos();
+            }
             
             if (length > 0) {
                 token = record.substring(offset - 1, offset + length - 1);
@@ -272,7 +277,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin
         }
         
         // check for unmapped non-whitespace data at the end of the line
-        if (offset <= record.length() && !(record.substring(offset - 1, record.length())).trim().equals("")) {
+        if (offset <= record.length() && !(record.substring(offset - 1, record.length())).trim().equals("") && !isIgnoreTrailingChars()) {
             throw new IllegalArgumentException("Unexpected / unmapped characters found at the end of the fixed-length record at line : " + line);
         }
 
@@ -479,6 +484,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin
                 
                 // Get skipHeader parameter
                 skipHeader = record.skipHeader();
+                LOG.debug("Skip Header: {}", skipHeader);
 
                 // Get hasFooter parameter
                 hasFooter = record.hasFooter();
@@ -486,12 +492,15 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin
                 
                 // Get skipFooter parameter
                 skipFooter = record.skipFooter();
+                LOG.debug("Skip Footer: {}", skipFooter);
                 
                 // Get isHeader parameter
                 isHeader = record.isHeader();
+                LOG.debug("Is Header: {}", isHeader);
                 
                 // Get isFooter parameter
                 isFooter = record.isFooter();
+                LOG.debug("Is Footer: {}", isFooter);
 
                 // Get padding character
                 paddingChar = record.paddingChar();
@@ -501,9 +510,9 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin
                 recordLength = record.length();
                 LOG.debug("Length of the record: {}", recordLength);
 
-                // Get length of the record
-                recordLength = record.length();
-                LOG.debug("Length of the record: {}", recordLength);    
+                // Get flag for ignore trailing characters
+                ignoreTrailingChars = record.ignoreTrailingChars();
+                LOG.debug("Ignore trailing chars: {}", ignoreTrailingChars);
             }
         }
         
@@ -578,4 +587,11 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin
         return recordLength;
     }
 
+    /**
+     * Flag indicating whether trailing characters beyond the last declared field may be ignored
+     */
+    public boolean isIgnoreTrailingChars() {
+        return this.ignoreTrailingChars;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/b7e0a366/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/FixedLengthRecord.java
----------------------------------------------------------------------
diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/FixedLengthRecord.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/FixedLengthRecord.java
index 694b98f..cf88a2d 100644
--- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/FixedLengthRecord.java
+++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/FixedLengthRecord.java
@@ -86,4 +86,9 @@ public @interface FixedLengthRecord {
      */
     boolean isFooter() default false;
 
+    /**
+     * Indicates whether trailing characters beyond the last mapped field may be ignored
+     */
+    boolean ignoreTrailingChars() default false;
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/b7e0a366/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/ignoretrailing/BindySimpleIgnoreTrailingCharsTest.java
----------------------------------------------------------------------
diff --git a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/ignoretrailing/BindySimpleIgnoreTrailingCharsTest.java b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/ignoretrailing/BindySimpleIgnoreTrailingCharsTest.java
new file mode 100644
index 0000000..a062ca0
--- /dev/null
+++ b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/ignoretrailing/BindySimpleIgnoreTrailingCharsTest.java
@@ -0,0 +1,249 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.camel.dataformat.bindy.fixed.ignoretrailing;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.dataformat.bindy.annotation.DataField;
+import org.apache.camel.dataformat.bindy.annotation.FixedLengthRecord;
+import org.apache.camel.model.dataformat.BindyDataFormat;
+import org.apache.camel.model.dataformat.BindyType;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * This test validates that bindy will ignore trailing characters in a record when the
+ * ignoreTrailingCharacters property is set to 'true' on the @FixedLengthRecord annotation
+ */
+public class BindySimpleIgnoreTrailingCharsTest extends CamelTestSupport {
+
+    public static final String URI_DIRECT_MARSHALL         = "direct:marshall";
+    public static final String URI_DIRECT_UNMARSHALL       = "direct:unmarshall";
+    public static final String URI_MOCK_MARSHALL_RESULT    = "mock:marshall-result";
+    public static final String URI_MOCK_UNMARSHALL_RESULT  = "mock:unmarshall-result";
+
+    private static final String TEST_RECORD = "10A9  PaulineM    ISINXD12345678BUYShare000002500.45USD01-08-2009Hello     xxx\r\n";
+
+    @EndpointInject(uri = URI_MOCK_MARSHALL_RESULT)
+    private MockEndpoint marshallResult;
+
+    @EndpointInject(uri = URI_MOCK_UNMARSHALL_RESULT)
+    private MockEndpoint unmarshallResult;
+
+    // *************************************************************************
+    // TESTS
+    // *************************************************************************
+
+    @Test
+    public void testUnmarshallMessage() throws Exception {
+
+        unmarshallResult.expectedMessageCount(1);
+        template.sendBody(URI_DIRECT_UNMARSHALL, TEST_RECORD);
+
+        unmarshallResult.assertIsSatisfied();
+
+        // check the model
+        BindySimpleIgnoreTrailingCharsTest.Order order =
+            (BindySimpleIgnoreTrailingCharsTest.Order) unmarshallResult.getReceivedExchanges().get(0).getIn().getBody();
+        Assert.assertEquals(10, order.getOrderNr());
+        // the field is not trimmed
+        Assert.assertEquals(null, order.getFirstName());
+        Assert.assertEquals("M    ", order.getLastName());
+        Assert.assertEquals("Hello     ", order.getComment());
+    }
+
+
+    // *************************************************************************
+    // ROUTES
+    // *************************************************************************
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        RouteBuilder routeBuilder = new RouteBuilder() {
+
+            @Override
+            public void configure() throws Exception {
+                BindyDataFormat bindy = new BindyDataFormat();
+                bindy.setClassType(BindySimpleIgnoreTrailingCharsTest.Order.class);
+                bindy.setLocale("en");
+                bindy.setType(BindyType.Fixed);
+
+                from(URI_DIRECT_MARSHALL)
+                    .marshal(bindy)
+                    .to(URI_MOCK_MARSHALL_RESULT);
+
+                from(URI_DIRECT_UNMARSHALL)
+                    .unmarshal().bindy(BindyType.Fixed, BindySimpleIgnoreTrailingCharsTest.Order.class)
+                    .to(URI_MOCK_UNMARSHALL_RESULT);
+            }
+        };
+        
+        return routeBuilder;
+    }
+
+    // *************************************************************************
+    // DATA MODEL
+    // *************************************************************************
+    @FixedLengthRecord(ignoreTrailingChars = true)
+    public static class Order {
+
+        @DataField(pos = 1, length = 2)
+        private int orderNr;
+
+        @DataField(pos = 3, length = 2)
+        private String clientNr;
+
+        // not annotated for this test
+        private String firstName;
+
+        @DataField(pos = 14, length = 5, align = "L")
+        private String lastName;
+
+        @DataField(pos = 19, length = 4)
+        private String instrumentCode;
+
+        @DataField(pos = 23, length = 10)
+        private String instrumentNumber;
+
+        @DataField(pos = 33, length = 3)
+        private String orderType;
+
+        @DataField(pos = 36, length = 5)
+        private String instrumentType;
+
+        @DataField(pos = 41, precision = 2, length = 12, paddingChar = '0')
+        private BigDecimal amount;
+
+        @DataField(pos = 53, length = 3)
+        private String currency;
+
+        @DataField(pos = 56, length = 10, pattern = "dd-MM-yyyy")
+        private Date orderDate;
+
+        @DataField(pos = 66, length = 10, align = "L", paddingChar = ' ')
+        private String comment;
+
+        public int getOrderNr() {
+            return orderNr;
+        }
+
+        public void setOrderNr(int orderNr) {
+            this.orderNr = orderNr;
+        }
+
+        public String getClientNr() {
+            return clientNr;
+        }
+
+        public void setClientNr(String clientNr) {
+            this.clientNr = clientNr;
+        }
+
+        public String getFirstName() {
+            return firstName;
+        }
+
+        public void setFirstName(String firstName) {
+            this.firstName = firstName;
+        }
+
+        public String getLastName() {
+            return lastName;
+        }
+
+        public void setLastName(String lastName) {
+            this.lastName = lastName;
+        }
+
+        public String getInstrumentCode() {
+            return instrumentCode;
+        }
+
+        public void setInstrumentCode(String instrumentCode) {
+            this.instrumentCode = instrumentCode;
+        }
+
+        public String getInstrumentNumber() {
+            return instrumentNumber;
+        }
+
+        public void setInstrumentNumber(String instrumentNumber) {
+            this.instrumentNumber = instrumentNumber;
+        }
+
+        public String getOrderType() {
+            return orderType;
+        }
+
+        public void setOrderType(String orderType) {
+            this.orderType = orderType;
+        }
+
+        public String getInstrumentType() {
+            return instrumentType;
+        }
+
+        public void setInstrumentType(String instrumentType) {
+            this.instrumentType = instrumentType;
+        }
+
+        public BigDecimal getAmount() {
+            return amount;
+        }
+
+        public void setAmount(BigDecimal amount) {
+            this.amount = amount;
+        }
+
+        public String getCurrency() {
+            return currency;
+        }
+
+        public void setCurrency(String currency) {
+            this.currency = currency;
+        }
+
+        public Date getOrderDate() {
+            return orderDate;
+        }
+
+        public void setOrderDate(Date orderDate) {
+            this.orderDate = orderDate;
+        }
+
+        public String getComment() {
+            return comment;
+        }
+
+        public void setComment(String comment) {
+            this.comment = comment;
+        }
+
+        @Override
+        public String toString() {
+            return "Model : " + Order.class.getName() + " : " + this.orderNr + ", " + this.orderType + ", " + String.valueOf(this.amount) + ", " + this.instrumentCode + ", "
+                   + this.instrumentNumber + ", " + this.instrumentType + ", " + this.currency + ", " + this.clientNr + ", " + this.firstName + ", " + this.lastName + ", "
+                   + String.valueOf(this.orderDate);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/b7e0a366/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/skipfields/BindySimpleSkipFieldsTest.java
----------------------------------------------------------------------
diff --git a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/skipfields/BindySimpleSkipFieldsTest.java b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/skipfields/BindySimpleSkipFieldsTest.java
new file mode 100644
index 0000000..6e43a9e
--- /dev/null
+++ b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/skipfields/BindySimpleSkipFieldsTest.java
@@ -0,0 +1,252 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.camel.dataformat.bindy.fixed.skipfields;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import org.apache.camel.EndpointInject;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.dataformat.bindy.annotation.DataField;
+import org.apache.camel.dataformat.bindy.annotation.FixedLengthRecord;
+
+import org.apache.camel.model.dataformat.BindyDataFormat;
+import org.apache.camel.model.dataformat.BindyType;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/**
+ * This test validates that bindy can skip values in the fixed-length record when absolute pos
+ * values are provided
+ */
+public class BindySimpleSkipFieldsTest extends CamelTestSupport {
+
+    public static final String URI_DIRECT_MARSHALL         = "direct:marshall";
+    public static final String URI_DIRECT_UNMARSHALL       = "direct:unmarshall";
+    public static final String URI_MOCK_MARSHALL_RESULT    = "mock:marshall-result";
+    public static final String URI_MOCK_UNMARSHALL_RESULT  = "mock:unmarshall-result";
+    
+    private static final String TEST_RECORD = "10A9  PaulineM    ISINXD12345678BUYShare000002500.45USD01-08-2009Hello     \r\n";
+
+    @EndpointInject(uri = URI_MOCK_MARSHALL_RESULT)
+    private MockEndpoint marshallResult;
+
+    @EndpointInject(uri = URI_MOCK_UNMARSHALL_RESULT)
+    private MockEndpoint unmarshallResult;
+
+    // *************************************************************************
+    // TESTS
+    // *************************************************************************
+
+    @Test
+    public void testUnmarshallMessage() throws Exception {
+
+        unmarshallResult.expectedMessageCount(1);
+        template.sendBody(URI_DIRECT_UNMARSHALL, TEST_RECORD);
+        
+        unmarshallResult.assertIsSatisfied();
+
+        // check the model
+        BindySimpleSkipFieldsTest.Order order = 
+            (BindySimpleSkipFieldsTest.Order) unmarshallResult.getReceivedExchanges().get(0).getIn().getBody();
+        Assert.assertEquals(10, order.getOrderNr());
+        // the field is not trimmed
+        Assert.assertEquals(null, order.getFirstName());
+        Assert.assertEquals("M    ", order.getLastName());
+        Assert.assertEquals("Hello     ", order.getComment());
+    }
+    
+    
+    // *************************************************************************
+    // ROUTES
+    // *************************************************************************
+    
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        RouteBuilder routeBuilder = new RouteBuilder() {
+
+            @Override
+            public void configure() throws Exception {
+                BindyDataFormat bindy = new BindyDataFormat();
+                bindy.setClassType(BindySimpleSkipFieldsTest.Order.class);
+                bindy.setLocale("en");
+                bindy.setType(BindyType.Fixed);
+
+                from(URI_DIRECT_MARSHALL)
+                    .marshal(bindy)
+                    .to(URI_MOCK_MARSHALL_RESULT);
+            
+                from(URI_DIRECT_UNMARSHALL)
+                    .unmarshal().bindy(BindyType.Fixed, BindySimpleSkipFieldsTest.Order.class)
+                    .to(URI_MOCK_UNMARSHALL_RESULT);
+            }
+        };
+        
+        return routeBuilder;
+    }
+
+    // *************************************************************************
+    // DATA MODEL
+    // *************************************************************************
+    @FixedLengthRecord(ignoreTrailingChars = false)
+    public static class Order {
+
+        @DataField(pos = 1, length = 2)
+        private int orderNr;
+
+        @DataField(pos = 3, length = 2)
+        private String clientNr;
+
+        // not annotated for this test
+        private String firstName;
+
+        @DataField(pos = 14, length = 5, align = "L")
+        private String lastName;
+
+        @DataField(pos = 19, length = 4)
+        private String instrumentCode;
+
+        @DataField(pos = 23, length = 10)
+        private String instrumentNumber;
+
+        @DataField(pos = 33, length = 3)
+        private String orderType;
+
+        @DataField(pos = 36, length = 5)
+        private String instrumentType;
+
+        @DataField(pos = 41, precision = 2, length = 12, paddingChar = '0')
+        private BigDecimal amount;
+
+        @DataField(pos = 53, length = 3)
+        private String currency;
+
+        @DataField(pos = 56, length = 10, pattern = "dd-MM-yyyy")
+        private Date orderDate;
+
+        @DataField(pos = 66, length = 10, align = "L", paddingChar = ' ')
+        private String comment;
+
+        public int getOrderNr() {
+            return orderNr;
+        }
+
+        public void setOrderNr(int orderNr) {
+            this.orderNr = orderNr;
+        }
+
+        public String getClientNr() {
+            return clientNr;
+        }
+
+        public void setClientNr(String clientNr) {
+            this.clientNr = clientNr;
+        }
+
+        public String getFirstName() {
+            return firstName;
+        }
+
+        public void setFirstName(String firstName) {
+            this.firstName = firstName;
+        }
+
+        public String getLastName() {
+            return lastName;
+        }
+
+        public void setLastName(String lastName) {
+            this.lastName = lastName;
+        }
+
+        public String getInstrumentCode() {
+            return instrumentCode;
+        }
+
+        public void setInstrumentCode(String instrumentCode) {
+            this.instrumentCode = instrumentCode;
+        }
+
+        public String getInstrumentNumber() {
+            return instrumentNumber;
+        }
+
+        public void setInstrumentNumber(String instrumentNumber) {
+            this.instrumentNumber = instrumentNumber;
+        }
+
+        public String getOrderType() {
+            return orderType;
+        }
+
+        public void setOrderType(String orderType) {
+            this.orderType = orderType;
+        }
+
+        public String getInstrumentType() {
+            return instrumentType;
+        }
+
+        public void setInstrumentType(String instrumentType) {
+            this.instrumentType = instrumentType;
+        }
+
+        public BigDecimal getAmount() {
+            return amount;
+        }
+
+        public void setAmount(BigDecimal amount) {
+            this.amount = amount;
+        }
+
+        public String getCurrency() {
+            return currency;
+        }
+
+        public void setCurrency(String currency) {
+            this.currency = currency;
+        }
+
+        public Date getOrderDate() {
+            return orderDate;
+        }
+
+        public void setOrderDate(Date orderDate) {
+            this.orderDate = orderDate;
+        }
+
+        public String getComment() {
+            return comment;
+        }
+
+        public void setComment(String comment) {
+            this.comment = comment;
+        }
+
+        @Override
+        public String toString() {
+            return "Model : " + Order.class.getName() + " : " + this.orderNr + ", " + this.orderType + ", " + String.valueOf(this.amount) + ", " + this.instrumentCode + ", "
+                   + this.instrumentNumber + ", " + this.instrumentType + ", " + this.currency + ", " + this.clientNr + ", " + this.firstName + ", " + this.lastName + ", "
+                   + String.valueOf(this.orderDate);
+        }
+    }
+
+}