2015-01-08 04:11:09 +08:00
|
|
|
#![macro_use]
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! submat_impl(
|
2016-04-17 23:26:58 +08:00
|
|
|
($t: ident, $submatrix: ident) => (
|
2013-10-06 22:54:09 +08:00
|
|
|
impl<N> $t<N> {
|
2016-03-25 02:04:01 +08:00
|
|
|
/// This rotation's underlying matrix.
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2016-05-06 21:08:06 +08:00
|
|
|
pub fn submatrix(&self) -> &$submatrix<N> {
|
2016-04-17 23:26:58 +08:00
|
|
|
&self.submatrix
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! rotate_impl(
|
2014-11-26 21:17:34 +08:00
|
|
|
($t: ident, $tv: ident, $tp: ident) => (
|
2014-12-18 06:28:32 +08:00
|
|
|
impl<N: BaseNum> Rotate<$tv<N>> for $t<N> {
|
2014-10-10 17:23:52 +08:00
|
|
|
#[inline]
|
2014-11-26 21:17:34 +08:00
|
|
|
fn rotate(&self, v: &$tv<N>) -> $tv<N> {
|
|
|
|
*self * *v
|
2014-10-10 17:23:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn inverse_rotate(&self, v: &$tv<N>) -> $tv<N> {
|
2014-11-26 21:17:34 +08:00
|
|
|
*v * *self
|
2014-10-10 17:23:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-18 06:28:32 +08:00
|
|
|
impl<N: BaseNum> Rotate<$tp<N>> for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2014-11-26 21:17:34 +08:00
|
|
|
fn rotate(&self, p: &$tp<N>) -> $tp<N> {
|
|
|
|
*self * *p
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn inverse_rotate(&self, p: &$tp<N>) -> $tp<N> {
|
2014-11-26 21:17:34 +08:00
|
|
|
*p * *self
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! transform_impl(
|
2014-11-26 21:17:34 +08:00
|
|
|
($t: ident, $tv: ident, $tp: ident) => (
|
2014-12-18 06:28:32 +08:00
|
|
|
impl<N: BaseNum> Transform<$tv<N>> for $t<N> {
|
2014-10-10 17:23:52 +08:00
|
|
|
#[inline]
|
2014-11-26 21:17:34 +08:00
|
|
|
fn transform(&self, v: &$tv<N>) -> $tv<N> {
|
|
|
|
self.rotate(v)
|
2014-10-10 17:23:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn inverse_transform(&self, v: &$tv<N>) -> $tv<N> {
|
|
|
|
self.inverse_rotate(v)
|
2014-10-10 17:23:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-18 06:28:32 +08:00
|
|
|
impl<N: BaseNum> Transform<$tp<N>> for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2014-11-26 21:17:34 +08:00
|
|
|
fn transform(&self, p: &$tp<N>) -> $tp<N> {
|
|
|
|
self.rotate(p)
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn inverse_transform(&self, p: &$tp<N>) -> $tp<N> {
|
|
|
|
self.inverse_rotate(p)
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! dim_impl(
|
2016-04-17 23:26:58 +08:00
|
|
|
($t: ident, $dimension: expr) => (
|
|
|
|
impl<N> Dimension for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn dimension(_: Option<$t<N>>) -> usize {
|
|
|
|
$dimension
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! rotation_matrix_impl(
|
|
|
|
($t: ident, $tlv: ident, $tav: ident) => (
|
2015-01-05 02:03:28 +08:00
|
|
|
impl<N: Zero + BaseNum + Cast<f64> + BaseFloat> RotationMatrix<N, $tlv<N>, $tav<N>> for $t<N> {
|
|
|
|
type Output = $t<N>;
|
|
|
|
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn to_rotation_matrix(&self) -> $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
self.clone()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! one_impl(
|
|
|
|
($t: ident) => (
|
2014-12-18 06:28:32 +08:00
|
|
|
impl<N: BaseNum> One for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
|
|
|
fn one() -> $t<N> {
|
2016-04-17 23:26:58 +08:00
|
|
|
$t { submatrix: ::one() }
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
2015-05-25 20:47:14 +08:00
|
|
|
macro_rules! eye_impl(
|
|
|
|
($t: ident) => (
|
|
|
|
impl<N: BaseNum> Eye for $t<N> {
|
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn new_identity(dimension: usize) -> $t<N> {
|
|
|
|
if dimension != ::dimension::<$t<N>>() {
|
|
|
|
panic!("Dimension mismatch: should be {}, got {}.", ::dimension::<$t<N>>(), dimension);
|
2015-05-25 20:47:14 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
::one()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
macro_rules! diag_impl(
|
|
|
|
($t: ident, $tv: ident) => (
|
2016-04-17 23:26:58 +08:00
|
|
|
impl<N: Copy + Zero> Diagonal<$tv<N>> for $t<N> {
|
2015-05-25 20:47:14 +08:00
|
|
|
#[inline]
|
2016-04-18 01:47:56 +08:00
|
|
|
fn from_diagonal(diagonal: &$tv<N>) -> $t<N> {
|
|
|
|
$t { submatrix: Diagonal::from_diagonal(diagonal) }
|
2015-05-25 20:47:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn diagonal(&self) -> $tv<N> {
|
|
|
|
self.submatrix.diagonal()
|
2015-05-25 20:47:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2016-04-17 23:26:58 +08:00
|
|
|
macro_rules! rotation_mul_rotation_impl(
|
2014-11-26 21:17:34 +08:00
|
|
|
($t: ident) => (
|
2015-01-05 02:03:28 +08:00
|
|
|
impl<N: BaseNum> Mul<$t<N>> for $t<N> {
|
|
|
|
type Output = $t<N>;
|
|
|
|
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2014-12-18 06:28:32 +08:00
|
|
|
fn mul(self, right: $t<N>) -> $t<N> {
|
2016-04-17 23:26:58 +08:00
|
|
|
$t { submatrix: self.submatrix * right.submatrix }
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
2016-04-17 18:57:54 +08:00
|
|
|
|
|
|
|
impl<N: Copy + BaseNum> MulAssign<$t<N>> for $t<N> {
|
|
|
|
#[inline]
|
|
|
|
fn mul_assign(&mut self, right: $t<N>) {
|
2016-04-17 23:26:58 +08:00
|
|
|
self.submatrix *= right.submatrix
|
2016-04-17 18:57:54 +08:00
|
|
|
}
|
|
|
|
}
|
2013-10-06 22:54:09 +08:00
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
2016-04-17 23:26:58 +08:00
|
|
|
macro_rules! rotation_mul_vec_impl(
|
2014-11-26 21:17:34 +08:00
|
|
|
($t: ident, $tv: ident) => (
|
2015-01-05 02:03:28 +08:00
|
|
|
impl<N: BaseNum> Mul<$tv<N>> for $t<N> {
|
|
|
|
type Output = $tv<N>;
|
|
|
|
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2014-12-18 06:28:32 +08:00
|
|
|
fn mul(self, right: $tv<N>) -> $tv<N> {
|
2016-04-17 23:26:58 +08:00
|
|
|
self.submatrix * right
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
2016-04-17 23:26:58 +08:00
|
|
|
macro_rules! rotation_mul_point_impl(
|
2014-11-26 21:17:34 +08:00
|
|
|
($t: ident, $tv: ident) => (
|
2016-04-17 23:26:58 +08:00
|
|
|
rotation_mul_vec_impl!($t, $tv);
|
2014-10-10 17:23:52 +08:00
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2014-10-10 17:23:52 +08:00
|
|
|
|
2016-04-17 23:26:58 +08:00
|
|
|
macro_rules! vec_mul_rotation_impl(
|
2014-11-26 21:17:34 +08:00
|
|
|
($t: ident, $tv: ident) => (
|
2015-01-05 02:03:28 +08:00
|
|
|
impl<N: BaseNum> Mul<$t<N>> for $tv<N> {
|
|
|
|
type Output = $tv<N>;
|
|
|
|
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2014-12-18 06:28:32 +08:00
|
|
|
fn mul(self, right: $t<N>) -> $tv<N> {
|
2016-04-17 23:26:58 +08:00
|
|
|
self * right.submatrix
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
2016-04-17 18:57:54 +08:00
|
|
|
|
|
|
|
impl<N: Copy + BaseNum> MulAssign<$t<N>> for $tv<N> {
|
|
|
|
#[inline]
|
|
|
|
fn mul_assign(&mut self, right: $t<N>) {
|
2016-04-17 23:26:58 +08:00
|
|
|
*self *= right.submatrix
|
2016-04-17 18:57:54 +08:00
|
|
|
}
|
|
|
|
}
|
2013-10-06 22:54:09 +08:00
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
2016-04-17 23:26:58 +08:00
|
|
|
macro_rules! point_mul_rotation_impl(
|
2014-11-26 21:17:34 +08:00
|
|
|
($t: ident, $tv: ident) => (
|
2016-04-17 23:26:58 +08:00
|
|
|
vec_mul_rotation_impl!($t, $tv);
|
2014-10-10 17:23:52 +08:00
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2014-10-10 17:23:52 +08:00
|
|
|
|
2016-04-17 23:26:58 +08:00
|
|
|
macro_rules! inverse_impl(
|
2013-10-06 22:54:09 +08:00
|
|
|
($t: ident) => (
|
2016-04-17 23:26:58 +08:00
|
|
|
impl<N: Copy> Inverse for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn inverse_mut(&mut self) -> bool {
|
2015-02-02 06:23:57 +08:00
|
|
|
self.transpose_mut();
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
// always succeed
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn inverse(&self) -> Option<$t<N>> {
|
2013-10-06 22:54:09 +08:00
|
|
|
// always succeed
|
2015-02-02 06:23:57 +08:00
|
|
|
Some(self.transpose())
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! transpose_impl(
|
|
|
|
($t: ident) => (
|
2014-12-18 06:28:32 +08:00
|
|
|
impl<N: Copy> Transpose for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2015-02-02 06:23:57 +08:00
|
|
|
fn transpose(&self) -> $t<N> {
|
2016-04-17 23:26:58 +08:00
|
|
|
$t { submatrix: Transpose::transpose(&self.submatrix) }
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2015-02-02 06:23:57 +08:00
|
|
|
fn transpose_mut(&mut self) {
|
2016-04-17 23:26:58 +08:00
|
|
|
self.submatrix.transpose_mut()
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! row_impl(
|
|
|
|
($t: ident, $tv: ident) => (
|
2014-12-18 06:28:32 +08:00
|
|
|
impl<N: Copy + Zero> Row<$tv<N>> for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2015-01-10 05:26:05 +08:00
|
|
|
fn nrows(&self) -> usize {
|
2016-04-17 23:26:58 +08:00
|
|
|
self.submatrix.nrows()
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
#[inline]
|
2015-01-10 05:26:05 +08:00
|
|
|
fn row(&self, i: usize) -> $tv<N> {
|
2016-04-17 23:26:58 +08:00
|
|
|
self.submatrix.row(i)
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2015-01-10 05:26:05 +08:00
|
|
|
fn set_row(&mut self, i: usize, row: $tv<N>) {
|
2016-04-17 23:26:58 +08:00
|
|
|
self.submatrix.set_row(i, row);
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
2016-04-18 14:29:22 +08:00
|
|
|
macro_rules! column_impl(
|
2013-10-06 22:54:09 +08:00
|
|
|
($t: ident, $tv: ident) => (
|
2016-04-17 23:26:58 +08:00
|
|
|
impl<N: Copy + Zero> Column<$tv<N>> for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2015-01-10 05:26:05 +08:00
|
|
|
fn ncols(&self) -> usize {
|
2016-04-17 23:26:58 +08:00
|
|
|
self.submatrix.ncols()
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
#[inline]
|
2016-04-17 23:26:58 +08:00
|
|
|
fn column(&self, i: usize) -> $tv<N> {
|
|
|
|
self.submatrix.column(i)
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-04-18 14:29:22 +08:00
|
|
|
fn set_column(&mut self, i: usize, column: $tv<N>) {
|
|
|
|
self.submatrix.set_column(i, column);
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
2014-09-18 10:20:36 +08:00
|
|
|
macro_rules! index_impl(
|
2014-10-26 05:02:16 +08:00
|
|
|
($t: ident) => (
|
2015-01-10 05:26:05 +08:00
|
|
|
impl<N> Index<(usize, usize)> for $t<N> {
|
2015-01-05 02:03:28 +08:00
|
|
|
type Output = N;
|
|
|
|
|
2015-03-26 05:36:19 +08:00
|
|
|
fn index(&self, i: (usize, usize)) -> &N {
|
2016-04-17 23:26:58 +08:00
|
|
|
&self.submatrix[i]
|
2014-09-18 10:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2014-09-18 10:20:36 +08:00
|
|
|
|
2013-10-06 22:54:09 +08:00
|
|
|
macro_rules! to_homogeneous_impl(
|
|
|
|
($t: ident, $tm: ident) => (
|
2014-12-18 06:28:32 +08:00
|
|
|
impl<N: BaseNum> ToHomogeneous<$tm<N>> for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2014-11-22 00:00:39 +08:00
|
|
|
fn to_homogeneous(&self) -> $tm<N> {
|
2016-04-17 23:26:58 +08:00
|
|
|
self.submatrix.to_homogeneous()
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! approx_eq_impl(
|
|
|
|
($t: ident) => (
|
|
|
|
impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> {
|
|
|
|
#[inline]
|
2014-01-10 03:48:30 +08:00
|
|
|
fn approx_epsilon(_: Option<$t<N>>) -> N {
|
|
|
|
ApproxEq::approx_epsilon(None::<N>)
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
|
2015-01-01 05:08:42 +08:00
|
|
|
#[inline]
|
|
|
|
fn approx_ulps(_: Option<$t<N>>) -> u32 {
|
|
|
|
ApproxEq::approx_ulps(None::<N>)
|
|
|
|
}
|
|
|
|
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2014-12-02 01:50:11 +08:00
|
|
|
fn approx_eq(&self, other: &$t<N>) -> bool {
|
2016-04-17 23:26:58 +08:00
|
|
|
ApproxEq::approx_eq(&self.submatrix, &other.submatrix)
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2014-12-02 01:50:11 +08:00
|
|
|
fn approx_eq_eps(&self, other: &$t<N>, epsilon: &N) -> bool {
|
2016-04-17 23:26:58 +08:00
|
|
|
ApproxEq::approx_eq_eps(&self.submatrix, &other.submatrix, epsilon)
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
2015-01-01 05:08:42 +08:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn approx_eq_ulps(&self, other: &$t<N>, ulps: u32) -> bool {
|
2016-04-17 23:26:58 +08:00
|
|
|
ApproxEq::approx_eq_ulps(&self.submatrix, &other.submatrix, ulps)
|
2015-01-01 05:08:42 +08:00
|
|
|
}
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2013-10-06 22:54:09 +08:00
|
|
|
|
|
|
|
macro_rules! absolute_impl(
|
|
|
|
($t: ident, $tm: ident) => (
|
2014-11-15 22:47:59 +08:00
|
|
|
impl<N: Absolute<N>> Absolute<$tm<N>> for $t<N> {
|
2013-10-06 22:54:09 +08:00
|
|
|
#[inline]
|
2013-10-17 03:44:33 +08:00
|
|
|
fn abs(m: &$t<N>) -> $tm<N> {
|
2016-04-17 23:26:58 +08:00
|
|
|
Absolute::abs(&m.submatrix)
|
2013-10-06 22:54:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2014-12-19 22:33:01 +08:00
|
|
|
);
|
2016-03-28 20:56:25 +08:00
|
|
|
|
2016-04-17 23:26:58 +08:00
|
|
|
macro_rules! rotation_display_impl(
|
2016-03-28 20:56:25 +08:00
|
|
|
($t: ident) => (
|
|
|
|
impl<N: fmt::Display + BaseFloat> fmt::Display for $t<N> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
let precision = f.precision().unwrap_or(3);
|
|
|
|
|
|
|
|
try!(writeln!(f, "Rotation matrix {{"));
|
2016-04-17 23:26:58 +08:00
|
|
|
try!(write!(f, "{:.*}", precision, self.submatrix));
|
2016-03-28 20:56:25 +08:00
|
|
|
writeln!(f, "}}")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|