Unverified Commit 39eecb1f authored by Justin Carpentier's avatar Justin Carpentier Committed by GitHub
Browse files

Merge pull request #154 from jcarpent/devel

core: revert previous settings
parents 17f37527 a4e857e4
language: python
sudo: required
git:
depth: false
compiler:
- gcc
# - clang
......
......@@ -141,6 +141,14 @@ SET(${PROJECT_NAME}_SOURCES
${${PROJECT_NAME}_DECOMPOSITIONS_SOURCES}
src/exception.cpp
src/eigenpy.cpp
src/matrix-float.cpp
src/matrix-complex-float.cpp
src/matrix-complex-double.cpp
src/matrix-double.cpp
src/matrix-long-double.cpp
src/matrix-complex-long-double.cpp
src/matrix-int.cpp
src/matrix-long.cpp
src/angle-axis.cpp
src/quaternion.cpp
src/geometry-conversion.cpp
......
......@@ -111,10 +111,14 @@ namespace eigenpy
struct CastMatToMat
{
template<typename MatrixIn, typename MatrixOut>
static void run(const Eigen::MatrixBase<MatrixIn> & input, const Eigen::MatrixBase<MatrixOut> & dest)
static void run(const Eigen::MatrixBase<MatrixIn> & input,
const Eigen::MatrixBase<MatrixOut> & dest)
{
MatrixOut & dest_ = const_cast<MatrixOut &>(dest.derived());
dest_ = input.template cast<NewScalar>();
if(dest.rows() == input.rows())
dest_ = input.template cast<NewScalar>();
else
dest_ = input.transpose().template cast<NewScalar>();
}
};
......@@ -126,6 +130,7 @@ namespace eigenpy
const Eigen::MatrixBase<MatrixOut> & /*dest*/)
{
// do nothing
assert("Must never happened");
}
};
......@@ -192,9 +197,15 @@ namespace eigenpy
const MatrixDerived & mat = const_cast<const MatrixDerived &>(mat_.derived());
const int pyArray_Type = GET_PY_ARRAY_TYPE(pyArray);
if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code)
typedef typename MapNumpy<MatType,Scalar>::EigenMap MapType;
if(pyArray_Type == NumpyEquivalentType<Scalar>::type_code) // no cast needed
{
MapNumpy<MatType,Scalar>::map(pyArray) = mat; // no cast needed
MapType map_pyArray = MapNumpy<MatType,Scalar>::map(pyArray);
if(mat.rows() == map_pyArray.rows())
map_pyArray = mat;
else
map_pyArray = mat.transpose();
return;
}
......@@ -260,13 +271,14 @@ namespace eigenpy
typedef typename MatType::Scalar Scalar;
assert( (mat.rows()<INT_MAX) && (mat.cols()<INT_MAX)
&& "Matrix range larger than int ... should never happen." );
const int R = (int)mat.rows(), C = (int)mat.cols();
const npy_intp R = (npy_intp)mat.rows(), C = (npy_intp)mat.cols();
PyArrayObject* pyArray;
// Allocate Python memory
if(C == 1 && NumpyType::getType() == ARRAY_TYPE && MatType::IsVectorAtCompileTime) // Handle array with a single dimension
if( ( (((C == 1) xor (R == 1)) && !MatType::IsVectorAtCompileTime) || MatType::IsVectorAtCompileTime)
&& NumpyType::getType() == ARRAY_TYPE) // Handle array with a single dimension
{
npy_intp shape[1] = { R };
npy_intp shape[1] = { C == 1 ? R : C };
pyArray = (PyArrayObject*) PyArray_SimpleNew(1, shape,
NumpyEquivalentType<Scalar>::type_code);
}
......
......@@ -24,12 +24,38 @@
#endif // if EIGEN_VERSION_AT_LEAST(3,2,0)
#define EIGENPY_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \
/** \ingroup matrixtypedefs */ \
typedef Eigen::Matrix<Type, Size, Size> Matrix##SizeSuffix##TypeSuffix; \
/** \ingroup matrixtypedefs */ \
typedef Eigen::Matrix<Type, Size, 1> Vector##SizeSuffix##TypeSuffix; \
/** \ingroup matrixtypedefs */ \
typedef Eigen::Matrix<Type, 1, Size> RowVector##SizeSuffix##TypeSuffix;
#define EIGENPY_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \
/** \ingroup matrixtypedefs */ \
typedef Eigen::Matrix<Type, Size, Eigen::Dynamic> Matrix##Size##X##TypeSuffix; \
/** \ingroup matrixtypedefs */ \
typedef Eigen::Matrix<Type, Eigen::Dynamic, Size> Matrix##X##Size##TypeSuffix;
#define EIGENPY_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \
EIGENPY_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \
EIGENPY_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \
EIGENPY_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \
EIGENPY_MAKE_TYPEDEFS(Type, TypeSuffix, Eigen::Dynamic, X) \
EIGENPY_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \
EIGENPY_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \
EIGENPY_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 4)
namespace eigenpy
{
/* Enable Eigen-Numpy serialization for a set of standard MatrixBase instance. */
void EIGENPY_DLLEXPORT enableEigenPy();
/* Enable the Eigen--Numpy serialization for the templated MatrixBase class.
* The second template argument is used for inheritance of Eigen classes. If
* using a native Eigen::MatrixBase, simply repeat the same arg twice. */
template<typename MatType>
void enableEigenPySpecific();
......@@ -39,10 +65,36 @@ namespace eigenpy
template<typename MatType,typename EigenEquivalentType>
EIGENPY_DEPRECATED void enableEigenPySpecific();
template<typename Scalar>
EIGEN_DONT_INLINE void exposeType()
{
EIGENPY_MAKE_TYPEDEFS_ALL_SIZES(Scalar,s);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2s);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector2s);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2s);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2Xs);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX2s);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3s);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector3s);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3s);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3Xs);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX3s);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4s);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector4s);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4s);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4Xs);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX4s);
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXs);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVectorXs);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXs);
}
} // namespace eigenpy
#include "eigenpy/details.hpp"
#endif // ifndef __eigenpy_eigenpy_hpp__
......@@ -6,38 +6,6 @@
#include "eigenpy/eigenpy.hpp"
#include <stdlib.h>
namespace Eigen
{
#define EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \
/** \ingroup matrixtypedefs */ \
typedef Matrix<Type, Size, Size> Matrix##SizeSuffix##TypeSuffix; \
/** \ingroup matrixtypedefs */ \
typedef Matrix<Type, Size, 1> Vector##SizeSuffix##TypeSuffix; \
/** \ingroup matrixtypedefs */ \
typedef Matrix<Type, 1, Size> RowVector##SizeSuffix##TypeSuffix;
#define EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \
/** \ingroup matrixtypedefs */ \
typedef Matrix<Type, Size, Dynamic> Matrix##Size##X##TypeSuffix; \
/** \ingroup matrixtypedefs */ \
typedef Matrix<Type, Dynamic, Size> Matrix##X##Size##TypeSuffix;
#define EIGEN_MAKE_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \
EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 2, 2) \
EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 3, 3) \
EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, 4, 4) \
EIGEN_MAKE_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \
EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \
EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \
EIGEN_MAKE_FIXED_TYPEDEFS(Type, TypeSuffix, 4)
EIGEN_MAKE_TYPEDEFS_ALL_SIZES(long double, ld)
EIGEN_MAKE_TYPEDEFS_ALL_SIZES(std::complex<long double>, cld)
#undef EIGEN_MAKE_TYPEDEFS_ALL_SIZES
#undef EIGEN_MAKE_TYPEDEFS
#undef EIGEN_MAKE_FIXED_TYPEDEFS
}
namespace eigenpy
{
......@@ -47,6 +15,16 @@ namespace eigenpy
srand(seed_value);
}
void exposeMatrixInt();
void exposeMatrixLong();
void exposeMatrixFloat();
void exposeMatrixDouble();
void exposeMatrixLongDouble();
void exposeMatrixComplexFloat();
void exposeMatrixComplexDouble();
void exposeMatrixComplexLongDouble();
/* Enable Eigen-Numpy serialization for a set of standard MatrixBase instances. */
void enableEigenPy()
{
......@@ -70,147 +48,15 @@ namespace eigenpy
bp::def("seed",&seed,bp::arg("seed_value"),
"Initialize the pseudo-random number generator with the argument seed_value.");
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2ld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2d);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2f);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2i);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2cf);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2cd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2cld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2Xld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2Xd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2Xf);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2Xi);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2Xcf);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2Xcd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix2Xcld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3ld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3d);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3f);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3i);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3cf);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3cd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3cld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3Xd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3Xf);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3Xi);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3Xcf);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3Xcd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix3Xcld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4ld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4d);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4f);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4i);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4cf);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4cd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4cld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4Xld);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4Xd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4Xf);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4Xi);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4Xcf);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4Xcd);
ENABLE_SPECIFIC_MATRIX_TYPE(Matrix4Xcld);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX2ld);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX2d);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX2f);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX2i);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX2cf);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX2cd);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX2cld);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX3ld);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX3d);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX3f);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX3i);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX3cf);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX3cd);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX3cld);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX4ld);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX4d);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX4f);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX4i);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX4cf);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX4cd);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixX4cld);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXld);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXd);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXf);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXi);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXcf);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXcd);
ENABLE_SPECIFIC_MATRIX_TYPE(MatrixXcld);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector2ld);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector2d);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector2f);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector2i);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector2cf);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector2cd);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector3ld);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector3d);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector3f);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector3i);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector3cf);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector3cd);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector3cld);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector4ld);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector4d);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector4f);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector4i);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector4cf);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector4cd);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVector4cld);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVectorXld);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVectorXd);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVectorXf);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVectorXi);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVectorXcf);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVectorXcd);
ENABLE_SPECIFIC_MATRIX_TYPE(RowVectorXcld);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2ld);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2d);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2f);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2i);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2cf);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2cd);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector2cld);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3ld);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3d);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3f);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3i);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3cf);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3cd);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector3cld);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4ld);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4d);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4f);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4i);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4cf);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4cd);
ENABLE_SPECIFIC_MATRIX_TYPE(Vector4cld);
exposeMatrixInt();
exposeMatrixLong();
exposeMatrixFloat();
exposeMatrixDouble();
exposeMatrixLongDouble();
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXld);
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXd);
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXf);
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXi);
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXcf);
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXcd);
ENABLE_SPECIFIC_MATRIX_TYPE(VectorXcld);
exposeMatrixComplexFloat();
exposeMatrixComplexDouble();
exposeMatrixComplexLongDouble();
}
} // namespace eigenpy
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy
{
void exposeMatrixComplexDouble()
{
exposeType<std::complex<double> >();
}
}
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy
{
void exposeMatrixComplexFloat()
{
exposeType<std::complex<float> >();
}
}
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy
{
void exposeMatrixComplexLongDouble()
{
exposeType<std::complex<long double> >();
}
}
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy
{
void exposeMatrixDouble()
{
exposeType<double>();
}
}
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy
{
void exposeMatrixFloat()
{
exposeType<float>();
}
}
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy
{
void exposeMatrixInt()
{
exposeType<int>();
}
}
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy
{
void exposeMatrixLongDouble()
{
exposeType<long double>();
}
}
/*
* Copyright 2020 INRIA
*/
#include "eigenpy/eigenpy.hpp"
namespace eigenpy
{
void exposeMatrixLong()
{
exposeType<long>();
}
}
......@@ -62,19 +62,19 @@ assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block Vector 1x0:6:2")
M = Mref[1:2,0:6:2]
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
assert( np.array_equal(M.squeeze(),eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block Vector 1x0:6:2 tanspose")
M = Mref[1:2,0:6:2].T
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
assert( np.array_equal(M.squeeze(),eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block Vector 0:6:2x1")
M = Mref[0:6:2,1:2]
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
assert( np.array_equal(M.squeeze(),eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block Vector 0:6:2x1 tanspose")
M = Mref[0:6:2,1:2].T
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
assert( np.array_equal(M.squeeze(),eigenpy.reflex(M,verbose)) );
if verbose: print("===> From Py to Eigen::VectorXd")
if verbose: print("===> From Py to Eigen::VectorXd")
......@@ -87,7 +87,7 @@ M = Mref[0:6:2,1].T
if verbose: print("===> Block Vector 0:6:2x1")
M = Mref[0:6:2,1:2]
assert( np.array_equal(M,eigenpy.reflexV(M,verbose)) );
assert( np.array_equal(M.squeeze(),eigenpy.reflexV(M,verbose)) );
if verbose: print("===> Block Vector 0:6:2x1 transpose")
M = Mref[0:6:2,1:2].T
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment