1use crate::error::ErrorField;
6use crate::pattern::{
7 DayPeriodNameLength, MonthNameLength, PatternLoadError, WeekdayNameLength, YearNameLength,
8};
9use crate::provider::neo::*;
10use crate::provider::time_zones::tz;
11use core::fmt;
12use icu_provider::prelude::*;
13use yoke::Yokeable;
14
15use super::UnstableSealed;
16
17#[allow(missing_docs)]
28pub trait DateTimeNamesMarker: UnstableSealed {
29 type YearNames: NamesContainer<YearNamesV1, YearNameLength>;
30 type MonthNames: NamesContainer<MonthNamesV1, MonthNameLength>;
31 type WeekdayNames: NamesContainer<WeekdayNamesV1, WeekdayNameLength>;
32 type DayPeriodNames: NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>;
33 type ZoneEssentials: NamesContainer<tz::EssentialsV1, ()>;
34 type ZoneLocations: NamesContainer<tz::LocationsOverrideV1, ()>;
35 type ZoneLocationsRoot: NamesContainer<tz::LocationsRootV1, ()>;
36 type ZoneExemplars: NamesContainer<tz::CitiesOverrideV1, ()>;
37 type ZoneExemplarsRoot: NamesContainer<tz::CitiesRootV1, ()>;
38 type ZoneGenericLong: NamesContainer<tz::MzGenericLongV1, ()>;
39 type ZoneGenericShort: NamesContainer<tz::MzGenericShortV1, ()>;
40 type ZoneStandardLong: NamesContainer<tz::MzStandardLongV1, ()>;
41 type ZoneSpecificLong: NamesContainer<tz::MzSpecificLongV1, ()>;
42 type ZoneSpecificShort: NamesContainer<tz::MzSpecificShortV1, ()>;
43 type MetazoneLookup: NamesContainer<tz::MzPeriodV1, ()>;
44}
45
46pub trait MaybeAsErrorField: UnstableSealed {
48 fn maybe_as_error_field(&self) -> Option<ErrorField>;
49}
50
51impl MaybeAsErrorField for () {
52 fn maybe_as_error_field(&self) -> Option<ErrorField> {
53 None
54 }
55}
56
57impl UnstableSealed for YearNameLength {}
58impl MaybeAsErrorField for YearNameLength {
59 fn maybe_as_error_field(&self) -> Option<ErrorField> {
60 Some(self.to_approximate_error_field())
61 }
62}
63
64impl UnstableSealed for MonthNameLength {}
65impl MaybeAsErrorField for MonthNameLength {
66 fn maybe_as_error_field(&self) -> Option<ErrorField> {
67 Some(self.to_approximate_error_field())
68 }
69}
70
71impl UnstableSealed for WeekdayNameLength {}
72impl MaybeAsErrorField for WeekdayNameLength {
73 fn maybe_as_error_field(&self) -> Option<ErrorField> {
74 Some(self.to_approximate_error_field())
75 }
76}
77
78impl UnstableSealed for DayPeriodNameLength {}
79impl MaybeAsErrorField for DayPeriodNameLength {
80 fn maybe_as_error_field(&self) -> Option<ErrorField> {
81 Some(self.to_approximate_error_field())
82 }
83}
84
85#[allow(missing_docs)]
92pub trait NamesContainer<M: DynamicDataMarker, Variables>: UnstableSealed
93where
94 Variables: PartialEq + Copy + fmt::Debug,
95{
96 type Container: MaybePayload<M, Variables> + fmt::Debug + Clone;
97}
98
99impl<M: DynamicDataMarker, Variables> NamesContainer<M, Variables> for ()
100where
101 Variables: PartialEq + Copy + fmt::Debug,
102{
103 type Container = ();
104}
105
106macro_rules! impl_holder_trait {
107 ($marker:path) => {
108 impl UnstableSealed for $marker {}
109 impl<Variables> NamesContainer<$marker, Variables> for $marker
110 where
111 Variables: PartialEq + Copy + MaybeAsErrorField + fmt::Debug,
112 {
113 type Container = DataPayloadWithVariables<$marker, Variables>;
114 }
115 };
116}
117
118impl_holder_trait!(YearNamesV1);
119impl_holder_trait!(MonthNamesV1);
120impl_holder_trait!(WeekdayNamesV1);
121impl_holder_trait!(DayPeriodNamesV1);
122impl_holder_trait!(tz::EssentialsV1);
123impl_holder_trait!(tz::LocationsOverrideV1);
124impl_holder_trait!(tz::LocationsRootV1);
125impl_holder_trait!(tz::CitiesOverrideV1);
126impl_holder_trait!(tz::CitiesRootV1);
127impl_holder_trait!(tz::MzGenericLongV1);
128impl_holder_trait!(tz::MzGenericShortV1);
129impl_holder_trait!(tz::MzStandardLongV1);
130impl_holder_trait!(tz::MzSpecificLongV1);
131impl_holder_trait!(tz::MzSpecificShortV1);
132impl_holder_trait!(tz::MzPeriodV1);
133
134#[allow(missing_docs)]
136#[derive(Debug, Copy, Clone, displaydoc::Display)]
137#[non_exhaustive]
138pub enum MaybePayloadError {
139 FormatterTooSpecific,
141 ConflictingField(ErrorField),
143}
144
145impl core::error::Error for MaybePayloadError {}
146
147impl MaybePayloadError {
148 pub(crate) fn into_load_error(self, error_field: ErrorField) -> PatternLoadError {
149 match self {
150 Self::FormatterTooSpecific => PatternLoadError::FormatterTooSpecific(error_field),
151 Self::ConflictingField(loaded_field) => PatternLoadError::ConflictingField {
152 field: error_field,
153 previous_field: loaded_field,
154 },
155 }
156 }
157}
158
159#[allow(missing_docs)]
169pub trait MaybePayload<M: DynamicDataMarker, Variables>: UnstableSealed {
170 fn new_empty() -> Self;
171 fn load_put<P>(
172 &mut self,
173 provider: &P,
174 req: DataRequest,
175 variables: Variables,
176 ) -> Result<Result<DataResponseMetadata, DataError>, MaybePayloadError>
177 where
178 P: BoundDataProvider<M> + ?Sized,
179 Self: Sized;
180 fn get(&self) -> DataPayloadWithVariablesBorrowed<M, Variables>;
181}
182
183pub struct DataPayloadWithVariables<M: DynamicDataMarker, Variables> {
186 inner: OptionalNames<Variables, DataPayload<M>>,
187}
188
189impl<M: DynamicDataMarker, Variables> Clone for DataPayloadWithVariables<M, Variables>
190where
191 Variables: Clone,
192 DataPayload<M>: Clone,
193{
194 fn clone(&self) -> Self {
195 Self {
196 inner: self.inner.clone(),
197 }
198 }
199}
200
201impl<M: DynamicDataMarker, Variables> UnstableSealed for DataPayloadWithVariables<M, Variables> {}
202
203impl<M: DynamicDataMarker, Variables> fmt::Debug for DataPayloadWithVariables<M, Variables>
204where
205 Variables: fmt::Debug,
206 DataPayload<M>: fmt::Debug,
207{
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 self.inner.fmt(f)
210 }
211}
212
213impl<M: DynamicDataMarker, Variables> From<()> for DataPayloadWithVariables<M, Variables> {
215 #[inline]
216 fn from(_: ()) -> Self {
217 Self {
218 inner: OptionalNames::None,
219 }
220 }
221}
222
223#[allow(missing_docs)]
225pub struct DataPayloadWithVariablesBorrowed<'data, M: DynamicDataMarker, Variables> {
226 pub(crate) inner: OptionalNames<Variables, &'data <M::DataStruct as Yokeable<'data>>::Output>,
227}
228
229impl<'data, M: DynamicDataMarker, Variables> fmt::Debug
230 for DataPayloadWithVariablesBorrowed<'data, M, Variables>
231where
232 <M::DataStruct as Yokeable<'data>>::Output: fmt::Debug,
233 Variables: fmt::Debug,
234{
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 f.debug_struct(core::any::type_name::<Self>())
237 .field("inner", &self.inner)
238 .finish()
239 }
240}
241
242impl<M: DynamicDataMarker, Variables> MaybePayload<M, Variables>
243 for DataPayloadWithVariables<M, Variables>
244where
245 Variables: PartialEq + Copy + MaybeAsErrorField,
246{
247 #[inline]
248 fn new_empty() -> Self {
249 Self {
250 inner: OptionalNames::None,
251 }
252 }
253 fn load_put<P>(
254 &mut self,
255 provider: &P,
256 req: DataRequest,
257 variables: Variables,
258 ) -> Result<Result<DataResponseMetadata, DataError>, MaybePayloadError>
259 where
260 P: BoundDataProvider<M> + ?Sized,
261 Self: Sized,
262 {
263 let arg_variables = variables;
264 match &self.inner {
265 OptionalNames::SingleLength { variables, .. } if arg_variables == *variables => {
266 return Ok(Ok(Default::default()));
268 }
269 OptionalNames::SingleLength { variables, .. } => {
270 let loaded_field = match variables.maybe_as_error_field() {
271 Some(x) => x,
272 None => {
273 debug_assert!(false, "all non-unit variables implement this trait");
274 use crate::provider::fields::*;
275 ErrorField(Field {
276 symbol: FieldSymbol::Era,
277 length: FieldLength::Six,
278 })
279 }
280 };
281 return Err(MaybePayloadError::ConflictingField(loaded_field));
282 }
283 OptionalNames::None => (),
284 };
285 match provider.load_bound(req) {
286 Ok(response) => {
287 self.inner = OptionalNames::SingleLength {
288 payload: response.payload,
289 variables: arg_variables,
290 };
291 Ok(Ok(response.metadata))
292 }
293 Err(e) => Ok(Err(e)),
294 }
295 }
296 #[inline]
297 fn get(&self) -> DataPayloadWithVariablesBorrowed<M, Variables> {
298 DataPayloadWithVariablesBorrowed {
299 inner: self.inner.as_borrowed(),
300 }
301 }
302}
303
304impl<M: DynamicDataMarker, Variables> MaybePayload<M, Variables> for () {
305 #[inline]
306 fn new_empty() -> Self {}
307 #[inline]
308 fn load_put<P>(
309 &mut self,
310 _: &P,
311 _: DataRequest,
312 _: Variables,
313 ) -> Result<Result<DataResponseMetadata, DataError>, MaybePayloadError>
314 where
315 P: BoundDataProvider<M> + ?Sized,
316 Self: Sized,
317 {
318 Err(MaybePayloadError::FormatterTooSpecific)
319 }
320 #[allow(clippy::needless_lifetimes)] #[inline]
322 fn get(&self) -> DataPayloadWithVariablesBorrowed<M, Variables> {
323 DataPayloadWithVariablesBorrowed {
324 inner: OptionalNames::None,
325 }
326 }
327}
328
329#[derive(Debug, Copy, Clone)]
332pub(crate) enum OptionalNames<Variables, Payload> {
333 None,
334 SingleLength {
335 variables: Variables,
336 payload: Payload,
337 },
338}
339
340impl<Variables, Payload> OptionalNames<Variables, Payload>
341where
342 Variables: Copy + PartialEq,
343 Payload: Copy,
344{
345 pub(crate) fn get_with_variables(&self, arg_variables: Variables) -> Option<Payload> {
346 match self {
347 Self::None => None,
348 Self::SingleLength { variables, payload } if arg_variables == *variables => {
349 Some(*payload)
350 }
351 _ => None,
352 }
353 }
354}
355
356impl<Payload> OptionalNames<(), Payload>
357where
358 Payload: Copy,
359{
360 pub(crate) fn get_option(&self) -> Option<Payload> {
361 match self {
362 Self::SingleLength {
363 variables: (),
364 payload,
365 } => Some(*payload),
366 _ => None,
367 }
368 }
369}
370
371impl<M: DynamicDataMarker, Variables> OptionalNames<Variables, DataPayload<M>>
372where
373 Variables: Copy,
374{
375 #[allow(clippy::needless_lifetimes)] #[inline]
377 pub(crate) fn as_borrowed<'a>(
378 &'a self,
379 ) -> OptionalNames<Variables, &'a <M::DataStruct as Yokeable<'a>>::Output> {
380 match self {
381 Self::None => OptionalNames::None,
382 Self::SingleLength { variables, payload } => OptionalNames::SingleLength {
383 variables: *variables,
384 payload: payload.get(),
385 },
386 }
387 }
388}
389
390#[allow(missing_docs)]
427pub trait DateTimeNamesFrom<M: DateTimeNamesMarker>: DateTimeNamesMarker {
429 fn map_year_names(
430 other: <M::YearNames as NamesContainer<YearNamesV1, YearNameLength>>::Container,
431 ) -> <Self::YearNames as NamesContainer<YearNamesV1, YearNameLength>>::Container;
432 fn map_month_names(
433 other: <M::MonthNames as NamesContainer<MonthNamesV1, MonthNameLength>>::Container,
434 ) -> <Self::MonthNames as NamesContainer<MonthNamesV1, MonthNameLength>>::Container;
435 fn map_weekday_names(
436 other: <M::WeekdayNames as NamesContainer<WeekdayNamesV1, WeekdayNameLength>>::Container,
437 ) -> <Self::WeekdayNames as NamesContainer<WeekdayNamesV1, WeekdayNameLength>>::Container;
438 fn map_day_period_names(
439 other: <M::DayPeriodNames as NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>>::Container,
440 ) -> <Self::DayPeriodNames as NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>>::Container;
441 fn map_zone_essentials(
442 other: <M::ZoneEssentials as NamesContainer<tz::EssentialsV1, ()>>::Container,
443 ) -> <Self::ZoneEssentials as NamesContainer<tz::EssentialsV1, ()>>::Container;
444 fn map_zone_locations(
445 other: <M::ZoneLocations as NamesContainer<tz::LocationsOverrideV1, ()>>::Container,
446 ) -> <Self::ZoneLocations as NamesContainer<tz::LocationsOverrideV1, ()>>::Container;
447 fn map_zone_locations_root(
448 other: <M::ZoneLocationsRoot as NamesContainer<tz::LocationsRootV1, ()>>::Container,
449 ) -> <Self::ZoneLocationsRoot as NamesContainer<tz::LocationsRootV1, ()>>::Container;
450 fn map_zone_exemplars(
451 other: <M::ZoneExemplars as NamesContainer<tz::CitiesOverrideV1, ()>>::Container,
452 ) -> <Self::ZoneExemplars as NamesContainer<tz::CitiesOverrideV1, ()>>::Container;
453 fn map_zone_exemplars_root(
454 other: <M::ZoneExemplarsRoot as NamesContainer<tz::CitiesRootV1, ()>>::Container,
455 ) -> <Self::ZoneExemplarsRoot as NamesContainer<tz::CitiesRootV1, ()>>::Container;
456 fn map_zone_generic_long(
457 other: <M::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1, ()>>::Container,
458 ) -> <Self::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1, ()>>::Container;
459 fn map_zone_generic_short(
460 other: <M::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1, ()>>::Container,
461 ) -> <Self::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1, ()>>::Container;
462 fn map_zone_standard_long(
463 other: <M::ZoneStandardLong as NamesContainer<tz::MzStandardLongV1, ()>>::Container,
464 ) -> <Self::ZoneStandardLong as NamesContainer<tz::MzStandardLongV1, ()>>::Container;
465 fn map_zone_specific_long(
466 other: <M::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1, ()>>::Container,
467 ) -> <Self::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1, ()>>::Container;
468 fn map_zone_specific_short(
469 other: <M::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1, ()>>::Container,
470 ) -> <Self::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1, ()>>::Container;
471 fn map_metazone_lookup(
472 other: <M::MetazoneLookup as NamesContainer<tz::MzPeriodV1, ()>>::Container,
473 ) -> <Self::MetazoneLookup as NamesContainer<tz::MzPeriodV1, ()>>::Container;
474}
475
476impl<M: DateTimeNamesMarker, T: DateTimeNamesMarker> DateTimeNamesFrom<M> for T
477where
478 <Self::YearNames as NamesContainer<YearNamesV1, YearNameLength>>::Container:
479 From<<M::YearNames as NamesContainer<YearNamesV1, YearNameLength>>::Container>,
480 <Self::MonthNames as NamesContainer<MonthNamesV1, MonthNameLength>>::Container:
481 From<<M::MonthNames as NamesContainer<MonthNamesV1, MonthNameLength>>::Container>,
482 <Self::WeekdayNames as NamesContainer<WeekdayNamesV1, WeekdayNameLength>>::Container:
483 From<<M::WeekdayNames as NamesContainer<WeekdayNamesV1, WeekdayNameLength>>::Container>,
484 <Self::DayPeriodNames as NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>>::Container:
485 From<
486 <M::DayPeriodNames as NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>>::Container,
487 >,
488 <Self::ZoneEssentials as NamesContainer<tz::EssentialsV1, ()>>::Container:
489 From<<M::ZoneEssentials as NamesContainer<tz::EssentialsV1, ()>>::Container>,
490 <Self::ZoneLocations as NamesContainer<tz::LocationsOverrideV1, ()>>::Container:
491 From<<M::ZoneLocations as NamesContainer<tz::LocationsOverrideV1, ()>>::Container>,
492 <Self::ZoneLocationsRoot as NamesContainer<tz::LocationsRootV1, ()>>::Container:
493 From<<M::ZoneLocationsRoot as NamesContainer<tz::LocationsRootV1, ()>>::Container>,
494 <Self::ZoneExemplars as NamesContainer<tz::CitiesOverrideV1, ()>>::Container:
495 From<<M::ZoneExemplars as NamesContainer<tz::CitiesOverrideV1, ()>>::Container>,
496 <Self::ZoneExemplarsRoot as NamesContainer<tz::CitiesRootV1, ()>>::Container:
497 From<<M::ZoneExemplarsRoot as NamesContainer<tz::CitiesRootV1, ()>>::Container>,
498 <Self::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1, ()>>::Container:
499 From<<M::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1, ()>>::Container>,
500 <Self::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1, ()>>::Container:
501 From<<M::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1, ()>>::Container>,
502 <Self::ZoneStandardLong as NamesContainer<tz::MzStandardLongV1, ()>>::Container:
503 From<<M::ZoneStandardLong as NamesContainer<tz::MzStandardLongV1, ()>>::Container>,
504 <Self::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1, ()>>::Container:
505 From<<M::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1, ()>>::Container>,
506 <Self::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1, ()>>::Container:
507 From<<M::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1, ()>>::Container>,
508 <Self::MetazoneLookup as NamesContainer<tz::MzPeriodV1, ()>>::Container:
509 From<<M::MetazoneLookup as NamesContainer<tz::MzPeriodV1, ()>>::Container>,
510{
511 #[inline]
512 fn map_year_names(
513 other: <M::YearNames as NamesContainer<YearNamesV1, YearNameLength>>::Container,
514 ) -> <Self::YearNames as NamesContainer<YearNamesV1, YearNameLength>>::Container {
515 other.into()
516 }
517 #[inline]
518 fn map_month_names(
519 other: <M::MonthNames as NamesContainer<MonthNamesV1, MonthNameLength>>::Container,
520 ) -> <Self::MonthNames as NamesContainer<MonthNamesV1, MonthNameLength>>::Container {
521 other.into()
522 }
523 #[inline]
524 fn map_weekday_names(
525 other: <M::WeekdayNames as NamesContainer<WeekdayNamesV1, WeekdayNameLength>>::Container,
526 ) -> <Self::WeekdayNames as NamesContainer<WeekdayNamesV1, WeekdayNameLength>>::Container {
527 other.into()
528 }
529 #[inline]
530 fn map_day_period_names(
531 other: <M::DayPeriodNames as NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>>::Container,
532 ) -> <Self::DayPeriodNames as NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>>::Container
533 {
534 other.into()
535 }
536 #[inline]
537 fn map_zone_essentials(
538 other: <M::ZoneEssentials as NamesContainer<tz::EssentialsV1, ()>>::Container,
539 ) -> <Self::ZoneEssentials as NamesContainer<tz::EssentialsV1, ()>>::Container {
540 other.into()
541 }
542 #[inline]
543 fn map_zone_locations(
544 other: <M::ZoneLocations as NamesContainer<tz::LocationsOverrideV1, ()>>::Container,
545 ) -> <Self::ZoneLocations as NamesContainer<tz::LocationsOverrideV1, ()>>::Container {
546 other.into()
547 }
548 #[inline]
549 fn map_zone_locations_root(
550 other: <M::ZoneLocationsRoot as NamesContainer<tz::LocationsRootV1, ()>>::Container,
551 ) -> <Self::ZoneLocationsRoot as NamesContainer<tz::LocationsRootV1, ()>>::Container {
552 other.into()
553 }
554 #[inline]
555 fn map_zone_exemplars(
556 other: <M::ZoneExemplars as NamesContainer<tz::CitiesOverrideV1, ()>>::Container,
557 ) -> <Self::ZoneExemplars as NamesContainer<tz::CitiesOverrideV1, ()>>::Container {
558 other.into()
559 }
560 #[inline]
561 fn map_zone_exemplars_root(
562 other: <M::ZoneExemplarsRoot as NamesContainer<tz::CitiesRootV1, ()>>::Container,
563 ) -> <Self::ZoneExemplarsRoot as NamesContainer<tz::CitiesRootV1, ()>>::Container {
564 other.into()
565 }
566 #[inline]
567 fn map_zone_generic_long(
568 other: <M::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1, ()>>::Container,
569 ) -> <Self::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1, ()>>::Container {
570 other.into()
571 }
572 #[inline]
573 fn map_zone_generic_short(
574 other: <M::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1, ()>>::Container,
575 ) -> <Self::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1, ()>>::Container {
576 other.into()
577 }
578 #[inline]
579 fn map_zone_standard_long(
580 other: <M::ZoneStandardLong as NamesContainer<tz::MzStandardLongV1, ()>>::Container,
581 ) -> <Self::ZoneStandardLong as NamesContainer<tz::MzStandardLongV1, ()>>::Container {
582 other.into()
583 }
584 #[inline]
585 fn map_zone_specific_long(
586 other: <M::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1, ()>>::Container,
587 ) -> <Self::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1, ()>>::Container {
588 other.into()
589 }
590 #[inline]
591 fn map_zone_specific_short(
592 other: <M::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1, ()>>::Container,
593 ) -> <Self::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1, ()>>::Container {
594 other.into()
595 }
596 #[inline]
597 fn map_metazone_lookup(
598 other: <M::MetazoneLookup as NamesContainer<tz::MzPeriodV1, ()>>::Container,
599 ) -> <Self::MetazoneLookup as NamesContainer<tz::MzPeriodV1, ()>>::Container {
600 other.into()
601 }
602}