1use crate::Printer;
2
3use super::{Builder, Cell, NumAttr, Port, RRC};
4use calyx_utils::Error;
5use itertools::Itertools;
6use std::collections::HashSet;
7use std::fmt::{Debug, Display};
8use std::mem;
9use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
10use std::{cmp::Ordering, hash::Hash, rc::Rc};
11
12#[derive(Debug, Clone, Default, Eq, PartialEq)]
13#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
14pub struct Nothing;
15
16impl Display for Nothing {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 write!(f, "")
19 }
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
24#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
25pub enum PortComp {
26 Eq,
28 Neq,
30 Gt,
32 Lt,
34 Geq,
36 Leq,
38}
39
40#[derive(Debug, Clone, Default)]
42#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
43pub enum Guard<T> {
44 Or(Box<Guard<T>>, Box<Guard<T>>),
46 And(Box<Guard<T>>, Box<Guard<T>>),
48 Not(Box<Guard<T>>),
50 #[default]
51 True,
53 CompOp(PortComp, RRC<Port>, RRC<Port>),
55 Port(RRC<Port>),
57 Info(T),
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
62#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
63pub struct StaticTiming {
64 interval: (u64, u64),
65}
66
67impl Display for StaticTiming {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 if self.interval.0 + 1 == self.interval.1 {
70 write!(f, "%{}", self.interval.0)
71 } else {
72 write!(f, "%[{}:{}]", self.interval.0, self.interval.1)
73 }
74 }
75}
76
77impl StaticTiming {
78 pub fn new(interval: (u64, u64)) -> Self {
80 StaticTiming { interval }
81 }
82
83 pub fn get_interval(&self) -> (u64, u64) {
85 self.interval
86 }
87
88 pub fn set_interval(&mut self, new_interval: (u64, u64)) {
90 self.interval = new_interval;
91 }
92}
93
94impl<T> Hash for Guard<T>
95where
96 T: ToString,
97{
98 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
99 match self {
100 Guard::Or(l, r) | Guard::And(l, r) => {
101 l.hash(state);
102 r.hash(state)
103 }
104 Guard::CompOp(_, l, r) => {
105 l.borrow().name.hash(state);
106 l.borrow().get_parent_name().hash(state);
107 r.borrow().name.hash(state);
108 r.borrow().get_parent_name().hash(state);
109 }
110 Guard::Not(inner) => inner.hash(state),
111 Guard::Port(p) => {
112 p.borrow().name.hash(state);
113 p.borrow().get_parent_name().hash(state);
114 }
115 Guard::True => {}
116 Guard::Info(i) => i.to_string().hash(state),
117 }
118 }
119}
120
121impl From<Guard<Nothing>> for Guard<StaticTiming> {
122 fn from(g: Guard<Nothing>) -> Self {
124 match g {
125 Guard::Or(left, right) => {
126 let l = Self::from(*left);
127 let r = Self::from(*right);
128 Guard::Or(Box::new(l), Box::new(r))
129 }
130 Guard::And(left, right) => {
131 let l = Self::from(*left);
132 let r = Self::from(*right);
133 Guard::And(Box::new(l), Box::new(r))
134 }
135 Guard::Not(c) => {
136 let inside = Self::from(*c);
137 Guard::Not(Box::new(inside))
138 }
139 Guard::True => Guard::True,
140 Guard::CompOp(pc, left, right) => Guard::CompOp(pc, left, right),
141 Guard::Port(p) => Guard::Port(p),
142 Guard::Info(_) => {
143 unreachable!(
144 "{:?}: Guard<Nothing> should not be of the
145 info variant type",
146 g
147 )
148 }
149 }
150 }
151}
152
153impl<T> Guard<T> {
154 pub fn is_true(&self) -> bool {
157 match self {
158 Guard::True => true,
159 Guard::Port(p) => p.borrow().is_constant(1, 1),
160 _ => false,
161 }
162 }
163
164 pub fn is_false(&self) -> bool {
167 match self {
168 Guard::Not(g) => g.is_true(),
169 _ => false,
170 }
171 }
172
173 pub fn is_not_done(&self, cell_name: &crate::Id) -> bool {
175 if let Guard::Not(g) = self {
176 if let Guard::Port(port) = &(**g) {
177 return port.borrow().attributes.has(NumAttr::Done)
178 && port.borrow().get_parent_name() == cell_name;
179 }
180 }
181 false
182 }
183
184 #[inline(always)]
187 pub fn update<F>(&mut self, upd: F)
188 where
189 F: FnOnce(Guard<T>) -> Guard<T>,
190 {
191 let old = mem::take(self);
192 let new = upd(old);
193 *self = new;
194 }
195
196 pub fn op_str(&self) -> String {
198 match self {
199 Guard::And(..) => "&".to_string(),
200 Guard::Or(..) => "|".to_string(),
201 Guard::CompOp(op, _, _) => match op {
202 PortComp::Eq => "==".to_string(),
203 PortComp::Neq => "!=".to_string(),
204 PortComp::Gt => ">".to_string(),
205 PortComp::Lt => "<".to_string(),
206 PortComp::Geq => ">=".to_string(),
207 PortComp::Leq => "<=".to_string(),
208 },
209 Guard::Not(..) => "!".to_string(),
210 Guard::Port(..) | Guard::True | Guard::Info(_) => {
211 panic!("No operator string for Guard::Port/True/Info")
212 }
213 }
214 }
215
216 pub fn port(p: RRC<Port>) -> Self {
217 if p.borrow().is_constant(1, 1) {
218 Guard::True
219 } else {
220 Guard::Port(p)
221 }
222 }
223
224 pub fn and(self, rhs: Guard<T>) -> Self
225 where
226 T: Eq,
227 {
228 if rhs == Guard::True {
229 self
230 } else if self == Guard::True {
231 rhs
232 } else if self == rhs {
233 self
234 } else {
235 Guard::And(Box::new(self), Box::new(rhs))
236 }
237 }
238
239 pub fn or(self, rhs: Guard<T>) -> Self
240 where
241 T: Eq,
242 {
243 match (self, rhs) {
244 (Guard::True, _) | (_, Guard::True) => Guard::True,
245 (Guard::Not(n), g) | (g, Guard::Not(n)) => {
246 if *n == Guard::True {
247 g
248 } else {
249 Guard::Or(Box::new(Guard::Not(n)), Box::new(g))
250 }
251 }
252 (l, r) => {
253 if l == r {
254 l
255 } else {
256 Guard::Or(Box::new(l), Box::new(r))
257 }
258 }
259 }
260 }
261
262 pub fn eq(self, other: Guard<T>) -> Self
263 where
264 T: Debug + Eq + ToString,
265 {
266 match (self, other) {
267 (Guard::Port(l), Guard::Port(r)) => {
268 Guard::CompOp(PortComp::Eq, l, r)
269 }
270 (l, r) => {
271 unreachable!(
272 "Cannot build Guard::Eq using `{}' and `{}'",
273 Printer::guard_str(&l),
274 Printer::guard_str(&r),
275 )
276 }
277 }
278 }
279
280 pub fn neq(self, other: Guard<T>) -> Self
281 where
282 T: Debug + Eq + ToString,
283 {
284 match (self, other) {
285 (Guard::Port(l), Guard::Port(r)) => {
286 Guard::CompOp(PortComp::Neq, l, r)
287 }
288 (l, r) => {
289 unreachable!(
290 "Cannot build Guard::Eq using `{}' and `{}'",
291 Printer::guard_str(&l),
292 Printer::guard_str(&r),
293 )
294 }
295 }
296 }
297
298 pub fn le(self, other: Guard<T>) -> Self
299 where
300 T: Debug + Eq + ToString,
301 {
302 match (self, other) {
303 (Guard::Port(l), Guard::Port(r)) => {
304 Guard::CompOp(PortComp::Leq, l, r)
305 }
306 (l, r) => {
307 unreachable!(
308 "Cannot build Guard::Eq using `{}' and `{}'",
309 Printer::guard_str(&l),
310 Printer::guard_str(&r),
311 )
312 }
313 }
314 }
315
316 pub fn lt(self, other: Guard<T>) -> Self
317 where
318 T: Debug + Eq + ToString,
319 {
320 match (self, other) {
321 (Guard::Port(l), Guard::Port(r)) => {
322 Guard::CompOp(PortComp::Lt, l, r)
323 }
324 (l, r) => {
325 unreachable!(
326 "Cannot build Guard::Eq using `{}' and `{}'",
327 Printer::guard_str(&l),
328 Printer::guard_str(&r),
329 )
330 }
331 }
332 }
333
334 pub fn ge(self, other: Guard<T>) -> Self
335 where
336 T: Debug + Eq + ToString,
337 {
338 match (self, other) {
339 (Guard::Port(l), Guard::Port(r)) => {
340 Guard::CompOp(PortComp::Geq, l, r)
341 }
342 (l, r) => {
343 unreachable!(
344 "Cannot build Guard::Eq using `{}' and `{}'",
345 Printer::guard_str(&l),
346 Printer::guard_str(&r),
347 )
348 }
349 }
350 }
351
352 pub fn gt(self, other: Guard<T>) -> Self
353 where
354 T: Debug + Eq + ToString,
355 {
356 match (self, other) {
357 (Guard::Port(l), Guard::Port(r)) => {
358 Guard::CompOp(PortComp::Gt, l, r)
359 }
360 (l, r) => {
361 unreachable!(
362 "Cannot build Guard::Eq using `{}' and `{}'",
363 Printer::guard_str(&l),
364 Printer::guard_str(&r),
365 )
366 }
367 }
368 }
369
370 pub fn all_ports(&self) -> Vec<RRC<Port>> {
372 match self {
373 Guard::Port(a) => vec![Rc::clone(a)],
374 Guard::And(l, r) | Guard::Or(l, r) => {
375 let mut atoms = l.all_ports();
376 atoms.append(&mut r.all_ports());
377 atoms
378 }
379 Guard::CompOp(_, l, r) => {
380 vec![Rc::clone(l), Rc::clone(r)]
381 }
382 Guard::Not(g) => g.all_ports(),
383 Guard::True => vec![],
384 Guard::Info(_) => vec![],
385 }
386 }
387}
388
389impl<T> Guard<T> {
391 pub fn for_each<F>(&mut self, f: &mut F)
395 where
396 F: FnMut(RRC<Port>) -> Option<Guard<T>>,
397 {
398 match self {
399 Guard::And(l, r) | Guard::Or(l, r) => {
400 l.for_each(f);
401 r.for_each(f);
402 }
403 Guard::Not(inner) => {
404 inner.for_each(f);
405 }
406 Guard::CompOp(_, l, r) => {
407 match f(Rc::clone(l)) {
408 Some(Guard::Port(p)) => *l = p,
409 Some(_) => unreachable!(
410 "Cannot replace port inside comparison operator"
411 ),
412 None => {}
413 }
414 match f(Rc::clone(r)) {
415 Some(Guard::Port(p)) => *r = p,
416 Some(_) => unreachable!(
417 "Cannot replace port inside comparison operator"
418 ),
419 None => {}
420 }
421 }
422 Guard::Port(port) => {
423 let guard = f(Rc::clone(port))
424 .unwrap_or_else(|| Guard::port(Rc::clone(port)));
425 *self = guard;
426 }
427 Guard::True => {}
428 Guard::Info(_) =>
429 {}
431 }
432 }
433
434 pub fn for_each_info<F>(&mut self, f: &mut F)
438 where
439 F: FnMut(&mut T) -> Option<Guard<T>>,
440 {
441 match self {
442 Guard::And(l, r) | Guard::Or(l, r) => {
443 l.for_each_info(f);
444 r.for_each_info(f);
445 }
446 Guard::Not(inner) => {
447 inner.for_each_info(f);
448 }
449 Guard::True | Guard::Port(_) | Guard::CompOp(_, _, _) => {}
450 Guard::Info(timing_interval) => {
451 if let Some(new_interval) = f(timing_interval) {
452 *self = new_interval
453 }
454 }
455 }
456 }
457
458 pub fn check_for_each_info<F>(&self, f: &mut F) -> Result<(), Error>
462 where
463 F: Fn(&T) -> Result<(), Error>,
464 {
465 match self {
466 Guard::And(l, r) | Guard::Or(l, r) => {
467 let l_result = l.check_for_each_info(f);
468 if l_result.is_err() {
469 l_result
470 } else {
471 r.check_for_each_info(f)
472 }
473 }
474 Guard::Not(inner) => inner.check_for_each_info(f),
475 Guard::True | Guard::Port(_) | Guard::CompOp(_, _, _) => Ok(()),
476 Guard::Info(timing_interval) => f(timing_interval),
477 }
478 }
479}
480
481impl Guard<StaticTiming> {
482 pub fn add_interval(&mut self, timing_interval: StaticTiming) {
484 self.update(|g| g.and(Guard::Info(timing_interval)));
485 }
486
487 pub fn compute_live_states(&self, group_latency: u64) -> HashSet<u64> {
491 match self {
492 Self::True => (0..group_latency).collect(),
493 Self::And(l, r) => l
494 .compute_live_states(group_latency)
495 .intersection(&r.compute_live_states(group_latency))
496 .cloned()
497 .collect(),
498 Self::Or(l, r) => l
499 .compute_live_states(group_latency)
500 .union(&r.compute_live_states(group_latency))
501 .cloned()
502 .collect(),
503 Self::Not(g) => {
504 let dont_include = g.compute_live_states(group_latency);
505 (0..group_latency)
506 .filter(|state| dont_include.contains(state))
507 .collect()
508 }
509 Self::Info(static_timing) => {
510 let (b, e) = static_timing.interval;
511 (b..e).collect()
512 }
513 Self::CompOp(..) | Self::Port(_) => {
514 HashSet::from_iter(0..group_latency)
515 }
516 }
517 }
518
519 pub fn replace_static_timing(
522 &mut self,
523 builder: &mut Builder,
524 counter: &RRC<Cell>,
525 width: &u64,
526 domain: &u64,
527 ) {
528 match self {
529 Self::True | Self::CompOp(..) | Self::Port(..) => (),
530 Self::Not(g) => {
531 g.replace_static_timing(builder, counter, width, domain)
532 }
533 Self::And(l, r) | Self::Or(l, r) => {
534 l.replace_static_timing(builder, counter, width, domain);
535 r.replace_static_timing(builder, counter, width, domain);
536 }
537 Self::Info(static_timing) => {
538 let (b, e) = static_timing.get_interval();
539 let interval = (b..e).collect_vec();
540 let complement = (0..b).chain(e..*domain).collect_vec();
541 self.update(|_| {
542 if interval.len() < complement.len() {
543 match interval.into_iter().fold(None, |acc, state| {
544 let state_const =
545 builder.add_constant(state, *width);
546 let state_guard = Self::CompOp(
547 PortComp::Eq,
548 counter.borrow().get("out"),
549 state_const.borrow().get("out"),
550 );
551 match acc {
552 None => Some(state_guard),
553 Some(existing_guard) => {
554 Some(existing_guard.or(state_guard))
555 }
556 }
557 }) {
558 Some(g) => g,
559 None => {
560 let zero = builder.add_constant(0, 1);
561 let out_port = zero.borrow().get("out");
562 Self::port(out_port)
563 }
564 }
565 } else {
566 match complement.into_iter().fold(None, |acc, state| {
567 let state_const =
568 builder.add_constant(state, *width);
569 let state_guard = Self::CompOp(
570 PortComp::Neq,
571 counter.borrow().get("out"),
572 state_const.borrow().get("out"),
573 );
574 match acc {
575 None => Some(state_guard),
576 Some(existing_guard) => {
577 Some(existing_guard.and(state_guard))
578 }
579 }
580 }) {
581 Some(g) => g,
582 None => Self::True,
583 }
584 }
585 });
586 }
587 }
588 }
589
590 pub fn remove_static_timing_info(&mut self) {
595 match self {
596 Self::Port(_) | Self::CompOp(..) | Self::True => (),
597 Self::Info(_) => {
598 self.update(|_| Self::True);
599 }
600 Self::Not(g) => match g.as_mut() {
601 Self::Info(_) => self.update(|_| Self::True),
602 _ => g.remove_static_timing_info(),
603 },
604 Self::And(l, r) => match (l.as_mut(), r.as_mut()) {
605 (Self::Info(_), Self::Info(_)) => self.update(|_| Self::True),
606 (Self::Info(_), _) => {
607 r.remove_static_timing_info();
608 l.update(|_| Self::True);
609 }
610 (_, Self::Info(_)) => {
611 l.remove_static_timing_info();
612 r.update(|_| Self::True);
613 }
614 _ => {
615 l.remove_static_timing_info();
616 r.remove_static_timing_info();
617 }
618 },
619 Self::Or(l, r) => match (l.as_mut(), r.as_mut()) {
620 (Self::Info(_), Self::Info(_)) => self.update(|_| Self::True),
621 (Self::Info(_), _) => {
622 r.remove_static_timing_info();
623 l.update(|_| Self::not(Self::True))
624 }
625 (_, Self::Info(_)) => {
626 l.remove_static_timing_info();
627 r.update(|_| Self::not(Self::True))
628 }
629 _ => {
630 l.remove_static_timing_info();
631 r.remove_static_timing_info();
632 }
633 },
634 }
635 }
636}
637
638impl From<Guard<StaticTiming>> for Guard<Nothing> {
639 fn from(guard: Guard<StaticTiming>) -> Guard<Nothing> {
640 match guard {
641 Guard::True => Guard::True,
642 Guard::Port(p) => Guard::Port(p),
643 Guard::CompOp(cmp, p1, p2) => Guard::CompOp(cmp, p1, p2),
644
645 Guard::And(l, r) => {
646 let l_new = Guard::from(*l);
647 let r_new = Guard::from(*r);
648 Guard::And(Box::new(l_new), Box::new(r_new))
649 }
650 Guard::Or(l, r) => {
651 let l_new = Guard::from(*l);
652 let r_new = Guard::from(*r);
653 Guard::Or(Box::new(l_new), Box::new(r_new))
654 }
655 Guard::Not(g) => {
656 let g_new = Guard::from(*g);
657 Guard::Not(Box::new(g_new))
658 }
659 Guard::Info(_) => {
660 unreachable!("Guard should not contain any `info` nodes;")
661 }
662 }
663 }
664}
665
666impl<T> From<RRC<Port>> for Guard<T> {
668 fn from(port: RRC<Port>) -> Self {
669 Guard::Port(Rc::clone(&port))
670 }
671}
672
673impl<T> PartialEq for Guard<T>
674where
675 T: Eq,
676{
677 fn eq(&self, other: &Self) -> bool {
678 match (self, other) {
679 (Guard::Or(la, ra), Guard::Or(lb, rb))
680 | (Guard::And(la, ra), Guard::And(lb, rb)) => la == lb && ra == rb,
681 (Guard::CompOp(opa, la, ra), Guard::CompOp(opb, lb, rb)) => {
682 (opa == opb)
683 && (la.borrow().get_parent_name(), &la.borrow().name)
684 == (lb.borrow().get_parent_name(), &lb.borrow().name)
685 && (ra.borrow().get_parent_name(), &ra.borrow().name)
686 == (rb.borrow().get_parent_name(), &rb.borrow().name)
687 }
688 (Guard::Not(a), Guard::Not(b)) => a == b,
689 (Guard::Port(a), Guard::Port(b)) => {
690 (a.borrow().get_parent_name(), &a.borrow().name)
691 == (b.borrow().get_parent_name(), &b.borrow().name)
692 }
693 (Guard::True, Guard::True) => true,
694 (Guard::Info(i1), Guard::Info(i2)) => i1 == i2,
695 _ => false,
696 }
697 }
698}
699
700impl<T> Eq for Guard<T> where T: Eq {}
701
702impl<T> PartialOrd for Guard<T>
704where
705 T: Eq,
706{
707 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
708 Some(self.cmp(other))
709 }
710}
711
712impl<T> Ord for Guard<T>
715where
716 T: Eq,
717{
718 fn cmp(&self, other: &Self) -> Ordering {
719 match (self, other) {
720 (Guard::Or(..), Guard::Or(..))
721 | (Guard::And(..), Guard::And(..))
722 | (Guard::CompOp(..), Guard::CompOp(..))
723 | (Guard::Not(..), Guard::Not(..))
724 | (Guard::Port(..), Guard::Port(..))
725 | (Guard::Info(_), Guard::Info(_))
726 | (Guard::True, Guard::True) => Ordering::Equal,
727 (Guard::Or(..), _) => Ordering::Greater,
728 (_, Guard::Or(..)) => Ordering::Less,
729 (Guard::And(..), _) => Ordering::Greater,
730 (_, Guard::And(..)) => Ordering::Less,
731 (Guard::CompOp(PortComp::Leq, ..), _) => Ordering::Greater,
732 (_, Guard::CompOp(PortComp::Leq, ..)) => Ordering::Less,
733 (Guard::CompOp(PortComp::Geq, ..), _) => Ordering::Greater,
734 (_, Guard::CompOp(PortComp::Geq, ..)) => Ordering::Less,
735 (Guard::CompOp(PortComp::Lt, ..), _) => Ordering::Greater,
736 (_, Guard::CompOp(PortComp::Lt, ..)) => Ordering::Less,
737 (Guard::CompOp(PortComp::Gt, ..), _) => Ordering::Greater,
738 (_, Guard::CompOp(PortComp::Gt, ..)) => Ordering::Less,
739 (Guard::CompOp(PortComp::Eq, ..), _) => Ordering::Greater,
740 (_, Guard::CompOp(PortComp::Eq, ..)) => Ordering::Less,
741 (Guard::CompOp(PortComp::Neq, ..), _) => Ordering::Greater,
742 (_, Guard::CompOp(PortComp::Neq, ..)) => Ordering::Less,
743 (Guard::Not(..), _) => Ordering::Greater,
744 (_, Guard::Not(..)) => Ordering::Less,
745 (Guard::Port(..), _) => Ordering::Greater,
746 (_, Guard::Port(..)) => Ordering::Less,
747 (Guard::Info(..), _) => Ordering::Greater,
749 (_, Guard::Info(..)) => Ordering::Less,
750 }
751 }
752}
753
754impl<T> BitAnd for Guard<T>
761where
762 T: Eq,
763{
764 type Output = Self;
765
766 fn bitand(self, other: Self) -> Self::Output {
767 self.and(other)
768 }
769}
770
771impl<T> BitOr for Guard<T>
776where
777 T: Eq,
778{
779 type Output = Self;
780
781 fn bitor(self, other: Self) -> Self::Output {
782 self.or(other)
783 }
784}
785
786impl<T> Not for Guard<T> {
791 type Output = Self;
792
793 fn not(self) -> Self {
794 match self {
795 Guard::CompOp(PortComp::Eq, lhs, rhs) => {
796 Guard::CompOp(PortComp::Neq, lhs, rhs)
797 }
798 Guard::CompOp(PortComp::Neq, lhs, rhs) => {
799 Guard::CompOp(PortComp::Eq, lhs, rhs)
800 }
801 Guard::CompOp(PortComp::Gt, lhs, rhs) => {
802 Guard::CompOp(PortComp::Leq, lhs, rhs)
803 }
804 Guard::CompOp(PortComp::Lt, lhs, rhs) => {
805 Guard::CompOp(PortComp::Geq, lhs, rhs)
806 }
807 Guard::CompOp(PortComp::Geq, lhs, rhs) => {
808 Guard::CompOp(PortComp::Lt, lhs, rhs)
809 }
810 Guard::CompOp(PortComp::Leq, lhs, rhs) => {
811 Guard::CompOp(PortComp::Gt, lhs, rhs)
812 }
813 Guard::Not(expr) => *expr,
814 _ => Guard::Not(Box::new(self)),
815 }
816 }
817}
818
819impl<T> BitOrAssign for Guard<T>
824where
825 T: Eq,
826{
827 fn bitor_assign(&mut self, other: Self) {
828 self.update(|old| old | other)
829 }
830}
831
832impl<T> BitAndAssign for Guard<T>
837where
838 T: Eq,
839{
840 fn bitand_assign(&mut self, other: Self) {
841 self.update(|old| old & other)
842 }
843}