|  | @@ -152,56 +152,50 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
 | 
	
		
			
				|  |  |          this.repeated = repeated;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    protected boolean isMatch(int unknownDataTag) {
 | 
	
		
			
				|  |  | -        // This implementation is for message/group extensions.
 | 
	
		
			
				|  |  | -        return unknownDataTag == tag;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      /**
 | 
	
		
			
				|  |  |       * Returns the value of this extension stored in the given list of unknown fields, or
 | 
	
		
			
				|  |  |       * {@code null} if no unknown fields matches this extension.
 | 
	
		
			
				|  |  | +     *
 | 
	
		
			
				|  |  | +     * @param unknownFields a list of {@link UnknownFieldData}. All of the elements must have a tag
 | 
	
		
			
				|  |  | +     *                      that matches this Extension's tag.
 | 
	
		
			
				|  |  | +     *
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  |      final T getValueFrom(List<UnknownFieldData> unknownFields) {
 | 
	
		
			
				|  |  |          if (unknownFields == null) {
 | 
	
		
			
				|  |  |              return null;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        return repeated ? getRepeatedValueFrom(unknownFields) : getSingularValueFrom(unknownFields);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if (repeated) {
 | 
	
		
			
				|  |  | -            // For repeated extensions, read all matching unknown fields in their original order.
 | 
	
		
			
				|  |  | -            List<Object> resultList = new ArrayList<Object>();
 | 
	
		
			
				|  |  | -            for (int i = 0; i < unknownFields.size(); i++) {
 | 
	
		
			
				|  |  | -                UnknownFieldData data = unknownFields.get(i);
 | 
	
		
			
				|  |  | -                if (isMatch(data.tag) && data.bytes.length != 0) {
 | 
	
		
			
				|  |  | -                    readDataInto(data, resultList);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            int resultSize = resultList.size();
 | 
	
		
			
				|  |  | -            if (resultSize == 0) {
 | 
	
		
			
				|  |  | -                return null;
 | 
	
		
			
				|  |  | +    private T getRepeatedValueFrom(List<UnknownFieldData> unknownFields) {
 | 
	
		
			
				|  |  | +        // For repeated extensions, read all matching unknown fields in their original order.
 | 
	
		
			
				|  |  | +        List<Object> resultList = new ArrayList<Object>();
 | 
	
		
			
				|  |  | +        for (int i = 0; i < unknownFields.size(); i++) {
 | 
	
		
			
				|  |  | +            UnknownFieldData data = unknownFields.get(i);
 | 
	
		
			
				|  |  | +            if (data.bytes.length != 0) {
 | 
	
		
			
				|  |  | +                readDataInto(data, resultList);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        int resultSize = resultList.size();
 | 
	
		
			
				|  |  | +        if (resultSize == 0) {
 | 
	
		
			
				|  |  | +            return null;
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  |              T result = clazz.cast(Array.newInstance(clazz.getComponentType(), resultSize));
 | 
	
		
			
				|  |  |              for (int i = 0; i < resultSize; i++) {
 | 
	
		
			
				|  |  |                  Array.set(result, i, resultList.get(i));
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              return result;
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -            // For singular extensions, get the last piece of data stored under this extension.
 | 
	
		
			
				|  |  | -            UnknownFieldData lastData = null;
 | 
	
		
			
				|  |  | -            for (int i = unknownFields.size() - 1; lastData == null && i >= 0; i--) {
 | 
	
		
			
				|  |  | -                UnknownFieldData data = unknownFields.get(i);
 | 
	
		
			
				|  |  | -                if (isMatch(data.tag) && data.bytes.length != 0) {
 | 
	
		
			
				|  |  | -                    lastData = data;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if (lastData == null) {
 | 
	
		
			
				|  |  | -                return null;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            return clazz.cast(readData(CodedInputByteBufferNano.newInstance(lastData.bytes)));
 | 
	
		
			
				|  |  | +    private T getSingularValueFrom(List<UnknownFieldData> unknownFields) {
 | 
	
		
			
				|  |  | +        // For singular extensions, get the last piece of data stored under this extension.
 | 
	
		
			
				|  |  | +        if (unknownFields.isEmpty()) {
 | 
	
		
			
				|  |  | +            return null;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        UnknownFieldData lastData = unknownFields.get(unknownFields.size() - 1);
 | 
	
		
			
				|  |  | +        return clazz.cast(readData(CodedInputByteBufferNano.newInstance(lastData.bytes)));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      protected Object readData(CodedInputByteBufferNano input) {
 | 
	
	
		
			
				|  | @@ -236,61 +230,29 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
 | 
	
		
			
				|  |  |          resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /**
 | 
	
		
			
				|  |  | -     * Sets the value of this extension to the given list of unknown fields. This removes any
 | 
	
		
			
				|  |  | -     * previously stored data matching this extension.
 | 
	
		
			
				|  |  | -     *
 | 
	
		
			
				|  |  | -     * @param value The value of this extension, or {@code null} to clear this extension from the
 | 
	
		
			
				|  |  | -     *     unknown fields.
 | 
	
		
			
				|  |  | -     * @return The same {@code unknownFields} list, or a new list storing the extension value if
 | 
	
		
			
				|  |  | -     *     the argument was null.
 | 
	
		
			
				|  |  | -     */
 | 
	
		
			
				|  |  | -    final List<UnknownFieldData> setValueTo(T value, List<UnknownFieldData> unknownFields) {
 | 
	
		
			
				|  |  | -        if (unknownFields != null) {
 | 
	
		
			
				|  |  | -            // Delete all data matching this extension
 | 
	
		
			
				|  |  | -            for (int i = unknownFields.size() - 1; i >= 0; i--) {
 | 
	
		
			
				|  |  | -                if (isMatch(unknownFields.get(i).tag)) {
 | 
	
		
			
				|  |  | -                    unknownFields.remove(i);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if (value != null) {
 | 
	
		
			
				|  |  | -            if (unknownFields == null) {
 | 
	
		
			
				|  |  | -                unknownFields = new ArrayList<UnknownFieldData>();
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            if (repeated) {
 | 
	
		
			
				|  |  | -                writeDataInto(value, unknownFields);
 | 
	
		
			
				|  |  | -            } else {
 | 
	
		
			
				|  |  | -                unknownFields.add(writeData(value));
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | +    void writeTo(Object value, CodedOutputByteBufferNano output) throws IOException {
 | 
	
		
			
				|  |  | +        if (repeated) {
 | 
	
		
			
				|  |  | +            writeRepeatedData(value, output);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            writeSingularData(value, output);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        // After deletion or no-op addition (due to 'value' being an array of empty or
 | 
	
		
			
				|  |  | -        // null-only elements), unknownFields may be empty. Discard the ArrayList if so.
 | 
	
		
			
				|  |  | -        return (unknownFields == null || unknownFields.isEmpty()) ? null : unknownFields;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    protected UnknownFieldData writeData(Object value) {
 | 
	
		
			
				|  |  | +    protected void writeSingularData(Object value, CodedOutputByteBufferNano out) {
 | 
	
		
			
				|  |  |          // This implementation is for message/group extensions.
 | 
	
		
			
				|  |  | -        byte[] data;
 | 
	
		
			
				|  |  |          try {
 | 
	
		
			
				|  |  | +            out.writeRawVarint32(tag);
 | 
	
		
			
				|  |  |              switch (type) {
 | 
	
		
			
				|  |  |                  case TYPE_GROUP:
 | 
	
		
			
				|  |  |                      MessageNano groupValue = (MessageNano) value;
 | 
	
		
			
				|  |  |                      int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
 | 
	
		
			
				|  |  | -                    data = new byte[CodedOutputByteBufferNano.computeGroupSizeNoTag(groupValue)
 | 
	
		
			
				|  |  | -                            + CodedOutputByteBufferNano.computeTagSize(fieldNumber)];
 | 
	
		
			
				|  |  | -                    CodedOutputByteBufferNano out = CodedOutputByteBufferNano.newInstance(data);
 | 
	
		
			
				|  |  |                      out.writeGroupNoTag(groupValue);
 | 
	
		
			
				|  |  |                      // The endgroup tag must be included in the data payload.
 | 
	
		
			
				|  |  |                      out.writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
 | 
	
		
			
				|  |  |                      break;
 | 
	
		
			
				|  |  |                  case TYPE_MESSAGE:
 | 
	
		
			
				|  |  |                      MessageNano messageValue = (MessageNano) value;
 | 
	
		
			
				|  |  | -                    data = new byte[
 | 
	
		
			
				|  |  | -                            CodedOutputByteBufferNano.computeMessageSizeNoTag(messageValue)];
 | 
	
		
			
				|  |  | -                    CodedOutputByteBufferNano.newInstance(data).writeMessageNoTag(messageValue);
 | 
	
		
			
				|  |  | +                    out.writeMessageNoTag(messageValue);
 | 
	
		
			
				|  |  |                      break;
 | 
	
		
			
				|  |  |                  default:
 | 
	
		
			
				|  |  |                      throw new IllegalArgumentException("Unknown type " + type);
 | 
	
	
		
			
				|  | @@ -299,18 +261,53 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
 | 
	
		
			
				|  |  |              // Should not happen
 | 
	
		
			
				|  |  |              throw new IllegalStateException(e);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        return new UnknownFieldData(tag, data);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    protected void writeDataInto(T array, List<UnknownFieldData> unknownFields) {
 | 
	
		
			
				|  |  | +    protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
 | 
	
		
			
				|  |  | +        // This implementation is for non-packed extensions.
 | 
	
		
			
				|  |  | +        int arrayLength = Array.getLength(array);
 | 
	
		
			
				|  |  | +        for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | +            Object element = Array.get(array, i);
 | 
	
		
			
				|  |  | +            if (element != null) {
 | 
	
		
			
				|  |  | +                writeSingularData(element, output);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    int computeSerializedSize(Object value) {
 | 
	
		
			
				|  |  | +        if (repeated) {
 | 
	
		
			
				|  |  | +            return computeRepeatedSerializedSize(value);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            return computeSingularSerializedSize(value);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    protected int computeRepeatedSerializedSize(Object array) {
 | 
	
		
			
				|  |  |          // This implementation is for non-packed extensions.
 | 
	
		
			
				|  |  | +        int size = 0;
 | 
	
		
			
				|  |  |          int arrayLength = Array.getLength(array);
 | 
	
		
			
				|  |  |          for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  |              Object element = Array.get(array, i);
 | 
	
		
			
				|  |  |              if (element != null) {
 | 
	
		
			
				|  |  | -                unknownFields.add(writeData(element));
 | 
	
		
			
				|  |  | +                size += computeSingularSerializedSize(Array.get(array, i));
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        return size;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    protected int computeSingularSerializedSize(Object value) {
 | 
	
		
			
				|  |  | +        // This implementation is for message/group extensions.
 | 
	
		
			
				|  |  | +        int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
 | 
	
		
			
				|  |  | +        switch (type) {
 | 
	
		
			
				|  |  | +            case TYPE_GROUP:
 | 
	
		
			
				|  |  | +                MessageNano groupValue = (MessageNano) value;
 | 
	
		
			
				|  |  | +                return CodedOutputByteBufferNano.computeGroupSize(fieldNumber, groupValue);
 | 
	
		
			
				|  |  | +            case TYPE_MESSAGE:
 | 
	
		
			
				|  |  | +                MessageNano messageValue = (MessageNano) value;
 | 
	
		
			
				|  |  | +                return CodedOutputByteBufferNano.computeMessageSize(fieldNumber, messageValue);
 | 
	
		
			
				|  |  | +            default:
 | 
	
		
			
				|  |  | +                throw new IllegalArgumentException("Unknown type " + type);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /**
 | 
	
	
		
			
				|  | @@ -338,15 +335,6 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
 | 
	
		
			
				|  |  |              this.packedTag = packedTag;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        @Override
 | 
	
		
			
				|  |  | -        protected boolean isMatch(int unknownDataTag) {
 | 
	
		
			
				|  |  | -            if (repeated) {
 | 
	
		
			
				|  |  | -                return unknownDataTag == nonPackedTag || unknownDataTag == packedTag;
 | 
	
		
			
				|  |  | -            } else {
 | 
	
		
			
				|  |  | -                return unknownDataTag == tag;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          @Override
 | 
	
		
			
				|  |  |          protected Object readData(CodedInputByteBufferNano input) {
 | 
	
		
			
				|  |  |              try {
 | 
	
	
		
			
				|  | @@ -398,7 +386,8 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
 | 
	
		
			
				|  |  |              if (data.tag == nonPackedTag) {
 | 
	
		
			
				|  |  |                  resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
 | 
	
		
			
				|  |  |              } else {
 | 
	
		
			
				|  |  | -                CodedInputByteBufferNano buffer = CodedInputByteBufferNano.newInstance(data.bytes);
 | 
	
		
			
				|  |  | +                CodedInputByteBufferNano buffer =
 | 
	
		
			
				|  |  | +                        CodedInputByteBufferNano.newInstance(data.bytes);
 | 
	
		
			
				|  |  |                  try {
 | 
	
		
			
				|  |  |                      buffer.pushLimit(buffer.readRawVarint32()); // length limit
 | 
	
		
			
				|  |  |                  } catch (IOException e) {
 | 
	
	
		
			
				|  | @@ -411,105 +400,73 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          @Override
 | 
	
		
			
				|  |  | -        protected final UnknownFieldData writeData(Object value) {
 | 
	
		
			
				|  |  | -            byte[] data;
 | 
	
		
			
				|  |  | +        protected final void writeSingularData(Object value, CodedOutputByteBufferNano output) {
 | 
	
		
			
				|  |  |              try {
 | 
	
		
			
				|  |  | +                output.writeRawVarint32(tag);
 | 
	
		
			
				|  |  |                  switch (type) {
 | 
	
		
			
				|  |  |                      case TYPE_DOUBLE:
 | 
	
		
			
				|  |  |                          Double doubleValue = (Double) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeDoubleSizeNoTag(doubleValue)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeDoubleNoTag(doubleValue);
 | 
	
		
			
				|  |  | +                        output.writeDoubleNoTag(doubleValue);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_FLOAT:
 | 
	
		
			
				|  |  |                          Float floatValue = (Float) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeFloatSizeNoTag(floatValue)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeFloatNoTag(floatValue);
 | 
	
		
			
				|  |  | +                        output.writeFloatNoTag(floatValue);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_INT64:
 | 
	
		
			
				|  |  |                          Long int64Value = (Long) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeInt64SizeNoTag(int64Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeInt64NoTag(int64Value);
 | 
	
		
			
				|  |  | +                        output.writeInt64NoTag(int64Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_UINT64:
 | 
	
		
			
				|  |  |                          Long uint64Value = (Long) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeUInt64SizeNoTag(uint64Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeUInt64NoTag(uint64Value);
 | 
	
		
			
				|  |  | +                        output.writeUInt64NoTag(uint64Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_INT32:
 | 
	
		
			
				|  |  |                          Integer int32Value = (Integer) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeInt32SizeNoTag(int32Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeInt32NoTag(int32Value);
 | 
	
		
			
				|  |  | +                        output.writeInt32NoTag(int32Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_FIXED64:
 | 
	
		
			
				|  |  |                          Long fixed64Value = (Long) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeFixed64SizeNoTag(fixed64Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeFixed64NoTag(fixed64Value);
 | 
	
		
			
				|  |  | +                        output.writeFixed64NoTag(fixed64Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_FIXED32:
 | 
	
		
			
				|  |  |                          Integer fixed32Value = (Integer) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeFixed32SizeNoTag(fixed32Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeFixed32NoTag(fixed32Value);
 | 
	
		
			
				|  |  | +                        output.writeFixed32NoTag(fixed32Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_BOOL:
 | 
	
		
			
				|  |  |                          Boolean boolValue = (Boolean) value;
 | 
	
		
			
				|  |  | -                        data = new byte[CodedOutputByteBufferNano.computeBoolSizeNoTag(boolValue)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeBoolNoTag(boolValue);
 | 
	
		
			
				|  |  | +                        output.writeBoolNoTag(boolValue);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_STRING:
 | 
	
		
			
				|  |  |                          String stringValue = (String) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeStringSizeNoTag(stringValue)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeStringNoTag(stringValue);
 | 
	
		
			
				|  |  | +                        output.writeStringNoTag(stringValue);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_BYTES:
 | 
	
		
			
				|  |  |                          byte[] bytesValue = (byte[]) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeBytesSizeNoTag(bytesValue)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeBytesNoTag(bytesValue);
 | 
	
		
			
				|  |  | +                        output.writeBytesNoTag(bytesValue);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_UINT32:
 | 
	
		
			
				|  |  |                          Integer uint32Value = (Integer) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeUInt32SizeNoTag(uint32Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeUInt32NoTag(uint32Value);
 | 
	
		
			
				|  |  | +                        output.writeUInt32NoTag(uint32Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_ENUM:
 | 
	
		
			
				|  |  |                          Integer enumValue = (Integer) value;
 | 
	
		
			
				|  |  | -                        data = new byte[CodedOutputByteBufferNano.computeEnumSizeNoTag(enumValue)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeEnumNoTag(enumValue);
 | 
	
		
			
				|  |  | +                        output.writeEnumNoTag(enumValue);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_SFIXED32:
 | 
	
		
			
				|  |  |                          Integer sfixed32Value = (Integer) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeSFixed32SizeNoTag(sfixed32Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data)
 | 
	
		
			
				|  |  | -                                .writeSFixed32NoTag(sfixed32Value);
 | 
	
		
			
				|  |  | +                        output.writeSFixed32NoTag(sfixed32Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_SFIXED64:
 | 
	
		
			
				|  |  |                          Long sfixed64Value = (Long) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeSFixed64SizeNoTag(sfixed64Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data)
 | 
	
		
			
				|  |  | -                                .writeSFixed64NoTag(sfixed64Value);
 | 
	
		
			
				|  |  | +                        output.writeSFixed64NoTag(sfixed64Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_SINT32:
 | 
	
		
			
				|  |  |                          Integer sint32Value = (Integer) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeSInt32SizeNoTag(sint32Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeSInt32NoTag(sint32Value);
 | 
	
		
			
				|  |  | +                        output.writeSInt32NoTag(sint32Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      case TYPE_SINT64:
 | 
	
		
			
				|  |  |                          Long sint64Value = (Long) value;
 | 
	
		
			
				|  |  | -                        data = new byte[
 | 
	
		
			
				|  |  | -                                CodedOutputByteBufferNano.computeSInt64SizeNoTag(sint64Value)];
 | 
	
		
			
				|  |  | -                        CodedOutputByteBufferNano.newInstance(data).writeSInt64NoTag(sint64Value);
 | 
	
		
			
				|  |  | +                        output.writeSInt64NoTag(sint64Value);
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      default:
 | 
	
		
			
				|  |  |                          throw new IllegalArgumentException("Unknown type " + type);
 | 
	
	
		
			
				|  | @@ -518,86 +475,21 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
 | 
	
		
			
				|  |  |                  // Should not happen
 | 
	
		
			
				|  |  |                  throw new IllegalStateException(e);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            return new UnknownFieldData(tag, data);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          @Override
 | 
	
		
			
				|  |  | -        protected void writeDataInto(T array, List<UnknownFieldData> unknownFields) {
 | 
	
		
			
				|  |  | +        protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
 | 
	
		
			
				|  |  |              if (tag == nonPackedTag) {
 | 
	
		
			
				|  |  |                  // Use base implementation for non-packed data
 | 
	
		
			
				|  |  | -                super.writeDataInto(array, unknownFields);
 | 
	
		
			
				|  |  | +                super.writeRepeatedData(array, output);
 | 
	
		
			
				|  |  |              } else if (tag == packedTag) {
 | 
	
		
			
				|  |  |                  // Packed. Note that the array element type is guaranteed to be primitive, so there
 | 
	
		
			
				|  |  | -                // won't be any null elements, so no null check in this block. First get data size.
 | 
	
		
			
				|  |  | +                // won't be any null elements, so no null check in this block.
 | 
	
		
			
				|  |  |                  int arrayLength = Array.getLength(array);
 | 
	
		
			
				|  |  | -                int dataSize = 0;
 | 
	
		
			
				|  |  | -                switch (type) {
 | 
	
		
			
				|  |  | -                    case TYPE_BOOL:
 | 
	
		
			
				|  |  | -                        // Bools are stored as int32 but just as 0 or 1, so 1 byte each.
 | 
	
		
			
				|  |  | -                        dataSize = arrayLength;
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    case TYPE_FIXED32:
 | 
	
		
			
				|  |  | -                    case TYPE_SFIXED32:
 | 
	
		
			
				|  |  | -                    case TYPE_FLOAT:
 | 
	
		
			
				|  |  | -                        dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_32_SIZE;
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    case TYPE_FIXED64:
 | 
	
		
			
				|  |  | -                    case TYPE_SFIXED64:
 | 
	
		
			
				|  |  | -                    case TYPE_DOUBLE:
 | 
	
		
			
				|  |  | -                        dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_64_SIZE;
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    case TYPE_INT32:
 | 
	
		
			
				|  |  | -                        for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | -                            dataSize += CodedOutputByteBufferNano.computeInt32SizeNoTag(
 | 
	
		
			
				|  |  | -                                    Array.getInt(array, i));
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    case TYPE_SINT32:
 | 
	
		
			
				|  |  | -                        for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | -                            dataSize += CodedOutputByteBufferNano.computeSInt32SizeNoTag(
 | 
	
		
			
				|  |  | -                                    Array.getInt(array, i));
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    case TYPE_UINT32:
 | 
	
		
			
				|  |  | -                        for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | -                            dataSize += CodedOutputByteBufferNano.computeUInt32SizeNoTag(
 | 
	
		
			
				|  |  | -                                    Array.getInt(array, i));
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    case TYPE_INT64:
 | 
	
		
			
				|  |  | -                        for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | -                            dataSize += CodedOutputByteBufferNano.computeInt64SizeNoTag(
 | 
	
		
			
				|  |  | -                                    Array.getLong(array, i));
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    case TYPE_SINT64:
 | 
	
		
			
				|  |  | -                        for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | -                            dataSize += CodedOutputByteBufferNano.computeSInt64SizeNoTag(
 | 
	
		
			
				|  |  | -                                    Array.getLong(array, i));
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    case TYPE_UINT64:
 | 
	
		
			
				|  |  | -                        for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | -                            dataSize += CodedOutputByteBufferNano.computeUInt64SizeNoTag(
 | 
	
		
			
				|  |  | -                                    Array.getLong(array, i));
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    case TYPE_ENUM:
 | 
	
		
			
				|  |  | -                        for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | -                            dataSize += CodedOutputByteBufferNano.computeEnumSizeNoTag(
 | 
	
		
			
				|  |  | -                                    Array.getInt(array, i));
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        break;
 | 
	
		
			
				|  |  | -                    default:
 | 
	
		
			
				|  |  | -                        throw new IllegalArgumentException("Unexpected non-packable type " + type);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +                int dataSize = computePackedDataSize(array);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                // Then construct payload.
 | 
	
		
			
				|  |  | -                int payloadSize =
 | 
	
		
			
				|  |  | -                        dataSize + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
 | 
	
		
			
				|  |  | -                byte[] data = new byte[payloadSize];
 | 
	
		
			
				|  |  | -                CodedOutputByteBufferNano output = CodedOutputByteBufferNano.newInstance(data);
 | 
	
		
			
				|  |  |                  try {
 | 
	
		
			
				|  |  | +                    output.writeRawVarint32(tag);
 | 
	
		
			
				|  |  |                      output.writeRawVarint32(dataSize);
 | 
	
		
			
				|  |  |                      switch (type) {
 | 
	
		
			
				|  |  |                          case TYPE_BOOL:
 | 
	
	
		
			
				|  | @@ -677,12 +569,154 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
 | 
	
		
			
				|  |  |                      // Should not happen.
 | 
	
		
			
				|  |  |                      throw new IllegalStateException(e);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | -                unknownFields.add(new UnknownFieldData(tag, data));
 | 
	
		
			
				|  |  |              } else {
 | 
	
		
			
				|  |  |                  throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
 | 
	
		
			
				|  |  |                          + ", unequal to both non-packed variant " + nonPackedTag
 | 
	
		
			
				|  |  |                          + " and packed variant " + packedTag);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private int computePackedDataSize(Object array) {
 | 
	
		
			
				|  |  | +            int dataSize = 0;
 | 
	
		
			
				|  |  | +            int arrayLength = Array.getLength(array);
 | 
	
		
			
				|  |  | +            switch (type) {
 | 
	
		
			
				|  |  | +                case TYPE_BOOL:
 | 
	
		
			
				|  |  | +                    // Bools are stored as int32 but just as 0 or 1, so 1 byte each.
 | 
	
		
			
				|  |  | +                    dataSize = arrayLength;
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                case TYPE_FIXED32:
 | 
	
		
			
				|  |  | +                case TYPE_SFIXED32:
 | 
	
		
			
				|  |  | +                case TYPE_FLOAT:
 | 
	
		
			
				|  |  | +                    dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_32_SIZE;
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                case TYPE_FIXED64:
 | 
	
		
			
				|  |  | +                case TYPE_SFIXED64:
 | 
	
		
			
				|  |  | +                case TYPE_DOUBLE:
 | 
	
		
			
				|  |  | +                    dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_64_SIZE;
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                case TYPE_INT32:
 | 
	
		
			
				|  |  | +                    for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | +                        dataSize += CodedOutputByteBufferNano.computeInt32SizeNoTag(
 | 
	
		
			
				|  |  | +                                Array.getInt(array, i));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                case TYPE_SINT32:
 | 
	
		
			
				|  |  | +                    for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | +                        dataSize += CodedOutputByteBufferNano.computeSInt32SizeNoTag(
 | 
	
		
			
				|  |  | +                                Array.getInt(array, i));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                case TYPE_UINT32:
 | 
	
		
			
				|  |  | +                    for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | +                        dataSize += CodedOutputByteBufferNano.computeUInt32SizeNoTag(
 | 
	
		
			
				|  |  | +                                Array.getInt(array, i));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                case TYPE_INT64:
 | 
	
		
			
				|  |  | +                    for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | +                        dataSize += CodedOutputByteBufferNano.computeInt64SizeNoTag(
 | 
	
		
			
				|  |  | +                                Array.getLong(array, i));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                case TYPE_SINT64:
 | 
	
		
			
				|  |  | +                    for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | +                        dataSize += CodedOutputByteBufferNano.computeSInt64SizeNoTag(
 | 
	
		
			
				|  |  | +                                Array.getLong(array, i));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                case TYPE_UINT64:
 | 
	
		
			
				|  |  | +                    for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | +                        dataSize += CodedOutputByteBufferNano.computeUInt64SizeNoTag(
 | 
	
		
			
				|  |  | +                                Array.getLong(array, i));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                case TYPE_ENUM:
 | 
	
		
			
				|  |  | +                    for (int i = 0; i < arrayLength; i++) {
 | 
	
		
			
				|  |  | +                        dataSize += CodedOutputByteBufferNano.computeEnumSizeNoTag(
 | 
	
		
			
				|  |  | +                                Array.getInt(array, i));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    break;
 | 
	
		
			
				|  |  | +                default:
 | 
	
		
			
				|  |  | +                    throw new IllegalArgumentException("Unexpected non-packable type " + type);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            return dataSize;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        @Override
 | 
	
		
			
				|  |  | +        protected int computeRepeatedSerializedSize(Object array) {
 | 
	
		
			
				|  |  | +            if (tag == nonPackedTag) {
 | 
	
		
			
				|  |  | +                // Use base implementation for non-packed data
 | 
	
		
			
				|  |  | +                return super.computeRepeatedSerializedSize(array);
 | 
	
		
			
				|  |  | +            } else if (tag == packedTag) {
 | 
	
		
			
				|  |  | +                // Packed.
 | 
	
		
			
				|  |  | +                int dataSize = computePackedDataSize(array);
 | 
	
		
			
				|  |  | +                int payloadSize =
 | 
	
		
			
				|  |  | +                        dataSize + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
 | 
	
		
			
				|  |  | +                return payloadSize + CodedOutputByteBufferNano.computeRawVarint32Size(tag);
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
 | 
	
		
			
				|  |  | +                        + ", unequal to both non-packed variant " + nonPackedTag
 | 
	
		
			
				|  |  | +                        + " and packed variant " + packedTag);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        @Override
 | 
	
		
			
				|  |  | +        protected final int computeSingularSerializedSize(Object value) {
 | 
	
		
			
				|  |  | +            int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
 | 
	
		
			
				|  |  | +            switch (type) {
 | 
	
		
			
				|  |  | +                case TYPE_DOUBLE:
 | 
	
		
			
				|  |  | +                    Double doubleValue = (Double) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeDoubleSize(fieldNumber, doubleValue);
 | 
	
		
			
				|  |  | +                case TYPE_FLOAT:
 | 
	
		
			
				|  |  | +                    Float floatValue = (Float) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeFloatSize(fieldNumber, floatValue);
 | 
	
		
			
				|  |  | +                case TYPE_INT64:
 | 
	
		
			
				|  |  | +                    Long int64Value = (Long) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeInt64Size(fieldNumber, int64Value);
 | 
	
		
			
				|  |  | +                case TYPE_UINT64:
 | 
	
		
			
				|  |  | +                    Long uint64Value = (Long) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeUInt64Size(fieldNumber, uint64Value);
 | 
	
		
			
				|  |  | +                case TYPE_INT32:
 | 
	
		
			
				|  |  | +                    Integer int32Value = (Integer) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeInt32Size(fieldNumber, int32Value);
 | 
	
		
			
				|  |  | +                case TYPE_FIXED64:
 | 
	
		
			
				|  |  | +                    Long fixed64Value = (Long) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeFixed64Size(fieldNumber, fixed64Value);
 | 
	
		
			
				|  |  | +                case TYPE_FIXED32:
 | 
	
		
			
				|  |  | +                    Integer fixed32Value = (Integer) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeFixed32Size(fieldNumber, fixed32Value);
 | 
	
		
			
				|  |  | +                case TYPE_BOOL:
 | 
	
		
			
				|  |  | +                    Boolean boolValue = (Boolean) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeBoolSize(fieldNumber, boolValue);
 | 
	
		
			
				|  |  | +                case TYPE_STRING:
 | 
	
		
			
				|  |  | +                    String stringValue = (String) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeStringSize(fieldNumber, stringValue);
 | 
	
		
			
				|  |  | +                case TYPE_BYTES:
 | 
	
		
			
				|  |  | +                    byte[] bytesValue = (byte[]) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeBytesSize(fieldNumber, bytesValue);
 | 
	
		
			
				|  |  | +                case TYPE_UINT32:
 | 
	
		
			
				|  |  | +                    Integer uint32Value = (Integer) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeUInt32Size(fieldNumber, uint32Value);
 | 
	
		
			
				|  |  | +                case TYPE_ENUM:
 | 
	
		
			
				|  |  | +                    Integer enumValue = (Integer) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeEnumSize(fieldNumber, enumValue);
 | 
	
		
			
				|  |  | +                case TYPE_SFIXED32:
 | 
	
		
			
				|  |  | +                    Integer sfixed32Value = (Integer) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeSFixed32Size(fieldNumber,
 | 
	
		
			
				|  |  | +                            sfixed32Value);
 | 
	
		
			
				|  |  | +                case TYPE_SFIXED64:
 | 
	
		
			
				|  |  | +                    Long sfixed64Value = (Long) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeSFixed64Size(fieldNumber,
 | 
	
		
			
				|  |  | +                            sfixed64Value);
 | 
	
		
			
				|  |  | +                case TYPE_SINT32:
 | 
	
		
			
				|  |  | +                    Integer sint32Value = (Integer) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeSInt32Size(fieldNumber, sint32Value);
 | 
	
		
			
				|  |  | +                case TYPE_SINT64:
 | 
	
		
			
				|  |  | +                    Long sint64Value = (Long) value;
 | 
	
		
			
				|  |  | +                    return CodedOutputByteBufferNano.computeSInt64Size(fieldNumber, sint64Value);
 | 
	
		
			
				|  |  | +                default:
 | 
	
		
			
				|  |  | +                    throw new IllegalArgumentException("Unknown type " + type);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |