1use crate::{f32::math, swizzles::*, DMat2, Mat3, Mat3A, Vec2};
4use core::fmt;
5use core::iter::{Product, Sum};
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7
8use core::arch::aarch64::*;
9
10#[repr(C)]
11union UnionCast {
12 a: [f32; 4],
13 v: Mat2,
14}
15
16#[inline(always)]
18#[must_use]
19pub const fn mat2(x_axis: Vec2, y_axis: Vec2) -> Mat2 {
20 Mat2::from_cols(x_axis, y_axis)
21}
22
23#[derive(Clone, Copy)]
29#[cfg_attr(
30 all(feature = "bytemuck", not(target_arch = "spirv")),
31 derive(bytemuck::Pod, bytemuck::Zeroable)
32)]
33#[repr(transparent)]
34pub struct Mat2(pub(crate) float32x4_t);
35
36impl Mat2 {
37 pub const ZERO: Self = Self::from_cols(Vec2::ZERO, Vec2::ZERO);
39
40 pub const IDENTITY: Self = Self::from_cols(Vec2::X, Vec2::Y);
42
43 pub const NAN: Self = Self::from_cols(Vec2::NAN, Vec2::NAN);
45
46 #[allow(clippy::too_many_arguments)]
47 #[inline(always)]
48 #[must_use]
49 const fn new(m00: f32, m01: f32, m10: f32, m11: f32) -> Self {
50 unsafe {
51 UnionCast {
52 a: [m00, m01, m10, m11],
53 }
54 .v
55 }
56 }
57
58 #[inline(always)]
60 #[must_use]
61 pub const fn from_cols(x_axis: Vec2, y_axis: Vec2) -> Self {
62 unsafe {
63 UnionCast {
64 a: [x_axis.x, x_axis.y, y_axis.x, y_axis.y],
65 }
66 .v
67 }
68 }
69
70 #[inline]
74 #[must_use]
75 pub const fn from_cols_array(m: &[f32; 4]) -> Self {
76 Self::new(m[0], m[1], m[2], m[3])
77 }
78
79 #[inline]
82 #[must_use]
83 pub const fn to_cols_array(&self) -> [f32; 4] {
84 unsafe { *(self as *const Self as *const [f32; 4]) }
85 }
86
87 #[inline]
91 #[must_use]
92 pub const fn from_cols_array_2d(m: &[[f32; 2]; 2]) -> Self {
93 Self::from_cols(Vec2::from_array(m[0]), Vec2::from_array(m[1]))
94 }
95
96 #[inline]
99 #[must_use]
100 pub const fn to_cols_array_2d(&self) -> [[f32; 2]; 2] {
101 unsafe { *(self as *const Self as *const [[f32; 2]; 2]) }
102 }
103
104 #[doc(alias = "scale")]
106 #[inline]
107 #[must_use]
108 pub const fn from_diagonal(diagonal: Vec2) -> Self {
109 Self::new(diagonal.x, 0.0, 0.0, diagonal.y)
110 }
111
112 #[inline]
115 #[must_use]
116 pub fn from_scale_angle(scale: Vec2, angle: f32) -> Self {
117 let (sin, cos) = math::sin_cos(angle);
118 Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y)
119 }
120
121 #[inline]
123 #[must_use]
124 pub fn from_angle(angle: f32) -> Self {
125 let (sin, cos) = math::sin_cos(angle);
126 Self::new(cos, sin, -sin, cos)
127 }
128
129 #[inline]
131 #[must_use]
132 pub fn from_mat3(m: Mat3) -> Self {
133 Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
134 }
135
136 #[inline]
143 #[must_use]
144 pub fn from_mat3_minor(m: Mat3, i: usize, j: usize) -> Self {
145 match (i, j) {
146 (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
147 (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
148 (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
149 (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
150 (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
151 (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
152 (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
153 (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
154 (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
155 _ => panic!("index out of bounds"),
156 }
157 }
158
159 #[inline]
161 #[must_use]
162 pub fn from_mat3a(m: Mat3A) -> Self {
163 Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
164 }
165
166 #[inline]
173 #[must_use]
174 pub fn from_mat3a_minor(m: Mat3A, i: usize, j: usize) -> Self {
175 match (i, j) {
176 (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
177 (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
178 (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
179 (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
180 (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
181 (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
182 (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
183 (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
184 (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
185 _ => panic!("index out of bounds"),
186 }
187 }
188
189 #[inline]
195 #[must_use]
196 pub const fn from_cols_slice(slice: &[f32]) -> Self {
197 Self::new(slice[0], slice[1], slice[2], slice[3])
198 }
199
200 #[inline]
206 pub fn write_cols_to_slice(self, slice: &mut [f32]) {
207 slice[0] = self.x_axis.x;
208 slice[1] = self.x_axis.y;
209 slice[2] = self.y_axis.x;
210 slice[3] = self.y_axis.y;
211 }
212
213 #[inline]
219 #[must_use]
220 pub fn col(&self, index: usize) -> Vec2 {
221 match index {
222 0 => self.x_axis,
223 1 => self.y_axis,
224 _ => panic!("index out of bounds"),
225 }
226 }
227
228 #[inline]
234 pub fn col_mut(&mut self, index: usize) -> &mut Vec2 {
235 match index {
236 0 => &mut self.x_axis,
237 1 => &mut self.y_axis,
238 _ => panic!("index out of bounds"),
239 }
240 }
241
242 #[inline]
248 #[must_use]
249 pub fn row(&self, index: usize) -> Vec2 {
250 match index {
251 0 => Vec2::new(self.x_axis.x, self.y_axis.x),
252 1 => Vec2::new(self.x_axis.y, self.y_axis.y),
253 _ => panic!("index out of bounds"),
254 }
255 }
256
257 #[inline]
260 #[must_use]
261 pub fn is_finite(&self) -> bool {
262 self.x_axis.is_finite() && self.y_axis.is_finite()
263 }
264
265 #[inline]
267 #[must_use]
268 pub fn is_nan(&self) -> bool {
269 self.x_axis.is_nan() || self.y_axis.is_nan()
270 }
271
272 #[inline]
274 #[must_use]
275 pub fn transpose(&self) -> Self {
276 Self(unsafe {
277 vsetq_lane_f32(
278 vgetq_lane_f32(self.0, 2),
279 vsetq_lane_f32(vgetq_lane_f32(self.0, 1), self.0, 2),
280 1,
281 )
282 })
283 }
284
285 #[inline]
287 #[must_use]
288 pub fn determinant(&self) -> f32 {
289 unsafe {
290 let abcd = self.0;
291 let badc = vrev64q_f32(abcd);
292 let dcba = vextq_f32(badc, badc, 2);
293 let prod = vmulq_f32(abcd, dcba);
294 let det = vsubq_f32(prod, vdupq_laneq_f32(prod, 1));
295 vgetq_lane_f32(det, 0)
296 }
297 }
298
299 #[inline]
307 #[must_use]
308 pub fn inverse(&self) -> Self {
309 unsafe {
310 const SIGN: float32x4_t = crate::neon::f32x4_from_array([1.0, -1.0, -1.0, 1.0]);
311 let abcd = self.0;
312 let badc = vrev64q_f32(abcd);
313 let dcba = vextq_f32(badc, badc, 2);
314 let prod = vmulq_f32(abcd, dcba);
315 let sub = vsubq_f32(prod, vdupq_laneq_f32(prod, 1));
316 let det = vdupq_laneq_f32(sub, 0);
317 let tmp = vdivq_f32(SIGN, det);
318 glam_assert!(Mat2(tmp).is_finite());
319 let dbca = vsetq_lane_f32(
321 vgetq_lane_f32(abcd, 0),
322 vsetq_lane_f32(vgetq_lane_f32(abcd, 3), abcd, 0),
323 3,
324 );
325 Self(vmulq_f32(dbca, tmp))
326 }
327 }
328
329 #[inline]
331 #[must_use]
332 pub fn mul_vec2(&self, rhs: Vec2) -> Vec2 {
333 unsafe {
334 let abcd = self.0;
335 let xxyy = vld1q_f32([rhs.x, rhs.x, rhs.y, rhs.y].as_ptr());
336 let axbxcydy = vmulq_f32(abcd, xxyy);
337 let cydyaxbx = vextq_f32(axbxcydy, axbxcydy, 2);
339 let result = vaddq_f32(axbxcydy, cydyaxbx);
340 *(&result as *const float32x4_t as *const Vec2)
341 }
342 }
343
344 #[inline]
346 #[must_use]
347 pub fn mul_mat2(&self, rhs: &Self) -> Self {
348 self.mul(rhs)
349 }
350
351 #[inline]
353 #[must_use]
354 pub fn add_mat2(&self, rhs: &Self) -> Self {
355 self.add(rhs)
356 }
357
358 #[inline]
360 #[must_use]
361 pub fn sub_mat2(&self, rhs: &Self) -> Self {
362 self.sub(rhs)
363 }
364
365 #[inline]
367 #[must_use]
368 pub fn mul_scalar(&self, rhs: f32) -> Self {
369 Self(unsafe { vmulq_f32(self.0, vld1q_dup_f32(&rhs)) })
370 }
371
372 #[inline]
374 #[must_use]
375 pub fn div_scalar(&self, rhs: f32) -> Self {
376 Self(unsafe { vdivq_f32(self.0, vld1q_dup_f32(&rhs)) })
377 }
378
379 #[inline]
389 #[must_use]
390 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
391 self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
392 && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
393 }
394
395 #[inline]
397 #[must_use]
398 pub fn abs(&self) -> Self {
399 Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
400 }
401
402 #[inline]
403 pub fn as_dmat2(&self) -> DMat2 {
404 DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2())
405 }
406}
407
408impl Default for Mat2 {
409 #[inline]
410 fn default() -> Self {
411 Self::IDENTITY
412 }
413}
414
415impl Add for Mat2 {
416 type Output = Self;
417 #[inline]
418 fn add(self, rhs: Self) -> Self {
419 Self(unsafe { vaddq_f32(self.0, rhs.0) })
420 }
421}
422
423impl Add<&Self> for Mat2 {
424 type Output = Self;
425 #[inline]
426 fn add(self, rhs: &Self) -> Self {
427 self.add(*rhs)
428 }
429}
430
431impl Add<&Mat2> for &Mat2 {
432 type Output = Mat2;
433 #[inline]
434 fn add(self, rhs: &Mat2) -> Mat2 {
435 (*self).add(*rhs)
436 }
437}
438
439impl Add<Mat2> for &Mat2 {
440 type Output = Mat2;
441 #[inline]
442 fn add(self, rhs: Mat2) -> Mat2 {
443 (*self).add(rhs)
444 }
445}
446
447impl AddAssign for Mat2 {
448 #[inline]
449 fn add_assign(&mut self, rhs: Self) {
450 *self = self.add(rhs);
451 }
452}
453
454impl AddAssign<&Self> for Mat2 {
455 #[inline]
456 fn add_assign(&mut self, rhs: &Self) {
457 self.add_assign(*rhs);
458 }
459}
460
461impl Sub for Mat2 {
462 type Output = Self;
463 #[inline]
464 fn sub(self, rhs: Self) -> Self {
465 Self(unsafe { vsubq_f32(self.0, rhs.0) })
466 }
467}
468
469impl Sub<&Self> for Mat2 {
470 type Output = Self;
471 #[inline]
472 fn sub(self, rhs: &Self) -> Self {
473 self.sub(*rhs)
474 }
475}
476
477impl Sub<&Mat2> for &Mat2 {
478 type Output = Mat2;
479 #[inline]
480 fn sub(self, rhs: &Mat2) -> Mat2 {
481 (*self).sub(*rhs)
482 }
483}
484
485impl Sub<Mat2> for &Mat2 {
486 type Output = Mat2;
487 #[inline]
488 fn sub(self, rhs: Mat2) -> Mat2 {
489 (*self).sub(rhs)
490 }
491}
492
493impl SubAssign for Mat2 {
494 #[inline]
495 fn sub_assign(&mut self, rhs: Self) {
496 *self = self.sub(rhs);
497 }
498}
499
500impl SubAssign<&Self> for Mat2 {
501 #[inline]
502 fn sub_assign(&mut self, rhs: &Self) {
503 self.sub_assign(*rhs);
504 }
505}
506
507impl Neg for Mat2 {
508 type Output = Self;
509 #[inline]
510 fn neg(self) -> Self::Output {
511 Self(unsafe { vnegq_f32(self.0) })
512 }
513}
514
515impl Neg for &Mat2 {
516 type Output = Mat2;
517 #[inline]
518 fn neg(self) -> Mat2 {
519 (*self).neg()
520 }
521}
522
523impl Mul for Mat2 {
524 type Output = Self;
525 #[inline]
526 fn mul(self, rhs: Self) -> Self {
527 unsafe {
528 let abcd = self.0;
529 let xxyy0 = vzip1q_f32(rhs.0, rhs.0);
530 let xxyy1 = vzip2q_f32(rhs.0, rhs.0);
531 let axbxcydy0 = vmulq_f32(abcd, xxyy0);
532 let axbxcydy1 = vmulq_f32(abcd, xxyy1);
533 let cydyaxbx0 = vextq_f32(axbxcydy0, axbxcydy0, 2);
534 let cydyaxbx1 = vextq_f32(axbxcydy1, axbxcydy1, 2);
535 let result0 = vaddq_f32(axbxcydy0, cydyaxbx0);
536 let result1 = vaddq_f32(axbxcydy1, cydyaxbx1);
537 Self(vreinterpretq_f32_u64(vsetq_lane_u64(
538 vgetq_lane_u64(vreinterpretq_u64_f32(result1), 0),
539 vreinterpretq_u64_f32(result0),
540 1,
541 )))
542 }
543 }
544}
545
546impl Mul<&Self> for Mat2 {
547 type Output = Self;
548 #[inline]
549 fn mul(self, rhs: &Self) -> Self {
550 self.mul(*rhs)
551 }
552}
553
554impl Mul<&Mat2> for &Mat2 {
555 type Output = Mat2;
556 #[inline]
557 fn mul(self, rhs: &Mat2) -> Mat2 {
558 (*self).mul(*rhs)
559 }
560}
561
562impl Mul<Mat2> for &Mat2 {
563 type Output = Mat2;
564 #[inline]
565 fn mul(self, rhs: Mat2) -> Mat2 {
566 (*self).mul(rhs)
567 }
568}
569
570impl MulAssign for Mat2 {
571 #[inline]
572 fn mul_assign(&mut self, rhs: Self) {
573 *self = self.mul(rhs);
574 }
575}
576
577impl MulAssign<&Self> for Mat2 {
578 #[inline]
579 fn mul_assign(&mut self, rhs: &Self) {
580 self.mul_assign(*rhs);
581 }
582}
583
584impl Mul<Vec2> for Mat2 {
585 type Output = Vec2;
586 #[inline]
587 fn mul(self, rhs: Vec2) -> Self::Output {
588 self.mul_vec2(rhs)
589 }
590}
591
592impl Mul<&Vec2> for Mat2 {
593 type Output = Vec2;
594 #[inline]
595 fn mul(self, rhs: &Vec2) -> Vec2 {
596 self.mul(*rhs)
597 }
598}
599
600impl Mul<&Vec2> for &Mat2 {
601 type Output = Vec2;
602 #[inline]
603 fn mul(self, rhs: &Vec2) -> Vec2 {
604 (*self).mul(*rhs)
605 }
606}
607
608impl Mul<Vec2> for &Mat2 {
609 type Output = Vec2;
610 #[inline]
611 fn mul(self, rhs: Vec2) -> Vec2 {
612 (*self).mul(rhs)
613 }
614}
615
616impl Mul<Mat2> for f32 {
617 type Output = Mat2;
618 #[inline]
619 fn mul(self, rhs: Mat2) -> Self::Output {
620 rhs.mul_scalar(self)
621 }
622}
623
624impl Mul<&Mat2> for f32 {
625 type Output = Mat2;
626 #[inline]
627 fn mul(self, rhs: &Mat2) -> Mat2 {
628 self.mul(*rhs)
629 }
630}
631
632impl Mul<&Mat2> for &f32 {
633 type Output = Mat2;
634 #[inline]
635 fn mul(self, rhs: &Mat2) -> Mat2 {
636 (*self).mul(*rhs)
637 }
638}
639
640impl Mul<Mat2> for &f32 {
641 type Output = Mat2;
642 #[inline]
643 fn mul(self, rhs: Mat2) -> Mat2 {
644 (*self).mul(rhs)
645 }
646}
647
648impl Mul<f32> for Mat2 {
649 type Output = Self;
650 #[inline]
651 fn mul(self, rhs: f32) -> Self {
652 self.mul_scalar(rhs)
653 }
654}
655
656impl Mul<&f32> for Mat2 {
657 type Output = Self;
658 #[inline]
659 fn mul(self, rhs: &f32) -> Self {
660 self.mul(*rhs)
661 }
662}
663
664impl Mul<&f32> for &Mat2 {
665 type Output = Mat2;
666 #[inline]
667 fn mul(self, rhs: &f32) -> Mat2 {
668 (*self).mul(*rhs)
669 }
670}
671
672impl Mul<f32> for &Mat2 {
673 type Output = Mat2;
674 #[inline]
675 fn mul(self, rhs: f32) -> Mat2 {
676 (*self).mul(rhs)
677 }
678}
679
680impl MulAssign<f32> for Mat2 {
681 #[inline]
682 fn mul_assign(&mut self, rhs: f32) {
683 *self = self.mul(rhs);
684 }
685}
686
687impl MulAssign<&f32> for Mat2 {
688 #[inline]
689 fn mul_assign(&mut self, rhs: &f32) {
690 self.mul_assign(*rhs);
691 }
692}
693
694impl Div<Mat2> for f32 {
695 type Output = Mat2;
696 #[inline]
697 fn div(self, rhs: Mat2) -> Self::Output {
698 rhs.div_scalar(self)
699 }
700}
701
702impl Div<&Mat2> for f32 {
703 type Output = Mat2;
704 #[inline]
705 fn div(self, rhs: &Mat2) -> Mat2 {
706 self.div(*rhs)
707 }
708}
709
710impl Div<&Mat2> for &f32 {
711 type Output = Mat2;
712 #[inline]
713 fn div(self, rhs: &Mat2) -> Mat2 {
714 (*self).div(*rhs)
715 }
716}
717
718impl Div<Mat2> for &f32 {
719 type Output = Mat2;
720 #[inline]
721 fn div(self, rhs: Mat2) -> Mat2 {
722 (*self).div(rhs)
723 }
724}
725
726impl Div<f32> for Mat2 {
727 type Output = Self;
728 #[inline]
729 fn div(self, rhs: f32) -> Self {
730 self.div_scalar(rhs)
731 }
732}
733
734impl Div<&f32> for Mat2 {
735 type Output = Self;
736 #[inline]
737 fn div(self, rhs: &f32) -> Self {
738 self.div(*rhs)
739 }
740}
741
742impl Div<&f32> for &Mat2 {
743 type Output = Mat2;
744 #[inline]
745 fn div(self, rhs: &f32) -> Mat2 {
746 (*self).div(*rhs)
747 }
748}
749
750impl Div<f32> for &Mat2 {
751 type Output = Mat2;
752 #[inline]
753 fn div(self, rhs: f32) -> Mat2 {
754 (*self).div(rhs)
755 }
756}
757
758impl DivAssign<f32> for Mat2 {
759 #[inline]
760 fn div_assign(&mut self, rhs: f32) {
761 *self = self.div(rhs);
762 }
763}
764
765impl DivAssign<&f32> for Mat2 {
766 #[inline]
767 fn div_assign(&mut self, rhs: &f32) {
768 self.div_assign(*rhs);
769 }
770}
771
772impl Sum<Self> for Mat2 {
773 fn sum<I>(iter: I) -> Self
774 where
775 I: Iterator<Item = Self>,
776 {
777 iter.fold(Self::ZERO, Self::add)
778 }
779}
780
781impl<'a> Sum<&'a Self> for Mat2 {
782 fn sum<I>(iter: I) -> Self
783 where
784 I: Iterator<Item = &'a Self>,
785 {
786 iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
787 }
788}
789
790impl Product for Mat2 {
791 fn product<I>(iter: I) -> Self
792 where
793 I: Iterator<Item = Self>,
794 {
795 iter.fold(Self::IDENTITY, Self::mul)
796 }
797}
798
799impl<'a> Product<&'a Self> for Mat2 {
800 fn product<I>(iter: I) -> Self
801 where
802 I: Iterator<Item = &'a Self>,
803 {
804 iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
805 }
806}
807
808impl PartialEq for Mat2 {
809 #[inline]
810 fn eq(&self, rhs: &Self) -> bool {
811 self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis)
812 }
813}
814
815#[cfg(not(target_arch = "spirv"))]
816impl AsRef<[f32; 4]> for Mat2 {
817 #[inline]
818 fn as_ref(&self) -> &[f32; 4] {
819 unsafe { &*(self as *const Self as *const [f32; 4]) }
820 }
821}
822
823#[cfg(not(target_arch = "spirv"))]
824impl AsMut<[f32; 4]> for Mat2 {
825 #[inline]
826 fn as_mut(&mut self) -> &mut [f32; 4] {
827 unsafe { &mut *(self as *mut Self as *mut [f32; 4]) }
828 }
829}
830
831impl core::ops::Deref for Mat2 {
832 type Target = crate::deref::Cols2<Vec2>;
833 #[inline]
834 fn deref(&self) -> &Self::Target {
835 unsafe { &*(self as *const Self as *const Self::Target) }
836 }
837}
838
839impl core::ops::DerefMut for Mat2 {
840 #[inline]
841 fn deref_mut(&mut self) -> &mut Self::Target {
842 unsafe { &mut *(self as *mut Self as *mut Self::Target) }
843 }
844}
845
846impl fmt::Debug for Mat2 {
847 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
848 fmt.debug_struct(stringify!(Mat2))
849 .field("x_axis", &self.x_axis)
850 .field("y_axis", &self.y_axis)
851 .finish()
852 }
853}
854
855impl fmt::Display for Mat2 {
856 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
857 if let Some(p) = f.precision() {
858 write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
859 } else {
860 write!(f, "[{}, {}]", self.x_axis, self.y_axis)
861 }
862 }
863}