Skip to main content

serde_reflection/
de.rs

1// Copyright (c) Facebook, Inc. and its affiliates
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use crate::{
5    error::{Error, Result},
6    format::{ContainerFormat, ContainerFormatEntry, Format, FormatHolder, Named, VariantFormat},
7    trace::{IncompleteEnumReason, Samples, Tracer, VariantId},
8    value::IntoSeqDeserializer,
9};
10use erased_discriminant::Discriminant;
11use serde::de::{
12    self,
13    value::{BorrowedStrDeserializer, U32Deserializer},
14    DeserializeSeed, IntoDeserializer, Visitor,
15};
16use std::collections::btree_map::{BTreeMap, Entry};
17
18/// Deserialize a single value.
19/// * The lifetime 'a is set by the deserialization call site and the
20///   `&'a mut` references used to return tracing results.
21/// * The lifetime 'de is fixed and the `&'de` reference meant to let us
22///   borrow values from previous serialization runs.
23pub struct Deserializer<'de, 'a> {
24    tracer: &'a mut Tracer,
25    samples: &'de Samples,
26    format: &'a mut Format,
27}
28
29impl<'de, 'a> Deserializer<'de, 'a> {
30    /// Create a new Deserializer
31    pub fn new(tracer: &'a mut Tracer, samples: &'de Samples, format: &'a mut Format) -> Self {
32        Deserializer {
33            tracer,
34            samples,
35            format,
36        }
37    }
38}
39
40impl<'de, 'a> de::Deserializer<'de> for Deserializer<'de, 'a> {
41    type Error = Error;
42
43    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
44    where
45        V: Visitor<'de>,
46    {
47        Err(Error::NotSupported("deserialize_any"))
48    }
49
50    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
51    where
52        V: Visitor<'de>,
53    {
54        self.format.unify(Format::Bool)?;
55        visitor.visit_bool(self.tracer.config.default_bool_value)
56    }
57
58    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
59    where
60        V: Visitor<'de>,
61    {
62        self.format.unify(Format::I8)?;
63        visitor.visit_i8(self.tracer.config.default_i8_value)
64    }
65
66    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
67    where
68        V: Visitor<'de>,
69    {
70        self.format.unify(Format::I16)?;
71        visitor.visit_i16(self.tracer.config.default_i16_value)
72    }
73
74    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
75    where
76        V: Visitor<'de>,
77    {
78        self.format.unify(Format::I32)?;
79        visitor.visit_i32(self.tracer.config.default_i32_value)
80    }
81
82    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
83    where
84        V: Visitor<'de>,
85    {
86        self.format.unify(Format::I64)?;
87        visitor.visit_i64(self.tracer.config.default_i64_value)
88    }
89
90    fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value>
91    where
92        V: Visitor<'de>,
93    {
94        self.format.unify(Format::I128)?;
95        visitor.visit_i128(self.tracer.config.default_i128_value)
96    }
97
98    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
99    where
100        V: Visitor<'de>,
101    {
102        self.format.unify(Format::U8)?;
103        visitor.visit_u8(self.tracer.config.default_u8_value)
104    }
105
106    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
107    where
108        V: Visitor<'de>,
109    {
110        self.format.unify(Format::U16)?;
111        visitor.visit_u16(self.tracer.config.default_u16_value)
112    }
113
114    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
115    where
116        V: Visitor<'de>,
117    {
118        self.format.unify(Format::U32)?;
119        visitor.visit_u32(self.tracer.config.default_u32_value)
120    }
121
122    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
123    where
124        V: Visitor<'de>,
125    {
126        self.format.unify(Format::U64)?;
127        visitor.visit_u64(self.tracer.config.default_u64_value)
128    }
129
130    fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value>
131    where
132        V: Visitor<'de>,
133    {
134        self.format.unify(Format::U128)?;
135        visitor.visit_u128(self.tracer.config.default_u128_value)
136    }
137
138    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
139    where
140        V: Visitor<'de>,
141    {
142        self.format.unify(Format::F32)?;
143        visitor.visit_f32(self.tracer.config.default_f32_value)
144    }
145
146    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
147    where
148        V: Visitor<'de>,
149    {
150        self.format.unify(Format::F64)?;
151        visitor.visit_f64(self.tracer.config.default_f64_value)
152    }
153
154    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
155    where
156        V: Visitor<'de>,
157    {
158        self.format.unify(Format::Char)?;
159        visitor.visit_char(self.tracer.config.default_char_value)
160    }
161
162    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
163    where
164        V: Visitor<'de>,
165    {
166        self.format.unify(Format::Str)?;
167        visitor.visit_borrowed_str(self.tracer.config.default_borrowed_str_value)
168    }
169
170    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
171    where
172        V: Visitor<'de>,
173    {
174        self.format.unify(Format::Str)?;
175        visitor.visit_string(self.tracer.config.default_string_value.clone())
176    }
177
178    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
179    where
180        V: Visitor<'de>,
181    {
182        self.format.unify(Format::Bytes)?;
183        visitor.visit_borrowed_bytes(self.tracer.config.default_borrowed_bytes_value)
184    }
185
186    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
187    where
188        V: Visitor<'de>,
189    {
190        self.format.unify(Format::Bytes)?;
191        visitor.visit_byte_buf(self.tracer.config.default_byte_buf_value.clone())
192    }
193
194    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
195    where
196        V: Visitor<'de>,
197    {
198        let mut format = Format::unknown();
199        self.format
200            .unify(Format::Option(Box::new(format.clone())))?;
201        if format.is_unknown() {
202            let inner = Deserializer::new(self.tracer, self.samples, &mut format);
203            visitor.visit_some(inner)
204        } else {
205            // Cut exploration.
206            visitor.visit_none()
207        }
208    }
209
210    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
211    where
212        V: Visitor<'de>,
213    {
214        self.format.unify(Format::Unit)?;
215        visitor.visit_unit()
216    }
217
218    fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
219    where
220        V: Visitor<'de>,
221    {
222        self.format.unify(Format::TypeName(name.into()))?;
223        self.tracer
224            .registry
225            .entry(name.to_string())
226            .unify(ContainerFormat::UnitStruct)?;
227        visitor.visit_unit()
228    }
229
230    fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
231    where
232        V: Visitor<'de>,
233    {
234        self.format.unify(Format::TypeName(name.into()))?;
235        if self.tracer.config.record_samples_for_newtype_structs {
236            // If a value was recorded during serialization, use it.
237            if let Some((format, sample)) = self.tracer.get_sample(self.samples, name) {
238                return visitor
239                    .visit_newtype_struct(sample.into_deserializer())
240                    .map_err(|err| match err {
241                        Error::DeserializationError(msg) => {
242                            let mut format = format.clone();
243                            format.reduce();
244                            Error::UnexpectedDeserializationFormat(name, format, msg)
245                        }
246                        _ => err,
247                    });
248            }
249        }
250        // Pre-update the registry.
251        let mut format = Format::unknown();
252        self.tracer
253            .registry
254            .entry(name.to_string())
255            .unify(ContainerFormat::NewTypeStruct(Box::new(format.clone())))?;
256        // Compute the format.
257        let inner = Deserializer::new(self.tracer, self.samples, &mut format);
258        visitor.visit_newtype_struct(inner)
259    }
260
261    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
262    where
263        V: Visitor<'de>,
264    {
265        let mut format = Format::unknown();
266        self.format.unify(Format::Seq(Box::new(format.clone())))?;
267        if format.is_unknown() {
268            // Simulate vector of size 1.
269            let inner =
270                SeqDeserializer::new(self.tracer, self.samples, std::iter::once(&mut format));
271            visitor.visit_seq(inner)
272        } else {
273            // Cut exploration with a vector of size 0.
274            let inner = SeqDeserializer::new(self.tracer, self.samples, std::iter::empty());
275            visitor.visit_seq(inner)
276        }
277    }
278
279    fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
280    where
281        V: Visitor<'de>,
282    {
283        let mut formats: Vec<_> = std::iter::repeat_with(Format::unknown).take(len).collect();
284        self.format.unify(Format::Tuple(formats.clone()))?;
285        let inner = SeqDeserializer::new(self.tracer, self.samples, formats.iter_mut());
286        visitor.visit_seq(inner)
287    }
288
289    fn deserialize_tuple_struct<V>(
290        self,
291        name: &'static str,
292        len: usize,
293        visitor: V,
294    ) -> Result<V::Value>
295    where
296        V: Visitor<'de>,
297    {
298        self.format.unify(Format::TypeName(name.into()))?;
299        if self.tracer.config.record_samples_for_tuple_structs {
300            // If a value was recorded during serialization, use it.
301            if let Some((format, sample)) = self.tracer.get_sample(self.samples, name) {
302                let result = || visitor.visit_seq(sample.seq_values()?.into_seq_deserializer());
303                return result().map_err(|err| match err {
304                    Error::DeserializationError(msg) => {
305                        let mut format = format.clone();
306                        format.reduce();
307                        Error::UnexpectedDeserializationFormat(name, format, msg)
308                    }
309                    _ => err,
310                });
311            }
312        }
313        // Pre-update the registry.
314        let mut formats: Vec<_> = std::iter::repeat_with(Format::unknown).take(len).collect();
315        self.tracer
316            .registry
317            .entry(name.to_string())
318            .unify(ContainerFormat::TupleStruct(formats.clone()))?;
319        // Compute the formats.
320        let inner = SeqDeserializer::new(self.tracer, self.samples, formats.iter_mut());
321        visitor.visit_seq(inner)
322    }
323
324    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
325    where
326        V: Visitor<'de>,
327    {
328        let mut key_format = Format::unknown();
329        let mut value_format = Format::unknown();
330        self.format.unify(Format::Map {
331            key: Box::new(key_format.clone()),
332            value: Box::new(value_format.clone()),
333        })?;
334        if key_format.is_unknown() || value_format.is_unknown() {
335            // Simulate a map with one entry.
336            let inner = SeqDeserializer::new(
337                self.tracer,
338                self.samples,
339                vec![&mut key_format, &mut value_format].into_iter(),
340            );
341            visitor.visit_map(inner)
342        } else {
343            // Stop exploration.
344            let inner = SeqDeserializer::new(self.tracer, self.samples, std::iter::empty());
345            visitor.visit_map(inner)
346        }
347    }
348
349    fn deserialize_struct<V>(
350        self,
351        name: &'static str,
352        fields: &'static [&'static str],
353        visitor: V,
354    ) -> Result<V::Value>
355    where
356        V: Visitor<'de>,
357    {
358        self.format.unify(Format::TypeName(name.into()))?;
359        if self.tracer.config.record_samples_for_structs {
360            // If a value was recorded during serialization, use it.
361            if let Some((format, sample)) = self.tracer.get_sample(self.samples, name) {
362                let result = || visitor.visit_seq(sample.seq_values()?.into_seq_deserializer());
363                return result().map_err(|err| match err {
364                    Error::DeserializationError(msg) => {
365                        let mut format = format.clone();
366                        format.reduce();
367                        Error::UnexpectedDeserializationFormat(name, format, msg)
368                    }
369                    _ => err,
370                });
371            }
372        }
373        // Pre-update the registry.
374        let mut formats: Vec<_> = fields
375            .iter()
376            .map(|&name| Named {
377                name: name.into(),
378                value: Format::unknown(),
379            })
380            .collect();
381        self.tracer
382            .registry
383            .entry(name.to_string())
384            .unify(ContainerFormat::Struct(formats.clone()))?;
385        // Compute the formats.
386        let inner = SeqDeserializer::new(
387            self.tracer,
388            self.samples,
389            formats.iter_mut().map(|named| &mut named.value),
390        );
391        visitor.visit_seq(inner)
392    }
393
394    // Assumption: The first variant(s) should be "base cases", i.e. not cause infinite recursion
395    // while constructing sample values.
396    #[allow(clippy::map_entry)] // false positive https://github.com/rust-lang/rust-clippy/issues/9470
397    fn deserialize_enum<V>(
398        self,
399        enum_name: &'static str,
400        variants: &'static [&'static str],
401        visitor: V,
402    ) -> Result<V::Value>
403    where
404        V: Visitor<'de>,
405    {
406        if variants.is_empty() {
407            return Err(Error::NotSupported("deserialize_enum with 0 variants"));
408        }
409
410        let enum_type_id = typeid::of::<V::Value>();
411        self.format.unify(Format::TypeName(enum_name.into()))?;
412        // Pre-update the registry.
413        self.tracer
414            .registry
415            .entry(enum_name.to_string())
416            .unify(ContainerFormat::Enum(BTreeMap::new()))?;
417        let known_variants = match self.tracer.registry.get_mut(enum_name) {
418            Some(ContainerFormat::Enum(x)) => x,
419            _ => unreachable!(),
420        };
421
422        // If the enum is already marked as incomplete, visit the first index, hoping to
423        // avoid recursion.
424        if self.tracer.incomplete_enums.contains_key(enum_name) {
425            return visitor.visit_enum(EnumDeserializer::new(
426                self.tracer,
427                self.samples,
428                VariantId::Index(0),
429                &mut VariantFormat::unknown(),
430            ));
431        }
432
433        // First, visit each of the variants by name according to `variants`. Later, we
434        // will revisit them by u32 index until an index matching each of the named
435        // variants has been determined.
436        let provisional_min = u32::MAX - (variants.len() - 1) as u32;
437        for (i, &variant_name) in variants.iter().enumerate() {
438            if self
439                .tracer
440                .discriminants
441                .contains_key(&(enum_type_id, VariantId::Name(variant_name)))
442            {
443                continue;
444            }
445            // Insert into known_variants with a provisional index.
446            let provisional_index = provisional_min + i as u32;
447            let variant = known_variants
448                .entry(provisional_index)
449                .or_insert_with(|| Named {
450                    name: variant_name.to_owned(),
451                    value: VariantFormat::unknown(),
452                });
453            self.tracer.incomplete_enums.insert(
454                enum_name.into(),
455                IncompleteEnumReason::NamedVariantsRemaining,
456            );
457            // Compute the discriminant and format for this variant.
458            let mut value = variant.value.clone();
459            let enum_value = visitor.visit_enum(EnumDeserializer::new(
460                self.tracer,
461                self.samples,
462                VariantId::Name(variant_name),
463                &mut value,
464            ))?;
465            let discriminant = Discriminant::of(&enum_value);
466            self.tracer
467                .discriminants
468                .insert((enum_type_id, VariantId::Name(variant_name)), discriminant);
469            return Ok(enum_value);
470        }
471
472        // We know the discriminant for every variant name. Now visit them again
473        // by index to find the u32 id that goes with each name.
474        //
475        // If there are no provisional entries waiting for an index, just go
476        // with index 0.
477        let mut index = 0;
478        if known_variants.range(provisional_min..).next().is_some() {
479            self.tracer.incomplete_enums.insert(
480                enum_name.into(),
481                IncompleteEnumReason::IndexedVariantsRemaining,
482            );
483            while known_variants.contains_key(&index)
484                && self
485                    .tracer
486                    .discriminants
487                    .contains_key(&(enum_type_id, VariantId::Index(index)))
488            {
489                index += 1;
490            }
491        }
492
493        // Compute the discriminant and format for this variant.
494        let mut value = VariantFormat::unknown();
495        let enum_value = visitor.visit_enum(EnumDeserializer::new(
496            self.tracer,
497            self.samples,
498            VariantId::Index(index),
499            &mut value,
500        ))?;
501        let discriminant = Discriminant::of(&enum_value);
502        self.tracer.discriminants.insert(
503            (enum_type_id, VariantId::Index(index)),
504            discriminant.clone(),
505        );
506
507        // Rewrite provisional entries for which we now know a u32 index.
508        let known_variants = match self.tracer.registry.get_mut(enum_name) {
509            Some(ContainerFormat::Enum(x)) => x,
510            _ => unreachable!(),
511        };
512
513        let mut has_indexed_variants_remaining = false;
514        for provisional_index in provisional_min..=u32::MAX {
515            if let Entry::Occupied(provisional_entry) = known_variants.entry(provisional_index) {
516                if self.tracer.discriminants
517                    [&(enum_type_id, VariantId::Name(&provisional_entry.get().name))]
518                    == discriminant
519                {
520                    let provisional_entry = provisional_entry.remove();
521                    match known_variants.entry(index) {
522                        Entry::Vacant(vacant) => {
523                            vacant.insert(provisional_entry);
524                        }
525                        Entry::Occupied(mut existing_entry) => {
526                            // Discard the provisional entry's name and just
527                            // keep the existing one.
528                            existing_entry
529                                .get_mut()
530                                .value
531                                .unify(provisional_entry.value)?;
532                        }
533                    }
534                } else {
535                    has_indexed_variants_remaining = true;
536                }
537            }
538        }
539        if let Some(existing_entry) = known_variants.get_mut(&index) {
540            existing_entry.value.unify(value)?;
541        }
542        if has_indexed_variants_remaining {
543            // Signal that the top-level tracing must continue.
544            self.tracer.incomplete_enums.insert(
545                enum_name.into(),
546                IncompleteEnumReason::IndexedVariantsRemaining,
547            );
548        } else {
549            // Signal that the top-level tracing is complete for this enum.
550            self.tracer.incomplete_enums.remove(enum_name);
551        }
552
553        Ok(enum_value)
554    }
555
556    fn deserialize_identifier<V>(self, _visitor: V) -> Result<V::Value>
557    where
558        V: Visitor<'de>,
559    {
560        Err(Error::NotSupported("deserialize_identifier"))
561    }
562
563    fn deserialize_ignored_any<V>(self, _visitor: V) -> Result<V::Value>
564    where
565        V: Visitor<'de>,
566    {
567        Err(Error::NotSupported("deserialize_ignored_any"))
568    }
569
570    fn is_human_readable(&self) -> bool {
571        self.tracer.config.is_human_readable
572    }
573}
574
575struct SeqDeserializer<'de, 'a, I> {
576    tracer: &'a mut Tracer,
577    samples: &'de Samples,
578    formats: I,
579}
580
581impl<'de, 'a, I> SeqDeserializer<'de, 'a, I> {
582    fn new(tracer: &'a mut Tracer, samples: &'de Samples, formats: I) -> Self {
583        Self {
584            tracer,
585            samples,
586            formats,
587        }
588    }
589}
590
591impl<'de, 'a, I> de::SeqAccess<'de> for SeqDeserializer<'de, 'a, I>
592where
593    I: Iterator<Item = &'a mut Format>,
594{
595    type Error = Error;
596
597    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
598    where
599        T: DeserializeSeed<'de>,
600    {
601        let format = match self.formats.next() {
602            Some(x) => x,
603            None => return Ok(None),
604        };
605        let inner = Deserializer::new(self.tracer, self.samples, format);
606        seed.deserialize(inner).map(Some)
607    }
608
609    fn size_hint(&self) -> Option<usize> {
610        self.formats.size_hint().1
611    }
612}
613
614impl<'de, 'a, I> de::MapAccess<'de> for SeqDeserializer<'de, 'a, I>
615where
616    // Must have an even number of elements
617    I: Iterator<Item = &'a mut Format>,
618{
619    type Error = Error;
620
621    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
622    where
623        K: DeserializeSeed<'de>,
624    {
625        let format = match self.formats.next() {
626            Some(x) => x,
627            None => return Ok(None),
628        };
629        let inner = Deserializer::new(self.tracer, self.samples, format);
630        seed.deserialize(inner).map(Some)
631    }
632
633    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
634    where
635        V: DeserializeSeed<'de>,
636    {
637        let format = match self.formats.next() {
638            Some(x) => x,
639            None => unreachable!(),
640        };
641        let inner = Deserializer::new(self.tracer, self.samples, format);
642        seed.deserialize(inner)
643    }
644
645    fn size_hint(&self) -> Option<usize> {
646        self.formats.size_hint().1.map(|x| x / 2)
647    }
648}
649
650struct EnumDeserializer<'de, 'a> {
651    tracer: &'a mut Tracer,
652    samples: &'de Samples,
653    variant_id: VariantId<'static>,
654    format: &'a mut VariantFormat,
655}
656
657impl<'de, 'a> EnumDeserializer<'de, 'a> {
658    fn new(
659        tracer: &'a mut Tracer,
660        samples: &'de Samples,
661        variant_id: VariantId<'static>,
662        format: &'a mut VariantFormat,
663    ) -> Self {
664        Self {
665            tracer,
666            samples,
667            variant_id,
668            format,
669        }
670    }
671}
672
673impl<'de, 'a> de::EnumAccess<'de> for EnumDeserializer<'de, 'a> {
674    type Error = Error;
675    type Variant = Self;
676
677    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
678    where
679        V: DeserializeSeed<'de>,
680    {
681        let value = match self.variant_id {
682            VariantId::Index(index) => seed.deserialize(U32Deserializer::new(index)),
683            VariantId::Name(name) => seed.deserialize(BorrowedStrDeserializer::new(name)),
684        }?;
685        Ok((value, self))
686    }
687}
688
689impl<'de, 'a> de::VariantAccess<'de> for EnumDeserializer<'de, 'a> {
690    type Error = Error;
691
692    fn unit_variant(self) -> Result<()> {
693        self.format.unify(VariantFormat::Unit)
694    }
695
696    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
697    where
698        T: DeserializeSeed<'de>,
699    {
700        let mut format = Format::unknown();
701        self.format
702            .unify(VariantFormat::NewType(Box::new(format.clone())))?;
703        let inner = Deserializer::new(self.tracer, self.samples, &mut format);
704        seed.deserialize(inner)
705    }
706
707    fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
708    where
709        V: Visitor<'de>,
710    {
711        let mut formats: Vec<_> = std::iter::repeat_with(Format::unknown).take(len).collect();
712        self.format.unify(VariantFormat::Tuple(formats.clone()))?;
713        let inner = SeqDeserializer::new(self.tracer, self.samples, formats.iter_mut());
714        visitor.visit_seq(inner)
715    }
716
717    fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value>
718    where
719        V: Visitor<'de>,
720    {
721        let mut formats: Vec<_> = fields
722            .iter()
723            .map(|&name| Named {
724                name: name.into(),
725                value: Format::unknown(),
726            })
727            .collect();
728        self.format.unify(VariantFormat::Struct(formats.clone()))?;
729
730        let inner = SeqDeserializer::new(
731            self.tracer,
732            self.samples,
733            formats.iter_mut().map(|named| &mut named.value),
734        );
735        visitor.visit_seq(inner)
736    }
737}