mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-03 01:50:24 +08:00
fixed some warnings in Windows
fixed Transform::getNorm() git-svn-id: http://rtabmap.googlecode.com/svn/trunk/rtabmap@1436 f169173b-cf89-36c8-b27e-44dbe73f0c83
This commit is contained in:
@@ -74,7 +74,7 @@ public:
|
|||||||
bool addLoopClosureLink(int oldId, int newId, const Transform & transform, bool global);
|
bool addLoopClosureLink(int oldId, int newId, const Transform & transform, bool global);
|
||||||
void updateNeighborLink(int fromId, int toId, const Transform & transform);
|
void updateNeighborLink(int fromId, int toId, const Transform & transform);
|
||||||
std::map<int, int> getNeighborsId(int signatureId,
|
std::map<int, int> getNeighborsId(int signatureId,
|
||||||
unsigned int margin,
|
int margin,
|
||||||
int maxCheckedInDatabase = -1,
|
int maxCheckedInDatabase = -1,
|
||||||
bool incrementMarginOnLoop = false,
|
bool incrementMarginOnLoop = false,
|
||||||
bool ignoreLoopIds = false,
|
bool ignoreLoopIds = false,
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ pcl::PolygonMesh::Ptr RTABMAP_EXP createMesh(
|
|||||||
float gp3MaximumSurfaceAngle = M_PI/4,
|
float gp3MaximumSurfaceAngle = M_PI/4,
|
||||||
float gp3MinimumAngle = M_PI/18,
|
float gp3MinimumAngle = M_PI/18,
|
||||||
float gp3MaximumAngle = 2*M_PI/3,
|
float gp3MaximumAngle = 2*M_PI/3,
|
||||||
float gp3NormalConsistency = false);
|
bool gp3NormalConsistency = false);
|
||||||
|
|
||||||
void RTABMAP_EXP optimizeTOROGraph(
|
void RTABMAP_EXP optimizeTOROGraph(
|
||||||
const std::map<int, Transform> & poses,
|
const std::map<int, Transform> & poses,
|
||||||
|
|||||||
@@ -187,7 +187,8 @@ cv::Mat CameraImages::captureImage()
|
|||||||
if(fileName.size())
|
if(fileName.size())
|
||||||
{
|
{
|
||||||
ULOGGER_DEBUG("Loading image : %s", fullPath.c_str());
|
ULOGGER_DEBUG("Loading image : %s", fullPath.c_str());
|
||||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
|
||||||
|
#if CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4
|
||||||
img = cv::imread(fullPath.c_str(), cv::IMREAD_UNCHANGED);
|
img = cv::imread(fullPath.c_str(), cv::IMREAD_UNCHANGED);
|
||||||
#else
|
#else
|
||||||
img = cv::imread(fullPath.c_str(), -1);
|
img = cv::imread(fullPath.c_str(), -1);
|
||||||
|
|||||||
@@ -28,7 +28,8 @@
|
|||||||
#include <opencv2/imgproc/imgproc_c.h>
|
#include <opencv2/imgproc/imgproc_c.h>
|
||||||
#include <opencv2/gpu/gpu.hpp>
|
#include <opencv2/gpu/gpu.hpp>
|
||||||
#include <opencv2/core/version.hpp>
|
#include <opencv2/core/version.hpp>
|
||||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
|
||||||
|
#if CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4
|
||||||
#include <opencv2/nonfree/gpu.hpp>
|
#include <opencv2/nonfree/gpu.hpp>
|
||||||
#include <opencv2/nonfree/features2d.hpp>
|
#include <opencv2/nonfree/features2d.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -712,13 +712,14 @@ std::map<int, Transform> Memory::getNeighborLinks(int signatureId, bool ignoreNe
|
|||||||
// maxCheckedInDatabase = -1 means no limit to check in database (default)
|
// maxCheckedInDatabase = -1 means no limit to check in database (default)
|
||||||
// maxCheckedInDatabase = 0 means don't check in database
|
// maxCheckedInDatabase = 0 means don't check in database
|
||||||
std::map<int, int> Memory::getNeighborsId(int signatureId,
|
std::map<int, int> Memory::getNeighborsId(int signatureId,
|
||||||
unsigned int margin, // 0 means infinite margin
|
int margin, // 0 means infinite margin
|
||||||
int maxCheckedInDatabase, // default -1 (no limit)
|
int maxCheckedInDatabase, // default -1 (no limit)
|
||||||
bool incrementMarginOnLoop, // default false
|
bool incrementMarginOnLoop, // default false
|
||||||
bool ignoreLoopIds, // default false
|
bool ignoreLoopIds, // default false
|
||||||
double * dbAccessTime
|
double * dbAccessTime
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
|
UASSERT(margin >= 0);
|
||||||
//UDEBUG("signatureId=%d, neighborsMargin=%d", signatureId, margin);
|
//UDEBUG("signatureId=%d, neighborsMargin=%d", signatureId, margin);
|
||||||
if(dbAccessTime)
|
if(dbAccessTime)
|
||||||
{
|
{
|
||||||
@@ -734,7 +735,7 @@ std::map<int, int> Memory::getNeighborsId(int signatureId,
|
|||||||
std::set<int> currentMargin;
|
std::set<int> currentMargin;
|
||||||
std::set<int> nextMargin;
|
std::set<int> nextMargin;
|
||||||
nextMargin.insert(signatureId);
|
nextMargin.insert(signatureId);
|
||||||
unsigned int m = 0;
|
int m = 0;
|
||||||
while((margin == 0 || m < margin) && nextMargin.size())
|
while((margin == 0 || m < margin) && nextMargin.size())
|
||||||
{
|
{
|
||||||
curentMarginList = std::list<int>(nextMargin.begin(), nextMargin.end());
|
curentMarginList = std::list<int>(nextMargin.begin(), nextMargin.end());
|
||||||
|
|||||||
@@ -1094,8 +1094,9 @@ bool Rtabmap::process(const Image & image)
|
|||||||
{
|
{
|
||||||
//Load neighbors
|
//Load neighbors
|
||||||
ULOGGER_INFO("Retrieving locations... around id=%d", _retrievedId);
|
ULOGGER_INFO("Retrieving locations... around id=%d", _retrievedId);
|
||||||
unsigned int neighborhoodSize = _bayesFilter->getPredictionLC().size()-1;
|
int neighborhoodSize = (int)_bayesFilter->getPredictionLC().size()-1;
|
||||||
unsigned int margin = neighborhoodSize;
|
UASSERT(neighborhoodSize >= 0);
|
||||||
|
int margin = neighborhoodSize;
|
||||||
|
|
||||||
UTimer timeGetN;
|
UTimer timeGetN;
|
||||||
unsigned int nbLoadedFromDb = 0;
|
unsigned int nbLoadedFromDb = 0;
|
||||||
@@ -1105,7 +1106,7 @@ bool Rtabmap::process(const Image & image)
|
|||||||
double timeGetNeighborsSpaceDb = 0.0;
|
double timeGetNeighborsSpaceDb = 0.0;
|
||||||
std::map<int, int> neighbors;
|
std::map<int, int> neighbors;
|
||||||
bool firstPassDone = false;
|
bool firstPassDone = false;
|
||||||
unsigned int m = 0;
|
int m = 0;
|
||||||
int nbDirectNeighborsInDb = 0;
|
int nbDirectNeighborsInDb = 0;
|
||||||
|
|
||||||
// priority in time
|
// priority in time
|
||||||
@@ -1127,7 +1128,7 @@ bool Rtabmap::process(const Image & image)
|
|||||||
{
|
{
|
||||||
neighbors.erase(iter++);
|
neighbors.erase(iter++);
|
||||||
}
|
}
|
||||||
else if((unsigned int)iter->second == m)
|
else if(iter->second == m)
|
||||||
{
|
{
|
||||||
if(reactivatedIdsSet.find(iter->first) == reactivatedIdsSet.end())
|
if(reactivatedIdsSet.find(iter->first) == reactivatedIdsSet.end())
|
||||||
{
|
{
|
||||||
@@ -1178,7 +1179,7 @@ bool Rtabmap::process(const Image & image)
|
|||||||
{
|
{
|
||||||
neighbors.erase(iter++);
|
neighbors.erase(iter++);
|
||||||
}
|
}
|
||||||
else if((unsigned int)iter->second == m)
|
else if(iter->second == m)
|
||||||
{
|
{
|
||||||
if(reactivatedIdsSet.find(iter->first) == reactivatedIdsSet.end())
|
if(reactivatedIdsSet.find(iter->first) == reactivatedIdsSet.end())
|
||||||
{
|
{
|
||||||
@@ -1407,7 +1408,7 @@ bool Rtabmap::process(const Image & image)
|
|||||||
{
|
{
|
||||||
lcHypothesisReactivated = sLoop->isSaved()?1.0f:0.0f;
|
lcHypothesisReactivated = sLoop->isSaved()?1.0f:0.0f;
|
||||||
}
|
}
|
||||||
dictionarySize = _memory->getVWDictionary()->getVisualWords().size();
|
dictionarySize = (int)_memory->getVWDictionary()->getVisualWords().size();
|
||||||
refWordsCount = (int)signature->getWords().size();
|
refWordsCount = (int)signature->getWords().size();
|
||||||
refUniqueWordsCount = (int)uUniqueKeys(signature->getWords()).size();
|
refUniqueWordsCount = (int)uUniqueKeys(signature->getWords()).size();
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ void Transform::getTranslation(float & x, float & y, float & z) const
|
|||||||
|
|
||||||
float Transform::getNorm() const
|
float Transform::getNorm() const
|
||||||
{
|
{
|
||||||
return std::sqrt(this->getNorm());
|
return std::sqrt(this->getNormSquared());
|
||||||
}
|
}
|
||||||
|
|
||||||
float Transform::getNormSquared() const
|
float Transform::getNormSquared() const
|
||||||
|
|||||||
@@ -752,7 +752,7 @@ pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFromDepthRGB(
|
|||||||
|
|
||||||
cv::Mat depth2DFromPointCloud(const pcl::PointCloud<pcl::PointXYZ> & cloud)
|
cv::Mat depth2DFromPointCloud(const pcl::PointCloud<pcl::PointXYZ> & cloud)
|
||||||
{
|
{
|
||||||
cv::Mat depth2d(1, cloud.size(), CV_32FC2);
|
cv::Mat depth2d(1, (int)cloud.size(), CV_32FC2);
|
||||||
for(unsigned int i=0; i<cloud.size(); ++i)
|
for(unsigned int i=0; i<cloud.size(); ++i)
|
||||||
{
|
{
|
||||||
depth2d.at<cv::Vec2f>(i)[0] = cloud.at(i).x;
|
depth2d.at<cv::Vec2f>(i)[0] = cloud.at(i).x;
|
||||||
@@ -791,7 +791,7 @@ cv::Mat uncompressImage(const std::vector<unsigned char> & bytes)
|
|||||||
cv::Mat image;
|
cv::Mat image;
|
||||||
if(bytes.size())
|
if(bytes.size())
|
||||||
{
|
{
|
||||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
#if CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4
|
||||||
image = cv::imdecode(bytes, cv::IMREAD_UNCHANGED);
|
image = cv::imdecode(bytes, cv::IMREAD_UNCHANGED);
|
||||||
#else
|
#else
|
||||||
image = cv::imdecode(bytes, -1);
|
image = cv::imdecode(bytes, -1);
|
||||||
@@ -805,7 +805,7 @@ std::vector<unsigned char> compressData(const cv::Mat & data)
|
|||||||
std::vector<unsigned char> bytes;
|
std::vector<unsigned char> bytes;
|
||||||
if(!data.empty())
|
if(!data.empty())
|
||||||
{
|
{
|
||||||
uLong sourceLen = data.total()*data.elemSize();
|
uLong sourceLen = uLong(data.total())*uLong(data.elemSize());
|
||||||
uLong destLen = compressBound(sourceLen);
|
uLong destLen = compressBound(sourceLen);
|
||||||
bytes.resize(destLen);
|
bytes.resize(destLen);
|
||||||
int errCode = compress(
|
int errCode = compress(
|
||||||
@@ -847,13 +847,13 @@ cv::Mat uncompressData(const std::vector<unsigned char> & bytes)
|
|||||||
uFormat("size=%d, height=%d width=%d type=%d", bytes.size(), height, width, type).c_str());
|
uFormat("size=%d, height=%d width=%d type=%d", bytes.size(), height, width, type).c_str());
|
||||||
|
|
||||||
data = cv::Mat(height, width, type);
|
data = cv::Mat(height, width, type);
|
||||||
uLongf totalUncompressed = data.total()*data.elemSize();
|
uLongf totalUncompressed = uLongf(data.total())*uLongf(data.elemSize());
|
||||||
|
|
||||||
int errCode = uncompress(
|
int errCode = uncompress(
|
||||||
(Bytef*)data.data,
|
(Bytef*)data.data,
|
||||||
&totalUncompressed,
|
&totalUncompressed,
|
||||||
(const Bytef*)bytes.data(),
|
(const Bytef*)bytes.data(),
|
||||||
bytes.size());
|
uLong(bytes.size()));
|
||||||
|
|
||||||
if(errCode == Z_MEM_ERROR)
|
if(errCode == Z_MEM_ERROR)
|
||||||
{
|
{
|
||||||
@@ -918,8 +918,8 @@ void extractXYZCorrespondencesRANSAC(const std::multimap<int, pcl::PointXYZ> & w
|
|||||||
std::vector<uchar> status(pairs.size(), 0);
|
std::vector<uchar> status(pairs.size(), 0);
|
||||||
//Convert Keypoints to a structure that OpenCV understands
|
//Convert Keypoints to a structure that OpenCV understands
|
||||||
//3 dimensions (Homogeneous vectors)
|
//3 dimensions (Homogeneous vectors)
|
||||||
cv::Mat points1(1, pairs.size(), CV_32FC2);
|
cv::Mat points1(1, (int)pairs.size(), CV_32FC2);
|
||||||
cv::Mat points2(1, pairs.size(), CV_32FC2);
|
cv::Mat points2(1, (int)pairs.size(), CV_32FC2);
|
||||||
|
|
||||||
float * points1data = points1.ptr<float>(0);
|
float * points1data = points1.ptr<float>(0);
|
||||||
float * points2data = points2.ptr<float>(0);
|
float * points2data = points2.ptr<float>(0);
|
||||||
@@ -1147,7 +1147,7 @@ Transform transformFromXYZCorrespondences(
|
|||||||
}
|
}
|
||||||
else if(inliers)
|
else if(inliers)
|
||||||
{
|
{
|
||||||
*inliers = correspondencesInliers.size();
|
*inliers = (int)correspondencesInliers.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::cout << "transformMatrix: " << transformMatrix << std::endl;
|
//std::cout << "transformMatrix: " << transformMatrix << std::endl;
|
||||||
@@ -1521,7 +1521,7 @@ pcl::PolygonMesh::Ptr createMesh(
|
|||||||
float gp3MaximumSurfaceAngle,
|
float gp3MaximumSurfaceAngle,
|
||||||
float gp3MinimumAngle,
|
float gp3MinimumAngle,
|
||||||
float gp3MaximumAngle,
|
float gp3MaximumAngle,
|
||||||
float gp3NormalConsistency)
|
bool gp3NormalConsistency)
|
||||||
{
|
{
|
||||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormalsNoNaN = removeNaNNormalsFromPointCloud(cloudWithNormals);
|
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudWithNormalsNoNaN = removeNaNNormalsFromPointCloud(cloudWithNormals);
|
||||||
|
|
||||||
@@ -1663,7 +1663,13 @@ bool saveTOROGraph(
|
|||||||
const std::map<int, Transform> & poses,
|
const std::map<int, Transform> & poses,
|
||||||
const std::multimap<int, Link> & edgeConstraints)
|
const std::multimap<int, Link> & edgeConstraints)
|
||||||
{
|
{
|
||||||
FILE * file = fopen(fileName.c_str(), "w");
|
FILE * file = 0;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
fopen_s(&file, fileName.c_str(), "w");
|
||||||
|
#else
|
||||||
|
file = fopen(fileName.c_str(), "w");
|
||||||
|
#endif
|
||||||
|
|
||||||
if(file)
|
if(file)
|
||||||
{
|
{
|
||||||
@@ -1712,7 +1718,12 @@ bool loadTOROGraph(const std::string & fileName,
|
|||||||
std::map<int, Transform> & poses,
|
std::map<int, Transform> & poses,
|
||||||
std::multimap<int, std::pair<int, Transform> > & edgeConstraints)
|
std::multimap<int, std::pair<int, Transform> > & edgeConstraints)
|
||||||
{
|
{
|
||||||
FILE * file = fopen(fileName.c_str(), "r");
|
FILE * file = 0;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
fopen_s(&file, fileName.c_str(), "r");
|
||||||
|
#else
|
||||||
|
file = fopen(fileName.c_str(), "r");
|
||||||
|
#endif
|
||||||
|
|
||||||
if(file)
|
if(file)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
|
|||||||
{
|
{
|
||||||
for (int j = 0; j < map8S.cols; ++j)
|
for (int j = 0; j < map8S.cols; ++j)
|
||||||
{
|
{
|
||||||
char gray = map8S.at<char>(i, j);
|
unsigned char gray = map8S.at<unsigned char>(i, j);
|
||||||
if(gray == -1)
|
if(gray == -1)
|
||||||
{
|
{
|
||||||
gray = 89;
|
gray = 89;
|
||||||
@@ -332,7 +332,7 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
|
|||||||
{
|
{
|
||||||
gray = 0;
|
gray = 0;
|
||||||
}
|
}
|
||||||
map8U.at<char>(i, j) = gray;
|
map8U.at<unsigned char>(i, j) = gray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QImage image = uCvMat2QImage(map8U, false);
|
QImage image = uCvMat2QImage(map8U, false);
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
|||||||
_ui->actionView_point_cloud_as_mesh->setEnabled(false);
|
_ui->actionView_point_cloud_as_mesh->setEnabled(false);
|
||||||
_ui->actionReset_Odometry->setEnabled(false);
|
_ui->actionReset_Odometry->setEnabled(false);
|
||||||
|
|
||||||
#if defined(Q_WS_MAC) or defined(Q_WS_WIN)
|
#if defined(Q_WS_MAC) || defined(Q_WS_WIN)
|
||||||
connect(_ui->actionOpen_working_directory, SIGNAL(triggered()), SLOT(openWorkingDirectory()));
|
connect(_ui->actionOpen_working_directory, SIGNAL(triggered()), SLOT(openWorkingDirectory()));
|
||||||
#else
|
#else
|
||||||
_ui->menuEdit->removeAction(_ui->actionOpen_working_directory);
|
_ui->menuEdit->removeAction(_ui->actionOpen_working_directory);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ int main(int argc, char * argv[])
|
|||||||
std::list<std::vector<float> > objectDescriptors;
|
std::list<std::vector<float> > objectDescriptors;
|
||||||
//std::list<std::vector<float> > descriptors;
|
//std::list<std::vector<float> > descriptors;
|
||||||
std::map<int, std::vector<float> > descriptors;
|
std::map<int, std::vector<float> > descriptors;
|
||||||
unsigned int dimension = 0;
|
int dimension = 0;
|
||||||
UTimer timer;
|
UTimer timer;
|
||||||
int objectDescriptorsSize= 400;
|
int objectDescriptorsSize= 400;
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ int main(int argc, char * argv[])
|
|||||||
++iter;
|
++iter;
|
||||||
|
|
||||||
std::vector<float> descriptor(dimension);
|
std::vector<float> descriptor(dimension);
|
||||||
unsigned int i=0;
|
int i=0;
|
||||||
|
|
||||||
//get descriptor
|
//get descriptor
|
||||||
for(;i<dimension && iter != strList.end(); ++i, ++iter)
|
for(;i<dimension && iter != strList.end(); ++i, ++iter)
|
||||||
@@ -129,7 +129,7 @@ int main(int argc, char * argv[])
|
|||||||
|
|
||||||
UDEBUG("Creating data structures...");
|
UDEBUG("Creating data structures...");
|
||||||
// Create the data structure
|
// Create the data structure
|
||||||
dataTree = cv::Mat(descriptors.size(), dimension, CV_32F); // SURF descriptors are CV_32F
|
dataTree = cv::Mat((int)descriptors.size(), dimension, CV_32F); // SURF descriptors are CV_32F
|
||||||
{//scope
|
{//scope
|
||||||
//std::list<std::vector<float> >::const_iterator iter = descriptors.begin();
|
//std::list<std::vector<float> >::const_iterator iter = descriptors.begin();
|
||||||
std::map<int, std::vector<float> >::const_iterator iter = descriptors.begin();
|
std::map<int, std::vector<float> >::const_iterator iter = descriptors.begin();
|
||||||
@@ -143,7 +143,7 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queries = cv::Mat(objectDescriptors.size(), dimension, CV_32F); // SURF descriptors are CV_32F
|
queries = cv::Mat((int)objectDescriptors.size(), dimension, CV_32F); // SURF descriptors are CV_32F
|
||||||
{//scope
|
{//scope
|
||||||
std::list<std::vector<float> >::const_iterator iter = objectDescriptors.begin();
|
std::list<std::vector<float> >::const_iterator iter = objectDescriptors.begin();
|
||||||
for(unsigned int i=0; i < objectDescriptors.size(); ++i, ++iter)
|
for(unsigned int i=0; i < objectDescriptors.size(); ++i, ++iter)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ inline bool uIsNan(const T & value)
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
return std::isnan(value);
|
return std::isnan(value);
|
||||||
#elif _MSC_VER
|
#elif _MSC_VER
|
||||||
return _isnan(value);
|
return _isnan(value) != 0;
|
||||||
#else
|
#else
|
||||||
return isnan(value);
|
return isnan(value);
|
||||||
#endif
|
#endif
|
||||||
@@ -57,7 +57,7 @@ template<class T>
|
|||||||
inline bool uIsFinite(const T & value)
|
inline bool uIsFinite(const T & value)
|
||||||
{
|
{
|
||||||
#if _MSC_VER
|
#if _MSC_VER
|
||||||
return (bool)_finite(value);
|
return _finite(value) != 0;
|
||||||
#else
|
#else
|
||||||
return std::isfinite(value);
|
return std::isfinite(value);
|
||||||
#endif
|
#endif
|
||||||
@@ -335,7 +335,7 @@ inline T uSum(const T * v, unsigned int size)
|
|||||||
template<class T>
|
template<class T>
|
||||||
inline T uSum(const std::vector<T> & v)
|
inline T uSum(const std::vector<T> & v)
|
||||||
{
|
{
|
||||||
return uSum(v.data(), v.size());
|
return uSum(v.data(), (int)v.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user