Blame | Last modification | View Log | Download | RSS feed
// Protocol Buffers - Google's data interchange format// Copyright 2008 Google Inc. All rights reserved.// http://code.google.com/p/protobuf///// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.package com.google.protobuf;import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.List;import java.util.Map;import java.util.TreeMap;/*** {@code UnknownFieldSet} is used to keep track of fields which were seen when* parsing a protocol message but whose field numbers or types are unrecognized.* This most frequently occurs when new fields are added to a message type* and then messages containing those feilds are read by old software that was* compiled before the new types were added.** <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every* {@link Message.Builder} contains an {@link Builder}).** <p>Most users will never need to use this class.** @author kenton@google.com Kenton Varda*/public final class UnknownFieldSet implements MessageLite {private UnknownFieldSet() {}/** Create a new {@link Builder}. */public static Builder newBuilder() {return Builder.create();}/*** Create a new {@link Builder} and initialize it to be a copy* of {@code copyFrom}.*/public static Builder newBuilder(final UnknownFieldSet copyFrom) {return newBuilder().mergeFrom(copyFrom);}/** Get an empty {@code UnknownFieldSet}. */public static UnknownFieldSet getDefaultInstance() {return defaultInstance;}public UnknownFieldSet getDefaultInstanceForType() {return defaultInstance;}private static final UnknownFieldSet defaultInstance =new UnknownFieldSet(Collections.<Integer, Field>emptyMap());/*** Construct an {@code UnknownFieldSet} around the given map. The map is* expected to be immutable.*/private UnknownFieldSet(final Map<Integer, Field> fields) {this.fields = fields;}private Map<Integer, Field> fields;@Overridepublic boolean equals(final Object other) {if (this == other) {return true;}return (other instanceof UnknownFieldSet) &&fields.equals(((UnknownFieldSet) other).fields);}@Overridepublic int hashCode() {return fields.hashCode();}/** Get a map of fields in the set by number. */public Map<Integer, Field> asMap() {return fields;}/** Check if the given field number is present in the set. */public boolean hasField(final int number) {return fields.containsKey(number);}/*** Get a field by number. Returns an empty field if not present. Never* returns {@code null}.*/public Field getField(final int number) {final Field result = fields.get(number);return (result == null) ? Field.getDefaultInstance() : result;}/** Serializes the set and writes it to {@code output}. */public void writeTo(final CodedOutputStream output) throws IOException {for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {entry.getValue().writeTo(entry.getKey(), output);}}/*** Converts the set to a string in protocol buffer text format. This is* just a trivial wrapper around* {@link TextFormat#printToString(UnknownFieldSet)}.*/@Overridepublic String toString() {return TextFormat.printToString(this);}/*** Serializes the message to a {@code ByteString} and returns it. This is* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.*/public ByteString toByteString() {try {final ByteString.CodedBuilder out =ByteString.newCodedBuilder(getSerializedSize());writeTo(out.getCodedOutput());return out.build();} catch (final IOException e) {throw new RuntimeException("Serializing to a ByteString threw an IOException (should " +"never happen).", e);}}/*** Serializes the message to a {@code byte} array and returns it. This is* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.*/public byte[] toByteArray() {try {final byte[] result = new byte[getSerializedSize()];final CodedOutputStream output = CodedOutputStream.newInstance(result);writeTo(output);output.checkNoSpaceLeft();return result;} catch (final IOException e) {throw new RuntimeException("Serializing to a byte array threw an IOException " +"(should never happen).", e);}}/*** Serializes the message and writes it to {@code output}. This is just a* trivial wrapper around {@link #writeTo(CodedOutputStream)}.*/public void writeTo(final OutputStream output) throws IOException {final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);writeTo(codedOutput);codedOutput.flush();}public void writeDelimitedTo(OutputStream output) throws IOException {final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);codedOutput.writeRawVarint32(getSerializedSize());writeTo(codedOutput);codedOutput.flush();}/** Get the number of bytes required to encode this set. */public int getSerializedSize() {int result = 0;for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {result += entry.getValue().getSerializedSize(entry.getKey());}return result;}/*** Serializes the set and writes it to {@code output} using* {@code MessageSet} wire format.*/public void writeAsMessageSetTo(final CodedOutputStream output)throws IOException {for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), output);}}/*** Get the number of bytes required to encode this set using* {@code MessageSet} wire format.*/public int getSerializedSizeAsMessageSet() {int result = 0;for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {result += entry.getValue().getSerializedSizeAsMessageSetExtension(entry.getKey());}return result;}public boolean isInitialized() {// UnknownFieldSets do not have required fields, so they are always// initialized.return true;}/** Parse an {@code UnknownFieldSet} from the given input stream. */public static UnknownFieldSet parseFrom(final CodedInputStream input)throws IOException {return newBuilder().mergeFrom(input).build();}/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */public static UnknownFieldSet parseFrom(final ByteString data)throws InvalidProtocolBufferException {return newBuilder().mergeFrom(data).build();}/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */public static UnknownFieldSet parseFrom(final byte[] data)throws InvalidProtocolBufferException {return newBuilder().mergeFrom(data).build();}/** Parse an {@code UnknownFieldSet} from {@code input} and return it. */public static UnknownFieldSet parseFrom(final InputStream input)throws IOException {return newBuilder().mergeFrom(input).build();}public Builder newBuilderForType() {return newBuilder();}public Builder toBuilder() {return newBuilder().mergeFrom(this);}/*** Builder for {@link UnknownFieldSet}s.** <p>Note that this class maintains {@link Field.Builder}s for all fields* in the set. Thus, adding one element to an existing {@link Field} does not* require making a copy. This is important for efficient parsing of* unknown repeated fields. However, it implies that {@link Field}s cannot* be constructed independently, nor can two {@link UnknownFieldSet}s share* the same {@code Field} object.** <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.*/public static final class Builder implements MessageLite.Builder {// This constructor should never be called directly (except from 'create').private Builder() {}private Map<Integer, Field> fields;// Optimization: We keep around a builder for the last field that was// modified so that we can efficiently add to it multiple times in a// row (important when parsing an unknown repeated field).private int lastFieldNumber;private Field.Builder lastField;private static Builder create() {Builder builder = new Builder();builder.reinitialize();return builder;}/*** Get a field builder for the given field number which includes any* values that already exist.*/private Field.Builder getFieldBuilder(final int number) {if (lastField != null) {if (number == lastFieldNumber) {return lastField;}// Note: addField() will reset lastField and lastFieldNumber.addField(lastFieldNumber, lastField.build());}if (number == 0) {return null;} else {final Field existing = fields.get(number);lastFieldNumber = number;lastField = Field.newBuilder();if (existing != null) {lastField.mergeFrom(existing);}return lastField;}}/*** Build the {@link UnknownFieldSet} and return it.** <p>Once {@code build()} has been called, the {@code Builder} will no* longer be usable. Calling any method after {@code build()} will result* in undefined behavior and can cause a {@code NullPointerException} to be* thrown.*/public UnknownFieldSet build() {getFieldBuilder(0); // Force lastField to be built.final UnknownFieldSet result;if (fields.isEmpty()) {result = getDefaultInstance();} else {result = new UnknownFieldSet(Collections.unmodifiableMap(fields));}fields = null;return result;}public UnknownFieldSet buildPartial() {// No required fields, so this is the same as build().return build();}@Overridepublic Builder clone() {getFieldBuilder(0); // Force lastField to be built.return UnknownFieldSet.newBuilder().mergeFrom(new UnknownFieldSet(fields));}public UnknownFieldSet getDefaultInstanceForType() {return UnknownFieldSet.getDefaultInstance();}private void reinitialize() {fields = Collections.emptyMap();lastFieldNumber = 0;lastField = null;}/** Reset the builder to an empty set. */public Builder clear() {reinitialize();return this;}/*** Merge the fields from {@code other} into this set. If a field number* exists in both sets, {@code other}'s values for that field will be* appended to the values in this set.*/public Builder mergeFrom(final UnknownFieldSet other) {if (other != getDefaultInstance()) {for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {mergeField(entry.getKey(), entry.getValue());}}return this;}/*** Add a field to the {@code UnknownFieldSet}. If a field with the same* number already exists, the two are merged.*/public Builder mergeField(final int number, final Field field) {if (number == 0) {throw new IllegalArgumentException("Zero is not a valid field number.");}if (hasField(number)) {getFieldBuilder(number).mergeFrom(field);} else {// Optimization: We could call getFieldBuilder(number).mergeFrom(field)// in this case, but that would create a copy of the Field object.// We'd rather reuse the one passed to us, so call addField() instead.addField(number, field);}return this;}/*** Convenience method for merging a new field containing a single varint* value. This is used in particular when an unknown enum value is* encountered.*/public Builder mergeVarintField(final int number, final int value) {if (number == 0) {throw new IllegalArgumentException("Zero is not a valid field number.");}getFieldBuilder(number).addVarint(value);return this;}/** Check if the given field number is present in the set. */public boolean hasField(final int number) {if (number == 0) {throw new IllegalArgumentException("Zero is not a valid field number.");}return number == lastFieldNumber || fields.containsKey(number);}/*** Add a field to the {@code UnknownFieldSet}. If a field with the same* number already exists, it is removed.*/public Builder addField(final int number, final Field field) {if (number == 0) {throw new IllegalArgumentException("Zero is not a valid field number.");}if (lastField != null && lastFieldNumber == number) {// Discard this.lastField = null;lastFieldNumber = 0;}if (fields.isEmpty()) {fields = new TreeMap<Integer,Field>();}fields.put(number, field);return this;}/*** Get all present {@code Field}s as an immutable {@code Map}. If more* fields are added, the changes may or may not be reflected in this map.*/public Map<Integer, Field> asMap() {getFieldBuilder(0); // Force lastField to be built.return Collections.unmodifiableMap(fields);}/*** Parse an entire message from {@code input} and merge its fields into* this set.*/public Builder mergeFrom(final CodedInputStream input) throws IOException {while (true) {final int tag = input.readTag();if (tag == 0 || !mergeFieldFrom(tag, input)) {break;}}return this;}/*** Parse a single field from {@code input} and merge it into this set.* @param tag The field's tag number, which was already parsed.* @return {@code false} if the tag is an engroup tag.*/public boolean mergeFieldFrom(final int tag, final CodedInputStream input)throws IOException {final int number = WireFormat.getTagFieldNumber(tag);switch (WireFormat.getTagWireType(tag)) {case WireFormat.WIRETYPE_VARINT:getFieldBuilder(number).addVarint(input.readInt64());return true;case WireFormat.WIRETYPE_FIXED64:getFieldBuilder(number).addFixed64(input.readFixed64());return true;case WireFormat.WIRETYPE_LENGTH_DELIMITED:getFieldBuilder(number).addLengthDelimited(input.readBytes());return true;case WireFormat.WIRETYPE_START_GROUP:final Builder subBuilder = newBuilder();input.readGroup(number, subBuilder,ExtensionRegistry.getEmptyRegistry());getFieldBuilder(number).addGroup(subBuilder.build());return true;case WireFormat.WIRETYPE_END_GROUP:return false;case WireFormat.WIRETYPE_FIXED32:getFieldBuilder(number).addFixed32(input.readFixed32());return true;default:throw InvalidProtocolBufferException.invalidWireType();}}/*** Parse {@code data} as an {@code UnknownFieldSet} and merge it with the* set being built. This is just a small wrapper around* {@link #mergeFrom(CodedInputStream)}.*/public Builder mergeFrom(final ByteString data)throws InvalidProtocolBufferException {try {final CodedInputStream input = data.newCodedInput();mergeFrom(input);input.checkLastTagWas(0);return this;} catch (final InvalidProtocolBufferException e) {throw e;} catch (final IOException e) {throw new RuntimeException("Reading from a ByteString threw an IOException (should " +"never happen).", e);}}/*** Parse {@code data} as an {@code UnknownFieldSet} and merge it with the* set being built. This is just a small wrapper around* {@link #mergeFrom(CodedInputStream)}.*/public Builder mergeFrom(final byte[] data)throws InvalidProtocolBufferException {try {final CodedInputStream input = CodedInputStream.newInstance(data);mergeFrom(input);input.checkLastTagWas(0);return this;} catch (final InvalidProtocolBufferException e) {throw e;} catch (final IOException e) {throw new RuntimeException("Reading from a byte array threw an IOException (should " +"never happen).", e);}}/*** Parse an {@code UnknownFieldSet} from {@code input} and merge it with the* set being built. This is just a small wrapper around* {@link #mergeFrom(CodedInputStream)}.*/public Builder mergeFrom(final InputStream input) throws IOException {final CodedInputStream codedInput = CodedInputStream.newInstance(input);mergeFrom(codedInput);codedInput.checkLastTagWas(0);return this;}public boolean mergeDelimitedFrom(InputStream input)throws IOException {final int firstByte = input.read();if (firstByte == -1) {return false;}final int size = CodedInputStream.readRawVarint32(firstByte, input);final InputStream limitedInput = new LimitedInputStream(input, size);mergeFrom(limitedInput);return true;}public boolean mergeDelimitedFrom(InputStream input,ExtensionRegistryLite extensionRegistry) throws IOException {// UnknownFieldSet has no extensions.return mergeDelimitedFrom(input);}public Builder mergeFrom(CodedInputStream input,ExtensionRegistryLite extensionRegistry) throws IOException {// UnknownFieldSet has no extensions.return mergeFrom(input);}public Builder mergeFrom(ByteString data,ExtensionRegistryLite extensionRegistry)throws InvalidProtocolBufferException {// UnknownFieldSet has no extensions.return mergeFrom(data);}public Builder mergeFrom(byte[] data, int off, int len)throws InvalidProtocolBufferException {try {final CodedInputStream input =CodedInputStream.newInstance(data, off, len);mergeFrom(input);input.checkLastTagWas(0);return this;} catch (InvalidProtocolBufferException e) {throw e;} catch (IOException e) {throw new RuntimeException("Reading from a byte array threw an IOException (should " +"never happen).", e);}}public Builder mergeFrom(byte[] data,ExtensionRegistryLite extensionRegistry)throws InvalidProtocolBufferException {// UnknownFieldSet has no extensions.return mergeFrom(data);}public Builder mergeFrom(byte[] data, int off, int len,ExtensionRegistryLite extensionRegistry)throws InvalidProtocolBufferException {// UnknownFieldSet has no extensions.return mergeFrom(data, off, len);}public Builder mergeFrom(InputStream input,ExtensionRegistryLite extensionRegistry) throws IOException {// UnknownFieldSet has no extensions.return mergeFrom(input);}public boolean isInitialized() {// UnknownFieldSets do not have required fields, so they are always// initialized.return true;}}/*** Represents a single field in an {@code UnknownFieldSet}.** <p>A {@code Field} consists of five lists of values. The lists correspond* to the five "wire types" used in the protocol buffer binary format.* The wire type of each field can be determined from the encoded form alone,* without knowing the field's declared type. So, we are able to parse* unknown values at least this far and separate them. Normally, only one* of the five lists will contain any values, since it is impossible to* define a valid message type that declares two different types for the* same field number. However, the code is designed to allow for the case* where the same unknown field number is encountered using multiple different* wire types.** <p>{@code Field} is an immutable class. To construct one, you must use a* {@link Builder}.** @see UnknownFieldSet*/public static final class Field {private Field() {}/** Construct a new {@link Builder}. */public static Builder newBuilder() {return Builder.create();}/*** Construct a new {@link Builder} and initialize it to a copy of* {@code copyFrom}.*/public static Builder newBuilder(final Field copyFrom) {return newBuilder().mergeFrom(copyFrom);}/** Get an empty {@code Field}. */public static Field getDefaultInstance() {return fieldDefaultInstance;}private static final Field fieldDefaultInstance = newBuilder().build();/** Get the list of varint values for this field. */public List<Long> getVarintList() { return varint; }/** Get the list of fixed32 values for this field. */public List<Integer> getFixed32List() { return fixed32; }/** Get the list of fixed64 values for this field. */public List<Long> getFixed64List() { return fixed64; }/** Get the list of length-delimited values for this field. */public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }/*** Get the list of embedded group values for this field. These are* represented using {@link UnknownFieldSet}s rather than {@link Message}s* since the group's type is presumably unknown.*/public List<UnknownFieldSet> getGroupList() { return group; }@Overridepublic boolean equals(final Object other) {if (this == other) {return true;}if (!(other instanceof Field)) {return false;}return Arrays.equals(getIdentityArray(),((Field) other).getIdentityArray());}@Overridepublic int hashCode() {return Arrays.hashCode(getIdentityArray());}/*** Returns the array of objects to be used to uniquely identify this* {@link Field} instance.*/private Object[] getIdentityArray() {return new Object[] {varint,fixed32,fixed64,lengthDelimited,group};}/*** Serializes the field, including field number, and writes it to* {@code output}.*/public void writeTo(final int fieldNumber, final CodedOutputStream output)throws IOException {for (final long value : varint) {output.writeUInt64(fieldNumber, value);}for (final int value : fixed32) {output.writeFixed32(fieldNumber, value);}for (final long value : fixed64) {output.writeFixed64(fieldNumber, value);}for (final ByteString value : lengthDelimited) {output.writeBytes(fieldNumber, value);}for (final UnknownFieldSet value : group) {output.writeGroup(fieldNumber, value);}}/*** Get the number of bytes required to encode this field, including field* number.*/public int getSerializedSize(final int fieldNumber) {int result = 0;for (final long value : varint) {result += CodedOutputStream.computeUInt64Size(fieldNumber, value);}for (final int value : fixed32) {result += CodedOutputStream.computeFixed32Size(fieldNumber, value);}for (final long value : fixed64) {result += CodedOutputStream.computeFixed64Size(fieldNumber, value);}for (final ByteString value : lengthDelimited) {result += CodedOutputStream.computeBytesSize(fieldNumber, value);}for (final UnknownFieldSet value : group) {result += CodedOutputStream.computeGroupSize(fieldNumber, value);}return result;}/*** Serializes the field, including field number, and writes it to* {@code output}, using {@code MessageSet} wire format.*/public void writeAsMessageSetExtensionTo(final int fieldNumber,final CodedOutputStream output)throws IOException {for (final ByteString value : lengthDelimited) {output.writeRawMessageSetExtension(fieldNumber, value);}}/*** Get the number of bytes required to encode this field, including field* number, using {@code MessageSet} wire format.*/public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {int result = 0;for (final ByteString value : lengthDelimited) {result += CodedOutputStream.computeRawMessageSetExtensionSize(fieldNumber, value);}return result;}private List<Long> varint;private List<Integer> fixed32;private List<Long> fixed64;private List<ByteString> lengthDelimited;private List<UnknownFieldSet> group;/*** Used to build a {@link Field} within an {@link UnknownFieldSet}.** <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.*/public static final class Builder {// This constructor should never be called directly (except from 'create').private Builder() {}private static Builder create() {Builder builder = new Builder();builder.result = new Field();return builder;}private Field result;/*** Build the field. After {@code build()} has been called, the* {@code Builder} is no longer usable. Calling any other method will* result in undefined behavior and can cause a* {@code NullPointerException} to be thrown.*/public Field build() {if (result.varint == null) {result.varint = Collections.emptyList();} else {result.varint = Collections.unmodifiableList(result.varint);}if (result.fixed32 == null) {result.fixed32 = Collections.emptyList();} else {result.fixed32 = Collections.unmodifiableList(result.fixed32);}if (result.fixed64 == null) {result.fixed64 = Collections.emptyList();} else {result.fixed64 = Collections.unmodifiableList(result.fixed64);}if (result.lengthDelimited == null) {result.lengthDelimited = Collections.emptyList();} else {result.lengthDelimited =Collections.unmodifiableList(result.lengthDelimited);}if (result.group == null) {result.group = Collections.emptyList();} else {result.group = Collections.unmodifiableList(result.group);}final Field returnMe = result;result = null;return returnMe;}/** Discard the field's contents. */public Builder clear() {result = new Field();return this;}/*** Merge the values in {@code other} into this field. For each list* of values, {@code other}'s values are append to the ones in this* field.*/public Builder mergeFrom(final Field other) {if (!other.varint.isEmpty()) {if (result.varint == null) {result.varint = new ArrayList<Long>();}result.varint.addAll(other.varint);}if (!other.fixed32.isEmpty()) {if (result.fixed32 == null) {result.fixed32 = new ArrayList<Integer>();}result.fixed32.addAll(other.fixed32);}if (!other.fixed64.isEmpty()) {if (result.fixed64 == null) {result.fixed64 = new ArrayList<Long>();}result.fixed64.addAll(other.fixed64);}if (!other.lengthDelimited.isEmpty()) {if (result.lengthDelimited == null) {result.lengthDelimited = new ArrayList<ByteString>();}result.lengthDelimited.addAll(other.lengthDelimited);}if (!other.group.isEmpty()) {if (result.group == null) {result.group = new ArrayList<UnknownFieldSet>();}result.group.addAll(other.group);}return this;}/** Add a varint value. */public Builder addVarint(final long value) {if (result.varint == null) {result.varint = new ArrayList<Long>();}result.varint.add(value);return this;}/** Add a fixed32 value. */public Builder addFixed32(final int value) {if (result.fixed32 == null) {result.fixed32 = new ArrayList<Integer>();}result.fixed32.add(value);return this;}/** Add a fixed64 value. */public Builder addFixed64(final long value) {if (result.fixed64 == null) {result.fixed64 = new ArrayList<Long>();}result.fixed64.add(value);return this;}/** Add a length-delimited value. */public Builder addLengthDelimited(final ByteString value) {if (result.lengthDelimited == null) {result.lengthDelimited = new ArrayList<ByteString>();}result.lengthDelimited.add(value);return this;}/** Add an embedded group. */public Builder addGroup(final UnknownFieldSet value) {if (result.group == null) {result.group = new ArrayList<UnknownFieldSet>();}result.group.add(value);return this;}}}}