MapEntry.java
Go to the documentation of this file.
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf;
32 
36 import java.io.IOException;
37 import java.util.Collections;
38 import java.util.Map;
39 import java.util.TreeMap;
40 
50 public final class MapEntry<K, V> extends AbstractMessage {
51 
52  private static final class Metadata<K, V> extends MapEntryLite.Metadata<K, V> {
53 
54  public final Descriptor descriptor;
56 
57  public Metadata(
59  MapEntry<K, V> defaultInstance,
60  WireFormat.FieldType keyType,
61  WireFormat.FieldType valueType) {
62  super(keyType, defaultInstance.key, valueType, defaultInstance.value);
63  this.descriptor = descriptor;
64  this.parser =
66 
67  @Override
68  public MapEntry<K, V> parsePartialFrom(
69  CodedInputStream input, ExtensionRegistryLite extensionRegistry)
71  return new MapEntry<K, V>(Metadata.this, input, extensionRegistry);
72  }
73  };
74  }
75  }
76 
77  private final K key;
78  private final V value;
79  private final Metadata<K, V> metadata;
80 
82  private MapEntry(
84  WireFormat.FieldType keyType,
85  K defaultKey,
86  WireFormat.FieldType valueType,
87  V defaultValue) {
88  this.key = defaultKey;
89  this.value = defaultValue;
90  this.metadata = new Metadata<K, V>(descriptor, this, keyType, valueType);
91  }
92 
94  @SuppressWarnings("unchecked")
96  this.key = key;
97  this.value = value;
98  this.metadata = metadata;
99  }
100 
102  private MapEntry(
105  try {
106  this.metadata = metadata;
107  Map.Entry<K, V> entry = MapEntryLite.parseEntry(input, metadata, extensionRegistry);
108  this.key = entry.getKey();
109  this.value = entry.getValue();
110  } catch (InvalidProtocolBufferException e) {
111  throw e.setUnfinishedMessage(this);
112  } catch (IOException e) {
114  }
115  }
116 
122  public static <K, V> MapEntry<K, V> newDefaultInstance(
124  WireFormat.FieldType keyType,
125  K defaultKey,
126  WireFormat.FieldType valueType,
127  V defaultValue) {
128  return new MapEntry<K, V>(descriptor, keyType, defaultKey, valueType, defaultValue);
129  }
130 
131  public K getKey() {
132  return key;
133  }
134 
135  public V getValue() {
136  return value;
137  }
138 
139  private volatile int cachedSerializedSize = -1;
140 
141  @Override
142  public int getSerializedSize() {
143  if (cachedSerializedSize != -1) {
144  return cachedSerializedSize;
145  }
146 
147  int size = MapEntryLite.computeSerializedSize(metadata, key, value);
149  return size;
150  }
151 
152  @Override
153  public void writeTo(CodedOutputStream output) throws IOException {
154  MapEntryLite.writeTo(output, metadata, key, value);
155  }
156 
157  @Override
158  public boolean isInitialized() {
159  return isInitialized(metadata, value);
160  }
161 
162  @Override
164  return metadata.parser;
165  }
166 
167  @Override
169  return new Builder<K, V>(metadata);
170  }
171 
172  @Override
174  return new Builder<K, V>(metadata, key, value, true, true);
175  }
176 
177  @Override
179  return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
180  }
181 
182  @Override
184  return metadata.descriptor;
185  }
186 
187  @Override
188  public Map<FieldDescriptor, Object> getAllFields() {
189  TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
190  for (final FieldDescriptor field : metadata.descriptor.getFields()) {
191  if (hasField(field)) {
192  result.put(field, getField(field));
193  }
194  }
195  return Collections.unmodifiableMap(result);
196  }
197 
199  if (field.getContainingType() != metadata.descriptor) {
200  throw new RuntimeException(
201  "Wrong FieldDescriptor \""
202  + field.getFullName()
203  + "\" used in message \""
204  + metadata.descriptor.getFullName());
205  }
206  }
207 
208  @Override
209  public boolean hasField(FieldDescriptor field) {
211  ;
212  // A MapEntry always contains two fields.
213  return true;
214  }
215 
216  @Override
217  public Object getField(FieldDescriptor field) {
219  Object result = field.getNumber() == 1 ? getKey() : getValue();
220  // Convert enums to EnumValueDescriptor.
221  if (field.getType() == FieldDescriptor.Type.ENUM) {
222  result = field.getEnumType().findValueByNumberCreatingIfUnknown((java.lang.Integer) result);
223  }
224  return result;
225  }
226 
227  @Override
229  throw new RuntimeException("There is no repeated field in a map entry message.");
230  }
231 
232  @Override
234  throw new RuntimeException("There is no repeated field in a map entry message.");
235  }
236 
237  @Override
240  }
241 
243  public static class Builder<K, V> extends AbstractMessage.Builder<Builder<K, V>> {
244  private final Metadata<K, V> metadata;
245  private K key;
246  private V value;
247  private boolean hasKey;
248  private boolean hasValue;
249 
251  this(metadata, metadata.defaultKey, metadata.defaultValue, false, false);
252  }
253 
254  private Builder(Metadata<K, V> metadata, K key, V value, boolean hasKey, boolean hasValue) {
255  this.metadata = metadata;
256  this.key = key;
257  this.value = value;
258  this.hasKey = hasKey;
259  this.hasValue = hasValue;
260  }
261 
262  public K getKey() {
263  return key;
264  }
265 
266  public V getValue() {
267  return value;
268  }
269 
271  this.key = key;
272  this.hasKey = true;
273  return this;
274  }
275 
277  this.key = metadata.defaultKey;
278  this.hasKey = false;
279  return this;
280  }
281 
283  this.value = value;
284  this.hasValue = true;
285  return this;
286  }
287 
289  this.value = metadata.defaultValue;
290  this.hasValue = false;
291  return this;
292  }
293 
294  @Override
296  MapEntry<K, V> result = buildPartial();
297  if (!result.isInitialized()) {
298  throw newUninitializedMessageException(result);
299  }
300  return result;
301  }
302 
303  @Override
305  return new MapEntry<K, V>(metadata, key, value);
306  }
307 
308  @Override
310  return metadata.descriptor;
311  }
312 
314  if (field.getContainingType() != metadata.descriptor) {
315  throw new RuntimeException(
316  "Wrong FieldDescriptor \""
317  + field.getFullName()
318  + "\" used in message \""
319  + metadata.descriptor.getFullName());
320  }
321  }
322 
323  @Override
326  ;
327  // This method should be called for message fields and in a MapEntry
328  // message only the value field can possibly be a message field.
329  if (field.getNumber() != 2 || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
330  throw new RuntimeException("\"" + field.getFullName() + "\" is not a message value field.");
331  }
332  return ((Message) value).newBuilderForType();
333  }
334 
335  @SuppressWarnings("unchecked")
336  @Override
339  if (field.getNumber() == 1) {
340  setKey((K) value);
341  } else {
342  if (field.getType() == FieldDescriptor.Type.ENUM) {
343  value = ((EnumValueDescriptor) value).getNumber();
344  } else if (field.getType() == FieldDescriptor.Type.MESSAGE) {
345  if (value != null && !metadata.defaultValue.getClass().isInstance(value)) {
346  // The value is not the exact right message type. However, if it
347  // is an alternative implementation of the same type -- e.g. a
348  // DynamicMessage -- we should accept it. In this case we can make
349  // a copy of the message.
350  value =
351  ((Message) metadata.defaultValue).toBuilder().mergeFrom((Message) value).build();
352  }
353  }
354  setValue((V) value);
355  }
356  return this;
357  }
358 
359  @Override
362  if (field.getNumber() == 1) {
363  clearKey();
364  } else {
365  clearValue();
366  }
367  return this;
368  }
369 
370  @Override
372  throw new RuntimeException("There is no repeated field in a map entry message.");
373  }
374 
375  @Override
377  throw new RuntimeException("There is no repeated field in a map entry message.");
378  }
379 
380  @Override
382  // Unknown fields are discarded for MapEntry message.
383  return this;
384  }
385 
386  @Override
388  return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
389  }
390 
391  @Override
392  public boolean isInitialized() {
394  }
395 
396  @Override
397  public Map<FieldDescriptor, Object> getAllFields() {
398  final TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
399  for (final FieldDescriptor field : metadata.descriptor.getFields()) {
400  if (hasField(field)) {
401  result.put(field, getField(field));
402  }
403  }
404  return Collections.unmodifiableMap(result);
405  }
406 
407  @Override
408  public boolean hasField(FieldDescriptor field) {
410  return field.getNumber() == 1 ? hasKey : hasValue;
411  }
412 
413  @Override
414  public Object getField(FieldDescriptor field) {
416  Object result = field.getNumber() == 1 ? getKey() : getValue();
417  // Convert enums to EnumValueDescriptor.
418  if (field.getType() == FieldDescriptor.Type.ENUM) {
419  result = field.getEnumType().findValueByNumberCreatingIfUnknown((Integer) result);
420  }
421  return result;
422  }
423 
424  @Override
426  throw new RuntimeException("There is no repeated field in a map entry message.");
427  }
428 
429  @Override
431  throw new RuntimeException("There is no repeated field in a map entry message.");
432  }
433 
434  @Override
437  }
438 
439  @Override
440  @SuppressWarnings("unchecked")
441  public Builder<K, V> clone() {
442  return new Builder(metadata, key, value, hasKey, hasValue);
443  }
444  }
445 
446  private static <V> boolean isInitialized(Metadata metadata, V value) {
447  if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
448  return ((MessageLite) value).isInitialized();
449  }
450  return true;
451  }
452 
454  final Metadata<K, V> getMetadata() {
455  return metadata;
456  }
457 }
com.google.protobuf.Descriptors
Definition: Descriptors.java:80
Map
struct Map Map
Definition: php/ext/google/protobuf/protobuf.h:648
com.google.protobuf.MapEntry.Builder.setKey
Builder< K, V > setKey(K key)
Definition: MapEntry.java:270
com.google.protobuf.MapEntry.getDefaultInstanceForType
MapEntry< K, V > getDefaultInstanceForType()
Definition: MapEntry.java:178
java::lang
com.google.protobuf.MapEntryLite.parseEntry
Map.Entry< K, V > parseEntry(ByteString bytes, ExtensionRegistryLite extensionRegistry)
Definition: MapEntryLite.java:166
com.google.protobuf.MapEntry.key
final K key
Definition: MapEntry.java:77
K
#define K(t)
Definition: sha1.c:43
com.google.protobuf.UnknownFieldSet.getDefaultInstance
static UnknownFieldSet getDefaultInstance()
Definition: UnknownFieldSet.java:76
com.google.protobuf.MapEntry.getValue
V getValue()
Definition: MapEntry.java:135
com.google.protobuf.WireFormat.JavaType.MESSAGE
MESSAGE
Definition: WireFormat.java:93
com.google.protobuf.MapEntry.Builder.getRepeatedFieldCount
int getRepeatedFieldCount(FieldDescriptor field)
Definition: MapEntry.java:425
com.google.protobuf.MapEntry
Definition: MapEntry.java:50
input
std::string input
Definition: tokenizer_unittest.cc:197
com.google.protobuf.MapEntry.Builder.getKey
K getKey()
Definition: MapEntry.java:262
com.google.protobuf.MapEntry.Builder.setUnknownFields
Builder< K, V > setUnknownFields(UnknownFieldSet unknownFields)
Definition: MapEntry.java:381
com.google.protobuf.MapEntry.Metadata.Metadata
Metadata(Descriptor descriptor, MapEntry< K, V > defaultInstance, WireFormat.FieldType keyType, WireFormat.FieldType valueType)
Definition: MapEntry.java:57
com.google.protobuf.MapEntry.cachedSerializedSize
volatile int cachedSerializedSize
Definition: MapEntry.java:139
com.google.protobuf.MapEntry.Builder.metadata
final Metadata< K, V > metadata
Definition: MapEntry.java:244
com.google.protobuf.MapEntry.Builder.clearValue
Builder< K, V > clearValue()
Definition: MapEntry.java:288
com.google.protobuf.MapEntry.Builder.hasValue
boolean hasValue
Definition: MapEntry.java:248
com.google.protobuf.Descriptors.FieldDescriptor.Type.MESSAGE
MESSAGE
Definition: Descriptors.java:1226
com.google.protobuf.MapEntry.newBuilderForType
Builder< K, V > newBuilderForType()
Definition: MapEntry.java:168
com.google.protobuf
Definition: ProtoCaliperBenchmark.java:2
com.google.protobuf.MapEntry.Builder.Builder
Builder(Metadata< K, V > metadata, K key, V value, boolean hasKey, boolean hasValue)
Definition: MapEntry.java:254
descriptor
Descriptor * descriptor
Definition: php/ext/google/protobuf/protobuf.h:936
com.google.protobuf.WireFormat
Definition: WireFormat.java:45
com.google.protobuf.Descriptors.FieldDescriptor.Type
Definition: Descriptors.java:1215
com.google.protobuf.MapEntry.getSerializedSize
int getSerializedSize()
Definition: MapEntry.java:142
com.google.protobuf.MapEntry.Builder.getRepeatedField
Object getRepeatedField(FieldDescriptor field, int index)
Definition: MapEntry.java:430
com.google.protobuf.MapEntry.Builder.setField
Builder< K, V > setField(FieldDescriptor field, Object value)
Definition: MapEntry.java:337
com.google.protobuf.MapEntry.getKey
K getKey()
Definition: MapEntry.java:131
com.google.protobuf.MapEntry.MapEntry
MapEntry(Descriptor descriptor, WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue)
Definition: MapEntry.java:82
com.google.protobuf.MapEntry.Builder.isInitialized
boolean isInitialized()
Definition: MapEntry.java:392
com.google.protobuf.MapEntry.getAllFields
Map< FieldDescriptor, Object > getAllFields()
Definition: MapEntry.java:188
com.google.protobuf.Parser
Definition: Parser.java:47
com.google.protobuf.CodedInputStream
Definition: CodedInputStream.java:61
com.google.protobuf.MapEntry.isInitialized
boolean isInitialized()
Definition: MapEntry.java:158
com.google.protobuf.MapEntry.checkFieldDescriptor
void checkFieldDescriptor(FieldDescriptor field)
Definition: MapEntry.java:198
com.google.protobuf.Message.Builder
Definition: Message.java:104
com.google.protobuf.UnknownFieldSet
Definition: UnknownFieldSet.java:58
com.google.protobuf.MapEntry.Metadata.parser
final Parser< MapEntry< K, V > > parser
Definition: MapEntry.java:55
com.google.protobuf.MapEntry.toBuilder
Builder< K, V > toBuilder()
Definition: MapEntry.java:173
com.google.protobuf.MapEntry.Builder.getDefaultInstanceForType
MapEntry< K, V > getDefaultInstanceForType()
Definition: MapEntry.java:387
com.google.protobuf.MapEntry.Builder
Definition: MapEntry.java:243
com.google.protobuf.Descriptors.FieldDescriptor.JavaType
Definition: Descriptors.java:1262
com.google.protobuf.MapEntry.Builder.clone
Builder< K, V > clone()
Definition: MapEntry.java:441
com.google.protobuf.MapEntry.hasField
boolean hasField(FieldDescriptor field)
Definition: MapEntry.java:209
EnumValueDescriptor
struct EnumValueDescriptor EnumValueDescriptor
Definition: php/ext/google/protobuf/protobuf.h:634
com.google.protobuf.MapEntry.Builder.getValue
V getValue()
Definition: MapEntry.java:266
size
#define size
Definition: glcorearb.h:2944
com.google.protobuf.MapEntry.Builder.clearKey
Builder< K, V > clearKey()
Definition: MapEntry.java:276
com.google.protobuf.MapEntry.isInitialized
static< V > boolean isInitialized(Metadata metadata, V value)
Definition: MapEntry.java:446
com.google.protobuf.MapEntry.getParserForType
Parser< MapEntry< K, V > > getParserForType()
Definition: MapEntry.java:163
com.google.protobuf.MapEntry.Builder.build
MapEntry< K, V > build()
Definition: MapEntry.java:295
com.google.protobuf.ExtensionRegistryLite
Definition: ExtensionRegistryLite.java:70
com.google.protobuf.MapEntry.Builder.getAllFields
Map< FieldDescriptor, Object > getAllFields()
Definition: MapEntry.java:397
com.google.protobuf.MapEntry.Builder.Builder
Builder(Metadata< K, V > metadata)
Definition: MapEntry.java:250
field
const FieldDescriptor * field
Definition: parser_unittest.cc:2694
java
com.google.protobuf.Descriptors.Descriptor
Definition: Descriptors.java:629
com.google.protobuf.MapEntry.Builder.setValue
Builder< K, V > setValue(V value)
Definition: MapEntry.java:282
com.google.protobuf.MapEntry.Builder.setRepeatedField
Builder< K, V > setRepeatedField(FieldDescriptor field, int index, Object value)
Definition: MapEntry.java:371
com.google.protobuf.MapEntry.Builder.getField
Object getField(FieldDescriptor field)
Definition: MapEntry.java:414
com.google.protobuf.MapEntry.Builder.hasKey
boolean hasKey
Definition: MapEntry.java:247
com.google.protobuf.MapEntry.getRepeatedField
Object getRepeatedField(FieldDescriptor field, int index)
Definition: MapEntry.java:233
com.google.protobuf.MapEntry.Builder.hasField
boolean hasField(FieldDescriptor field)
Definition: MapEntry.java:408
com.google.protobuf.MapEntry.value
final V value
Definition: MapEntry.java:78
com.google.protobuf.MapEntry.Builder.addRepeatedField
Builder< K, V > addRepeatedField(FieldDescriptor field, Object value)
Definition: MapEntry.java:376
size
GLsizeiptr size
Definition: glcorearb.h:2943
com.google.protobuf.MapEntry.Builder.key
K key
Definition: MapEntry.java:245
com.google.protobuf.InvalidProtocolBufferException.setUnfinishedMessage
InvalidProtocolBufferException setUnfinishedMessage(MessageLite unfinishedMessage)
Definition: InvalidProtocolBufferException.java:63
com.google
com.google.protobuf.MapEntryLite
Definition: MapEntryLite.java:45
com
com.google.protobuf.AbstractMessage.Builder< Builder< K, V > >::newUninitializedMessageException
static UninitializedMessageException newUninitializedMessageException(Message message)
Definition: AbstractMessage.java:475
com.google.protobuf.MapEntry.Builder.buildPartial
MapEntry< K, V > buildPartial()
Definition: MapEntry.java:304
com.google.protobuf.MapEntry.Metadata.descriptor
final Descriptor descriptor
Definition: MapEntry.java:54
com.google.protobuf.AbstractMessage
Definition: AbstractMessage.java:52
com.google.protobuf.MapEntry.getDescriptorForType
Descriptor getDescriptorForType()
Definition: MapEntry.java:183
com.google.protobuf.MapEntry.newDefaultInstance
static< K, V > MapEntry< K, V > newDefaultInstance(Descriptor descriptor, WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue)
Definition: MapEntry.java:122
com.google.protobuf.AbstractParser
Definition: AbstractParser.java:48
com.google.protobuf.CodedOutputStream
Definition: CodedOutputStream.java:59
com.google.protobuf.MapEntry.Builder.newBuilderForField
Message.Builder newBuilderForField(FieldDescriptor field)
Definition: MapEntry.java:324
com.google.protobuf.InvalidProtocolBufferException
Definition: InvalidProtocolBufferException.java:41
com.google.protobuf.MapEntry.Builder.getDescriptorForType
Descriptor getDescriptorForType()
Definition: MapEntry.java:309
com.google.protobuf.MapEntry.Builder.getUnknownFields
UnknownFieldSet getUnknownFields()
Definition: MapEntry.java:435
com.google.protobuf.MapEntry.Builder.clearField
Builder< K, V > clearField(FieldDescriptor field)
Definition: MapEntry.java:360
com.google.protobuf.Descriptors.EnumValueDescriptor
Definition: Descriptors.java:1774
com.google.protobuf.MapEntry.getRepeatedFieldCount
int getRepeatedFieldCount(FieldDescriptor field)
Definition: MapEntry.java:228
com.google.protobuf.MapEntry.metadata
final Metadata< K, V > metadata
Definition: MapEntry.java:79
value
GLsizei const GLfloat * value
Definition: glcorearb.h:3093
com.google.protobuf.WireFormat.FieldType
Definition: WireFormat.java:111
output
const upb_json_parsermethod const upb_symtab upb_sink * output
Definition: ruby/ext/google/protobuf_c/upb.h:10503
com.google.protobuf.MapEntry.Builder.value
V value
Definition: MapEntry.java:246
index
GLuint index
Definition: glcorearb.h:3055
com.google.protobuf.MapEntry.MapEntry
MapEntry(Metadata< K, V > metadata, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
Definition: MapEntry.java:102
com.google.protobuf.MapEntry.Builder.checkFieldDescriptor
void checkFieldDescriptor(FieldDescriptor field)
Definition: MapEntry.java:313
com.google.protobuf.MapEntry.getUnknownFields
UnknownFieldSet getUnknownFields()
Definition: MapEntry.java:238
com.google.protobuf.MapEntry.writeTo
void writeTo(CodedOutputStream output)
Definition: MapEntry.java:153
com.google.protobuf.Message
Definition: Message.java:50
com.google.protobuf.MapEntry.Metadata
Definition: MapEntry.java:52
com.google.protobuf.MessageLite
Definition: MessageLite.java:65
com.google.protobuf.Descriptors.FieldDescriptor.Type.ENUM
ENUM
Definition: Descriptors.java:1229
com.google.protobuf.Descriptors.FieldDescriptor
Definition: Descriptors.java:949
com.google.protobuf.WireFormat.JavaType
Definition: WireFormat.java:84
com.google.protobuf.Descriptors.FieldDescriptor.JavaType.MESSAGE
MESSAGE
Definition: Descriptors.java:1271
com.google.protobuf.MapEntry.getField
Object getField(FieldDescriptor field)
Definition: MapEntry.java:217


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:56