Refactored the code
Project: http://git-wip-us.apache.org/repos/asf/gora/repo Commit: http://git-wip-us.apache.org/repos/asf/gora/commit/962d7a6a Tree: http://git-wip-us.apache.org/repos/asf/gora/tree/962d7a6a Diff: http://git-wip-us.apache.org/repos/asf/gora/diff/962d7a6a Branch: refs/heads/master Commit: 962d7a6ad830b8a6feca752ddf39f4d705bd563e Parents: 99894b8 Author: madhawa <madhaw...@gmail.com> Authored: Sun Jul 30 23:11:09 2017 +0530 Committer: madhawa <madhaw...@gmail.com> Committed: Wed Aug 2 07:14:55 2017 +0530 ---------------------------------------------------------------------- gora-cassandra-cql/pom.xml | 7 +- .../AvroSerialization/CassandraKey.java | 517 +++--- .../AvroSerialization/CassandraRecord.java | 1582 ++++++++++-------- .../nativeSerialization/ComplexTypes.java | 15 +- .../generated/nativeSerialization/User.java | 25 +- .../gora/cassandra/bean/CassandraKey.java | 24 +- .../gora/cassandra/bean/ClusterKeyField.java | 23 +- .../org/apache/gora/cassandra/bean/Field.java | 19 +- .../apache/gora/cassandra/bean/KeySpace.java | 46 +- .../gora/cassandra/bean/PartitionKeyField.java | 2 +- .../org/apache/gora/cassandra/package-info.java | 7 +- .../persistent/CassandraNativePersistent.java | 13 +- .../gora/cassandra/query/CassandraQuery.java | 2 +- .../cassandra/query/CassandraResultSet.java | 27 +- .../gora/cassandra/query/package-info.java | 7 +- .../serializers/AvroCassandraUtils.java | 156 +- .../cassandra/serializers/AvroSerializer.java | 236 +-- .../serializers/CassandraQueryFactory.java | 203 ++- .../serializers/CassandraSerializer.java | 100 +- .../cassandra/serializers/NativeSerializer.java | 31 +- .../cassandra/serializers/package-info.java | 7 +- .../gora/cassandra/store/CassandraClient.java | 24 +- .../gora/cassandra/store/CassandraMapping.java | 154 +- .../store/CassandraMappingBuilder.java | 26 +- .../gora/cassandra/store/CassandraStore.java | 48 +- .../store/CassandraStoreParameters.java | 8 +- .../gora/cassandra/store/package-info.java | 7 +- .../test/conf/avro/gora-cassandra-mapping.xml | 48 +- .../compositeKey/gora-cassandra-mapping.xml | 12 +- .../src/test/conf/gora-cassandra-mapping.xml | 3 +- .../src/test/conf/gora.properties | 1 - .../src/test/conf/log4j-server.properties | 9 +- .../gora-cassandra-mapping.xml | 49 +- .../conf/nativeSerialization/gora.properties | 1 - .../gora/cassandra/GoraCassandraTestDriver.java | 128 +- .../cassandra/store/TestCassandraStore.java | 133 ++ .../TestCassandraStoreWithCassandraKey.java | 34 +- ...stCassandraStoreWithNativeSerialization.java | 10 +- 38 files changed, 2225 insertions(+), 1519 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/gora/blob/962d7a6a/gora-cassandra-cql/pom.xml ---------------------------------------------------------------------- diff --git a/gora-cassandra-cql/pom.xml b/gora-cassandra-cql/pom.xml index 13e5a1a..ed98a18 100644 --- a/gora-cassandra-cql/pom.xml +++ b/gora-cassandra-cql/pom.xml @@ -16,7 +16,7 @@ ~ limitations under the License. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> @@ -173,6 +173,11 @@ <version>4.0.37.Final</version> </dependency> + <dependency> + <groupId>org.apache.gora</groupId> + <artifactId>gora-hbase</artifactId> + </dependency> + <!-- Misc Dependencies --> <dependency> <groupId>com.google.guava</groupId> http://git-wip-us.apache.org/repos/asf/gora/blob/962d7a6a/gora-cassandra-cql/src/examples/java/org/apache/gora/cassandra/example/generated/AvroSerialization/CassandraKey.java ---------------------------------------------------------------------- diff --git a/gora-cassandra-cql/src/examples/java/org/apache/gora/cassandra/example/generated/AvroSerialization/CassandraKey.java b/gora-cassandra-cql/src/examples/java/org/apache/gora/cassandra/example/generated/AvroSerialization/CassandraKey.java index 478690d..6b89c33 100644 --- a/gora-cassandra-cql/src/examples/java/org/apache/gora/cassandra/example/generated/AvroSerialization/CassandraKey.java +++ b/gora-cassandra-cql/src/examples/java/org/apache/gora/cassandra/example/generated/AvroSerialization/CassandraKey.java @@ -1,99 +1,123 @@ /** - *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. + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.gora.cassandra.example.generated.AvroSerialization; +package org.apache.gora.cassandra.example.generated.AvroSerialization; -/** This Object is created to used as Cassandra Key to test cassandra data store, Cassandra Key can be used to define partition keys, clustering keys. */ +/** + * This Object is created to used as Cassandra Key to test cassandra data store, Cassandra Key can be used to define partition keys, clustering keys. + */ public class CassandraKey extends org.apache.gora.persistency.impl.PersistentBase implements org.apache.avro.specific.SpecificRecord, org.apache.gora.persistency.Persistent { public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"CassandraKey\",\"namespace\":\"org.apache.gora.cassandra.example.generated.AvroSerialization\",\"doc\":\"This Object is created to used as Cassandra Key to test cassandra data store, Cassandra Key can be used to define partition keys, clustering keys. \",\"fields\":[{\"name\":\"url\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"timestamp\",\"type\":\"long\",\"default\":0}],\"default\":null}"); + public static final String[] _ALL_FIELDS = { + "url", + "timestamp", + }; private static final long serialVersionUID = -4231222814786458061L; - /** Enum containing all data bean's fields. */ - public static enum Field { - URL(0, "url"), - TIMESTAMP(1, "timestamp"), - ; - /** - * Field's index. - */ - private int index; - /** - * Field's name. - */ - private String name; - - /** - * Field's constructor - * @param index field's index. - * @param name field's name. - */ - Field(int index, String name) {this.index=index;this.name=name;} + ; + private static final Tombstone TOMBSTONE = new Tombstone(); + private static final org.apache.avro.io.DatumWriter + DATUM_WRITER$ = new org.apache.avro.specific.SpecificDatumWriter(SCHEMA$); + private static final org.apache.avro.io.DatumReader + DATUM_READER$ = new org.apache.avro.specific.SpecificDatumReader(SCHEMA$); + private java.lang.CharSequence url; + private long timestamp; - /** - * Gets field's index. - * @return int field's index. - */ - public int getIndex() {return index;} + /** + * Creates a new CassandraKey RecordBuilder + */ + public static org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder newBuilder() { + return new org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder(); + } - /** - * Gets field's name. - * @return String field's name. - */ - public String getName() {return name;} + /** + * Creates a new CassandraKey RecordBuilder by copying an existing Builder + */ + public static org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder newBuilder(org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder other) { + return new org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder(other); + } - /** - * Gets field's attributes to string. - * @return String field's attributes to string. - */ - public String toString() {return name;} - }; + /** + * Creates a new CassandraKey RecordBuilder by copying an existing CassandraKey instance + */ + public static org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder newBuilder(org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey other) { + return new org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder(other); + } - public static final String[] _ALL_FIELDS = { - "url", - "timestamp", - }; + private static java.nio.ByteBuffer deepCopyToReadOnlyBuffer( + java.nio.ByteBuffer input) { + java.nio.ByteBuffer copy = java.nio.ByteBuffer.allocate(input.capacity()); + int position = input.position(); + input.reset(); + int mark = input.position(); + int limit = input.limit(); + input.rewind(); + input.limit(input.capacity()); + copy.put(input); + input.rewind(); + copy.rewind(); + input.position(mark); + input.mark(); + copy.position(mark); + copy.mark(); + input.position(position); + copy.position(position); + input.limit(limit); + copy.limit(limit); + return copy.asReadOnlyBuffer(); + } /** * Gets the total field count. + * * @return int field count */ public int getFieldsCount() { return CassandraKey._ALL_FIELDS.length; } - private java.lang.CharSequence url; - private long timestamp; - public org.apache.avro.Schema getSchema() { return SCHEMA$; } - // Used by DatumWriter. Applications should not call. + public org.apache.avro.Schema getSchema() { + return SCHEMA$; + } + + // Used by DatumWriter. Applications should not call. public java.lang.Object get(int field$) { switch (field$) { - case 0: return url; - case 1: return timestamp; - default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + case 0: + return url; + case 1: + return timestamp; + default: + throw new org.apache.avro.AvroRuntimeException("Bad index"); } } - - // Used by DatumReader. Applications should not call. - @SuppressWarnings(value="unchecked") + + // Used by DatumReader. Applications should not call. + @SuppressWarnings(value = "unchecked") public void put(int field$, java.lang.Object value) { switch (field$) { - case 0: url = (java.lang.CharSequence)(value); break; - case 1: timestamp = (java.lang.Long)(value); break; - default: throw new org.apache.avro.AvroRuntimeException("Bad index"); + case 0: + url = (java.lang.CharSequence) (value); + break; + case 1: + timestamp = (java.lang.Long) (value); + break; + default: + throw new org.apache.avro.AvroRuntimeException("Bad index"); } } @@ -106,15 +130,17 @@ public class CassandraKey extends org.apache.gora.persistency.impl.PersistentBas /** * Sets the value of the 'url' field. + * * @param value the value to set. */ public void setUrl(java.lang.CharSequence value) { this.url = value; setDirty(0); } - + /** * Checks the dirty status of the 'url' field. A field is dirty if it represents a change that has not yet been written to the database. + * * @param value the value to set. */ public boolean isUrlDirty() { @@ -130,81 +156,146 @@ public class CassandraKey extends org.apache.gora.persistency.impl.PersistentBas /** * Sets the value of the 'timestamp' field. + * * @param value the value to set. */ public void setTimestamp(java.lang.Long value) { this.timestamp = value; setDirty(1); } - + /** * Checks the dirty status of the 'timestamp' field. A field is dirty if it represents a change that has not yet been written to the database. + * * @param value the value to set. */ public boolean isTimestampDirty() { return isDirty(1); } - /** Creates a new CassandraKey RecordBuilder */ - public static org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder newBuilder() { - return new org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder(); + public CassandraKey.Tombstone getTombstone() { + return TOMBSTONE; } - - /** Creates a new CassandraKey RecordBuilder by copying an existing Builder */ - public static org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder newBuilder(org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder other) { - return new org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder(other); + + public CassandraKey newInstance() { + return newBuilder().build(); } - - /** Creates a new CassandraKey RecordBuilder by copying an existing CassandraKey instance */ - public static org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder newBuilder(org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey other) { - return new org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder(other); + + /** + * Writes AVRO data bean to output stream in the form of AVRO Binary encoding format. This will transform + * AVRO data bean from its Java object form to it s serializable form. + * + * @param out java.io.ObjectOutput output stream to write data bean in serializable form + */ + @Override + public void writeExternal(java.io.ObjectOutput out) + throws java.io.IOException { + out.write(super.getDirtyBytes().array()); + DATUM_WRITER$.write(this, org.apache.avro.io.EncoderFactory.get() + .directBinaryEncoder((java.io.OutputStream) out, + null)); } - - private static java.nio.ByteBuffer deepCopyToReadOnlyBuffer( - java.nio.ByteBuffer input) { - java.nio.ByteBuffer copy = java.nio.ByteBuffer.allocate(input.capacity()); - int position = input.position(); - input.reset(); - int mark = input.position(); - int limit = input.limit(); - input.rewind(); - input.limit(input.capacity()); - copy.put(input); - input.rewind(); - copy.rewind(); - input.position(mark); - input.mark(); - copy.position(mark); - copy.mark(); - input.position(position); - copy.position(position); - input.limit(limit); - copy.limit(limit); - return copy.asReadOnlyBuffer(); + + /** + * Reads AVRO data bean from input stream in it s AVRO Binary encoding format to Java object format. + * This will transform AVRO data bean from it s serializable form to deserialized Java object form. + * + * @param in java.io.ObjectOutput input stream to read data bean in serializable form + */ + @Override + public void readExternal(java.io.ObjectInput in) + throws java.io.IOException { + byte[] __g__dirty = new byte[getFieldsCount()]; + in.read(__g__dirty); + super.setDirtyBytes(java.nio.ByteBuffer.wrap(__g__dirty)); + DATUM_READER$.read(this, org.apache.avro.io.DecoderFactory.get() + .directBinaryDecoder((java.io.InputStream) in, + null)); } - + + /** + * Enum containing all data bean's fields. + */ + public static enum Field { + URL(0, "url"), + TIMESTAMP(1, "timestamp"),; + /** + * Field's index. + */ + private int index; + + /** + * Field's name. + */ + private String name; + + /** + * Field's constructor + * + * @param index field's index. + * @param name field's name. + */ + Field(int index, String name) { + this.index = index; + this.name = name; + } + + /** + * Gets field's index. + * + * @return int field's index. + */ + public int getIndex() { + return index; + } + + /** + * Gets field's name. + * + * @return String field's name. + */ + public String getName() { + return name; + } + + /** + * Gets field's attributes to string. + * + * @return String field's attributes to string. + */ + public String toString() { + return name; + } + } + /** * RecordBuilder for CassandraKey instances. */ public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<CassandraKey> - implements org.apache.avro.data.RecordBuilder<CassandraKey> { + implements org.apache.avro.data.RecordBuilder<CassandraKey> { private java.lang.CharSequence url; private long timestamp; - /** Creates a new Builder */ + /** + * Creates a new Builder + */ private Builder() { super(org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.SCHEMA$); } - - /** Creates a Builder by copying an existing Builder */ + + /** + * Creates a Builder by copying an existing Builder + */ private Builder(org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder other) { super(other); } - - /** Creates a Builder by copying an existing CassandraKey instance */ + + /** + * Creates a Builder by copying an existing CassandraKey instance + */ private Builder(org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey other) { - super(org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.SCHEMA$); + super(org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.SCHEMA$); if (isValidValue(fields()[0], other.url)) { this.url = (java.lang.CharSequence) data().deepCopy(fields()[0].schema(), other.url); fieldSetFlags()[0] = true; @@ -215,55 +306,71 @@ public class CassandraKey extends org.apache.gora.persistency.impl.PersistentBas } } - /** Gets the value of the 'url' field */ + /** + * Gets the value of the 'url' field + */ public java.lang.CharSequence getUrl() { return url; } - - /** Sets the value of the 'url' field */ + + /** + * Sets the value of the 'url' field + */ public org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder setUrl(java.lang.CharSequence value) { validate(fields()[0], value); this.url = value; fieldSetFlags()[0] = true; - return this; + return this; } - - /** Checks whether the 'url' field has been set */ + + /** + * Checks whether the 'url' field has been set + */ public boolean hasUrl() { return fieldSetFlags()[0]; } - - /** Clears the value of the 'url' field */ + + /** + * Clears the value of the 'url' field + */ public org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder clearUrl() { url = null; fieldSetFlags()[0] = false; return this; } - - /** Gets the value of the 'timestamp' field */ + + /** + * Gets the value of the 'timestamp' field + */ public java.lang.Long getTimestamp() { return timestamp; } - - /** Sets the value of the 'timestamp' field */ + + /** + * Sets the value of the 'timestamp' field + */ public org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder setTimestamp(long value) { validate(fields()[1], value); this.timestamp = value; fieldSetFlags()[1] = true; - return this; + return this; } - - /** Checks whether the 'timestamp' field has been set */ + + /** + * Checks whether the 'timestamp' field has been set + */ public boolean hasTimestamp() { return fieldSetFlags()[1]; } - - /** Clears the value of the 'timestamp' field */ + + /** + * Clears the value of the 'timestamp' field + */ public org.apache.gora.cassandra.example.generated.AvroSerialization.CassandraKey.Builder clearTimestamp() { fieldSetFlags()[1] = false; return this; } - + @Override public CassandraKey build() { try { @@ -276,106 +383,64 @@ public class CassandraKey extends org.apache.gora.persistency.impl.PersistentBas } } } - - public CassandraKey.Tombstone getTombstone(){ - return TOMBSTONE; - } - - public CassandraKey newInstance(){ - return newBuilder().build(); - } - private static final Tombstone TOMBSTONE = new Tombstone(); - public static final class Tombstone extends CassandraKey implements org.apache.gora.persistency.Tombstone { - - private Tombstone() { } - - /** - * Gets the value of the 'url' field. - */ - public java.lang.CharSequence getUrl() { - throw new java.lang.UnsupportedOperationException("Get is not supported on tombstones"); - } - - /** - * Sets the value of the 'url' field. - * @param value the value to set. - */ - public void setUrl(java.lang.CharSequence value) { - throw new java.lang.UnsupportedOperationException("Set is not supported on tombstones"); - } - - /** - * Checks the dirty status of the 'url' field. A field is dirty if it represents a change that has not yet been written to the database. - * @param value the value to set. - */ - public boolean isUrlDirty() { - throw new java.lang.UnsupportedOperationException("IsDirty is not supported on tombstones"); - } - - /** - * Gets the value of the 'timestamp' field. - */ - public java.lang.Long getTimestamp() { - throw new java.lang.UnsupportedOperationException("Get is not supported on tombstones"); - } - - /** - * Sets the value of the 'timestamp' field. - * @param value the value to set. - */ - public void setTimestamp(java.lang.Long value) { - throw new java.lang.UnsupportedOperationException("Set is not supported on tombstones"); - } - - /** - * Checks the dirty status of the 'timestamp' field. A field is dirty if it represents a change that has not yet been written to the database. - * @param value the value to set. - */ - public boolean isTimestampDirty() { - throw new java.lang.UnsupportedOperationException("IsDirty is not supported on tombstones"); - } - - - } - private static final org.apache.avro.io.DatumWriter - DATUM_WRITER$ = new org.apache.avro.specific.SpecificDatumWriter(SCHEMA$); - private static final org.apache.avro.io.DatumReader - DATUM_READER$ = new org.apache.avro.specific.SpecificDatumReader(SCHEMA$); + private Tombstone() { + } + + /** + * Gets the value of the 'url' field. + */ + public java.lang.CharSequence getUrl() { + throw new java.lang.UnsupportedOperationException("Get is not supported on tombstones"); + } + + /** + * Sets the value of the 'url' field. + * + * @param value the value to set. + */ + public void setUrl(java.lang.CharSequence value) { + throw new java.lang.UnsupportedOperationException("Set is not supported on tombstones"); + } + + /** + * Checks the dirty status of the 'url' field. A field is dirty if it represents a change that has not yet been written to the database. + * + * @param value the value to set. + */ + public boolean isUrlDirty() { + throw new java.lang.UnsupportedOperationException("IsDirty is not supported on tombstones"); + } + + /** + * Gets the value of the 'timestamp' field. + */ + public java.lang.Long getTimestamp() { + throw new java.lang.UnsupportedOperationException("Get is not supported on tombstones"); + } + + /** + * Sets the value of the 'timestamp' field. + * + * @param value the value to set. + */ + public void setTimestamp(java.lang.Long value) { + throw new java.lang.UnsupportedOperationException("Set is not supported on tombstones"); + } + + /** + * Checks the dirty status of the 'timestamp' field. A field is dirty if it represents a change that has not yet been written to the database. + * + * @param value the value to set. + */ + public boolean isTimestampDirty() { + throw new java.lang.UnsupportedOperationException("IsDirty is not supported on tombstones"); + } - /** - * Writes AVRO data bean to output stream in the form of AVRO Binary encoding format. This will transform - * AVRO data bean from its Java object form to it s serializable form. - * - * @param out java.io.ObjectOutput output stream to write data bean in serializable form - */ - @Override - public void writeExternal(java.io.ObjectOutput out) - throws java.io.IOException { - out.write(super.getDirtyBytes().array()); - DATUM_WRITER$.write(this, org.apache.avro.io.EncoderFactory.get() - .directBinaryEncoder((java.io.OutputStream) out, - null)); - } - /** - * Reads AVRO data bean from input stream in it s AVRO Binary encoding format to Java object format. - * This will transform AVRO data bean from it s serializable form to deserialized Java object form. - * - * @param in java.io.ObjectOutput input stream to read data bean in serializable form - */ - @Override - public void readExternal(java.io.ObjectInput in) - throws java.io.IOException { - byte[] __g__dirty = new byte[getFieldsCount()]; - in.read(__g__dirty); - super.setDirtyBytes(java.nio.ByteBuffer.wrap(__g__dirty)); - DATUM_READER$.read(this, org.apache.avro.io.DecoderFactory.get() - .directBinaryDecoder((java.io.InputStream) in, - null)); } - + }