Skip to main content

repose_core/
locals.rs

1//! # Theming and locals
2//!
3//! Repose uses thread‑local “composition locals” for global UI parameters:
4//!
5//! - `Theme` — colors for surfaces, text, controls, etc.
6//! - `Density` — dp→px device scale factor (platform sets this).
7//! - `UiScale` — app-controlled UI scale multiplier (defaults to 1.0).
8//! - `TextScale` — user text scaling (defaults to 1.0).
9//! - `TextDirection` — LTR or RTL (defaults to LTR).
10//!
11//! Locals can be overridden for a subtree with `with_*`. If no local is set,
12//! getters fall back to global defaults (which an app can set each frame).
13
14use std::any::{Any, TypeId};
15use std::cell::RefCell;
16use std::collections::HashMap;
17use std::sync::OnceLock;
18
19use parking_lot::RwLock;
20
21use crate::Color;
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
24pub enum TextDirection {
25    #[default]
26    Ltr,
27    Rtl,
28}
29
30thread_local! {
31    static LOCALS_STACK: RefCell<Vec<HashMap<TypeId, Box<dyn Any>>>> = RefCell::new(Vec::new());
32}
33
34#[derive(Clone, Copy, Debug)]
35struct Defaults {
36    theme: Theme,
37    text_direction: TextDirection,
38    ui_scale: UiScale,
39    text_scale: TextScale,
40    density: Density,
41}
42
43impl Default for Defaults {
44    fn default() -> Self {
45        Self {
46            theme: Theme::default(),
47            text_direction: TextDirection::default(),
48            ui_scale: UiScale::default(),
49            text_scale: TextScale::default(),
50            density: Density::default(),
51        }
52    }
53}
54
55static DEFAULTS: OnceLock<RwLock<Defaults>> = OnceLock::new();
56
57fn defaults() -> &'static RwLock<Defaults> {
58    DEFAULTS.get_or_init(|| RwLock::new(Defaults::default()))
59}
60
61/// Set the global default theme used when no local Theme is active.
62pub fn set_theme_default(t: Theme) {
63    defaults().write().theme = t;
64}
65
66/// Set the global default text direction used when no local TextDirection is active.
67pub fn set_text_direction_default(d: TextDirection) {
68    defaults().write().text_direction = d;
69}
70
71/// Set the global default UI scale used when no local UiScale is active.
72pub fn set_ui_scale_default(s: UiScale) {
73    defaults().write().ui_scale = UiScale(s.0.max(0.0));
74}
75
76/// Set the global default text scale used when no local TextScale is active.
77pub fn set_text_scale_default(s: TextScale) {
78    defaults().write().text_scale = TextScale(s.0.max(0.0));
79}
80
81/// Set the global default device density (dp→px) used when no local Density is active.
82/// Platform runners should call this whenever the window scale factor changes.
83pub fn set_density_default(d: Density) {
84    defaults().write().density = Density {
85        scale: d.scale.max(0.0),
86    };
87}
88
89// ---- Units ----
90
91/// density‑independent pixels (dp)
92#[derive(Clone, Copy, Debug, PartialEq)]
93pub struct Dp(pub f32);
94
95impl Dp {
96    /// Converts this dp value into physical pixels using current Density * UiScale.
97    pub fn to_px(self) -> f32 {
98        self.0 * density().scale * ui_scale().0
99    }
100}
101
102/// Convenience: convert a raw dp scalar into px using current Density * UiScale.
103pub fn dp_to_px(dp: f32) -> f32 {
104    Dp(dp).to_px()
105}
106
107fn with_locals_frame<R>(f: impl FnOnce() -> R) -> R {
108    struct Guard;
109    impl Drop for Guard {
110        fn drop(&mut self) {
111            LOCALS_STACK.with(|st| {
112                st.borrow_mut().pop();
113            });
114        }
115    }
116    LOCALS_STACK.with(|st| st.borrow_mut().push(HashMap::new()));
117    let _guard = Guard;
118    f()
119}
120
121fn set_local_boxed(t: TypeId, v: Box<dyn Any>) {
122    LOCALS_STACK.with(|st| {
123        if let Some(top) = st.borrow_mut().last_mut() {
124            top.insert(t, v);
125        } else {
126            // no frame: create a temporary one
127            let mut m = HashMap::new();
128            m.insert(t, v);
129            st.borrow_mut().push(m);
130        }
131    });
132}
133
134fn get_local<T: 'static + Copy>() -> Option<T> {
135    LOCALS_STACK.with(|st| {
136        for frame in st.borrow().iter().rev() {
137            if let Some(v) = frame.get(&TypeId::of::<T>())
138                && let Some(t) = v.downcast_ref::<T>()
139            {
140                return Some(*t);
141            }
142        }
143        None
144    })
145}
146
147#[derive(Clone, Copy, Debug)]
148#[must_use]
149pub struct ColorScheme {
150    pub primary: Color,
151    pub on_primary: Color,
152    pub primary_container: Color,
153    pub on_primary_container: Color,
154
155    pub secondary: Color,
156    pub on_secondary: Color,
157    pub secondary_container: Color,
158    pub on_secondary_container: Color,
159
160    pub tertiary: Color,
161    pub on_tertiary: Color,
162    pub tertiary_container: Color,
163    pub on_tertiary_container: Color,
164
165    pub error: Color,
166    pub on_error: Color,
167    pub error_container: Color,
168    pub on_error_container: Color,
169
170    pub background: Color,
171    pub on_background: Color,
172    pub surface: Color,
173    pub on_surface: Color,
174    pub surface_variant: Color,
175    pub on_surface_variant: Color,
176    pub surface_container_lowest: Color,
177    pub surface_container_low: Color,
178    pub surface_container: Color,
179    pub surface_container_high: Color,
180    pub surface_container_highest: Color,
181    pub surface_bright: Color,
182    pub surface_dim: Color,
183    pub surface_tint: Color,
184
185    pub inverse_surface: Color,
186    pub inverse_on_surface: Color,
187    pub inverse_primary: Color,
188
189    pub outline: Color,
190    pub outline_variant: Color,
191
192    pub scrim: Color,
193    pub shadow: Color,
194    pub focus: Color,
195}
196
197impl ColorScheme {
198    pub fn dark() -> Self {
199        Self {
200            primary: Color::from_hex("#D0BCFF"),
201            on_primary: Color::from_hex("#381E72"),
202            primary_container: Color::from_hex("#4F378B"),
203            on_primary_container: Color::from_hex("#EADDFF"),
204
205            secondary: Color::from_hex("#CCC2DC"),
206            on_secondary: Color::from_hex("#332D41"),
207            secondary_container: Color::from_hex("#4A4458"),
208            on_secondary_container: Color::from_hex("#E8DEF8"),
209
210            tertiary: Color::from_hex("#EFB8C8"),
211            on_tertiary: Color::from_hex("#492532"),
212            tertiary_container: Color::from_hex("#633B48"),
213            on_tertiary_container: Color::from_hex("#FFD8E4"),
214
215            error: Color::from_hex("#F2B8B5"),
216            on_error: Color::from_hex("#601410"),
217            error_container: Color::from_hex("#8C1D18"),
218            on_error_container: Color::from_hex("#F9DEDC"),
219
220            background: Color::from_hex("#141218"),
221            on_background: Color::from_hex("#E6E0E9"),
222            surface: Color::from_hex("#141218"),
223            on_surface: Color::from_hex("#E6E0E9"),
224            surface_variant: Color::from_hex("#49454F"),
225            on_surface_variant: Color::from_hex("#CAC4D0"),
226            surface_container_lowest: Color::from_hex("#0F0D13"),
227            surface_container_low: Color::from_hex("#1D1B20"),
228            surface_container: Color::from_hex("#211F26"),
229            surface_container_high: Color::from_hex("#2B2930"),
230            surface_container_highest: Color::from_hex("#36343B"),
231            surface_bright: Color::from_hex("#3B383E"),
232            surface_dim: Color::from_hex("#141218"),
233            surface_tint: Color::from_hex("#D0BCFF"),
234
235            inverse_surface: Color::from_hex("#E6E0E9"),
236            inverse_on_surface: Color::from_hex("#322F35"),
237            inverse_primary: Color::from_hex("#6750A4"),
238
239            outline: Color::from_hex("#938F99"),
240            outline_variant: Color::from_hex("#49454F"),
241
242            scrim: Color::from_hex("#000000"),
243            shadow: Color::from_hex("#000000"),
244            focus: Color::from_hex("#88CCFF"),
245        }
246    }
247
248    pub fn light() -> Self {
249        Self {
250            primary: Color::from_hex("#6750A4"),
251            on_primary: Color::WHITE,
252            primary_container: Color::from_hex("#EADDFF"),
253            on_primary_container: Color::from_hex("#21005D"),
254
255            secondary: Color::from_hex("#625B71"),
256            on_secondary: Color::WHITE,
257            secondary_container: Color::from_hex("#E8DEF8"),
258            on_secondary_container: Color::from_hex("#1D192B"),
259
260            tertiary: Color::from_hex("#7D5260"),
261            on_tertiary: Color::WHITE,
262            tertiary_container: Color::from_hex("#FFD8E4"),
263            on_tertiary_container: Color::from_hex("#31111D"),
264
265            error: Color::from_hex("#B3261E"),
266            on_error: Color::WHITE,
267            error_container: Color::from_hex("#F9DEDC"),
268            on_error_container: Color::from_hex("#410E0B"),
269
270            background: Color::from_hex("#FEF7FF"),
271            on_background: Color::from_hex("#1D1B20"),
272            surface: Color::from_hex("#FEF7FF"),
273            on_surface: Color::from_hex("#1D1B20"),
274            surface_variant: Color::from_hex("#E7E0EC"),
275            on_surface_variant: Color::from_hex("#49454F"),
276            surface_container_lowest: Color::WHITE,
277            surface_container_low: Color::from_hex("#F7F2FA"),
278            surface_container: Color::from_hex("#F3EDF7"),
279            surface_container_high: Color::from_hex("#ECE6F0"),
280            surface_container_highest: Color::from_hex("#E6E0E9"),
281            surface_bright: Color::from_hex("#FEF7FF"),
282            surface_dim: Color::from_hex("#DED8E1"),
283            surface_tint: Color::from_hex("#6750A4"),
284
285            inverse_surface: Color::from_hex("#322F35"),
286            inverse_on_surface: Color::from_hex("#F5EFF7"),
287            inverse_primary: Color::from_hex("#D0BCFF"),
288
289            outline: Color::from_hex("#79747E"),
290            outline_variant: Color::from_hex("#CAC4D0"),
291
292            scrim: Color::from_hex("#000000"),
293            shadow: Color::from_hex("#000000"),
294            focus: Color::from_hex("#1D4ED8"),
295        }
296    }
297}
298
299impl Default for ColorScheme {
300    fn default() -> Self {
301        Self::dark()
302    }
303}
304
305#[derive(Clone, Copy, Debug)]
306#[must_use]
307pub struct Typography {
308    pub display_large: f32,
309    pub display_medium: f32,
310    pub display_small: f32,
311    pub headline_large: f32,
312    pub headline_medium: f32,
313    pub headline_small: f32,
314    pub title_large: f32,
315    pub title_medium: f32,
316    pub title_small: f32,
317    pub body_large: f32,
318    pub body_medium: f32,
319    pub body_small: f32,
320    pub label_large: f32,
321    pub label_medium: f32,
322    pub label_small: f32,
323}
324
325impl Default for Typography {
326    fn default() -> Self {
327        Self {
328            display_large: 57.0,
329            display_medium: 45.0,
330            display_small: 36.0,
331            headline_large: 32.0,
332            headline_medium: 28.0,
333            headline_small: 24.0,
334            title_large: 22.0,
335            title_medium: 16.0,
336            title_small: 14.0,
337            body_large: 16.0,
338            body_medium: 14.0,
339            body_small: 12.0,
340            label_large: 14.0,
341            label_medium: 12.0,
342            label_small: 11.0,
343        }
344    }
345}
346
347#[derive(Clone, Copy, Debug)]
348#[must_use]
349pub struct Shapes {
350    pub extra_small: f32,
351    pub small: f32,
352    pub medium: f32,
353    pub large: f32,
354    pub extra_large: f32,
355}
356
357impl Default for Shapes {
358    fn default() -> Self {
359        Self {
360            extra_small: 4.0,
361            small: 8.0,
362            medium: 12.0,
363            large: 16.0,
364            extra_large: 28.0,
365        }
366    }
367}
368
369#[derive(Clone, Copy, Debug)]
370#[must_use]
371pub struct Spacing {
372    pub xs: f32,
373    pub sm: f32,
374    pub md: f32,
375    pub lg: f32,
376    pub xl: f32,
377    pub xxl: f32,
378}
379
380impl Default for Spacing {
381    fn default() -> Self {
382        Self {
383            xs: 4.0,
384            sm: 8.0,
385            md: 12.0,
386            lg: 16.0,
387            xl: 24.0,
388            xxl: 32.0,
389        }
390    }
391}
392
393#[derive(Clone, Copy, Debug)]
394#[must_use]
395pub struct Elevation {
396    pub level0: f32,
397    pub level1: f32,
398    pub level2: f32,
399    pub level3: f32,
400    pub level4: f32,
401    pub level5: f32,
402}
403
404impl Default for Elevation {
405    fn default() -> Self {
406        Self {
407            level0: 0.0,
408            level1: 1.0,
409            level2: 3.0,
410            level3: 6.0,
411            level4: 8.0,
412            level5: 12.0,
413        }
414    }
415}
416
417#[derive(Clone, Copy, Debug)]
418#[must_use]
419pub struct Motion {
420    pub fast_ms: u32,
421    pub medium_ms: u32,
422    pub slow_ms: u32,
423}
424
425impl Default for Motion {
426    fn default() -> Self {
427        Self {
428            fast_ms: 120,
429            medium_ms: 240,
430            slow_ms: 360,
431        }
432    }
433}
434
435#[derive(Clone, Copy, Debug)]
436#[must_use]
437pub struct Theme {
438    pub colors: ColorScheme,
439    pub typography: Typography,
440    pub shapes: Shapes,
441    pub spacing: Spacing,
442    pub elevation: Elevation,
443    pub motion: Motion,
444
445    pub focus: Color,
446    pub scrollbar_track: Color,
447    pub scrollbar_thumb: Color,
448    pub button_bg: Color,
449    pub button_bg_hover: Color,
450    pub button_bg_pressed: Color,
451
452    pub background: Color,
453    pub on_background: Color,
454    pub surface: Color,
455    pub surface_variant: Color,
456    pub on_surface: Color,
457    pub on_surface_variant: Color,
458    pub surface_container_lowest: Color,
459    pub surface_container_low: Color,
460    pub surface_container: Color,
461    pub surface_container_high: Color,
462    pub surface_container_highest: Color,
463    pub surface_bright: Color,
464    pub surface_dim: Color,
465    pub surface_tint: Color,
466    pub primary: Color,
467    pub on_primary: Color,
468    pub primary_container: Color,
469    pub on_primary_container: Color,
470    pub secondary: Color,
471    pub on_secondary: Color,
472    pub secondary_container: Color,
473    pub on_secondary_container: Color,
474    pub tertiary: Color,
475    pub on_tertiary: Color,
476    pub tertiary_container: Color,
477    pub on_tertiary_container: Color,
478    pub error: Color,
479    pub on_error: Color,
480    pub error_container: Color,
481    pub on_error_container: Color,
482    pub inverse_surface: Color,
483    pub inverse_on_surface: Color,
484    pub inverse_primary: Color,
485    pub outline: Color,
486    pub outline_variant: Color,
487    pub scrim: Color,
488    pub shadow: Color,
489}
490
491impl Default for Theme {
492    fn default() -> Self {
493        let colors = ColorScheme::default();
494        Self {
495            background: colors.background,
496            on_background: colors.on_background,
497            surface: colors.surface,
498            surface_variant: colors.surface_variant,
499            on_surface: colors.on_surface,
500            on_surface_variant: colors.on_surface_variant,
501            surface_container_lowest: colors.surface_container_lowest,
502            surface_container_low: colors.surface_container_low,
503            surface_container: colors.surface_container,
504            surface_container_high: colors.surface_container_high,
505            surface_container_highest: colors.surface_container_highest,
506            surface_bright: colors.surface_bright,
507            surface_dim: colors.surface_dim,
508            surface_tint: colors.surface_tint,
509            primary: colors.primary,
510            on_primary: colors.on_primary,
511            primary_container: colors.primary_container,
512            on_primary_container: colors.on_primary_container,
513            secondary: colors.secondary,
514            on_secondary: colors.on_secondary,
515            secondary_container: colors.secondary_container,
516            on_secondary_container: colors.on_secondary_container,
517            tertiary: colors.tertiary,
518            on_tertiary: colors.on_tertiary,
519            tertiary_container: colors.tertiary_container,
520            on_tertiary_container: colors.on_tertiary_container,
521            error: colors.error,
522            on_error: colors.on_error,
523            error_container: colors.error_container,
524            on_error_container: colors.on_error_container,
525            inverse_surface: colors.inverse_surface,
526            inverse_on_surface: colors.inverse_on_surface,
527            inverse_primary: colors.inverse_primary,
528            outline: colors.outline,
529            outline_variant: colors.outline_variant,
530            scrim: colors.scrim,
531            shadow: colors.shadow,
532            colors,
533            typography: Typography::default(),
534            shapes: Shapes::default(),
535            spacing: Spacing::default(),
536            elevation: Elevation::default(),
537            motion: Motion::default(),
538            focus: colors.focus,
539            scrollbar_track: Color(0xDD, 0xDD, 0xDD, 32),
540            scrollbar_thumb: Color(0xDD, 0xDD, 0xDD, 140),
541            button_bg: colors.primary,
542            button_bg_hover: colors.primary_container,
543            button_bg_pressed: colors.on_primary_container,
544        }
545    }
546}
547
548impl Theme {
549    pub fn apply_colors(&mut self) {
550        self.background = self.colors.background;
551        self.on_background = self.colors.on_background;
552        self.surface = self.colors.surface;
553        self.surface_variant = self.colors.surface_variant;
554        self.on_surface = self.colors.on_surface;
555        self.on_surface_variant = self.colors.on_surface_variant;
556        self.surface_container_lowest = self.colors.surface_container_lowest;
557        self.surface_container_low = self.colors.surface_container_low;
558        self.surface_container = self.colors.surface_container;
559        self.surface_container_high = self.colors.surface_container_high;
560        self.surface_container_highest = self.colors.surface_container_highest;
561        self.surface_bright = self.colors.surface_bright;
562        self.surface_dim = self.colors.surface_dim;
563        self.surface_tint = self.colors.surface_tint;
564        self.primary = self.colors.primary;
565        self.on_primary = self.colors.on_primary;
566        self.primary_container = self.colors.primary_container;
567        self.on_primary_container = self.colors.on_primary_container;
568        self.secondary = self.colors.secondary;
569        self.on_secondary = self.colors.on_secondary;
570        self.secondary_container = self.colors.secondary_container;
571        self.on_secondary_container = self.colors.on_secondary_container;
572        self.tertiary = self.colors.tertiary;
573        self.on_tertiary = self.colors.on_tertiary;
574        self.tertiary_container = self.colors.tertiary_container;
575        self.on_tertiary_container = self.colors.on_tertiary_container;
576        self.error = self.colors.error;
577        self.on_error = self.colors.on_error;
578        self.error_container = self.colors.error_container;
579        self.on_error_container = self.colors.on_error_container;
580        self.inverse_surface = self.colors.inverse_surface;
581        self.inverse_on_surface = self.colors.inverse_on_surface;
582        self.inverse_primary = self.colors.inverse_primary;
583        self.outline = self.colors.outline;
584        self.outline_variant = self.colors.outline_variant;
585        self.scrim = self.colors.scrim;
586        self.shadow = self.colors.shadow;
587        self.focus = self.colors.focus;
588        self.button_bg = self.colors.primary;
589        self.button_bg_hover = self.colors.primary_container;
590        self.button_bg_pressed = self.colors.on_primary_container;
591    }
592
593    pub fn sync_colors_from_fields(&mut self) {
594        self.colors.background = self.background;
595        self.colors.on_background = self.on_background;
596        self.colors.surface = self.surface;
597        self.colors.surface_variant = self.surface_variant;
598        self.colors.on_surface = self.on_surface;
599        self.colors.on_surface_variant = self.on_surface_variant;
600        self.colors.surface_container_lowest = self.surface_container_lowest;
601        self.colors.surface_container_low = self.surface_container_low;
602        self.colors.surface_container = self.surface_container;
603        self.colors.surface_container_high = self.surface_container_high;
604        self.colors.surface_container_highest = self.surface_container_highest;
605        self.colors.surface_bright = self.surface_bright;
606        self.colors.surface_dim = self.surface_dim;
607        self.colors.surface_tint = self.surface_tint;
608        self.colors.primary = self.primary;
609        self.colors.on_primary = self.on_primary;
610        self.colors.primary_container = self.primary_container;
611        self.colors.on_primary_container = self.on_primary_container;
612        self.colors.secondary = self.secondary;
613        self.colors.on_secondary = self.on_secondary;
614        self.colors.secondary_container = self.secondary_container;
615        self.colors.on_secondary_container = self.on_secondary_container;
616        self.colors.tertiary = self.tertiary;
617        self.colors.on_tertiary = self.on_tertiary;
618        self.colors.tertiary_container = self.tertiary_container;
619        self.colors.on_tertiary_container = self.on_tertiary_container;
620        self.colors.error = self.error;
621        self.colors.on_error = self.on_error;
622        self.colors.error_container = self.error_container;
623        self.colors.on_error_container = self.on_error_container;
624        self.colors.inverse_surface = self.inverse_surface;
625        self.colors.inverse_on_surface = self.inverse_on_surface;
626        self.colors.inverse_primary = self.inverse_primary;
627        self.colors.outline = self.outline;
628        self.colors.outline_variant = self.outline_variant;
629        self.colors.scrim = self.scrim;
630        self.colors.shadow = self.shadow;
631        self.colors.focus = self.focus;
632    }
633
634    pub fn with_colors(mut self, colors: ColorScheme) -> Self {
635        self.colors = colors;
636        self.apply_colors();
637        self
638    }
639}
640
641/// Platform/device scale (dp→px multiplier). Platform runner should set this.
642#[derive(Clone, Copy, Debug)]
643pub struct Density {
644    pub scale: f32,
645}
646impl Default for Density {
647    fn default() -> Self {
648        Self { scale: 1.0 }
649    }
650}
651
652/// Additional UI scale multiplier (app-controlled).
653#[derive(Clone, Copy, Debug)]
654pub struct UiScale(pub f32);
655impl Default for UiScale {
656    fn default() -> Self {
657        Self(1.0)
658    }
659}
660
661#[derive(Clone, Copy, Debug)]
662pub struct TextScale(pub f32);
663impl Default for TextScale {
664    fn default() -> Self {
665        Self(1.0)
666    }
667}
668
669pub fn with_theme<R>(theme: Theme, f: impl FnOnce() -> R) -> R {
670    with_locals_frame(|| {
671        set_local_boxed(TypeId::of::<Theme>(), Box::new(theme));
672        f()
673    })
674}
675
676pub fn with_density<R>(density: Density, f: impl FnOnce() -> R) -> R {
677    with_locals_frame(|| {
678        set_local_boxed(TypeId::of::<Density>(), Box::new(density));
679        f()
680    })
681}
682
683pub fn with_ui_scale<R>(s: UiScale, f: impl FnOnce() -> R) -> R {
684    with_locals_frame(|| {
685        set_local_boxed(TypeId::of::<UiScale>(), Box::new(s));
686        f()
687    })
688}
689
690pub fn with_text_scale<R>(ts: TextScale, f: impl FnOnce() -> R) -> R {
691    with_locals_frame(|| {
692        set_local_boxed(TypeId::of::<TextScale>(), Box::new(ts));
693        f()
694    })
695}
696
697pub fn with_text_direction<R>(dir: TextDirection, f: impl FnOnce() -> R) -> R {
698    with_locals_frame(|| {
699        set_local_boxed(TypeId::of::<TextDirection>(), Box::new(dir));
700        f()
701    })
702}
703
704pub fn theme() -> Theme {
705    get_local::<Theme>().unwrap_or_else(|| defaults().read().theme)
706}
707
708pub fn density() -> Density {
709    get_local::<Density>().unwrap_or_else(|| defaults().read().density)
710}
711
712pub fn ui_scale() -> UiScale {
713    get_local::<UiScale>().unwrap_or_else(|| defaults().read().ui_scale)
714}
715
716pub fn text_scale() -> TextScale {
717    get_local::<TextScale>().unwrap_or_else(|| defaults().read().text_scale)
718}
719
720pub fn text_direction() -> TextDirection {
721    get_local::<TextDirection>().unwrap_or_else(|| defaults().read().text_direction)
722}