mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-07-19 11:24:26 +08:00
a couple of fixes and cleaning
This commit is contained in:
parent
2033903376
commit
34c95029ca
@ -104,7 +104,7 @@ template<typename Derived> struct AnyMatrixBase
|
|||||||
* special matrix without having to modify MatrixBase */
|
* special matrix without having to modify MatrixBase */
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
Derived& MatrixBase<Derived>::operator=(const AnyMatrixBase<OtherDerived> &other)
|
Derived& DenseBase<Derived>::operator=(const AnyMatrixBase<OtherDerived> &other)
|
||||||
{
|
{
|
||||||
other.derived().evalTo(derived());
|
other.derived().evalTo(derived());
|
||||||
return derived();
|
return derived();
|
||||||
@ -112,7 +112,7 @@ Derived& MatrixBase<Derived>::operator=(const AnyMatrixBase<OtherDerived> &other
|
|||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
Derived& MatrixBase<Derived>::operator+=(const AnyMatrixBase<OtherDerived> &other)
|
Derived& DenseBase<Derived>::operator+=(const AnyMatrixBase<OtherDerived> &other)
|
||||||
{
|
{
|
||||||
other.derived().addToDense(derived());
|
other.derived().addToDense(derived());
|
||||||
return derived();
|
return derived();
|
||||||
@ -120,7 +120,7 @@ Derived& MatrixBase<Derived>::operator+=(const AnyMatrixBase<OtherDerived> &othe
|
|||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
Derived& MatrixBase<Derived>::operator-=(const AnyMatrixBase<OtherDerived> &other)
|
Derived& DenseBase<Derived>::operator-=(const AnyMatrixBase<OtherDerived> &other)
|
||||||
{
|
{
|
||||||
other.derived().subToDense(derived());
|
other.derived().subToDense(derived());
|
||||||
return derived();
|
return derived();
|
||||||
|
@ -434,7 +434,7 @@ template<typename Derived> class DenseBase
|
|||||||
* Combined with coeffRef() and the \ref flags flags, it allows a direct access to the data
|
* Combined with coeffRef() and the \ref flags flags, it allows a direct access to the data
|
||||||
* of the underlying matrix.
|
* of the underlying matrix.
|
||||||
*/
|
*/
|
||||||
inline int stride(void) const { return derived().stride(); }
|
inline int stride() const { return derived().stride(); }
|
||||||
|
|
||||||
inline const NestByValue<Derived> nestByValue() const;
|
inline const NestByValue<Derived> nestByValue() const;
|
||||||
inline const ForceAlignedAccess<Derived> forceAlignedAccess() const;
|
inline const ForceAlignedAccess<Derived> forceAlignedAccess() const;
|
||||||
|
@ -118,25 +118,6 @@ template<typename Derived> class MatrixBase
|
|||||||
* \sa rows(), cols(), SizeAtCompileTime. */
|
* \sa rows(), cols(), SizeAtCompileTime. */
|
||||||
inline int diagonalSize() const { return std::min(rows(),cols()); }
|
inline int diagonalSize() const { return std::min(rows(),cols()); }
|
||||||
|
|
||||||
/** Only plain matrices, not expressions may be resized; therefore the only useful resize method is
|
|
||||||
* Matrix::resize(). The present method only asserts that the new size equals the old size, and does
|
|
||||||
* nothing else.
|
|
||||||
*/
|
|
||||||
void resize(int size)
|
|
||||||
{
|
|
||||||
ei_assert(size == this->size()
|
|
||||||
&& "MatrixBase::resize() does not actually allow to resize.");
|
|
||||||
}
|
|
||||||
/** Only plain matrices, not expressions may be resized; therefore the only useful resize method is
|
|
||||||
* Matrix::resize(). The present method only asserts that the new size equals the old size, and does
|
|
||||||
* nothing else.
|
|
||||||
*/
|
|
||||||
void resize(int rows, int cols)
|
|
||||||
{
|
|
||||||
ei_assert(rows == this->rows() && cols == this->cols()
|
|
||||||
&& "MatrixBase::resize() does not actually allow to resize.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||||
/** \internal the plain matrix type corresponding to this expression. Note that is not necessarily
|
/** \internal the plain matrix type corresponding to this expression. Note that is not necessarily
|
||||||
* exactly the return type of eval(): in the case of plain matrices, the return type of eval() is a const
|
* exactly the return type of eval(): in the case of plain matrices, the return type of eval() is a const
|
||||||
@ -180,41 +161,24 @@ template<typename Derived> class MatrixBase
|
|||||||
ei_traits<Derived>::ColsAtCompileTime> BasisReturnType;
|
ei_traits<Derived>::ColsAtCompileTime> BasisReturnType;
|
||||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||||
|
|
||||||
#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase
|
#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase
|
||||||
#include "../plugins/CommonCwiseUnaryOps.h"
|
# include "../plugins/CommonCwiseUnaryOps.h"
|
||||||
#include "../plugins/CommonCwiseBinaryOps.h"
|
# include "../plugins/CommonCwiseBinaryOps.h"
|
||||||
#include "../plugins/MatrixCwiseUnaryOps.h"
|
# include "../plugins/MatrixCwiseUnaryOps.h"
|
||||||
#include "../plugins/MatrixCwiseBinaryOps.h"
|
# include "../plugins/MatrixCwiseBinaryOps.h"
|
||||||
#undef EIGEN_CURRENT_STORAGE_BASE_CLASS
|
# ifdef EIGEN_MATRIXBASE_PLUGIN
|
||||||
|
# include EIGEN_MATRIXBASE_PLUGIN
|
||||||
|
# endif
|
||||||
|
#undef EIGEN_CURRENT_STORAGE_BASE_CLASS
|
||||||
|
|
||||||
/** Special case of the template operator=, in order to prevent the compiler
|
/** Special case of the template operator=, in order to prevent the compiler
|
||||||
* from generating a default operator= (issue hit with g++ 4.1)
|
* from generating a default operator= (issue hit with g++ 4.1)
|
||||||
*/
|
*/
|
||||||
Derived& operator=(const MatrixBase& other);
|
Derived& operator=(const MatrixBase& other);
|
||||||
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Derived& operator=(const AnyMatrixBase<OtherDerived> &other);
|
|
||||||
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Derived& operator+=(const AnyMatrixBase<OtherDerived> &other);
|
|
||||||
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Derived& operator-=(const AnyMatrixBase<OtherDerived> &other);
|
|
||||||
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Derived& operator=(const ReturnByValue<OtherDerived>& func);
|
|
||||||
|
|
||||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||||
template<typename ProductDerived, typename Lhs, typename Rhs>
|
template<typename ProductDerived, typename Lhs, typename Rhs>
|
||||||
Derived& lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other);
|
Derived& lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other);
|
||||||
|
|
||||||
template<typename ProductDerived, typename Lhs, typename Rhs>
|
|
||||||
Derived& operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
|
|
||||||
EvalBeforeAssigningBit>& other);
|
|
||||||
|
|
||||||
template<typename ProductDerived, typename Lhs, typename Rhs>
|
|
||||||
Derived& operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
|
|
||||||
EvalBeforeAssigningBit>& other);
|
|
||||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||||
|
|
||||||
const CoeffReturnType x() const;
|
const CoeffReturnType x() const;
|
||||||
@ -306,10 +270,18 @@ template<typename Derived> class MatrixBase
|
|||||||
RealScalar prec = precision<Scalar>()) const;
|
RealScalar prec = precision<Scalar>()) const;
|
||||||
bool isUnitary(RealScalar prec = precision<Scalar>()) const;
|
bool isUnitary(RealScalar prec = precision<Scalar>()) const;
|
||||||
|
|
||||||
|
/** \returns true if each coefficients of \c *this and \a other are all exactly equal.
|
||||||
|
* \warning When using floating point scalar values you probably should rather use a
|
||||||
|
* fuzzy comparison such as isApprox()
|
||||||
|
* \sa isApprox(), operator!= */
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
inline bool operator==(const MatrixBase<OtherDerived>& other) const
|
inline bool operator==(const MatrixBase<OtherDerived>& other) const
|
||||||
{ return cwiseEqual(other).all(); }
|
{ return cwiseEqual(other).all(); }
|
||||||
|
|
||||||
|
/** \returns true if at least one pair of coefficients of \c *this and \a other are not exactly equal to each other.
|
||||||
|
* \warning When using floating point scalar values you probably should rather use a
|
||||||
|
* fuzzy comparison such as isApprox()
|
||||||
|
* \sa isApprox(), operator== */
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
inline bool operator!=(const MatrixBase<OtherDerived>& other) const
|
inline bool operator!=(const MatrixBase<OtherDerived>& other) const
|
||||||
{ return cwiseNotEqual(other).all(); }
|
{ return cwiseNotEqual(other).all(); }
|
||||||
@ -328,13 +300,6 @@ template<typename Derived> class MatrixBase
|
|||||||
|
|
||||||
NoAlias<Derived,Eigen::MatrixBase > noalias();
|
NoAlias<Derived,Eigen::MatrixBase > noalias();
|
||||||
|
|
||||||
/** \returns number of elements to skip to pass from one row (resp. column) to another
|
|
||||||
* for a row-major (resp. column-major) matrix.
|
|
||||||
* Combined with coeffRef() and the \ref flags flags, it allows a direct access to the data
|
|
||||||
* of the underlying matrix.
|
|
||||||
*/
|
|
||||||
inline int stride(void) const { return derived().stride(); }
|
|
||||||
|
|
||||||
inline const NestByValue<Derived> nestByValue() const;
|
inline const NestByValue<Derived> nestByValue() const;
|
||||||
inline const ForceAlignedAccess<Derived> forceAlignedAccess() const;
|
inline const ForceAlignedAccess<Derived> forceAlignedAccess() const;
|
||||||
inline ForceAlignedAccess<Derived> forceAlignedAccess();
|
inline ForceAlignedAccess<Derived> forceAlignedAccess();
|
||||||
@ -439,11 +404,15 @@ template<typename Derived> class MatrixBase
|
|||||||
template<typename OtherScalar>
|
template<typename OtherScalar>
|
||||||
void applyOnTheRight(int p, int q, const PlanarRotation<OtherScalar>& j);
|
void applyOnTheRight(int p, int q, const PlanarRotation<OtherScalar>& j);
|
||||||
|
|
||||||
#ifdef EIGEN_MATRIXBASE_PLUGIN
|
|
||||||
#include EIGEN_MATRIXBASE_PLUGIN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef EIGEN2_SUPPORT
|
#ifdef EIGEN2_SUPPORT
|
||||||
|
template<typename ProductDerived, typename Lhs, typename Rhs>
|
||||||
|
Derived& operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
|
||||||
|
EvalBeforeAssigningBit>& other);
|
||||||
|
|
||||||
|
template<typename ProductDerived, typename Lhs, typename Rhs>
|
||||||
|
Derived& operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
|
||||||
|
EvalBeforeAssigningBit>& other);
|
||||||
|
|
||||||
/** \deprecated because .lazy() is deprecated
|
/** \deprecated because .lazy() is deprecated
|
||||||
* Overloaded for cache friendly product evaluation */
|
* Overloaded for cache friendly product evaluation */
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
@ -457,11 +426,6 @@ template<typename Derived> class MatrixBase
|
|||||||
inline const Cwise<Derived> cwise() const;
|
inline const Cwise<Derived> cwise() const;
|
||||||
inline Cwise<Derived> cwise();
|
inline Cwise<Derived> cwise();
|
||||||
|
|
||||||
// a workaround waiting the Array class
|
|
||||||
// inline const Cwise<Derived> array() const { return cwise(); }
|
|
||||||
// a workaround waiting the Array class
|
|
||||||
// inline Cwise<Derived> array() { return cwise(); }
|
|
||||||
|
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
typename ei_plain_matrix_type_column_major<OtherDerived>::type
|
typename ei_plain_matrix_type_column_major<OtherDerived>::type
|
||||||
solveTriangular(const MatrixBase<OtherDerived>& other) const;
|
solveTriangular(const MatrixBase<OtherDerived>& other) const;
|
||||||
|
@ -223,27 +223,9 @@ template<typename Derived>
|
|||||||
template<typename ProductDerived, typename Lhs, typename Rhs>
|
template<typename ProductDerived, typename Lhs, typename Rhs>
|
||||||
Derived& MatrixBase<Derived>::lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other)
|
Derived& MatrixBase<Derived>::lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other)
|
||||||
{
|
{
|
||||||
other.derived().evalTo(derived()); return derived();
|
other.derived().evalTo(derived());
|
||||||
|
return derived();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \internal
|
|
||||||
* Overloaded to perform an efficient C += (A*B).lazy() */
|
|
||||||
template<typename Derived>
|
|
||||||
template<typename ProductDerived, typename Lhs, typename Rhs>
|
|
||||||
Derived& MatrixBase<Derived>::operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
|
|
||||||
EvalBeforeAssigningBit>& other)
|
|
||||||
{
|
|
||||||
other._expression().derived().addTo(derived()); return derived();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \internal
|
|
||||||
* Overloaded to perform an efficient C -= (A*B).lazy() */
|
|
||||||
template<typename Derived>
|
|
||||||
template<typename ProductDerived, typename Lhs, typename Rhs>
|
|
||||||
Derived& MatrixBase<Derived>::operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
|
|
||||||
EvalBeforeAssigningBit>& other)
|
|
||||||
{
|
|
||||||
other._expression().derived().subTo(derived()); return derived();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // EIGEN_PRODUCTBASE_H
|
#endif // EIGEN_PRODUCTBASE_H
|
||||||
|
@ -72,7 +72,7 @@ template<typename Derived>
|
|||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
Derived& MatrixBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other)
|
Derived& DenseBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other)
|
||||||
{
|
{
|
||||||
other.evalTo(derived());
|
other.evalTo(derived());
|
||||||
return derived();
|
return derived();
|
||||||
|
@ -203,7 +203,7 @@ struct ei_triangular_solver_selector<Lhs,Rhs,OnTheLeft,Mode,CompleteUnrolling,St
|
|||||||
* TriangularView methods
|
* TriangularView methods
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/** "in-place" version of MatrixBase::solveTriangular() where the result is written in \a other
|
/** "in-place" version of TriangularView::solve() where the result is written in \a other
|
||||||
*
|
*
|
||||||
* \nonstableyet
|
* \nonstableyet
|
||||||
*
|
*
|
||||||
|
@ -146,4 +146,25 @@ MatrixBase<Derived>::lazy() const
|
|||||||
return derived();
|
return derived();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \internal
|
||||||
|
* Overloaded to perform an efficient C += (A*B).lazy() */
|
||||||
|
template<typename Derived>
|
||||||
|
template<typename ProductDerived, typename Lhs, typename Rhs>
|
||||||
|
Derived& MatrixBase<Derived>::operator+=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
|
||||||
|
EvalBeforeAssigningBit>& other)
|
||||||
|
{
|
||||||
|
other._expression().derived().addTo(derived()); return derived();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \internal
|
||||||
|
* Overloaded to perform an efficient C -= (A*B).lazy() */
|
||||||
|
template<typename Derived>
|
||||||
|
template<typename ProductDerived, typename Lhs, typename Rhs>
|
||||||
|
Derived& MatrixBase<Derived>::operator-=(const Flagged<ProductBase<ProductDerived, Lhs,Rhs>, 0,
|
||||||
|
EvalBeforeAssigningBit>& other)
|
||||||
|
{
|
||||||
|
other._expression().derived().subTo(derived()); return derived();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // EIGEN_FLAGGED_H
|
#endif // EIGEN_FLAGGED_H
|
||||||
|
@ -58,30 +58,30 @@ template<typename MatrixType> void linearStructure(const MatrixType& m)
|
|||||||
VERIFY_IS_APPROX((-m1+m2)*s1, -s1*m1+s1*m2);
|
VERIFY_IS_APPROX((-m1+m2)*s1, -s1*m1+s1*m2);
|
||||||
m3 = m2; m3 += m1;
|
m3 = m2; m3 += m1;
|
||||||
VERIFY_IS_APPROX(m3, m1+m2);
|
VERIFY_IS_APPROX(m3, m1+m2);
|
||||||
// m3 = m2; m3 -= m1;
|
m3 = m2; m3 -= m1;
|
||||||
// VERIFY_IS_APPROX(m3, m2-m1);
|
VERIFY_IS_APPROX(m3, m2-m1);
|
||||||
// m3 = m2; m3 *= s1;
|
m3 = m2; m3 *= s1;
|
||||||
// VERIFY_IS_APPROX(m3, s1*m2);
|
VERIFY_IS_APPROX(m3, s1*m2);
|
||||||
// if(NumTraits<Scalar>::HasFloatingPoint)
|
if(NumTraits<Scalar>::HasFloatingPoint)
|
||||||
// {
|
{
|
||||||
// m3 = m2; m3 /= s1;
|
m3 = m2; m3 /= s1;
|
||||||
// VERIFY_IS_APPROX(m3, m2/s1);
|
VERIFY_IS_APPROX(m3, m2/s1);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // again, test operator() to check const-qualification
|
// again, test operator() to check const-qualification
|
||||||
// VERIFY_IS_APPROX((-m1)(r,c), -(m1(r,c)));
|
VERIFY_IS_APPROX((-m1)(r,c), -(m1(r,c)));
|
||||||
// VERIFY_IS_APPROX((m1-m2)(r,c), (m1(r,c))-(m2(r,c)));
|
VERIFY_IS_APPROX((m1-m2)(r,c), (m1(r,c))-(m2(r,c)));
|
||||||
// VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
|
VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
|
||||||
// VERIFY_IS_APPROX((s1*m1)(r,c), s1*(m1(r,c)));
|
VERIFY_IS_APPROX((s1*m1)(r,c), s1*(m1(r,c)));
|
||||||
// VERIFY_IS_APPROX((m1*s1)(r,c), (m1(r,c))*s1);
|
VERIFY_IS_APPROX((m1*s1)(r,c), (m1(r,c))*s1);
|
||||||
// if(NumTraits<Scalar>::HasFloatingPoint)
|
if(NumTraits<Scalar>::HasFloatingPoint)
|
||||||
// VERIFY_IS_APPROX((m1/s1)(r,c), (m1(r,c))/s1);
|
VERIFY_IS_APPROX((m1/s1)(r,c), (m1(r,c))/s1);
|
||||||
//
|
|
||||||
// // use .block to disable vectorization and compare to the vectorized version
|
// use .block to disable vectorization and compare to the vectorized version
|
||||||
// VERIFY_IS_APPROX(m1+m1.block(0,0,rows,cols), m1+m1);
|
VERIFY_IS_APPROX(m1+m1.block(0,0,rows,cols), m1+m1);
|
||||||
// VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0,0,rows,cols)), m1.cwiseProduct(m1));
|
VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0,0,rows,cols)), m1.cwiseProduct(m1));
|
||||||
// VERIFY_IS_APPROX(m1 - m1.block(0,0,rows,cols), m1 - m1);
|
VERIFY_IS_APPROX(m1 - m1.block(0,0,rows,cols), m1 - m1);
|
||||||
// VERIFY_IS_APPROX(m1.block(0,0,rows,cols) * s1, m1 * s1);
|
VERIFY_IS_APPROX(m1.block(0,0,rows,cols) * s1, m1 * s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_linearstructure()
|
void test_linearstructure()
|
||||||
|
@ -64,7 +64,7 @@ template<typename MatrixType> void nomalloc(const MatrixType& m)
|
|||||||
|
|
||||||
VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
|
VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
|
||||||
VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
|
VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
|
||||||
VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0,0,rows,cols)), (m1.array()*m1.array()));
|
VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0,0,rows,cols)), (m1.array()*m1.array()).asMatrix());
|
||||||
if (MatrixType::RowsAtCompileTime<EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD) {
|
if (MatrixType::RowsAtCompileTime<EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD) {
|
||||||
// If the matrices are too large, we have better to use the optimized GEMM
|
// If the matrices are too large, we have better to use the optimized GEMM
|
||||||
// routines which allocates temporaries. However, on some platforms
|
// routines which allocates temporaries. However, on some platforms
|
||||||
|
Loading…
x
Reference in New Issue
Block a user