You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by cu...@apache.org on 2010/02/02 22:51:50 UTC

svn commit: r905807 - in /hadoop/avro/trunk: ./ lang/java/src/java/org/apache/avro/generic/ lang/java/src/java/org/apache/avro/specific/ lang/java/src/test/java/org/apache/avro/generic/ lang/java/src/test/java/org/apache/avro/specific/

Author: cutting
Date: Tue Feb  2 21:51:49 2010
New Revision: 905807

URL: http://svn.apache.org/viewvc?rev=905807&view=rev
Log:
AVRO-387.  Add IndexedRecord interface, so that specific & generic may share #toString(), #hashCode(), #compare(), etc.  Also fix toString() and hashCode() to not throw NPE for uninitialized records.

Added:
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java
    hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java
Modified:
    hadoop/avro/trunk/CHANGES.txt
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java
    hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java
    hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java

Modified: hadoop/avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/CHANGES.txt?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/CHANGES.txt (original)
+++ hadoop/avro/trunk/CHANGES.txt Tue Feb  2 21:51:49 2010
@@ -36,6 +36,11 @@
 
     AVRO-374. Remove and ignore files that are created by autoreconf. (sbanacho)
 
+    AVRO-387. Add IndexedRecord interface, common to both specific and
+    generic records, so that toString() and hashCode() implementations
+    can be shared.  Also fix toString() and hashCode() to not throw
+    NPE for uninitialized records. (cutting)
+
   NEW FEATURES
 
     AVRO-151. Validating Avro schema parser for C (massie)

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java Tue Feb  2 21:51:49 2010
@@ -175,8 +175,8 @@
   public boolean validate(Schema schema, Object datum) {
     switch (schema.getType()) {
     case RECORD:
-      if (!(datum instanceof GenericRecord)) return false;
-      GenericRecord fields = (GenericRecord)datum;
+      if (!(datum instanceof IndexedRecord)) return false;
+      IndexedRecord fields = (IndexedRecord)datum;
       for (Map.Entry<String, Field> entry : schema.getFields().entrySet()) {
         Field f = entry.getValue();
         if (!validate(f.schema(), fields.get(f.pos())))
@@ -225,11 +225,12 @@
     toString(datum, buffer);
     return buffer.toString();
   }
-  private void toString(Object datum, StringBuilder buffer) {
-    if (datum instanceof GenericRecord) {
+  /** Renders a Java datum as <a href="http://www.json.org/">JSON</a>. */
+  protected void toString(Object datum, StringBuilder buffer) {
+    if (datum instanceof IndexedRecord) {
       buffer.append("{");
       int count = 0;
-      GenericRecord record = (GenericRecord)datum;
+      IndexedRecord record = (IndexedRecord)datum;
       for (Map.Entry<String,Field> e :
              record.getSchema().getFields().entrySet()) {
         toString(e.getKey(), buffer);
@@ -280,8 +281,8 @@
 
   /** Create a schema given an example datum. */
   public Schema induce(Object datum) {
-    if (datum instanceof GenericRecord) {
-      return ((GenericRecord)datum).getSchema();
+    if (datum instanceof IndexedRecord) {
+      return ((IndexedRecord)datum).getSchema();
     } else if (datum instanceof GenericArray) {
       Schema elementType = null;
       for (Object element : (GenericArray)datum) {
@@ -370,11 +371,11 @@
 
   /** Called by the default implementation of {@link #instanceOf}.*/
   protected boolean isRecord(Object datum) {
-    return datum instanceof GenericRecord;
+    return datum instanceof IndexedRecord;
   }
 
   /** Called to obtain the schema of a record.  By default calls
-   * {GenericRecord#getSchema().  May be overridden for alternate record
+   * {GenericContainer#getSchema().  May be overridden for alternate record
    * representations. */
   protected Schema getRecordSchema(Object record) {
     return ((GenericContainer)record).getSchema();
@@ -387,7 +388,7 @@
   
   /** Called by the default implementation of {@link #instanceOf}.*/
   protected boolean isMap(Object datum) {
-    return (datum instanceof Map) && (!(datum instanceof GenericRecord));
+    return datum instanceof Map;
   }
   
   /** Called by the default implementation of {@link #instanceOf}.*/
@@ -408,10 +409,11 @@
   /** Compute a hash code according to a schema, consistent with {@link
    * #compare(Object,Object,Schema)}. */
   public int hashCode(Object o, Schema s) {
+    if (o == null) return 0;                      // incomplete datum
     int hashCode = 1;
     switch (s.getType()) {
     case RECORD:
-      GenericRecord r = (GenericRecord)o;
+      IndexedRecord r = (IndexedRecord)o;
       for (Map.Entry<String, Field> e : s.getFields().entrySet()) {
         Field f = e.getValue();
         if (f.order() == Field.Order.IGNORE)
@@ -430,7 +432,7 @@
     case NULL:
       return 0;
     default:
-      return (o == null) ? 0 : o.hashCode();
+      return o.hashCode();
     }
   }
 
@@ -448,8 +450,8 @@
     if (o1 == o2) return 0;
     switch (s.getType()) {
     case RECORD:
-      GenericRecord r1 = (GenericRecord)o1;
-      GenericRecord r2 = (GenericRecord)o2;
+      IndexedRecord r1 = (IndexedRecord)o1;
+      IndexedRecord r2 = (IndexedRecord)o2;
       for (Map.Entry<String, Field> e : s.getFields().entrySet()) {
         Field f = e.getValue();
         if (f.order() == Field.Order.IGNORE)

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java Tue Feb  2 21:51:49 2010
@@ -174,16 +174,16 @@
 
   /** Called by the default implementation of {@link #readRecord} to set a
    * record fields value to a record instance.  The default implementation is
-   * for {@link GenericRecord}.*/
+   * for {@link IndexedRecord}.*/
   protected void setField(Object record, String name, int position, Object o) {
-    ((GenericRecord)record).put(position, o);
+    ((IndexedRecord)record).put(position, o);
   }
   
   /** Called by the default implementation of {@link #readRecord} to retrieve a
    * record field value from a reused instance.  The default implementation is
-   * for {@link GenericRecord}.*/
+   * for {@link IndexedRecord}.*/
   protected Object getField(Object record, String name, int position) {
-    return ((GenericRecord)record).get(position);
+    return ((IndexedRecord)record).get(position);
   }
 
   /** Called by the default implementation of {@link #readRecord} to construct
@@ -359,8 +359,8 @@
    * a {@link GenericData.Record}.
    */
   protected Object newRecord(Object old, Schema schema) {
-    if (old instanceof GenericRecord) {
-      GenericRecord record = (GenericRecord)old;
+    if (old instanceof IndexedRecord) {
+      IndexedRecord record = (IndexedRecord)old;
       if (record.getSchema() == schema)
         return record;
     }

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java Tue Feb  2 21:51:49 2010
@@ -93,9 +93,9 @@
   
   /** Called by the default implementation of {@link #writeRecord} to retrieve
    * a record field value.  The default implementation is for {@link
-   * GenericRecord}.*/
+   * IndexedRecord}.*/
   protected Object getField(Object record, String field, int position) {
-    return ((GenericRecord) record).get(position);
+    return ((IndexedRecord) record).get(position);
   }
   
   /** Called to write an enum value.  May be overridden for alternate enum

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java Tue Feb  2 21:51:49 2010
@@ -17,14 +17,11 @@
  */
 package org.apache.avro.generic;
 
-/** An instance of a record schema.*/
-public interface GenericRecord extends GenericContainer {
+/** A generic instance of a record schema.  Fields are accessible by name as
+ * well as by index. */
+public interface GenericRecord extends IndexedRecord {
   /** Set the value of a field given its name. */
   void put(String key, Object v);
-  /** Set the value of a field given its position in the schema. */
-  void put(int i, Object v);
   /** Return the value of a field given its name. */
   Object get(String key);
-  /** Return the value of a field given its position in the schema. */
-  Object get(int i);
 }

Added: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java?rev=905807&view=auto
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java (added)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java Tue Feb  2 21:51:49 2010
@@ -0,0 +1,26 @@
+/**
+ * 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.avro.generic;
+
+/** A record implementation that permits field access by integer index.*/
+public interface IndexedRecord extends GenericContainer {
+  /** Set the value of a field given its position in the schema. */
+  void put(int i, Object v);
+  /** Return the value of a field given its position in the schema. */
+  Object get(int i);
+}

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java Tue Feb  2 21:51:49 2010
@@ -275,7 +275,7 @@
       line(out, 1, "}");
       // set method
       line(out, 1, "@SuppressWarnings(value=\"unchecked\")");
-      line(out, 1, "public void set(int field$, java.lang.Object value$) {");
+      line(out, 1, "public void put(int field$, java.lang.Object value$) {");
       line(out, 2, "switch (field$) {");
       i = 0;
       for (Map.Entry<String, Schema> field : schema.getFieldSchemas())

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java Tue Feb  2 21:51:49 2010
@@ -17,7 +17,6 @@
  */
 package org.apache.avro.specific;
 
-import java.util.Iterator;
 import java.util.Map;
 import java.util.List;
 import java.util.WeakHashMap;
@@ -30,7 +29,6 @@
 import org.apache.avro.Protocol;
 import org.apache.avro.AvroRuntimeException;
 import org.apache.avro.AvroTypeException;
-import org.apache.avro.Schema.Field;
 import org.apache.avro.Schema.Type;
 import org.apache.avro.generic.GenericData;
 import org.apache.avro.generic.GenericArray;
@@ -64,15 +62,6 @@
   @Override
   public boolean validate(Schema schema, Object datum) {
     switch (schema.getType()) {
-    case RECORD:
-      Class c = datum.getClass(); 
-      if (!(datum instanceof SpecificRecord)) return false;
-      SpecificRecord record = (SpecificRecord)datum;
-      Iterator<Field> fields = schema.getFields().values().iterator();
-      for (int i = 0; fields.hasNext(); i++)
-        if (!validate(fields.next().schema(), record.get(i)))
-          return false;
-      return true;
     case ENUM:
       return datum instanceof Enum
         && schema.getEnumSymbols().contains(((Enum)datum).name());
@@ -210,40 +199,8 @@
   }
 
   @Override
-  public int hashCode(Object o, Schema s) {
-    switch (s.getType()) {
-    case RECORD:
-      int hashCode = 1;
-      SpecificRecord r = (SpecificRecord)o;
-      Iterator<Field> fields = s.getFields().values().iterator();
-      for (int i = 0; fields.hasNext(); i++) {
-        Field f = fields.next();
-        if (f.order() == Field.Order.IGNORE)
-          continue;
-        hashCode = hashCodeAdd(hashCode, r.get(i), f.schema());
-      }
-      return hashCode;
-    default:
-      return super.hashCode(o, s);
-    }
-  }
-
-  @Override
   public int compare(Object o1, Object o2, Schema s) {
     switch (s.getType()) {
-    case RECORD:
-      SpecificRecord r1 = (SpecificRecord)o1;
-      SpecificRecord r2 = (SpecificRecord)o2;
-      Iterator<Field> fields = s.getFields().values().iterator();
-      for (int i = 0; fields.hasNext(); i++) {
-        Field f = fields.next();
-        if (f.order() == Field.Order.IGNORE)
-          continue;                               // ignore this field
-        int compare = compare(r1.get(i), r2.get(i), f.schema());
-        if (compare != 0)                         // not equal
-          return f.order() == Field.Order.DESCENDING ? -compare : compare;
-      }
-      return 0;
     case ENUM:
       return ((Enum)o1).ordinal() - ((Enum)o2).ordinal();
     default:

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java Tue Feb  2 21:51:49 2010
@@ -44,7 +44,7 @@
 
   @Override
   protected void setField(Object record, String name, int position, Object o) {
-    ((SpecificRecord)record).set(position, o);
+    ((SpecificRecord)record).put(position, o);
   }
   @Override
   protected Object getField(Object record, String name, int position) {

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java Tue Feb  2 21:51:49 2010
@@ -27,7 +27,7 @@
 
   public abstract Schema getSchema();
   public abstract Object get(int field);
-  public abstract void set(int field, Object value);
+  public abstract void put(int field, Object value);
 
   public boolean equals(Object that) {
     if (that == this) return true;                        // identical object

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java Tue Feb  2 21:51:49 2010
@@ -17,12 +17,10 @@
  */
 package org.apache.avro.specific;
 
-import org.apache.avro.generic.GenericContainer;
+import org.apache.avro.generic.IndexedRecord;
 
 /** Implemented by generated record classes. Permits efficient access to
  * fields.*/
-public interface SpecificRecord extends GenericContainer {
-  Object get(int field);
-  void set(int field, Object value);
+public interface SpecificRecord extends IndexedRecord {
 }
 

Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java Tue Feb  2 21:51:49 2010
@@ -25,7 +25,7 @@
 
   public abstract Schema getSchema();
   public abstract Object get(int field);
-  public abstract void set(int field, Object value);
+  public abstract void put(int field, Object value);
 
   @Override
   public boolean equals(Object that) {
@@ -45,5 +45,10 @@
     return SpecificData.get().compare(this, that, this.getSchema());
   }
 
+  @Override
+  public String toString() {
+    return SpecificData.get().toString(this);
+  }
+
 }
 

Modified: hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java (original)
+++ hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java Tue Feb  2 21:51:49 2010
@@ -19,8 +19,11 @@
 
 import static org.junit.Assert.*;
 
+import java.util.Arrays;
+
 import org.apache.avro.Schema;
 import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.Schema.Type;
 
 import org.junit.Test;
 
@@ -45,5 +48,13 @@
     public void testArrayConstructorWrongSchema() throws Exception {
     new GenericData.Array<Object>(1, Schema.create(Schema.Type.INT));
   }
+  
+  @Test
+  /** Make sure that even with nulls, hashCode() doesn't throw NPE. */
+  public void testHashCode() {
+    GenericData.get().hashCode(null, Schema.create(Type.NULL));
+    GenericData.get().hashCode(null, Schema.createUnion(
+        Arrays.asList(Schema.create(Type.BOOLEAN), Schema.create(Type.STRING))));
+  }
 
 }

Added: hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java?rev=905807&view=auto
==============================================================================
--- hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java (added)
+++ hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java Tue Feb  2 21:51:49 2010
@@ -0,0 +1,41 @@
+/**
+ * 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.avro.specific;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import org.apache.avro.test.TestRecord;
+
+public class TestSpecificData {
+  
+  @Test
+  /** Make sure that even with nulls, hashCode() doesn't throw NPE. */
+  public void testHashCode() {
+    new TestRecord().hashCode();
+    SpecificData.get().hashCode(null, TestRecord.SCHEMA$);
+  }
+
+  @Test
+  /** Make sure that even with nulls, toString() doesn't throw NPE. */
+  public void testToString() {
+    new TestRecord().toString();
+  }
+
+}