Fix the conflict
This commit is contained in:
@@ -49,6 +49,10 @@ message(STATUS "Found mynteye: ${mynteye_VERSION}")
|
||||
|
||||
include(${PRO_DIR}/cmake/DetectOpenCV.cmake)
|
||||
|
||||
if(mynteye_WITH_GLOG)
|
||||
include(${PRO_DIR}/cmake/DetectGLog.cmake)
|
||||
endif()
|
||||
|
||||
#LIST(APPEND CMAKE_MODULE_PATH ${PRO_DIR}/cmake)
|
||||
|
||||
# targets
|
||||
|
||||
@@ -31,3 +31,9 @@ make_executable(record
|
||||
LINK_LIBS mynteye ${OpenCV_LIBS}
|
||||
DLL_SEARCH_PATHS ${PRO_DIR}/_install/bin ${OpenCV_LIB_SEARCH_PATH}
|
||||
)
|
||||
|
||||
make_executable(record2
|
||||
SRCS record2.cc dataset.cc
|
||||
LINK_LIBS mynteye ${OpenCV_LIBS}
|
||||
DLL_SEARCH_PATHS ${PRO_DIR}/_install/bin ${OpenCV_LIB_SEARCH_PATH}
|
||||
)
|
||||
|
||||
@@ -12,16 +12,20 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "dataset/dataset.h"
|
||||
|
||||
#ifdef WITH_OPENCV2
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#else
|
||||
#include <opencv2/imgcodecs/imgcodecs.hpp>
|
||||
#endif
|
||||
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "mynteye/files.h"
|
||||
#include "mynteye/logger.h"
|
||||
#include "mynteye/util/files.h"
|
||||
|
||||
#define FULL_PRECISION \
|
||||
std::fixed << std::setprecision(std::numeric_limits<double>::max_digits10)
|
||||
@@ -113,6 +117,34 @@ void Dataset::SaveMotionData(const device::MotionData &data) {
|
||||
*/
|
||||
}
|
||||
|
||||
void Dataset::SaveStreamData(
|
||||
const Stream &stream, const api::StreamData &data) {
|
||||
auto &&writer = GetStreamWriter(stream);
|
||||
auto seq = stream_counts_[stream];
|
||||
writer->ofs << seq << ", " << data.img->frame_id << ", "
|
||||
<< data.img->timestamp << ", " << data.img->exposure_time
|
||||
<< std::endl;
|
||||
if (!data.frame.empty()) {
|
||||
std::stringstream ss;
|
||||
ss << writer->outdir << MYNTEYE_OS_SEP << std::dec
|
||||
<< std::setw(IMAGE_FILENAME_WIDTH) << std::setfill('0') << seq << ".png";
|
||||
cv::imwrite(ss.str(), data.frame);
|
||||
}
|
||||
++stream_counts_[stream];
|
||||
}
|
||||
|
||||
void Dataset::SaveMotionData(const api::MotionData &data) {
|
||||
auto &&writer = GetMotionWriter();
|
||||
auto seq = motion_count_;
|
||||
writer->ofs << seq << ", " << data.imu->frame_id << ", "
|
||||
<< data.imu->timestamp << ", " << data.imu->accel[0] << ", "
|
||||
<< data.imu->accel[1] << ", " << data.imu->accel[2] << ", "
|
||||
<< data.imu->gyro[0] << ", " << data.imu->gyro[1] << ", "
|
||||
<< data.imu->gyro[2] << ", " << data.imu->temperature
|
||||
<< std::endl;
|
||||
++motion_count_;
|
||||
}
|
||||
|
||||
Dataset::writer_t Dataset::GetStreamWriter(const Stream &stream) {
|
||||
try {
|
||||
return stream_writers_.at(stream);
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "mynteye/callbacks.h"
|
||||
#include "mynteye/mynteye.h"
|
||||
#include "mynteye/api/api.h"
|
||||
#include "mynteye/device/callbacks.h"
|
||||
|
||||
MYNTEYE_BEGIN_NAMESPACE
|
||||
|
||||
@@ -43,6 +44,9 @@ class Dataset {
|
||||
void SaveStreamData(const Stream &stream, const device::StreamData &data);
|
||||
void SaveMotionData(const device::MotionData &data);
|
||||
|
||||
void SaveStreamData(const Stream &stream, const api::StreamData &data);
|
||||
void SaveMotionData(const api::MotionData &data);
|
||||
|
||||
private:
|
||||
writer_t GetStreamWriter(const Stream &stream);
|
||||
writer_t GetMotionWriter();
|
||||
|
||||
@@ -14,30 +14,25 @@
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
|
||||
#include "mynteye/glog_init.h"
|
||||
|
||||
#include "mynteye/device.h"
|
||||
#include "mynteye/utils.h"
|
||||
|
||||
#include "mynteye/times.h"
|
||||
#include "mynteye/logger.h"
|
||||
#include "mynteye/api/api.h"
|
||||
#include "mynteye/util/times.h"
|
||||
|
||||
#include "dataset/dataset.h"
|
||||
|
||||
MYNTEYE_USE_NAMESPACE
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
glog_init _(argc, argv);
|
||||
|
||||
auto &&device = device::select();
|
||||
if (!device)
|
||||
auto &&api = API::Create(argc, argv);
|
||||
if (!api)
|
||||
return 1;
|
||||
device->InitResolution(Resolution::RES_1280x400);
|
||||
device->SetStreamRequest(Format::BGR888, FrameRate::RATE_30_FPS);
|
||||
device->LogOptionInfos();
|
||||
api->InitResolution(Resolution::RES_1280x400);
|
||||
api->SetStreamRequest(Format::BGR888, FrameRate::RATE_30_FPS);
|
||||
api->LogOptionInfos();
|
||||
|
||||
// Enable this will cache the motion datas until you get them.
|
||||
device->EnableMotionDatas();
|
||||
device->Start(Source::ALL);
|
||||
api->EnableMotionDatas();
|
||||
api->Start(Source::ALL);
|
||||
|
||||
const char *outdir;
|
||||
if (argc >= 2) {
|
||||
@@ -53,13 +48,13 @@ int main(int argc, char *argv[]) {
|
||||
std::size_t imu_count = 0;
|
||||
auto &&time_beg = times::now();
|
||||
while (true) {
|
||||
device->WaitForStreams();
|
||||
api->WaitForStreams();
|
||||
|
||||
auto &&left_datas = device->GetStreamDatas(Stream::LEFT);
|
||||
auto &&right_datas = device->GetStreamDatas(Stream::RIGHT);
|
||||
auto &&left_datas = api->GetStreamDatas(Stream::LEFT);
|
||||
auto &&right_datas = api->GetStreamDatas(Stream::RIGHT);
|
||||
img_count += left_datas.size();
|
||||
|
||||
auto &&motion_datas = device->GetMotionDatas();
|
||||
auto &&motion_datas = api->GetMotionDatas();
|
||||
imu_count += motion_datas.size();
|
||||
|
||||
auto &&left_frame = left_datas.back().frame;
|
||||
@@ -123,7 +118,7 @@ int main(int argc, char *argv[]) {
|
||||
std::cout << " to " << outdir << std::endl;
|
||||
auto &&time_end = times::now();
|
||||
|
||||
device->Stop(Source::ALL);
|
||||
api->Stop(Source::ALL);
|
||||
|
||||
float elapsed_ms =
|
||||
times::count<times::microseconds>(time_end - time_beg) * 0.001f;
|
||||
|
||||
128
tools/dataset/record2.cc
Normal file
128
tools/dataset/record2.cc
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright 2018 Slightech Co., Ltd. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
|
||||
#include "mynteye/logger.h"
|
||||
#include "mynteye/device/device.h"
|
||||
#include "mynteye/device/utils.h"
|
||||
#include "mynteye/util/times.h"
|
||||
|
||||
#include "dataset/dataset.h"
|
||||
|
||||
MYNTEYE_USE_NAMESPACE
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
glog_init _(argc, argv);
|
||||
|
||||
auto &&device = device::select();
|
||||
if (!device)
|
||||
return 1;
|
||||
/*
|
||||
{ // auto-exposure
|
||||
device->SetOptionValue(Option::EXPOSURE_MODE, 0);
|
||||
device->SetOptionValue(Option::MAX_GAIN, 40); // [0.48]
|
||||
device->SetOptionValue(Option::MAX_EXPOSURE_TIME, 120); // [0,240]
|
||||
device->SetOptionValue(Option::DESIRED_BRIGHTNESS, 200); // [0,255]
|
||||
}
|
||||
{ // manual-exposure
|
||||
device->SetOptionValue(Option::EXPOSURE_MODE, 1);
|
||||
device->SetOptionValue(Option::GAIN, 20); // [0.48]
|
||||
device->SetOptionValue(Option::BRIGHTNESS, 20); // [0,240]
|
||||
device->SetOptionValue(Option::CONTRAST, 20); // [0,255]
|
||||
}
|
||||
device->SetOptionValue(Option::IR_CONTROL, 80);
|
||||
device->SetOptionValue(Option::FRAME_RATE, 25);
|
||||
device->SetOptionValue(Option::IMU_FREQUENCY, 500);
|
||||
*/
|
||||
device->InitResolution(Resolution::RES_1280x400);
|
||||
device->SetStreamRequest(Format::BGR888, FrameRate::RATE_30_FPS);
|
||||
device->LogOptionInfos();
|
||||
|
||||
// Enable this will cache the motion datas until you get them.
|
||||
device->EnableMotionDatas();
|
||||
device->Start(Source::ALL);
|
||||
|
||||
const char *outdir;
|
||||
if (argc >= 2) {
|
||||
outdir = argv[1];
|
||||
} else {
|
||||
outdir = "./dataset";
|
||||
}
|
||||
tools::Dataset dataset(outdir);
|
||||
|
||||
cv::namedWindow("frame");
|
||||
|
||||
std::size_t img_count = 0;
|
||||
std::size_t imu_count = 0;
|
||||
auto &&time_beg = times::now();
|
||||
while (true) {
|
||||
device->WaitForStreams();
|
||||
|
||||
auto &&left_datas = device->GetStreamDatas(Stream::LEFT);
|
||||
auto &&right_datas = device->GetStreamDatas(Stream::RIGHT);
|
||||
img_count += left_datas.size();
|
||||
|
||||
auto &&motion_datas = device->GetMotionDatas();
|
||||
imu_count += motion_datas.size();
|
||||
|
||||
auto &&left_frame = left_datas.back().frame;
|
||||
auto &&right_frame = right_datas.back().frame;
|
||||
cv::Mat left_img(
|
||||
left_frame->height(), left_frame->width(), CV_8UC1, left_frame->data());
|
||||
cv::Mat right_img(
|
||||
right_frame->height(), right_frame->width(), CV_8UC1,
|
||||
right_frame->data());
|
||||
|
||||
cv::Mat img;
|
||||
cv::hconcat(left_img, right_img, img);
|
||||
cv::imshow("frame", img);
|
||||
|
||||
{ // save
|
||||
for (auto &&left : left_datas) {
|
||||
dataset.SaveStreamData(Stream::LEFT, left);
|
||||
}
|
||||
for (auto &&right : right_datas) {
|
||||
dataset.SaveStreamData(Stream::RIGHT, right);
|
||||
}
|
||||
|
||||
for (auto &&motion : motion_datas) {
|
||||
dataset.SaveMotionData(motion);
|
||||
}
|
||||
|
||||
std::cout << "\rSaved " << img_count << " imgs"
|
||||
<< ", " << imu_count << " imus" << std::flush;
|
||||
}
|
||||
|
||||
char key = static_cast<char>(cv::waitKey(1));
|
||||
if (key == 27 || key == 'q' || key == 'Q') { // ESC/Q
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cout << " to " << outdir << std::endl;
|
||||
auto &&time_end = times::now();
|
||||
|
||||
device->Stop(Source::ALL);
|
||||
|
||||
float elapsed_ms =
|
||||
times::count<times::microseconds>(time_end - time_beg) * 0.001f;
|
||||
LOG(INFO) << "Time beg: " << times::to_local_string(time_beg)
|
||||
<< ", end: " << times::to_local_string(time_end)
|
||||
<< ", cost: " << elapsed_ms << "ms";
|
||||
LOG(INFO) << "Img count: " << img_count
|
||||
<< ", fps: " << (1000.f * img_count / elapsed_ms);
|
||||
LOG(INFO) << "Imu count: " << imu_count
|
||||
<< ", hz: " << (1000.f * imu_count / elapsed_ms);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
%YAML:1.0
|
||||
---
|
||||
device_name: MYNT-EYE-S1000
|
||||
device_name: MYNT-EYE-S210A
|
||||
serial_number: "0386322C0009070E"
|
||||
firmware_version: "2.0"
|
||||
hardware_version: "2.0"
|
||||
spec_version: "1.0"
|
||||
firmware_version: "1.0"
|
||||
hardware_version: "1.0"
|
||||
spec_version: "1.1"
|
||||
lens_type: "0000"
|
||||
imu_type: "0000"
|
||||
nominal_baseline: 120
|
||||
|
||||
@@ -43,7 +43,7 @@ in_right_map:
|
||||
model: 0
|
||||
coeffs: [ 2.2904330559241560e-02, -2.9561990079971841e-02,
|
||||
3.9725942760981507e-03, -3.9689073214945591e-03, 0. ]
|
||||
ex_left_to_right:
|
||||
ex_right_to_left:
|
||||
rotation: [ 9.9998850083695123e-01, -1.9263678722299450e-03,
|
||||
-4.3917309443490191e-03, 1.8166060642710027e-03,
|
||||
9.9968925981619028e-01, -2.4861290203142431e-02,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
%YAML:1.0
|
||||
---
|
||||
in_accel:
|
||||
scale: [ 0., 0., 0., 0., 0., 0., 0., 0., 0. ]
|
||||
drift: [ 0., 0., 0. ]
|
||||
noise: [ 0., 0., 0. ]
|
||||
bias: [ 0., 0., 0. ]
|
||||
scale: [ 1., 0., 0., 0., 1., 0., 0., 0., 1. ]
|
||||
drift: [ 0.0, 0.0, 0.0 ]
|
||||
noise: [ 0.016925432397973516, 0.016735310195561025, 0.017452487504590969 ]
|
||||
bias: [ 0.00019031356589714596, 0.00016996777864587261, 0.00054490537096493644 ]
|
||||
in_gyro:
|
||||
scale: [ 0., 0., 0., 0., 0., 0., 0., 0., 0. ]
|
||||
scale: [ 1., 0., 0., 0., 1., 0., 0., 0., 1. ]
|
||||
drift: [ 0., 0., 0. ]
|
||||
noise: [ 0., 0., 0. ]
|
||||
bias: [ 0., 0., 0. ]
|
||||
noise: [ 0.0010848026158819934, 0.0012466367883501759, 0.0011003229919806443 ]
|
||||
bias: [ 0.000023404834136742844, 0.000023596771567764949, 0.000014970418056326829 ]
|
||||
ex_left_to_imu:
|
||||
rotation: [ 0., 0., 0., 0., 0., 0., 0., 0., 0. ]
|
||||
translation: [ 0., 0., 0. ]
|
||||
rotation: [ -0.0064662, -0.99994994, -0.00763565, 0.99997909, -0.00646566, -0.00009558, 0.0000462, -0.00763611, 0.99997084 ]
|
||||
translation: [ 0.00533646, -0.04302922, 0.02303124 ]
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "mynteye/glog_init.h"
|
||||
|
||||
#include "mynteye/device.h"
|
||||
#include "mynteye/utils.h"
|
||||
#include "mynteye/logger.h"
|
||||
#include "mynteye/device/device.h"
|
||||
#include "mynteye/device/utils.h"
|
||||
|
||||
#include "writer/device_writer.h"
|
||||
|
||||
|
||||
@@ -13,17 +13,14 @@
|
||||
// limitations under the License.
|
||||
#include "writer/device_writer.h"
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "mynteye/device.h"
|
||||
#include "mynteye/files.h"
|
||||
#include "mynteye/logger.h"
|
||||
#include "mynteye/types.h"
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
#include "internal/types.h"
|
||||
#include "mynteye/logger.h"
|
||||
#include "mynteye/device/device.h"
|
||||
#include "mynteye/util/files.h"
|
||||
|
||||
MYNTEYE_BEGIN_NAMESPACE
|
||||
|
||||
@@ -75,7 +72,7 @@ bool DeviceWriter::WriteImgParams(const img_params_t ¶ms) {
|
||||
LOG(INFO) << "Write img params success";
|
||||
// LOG(INFO) << "Intrinsics left: {" << params.in_left << "}";
|
||||
// LOG(INFO) << "Intrinsics right: {" << params.in_right << "}";
|
||||
LOG(INFO) << "Extrinsics left to right: {" << params.ex_left_to_right
|
||||
LOG(INFO) << "Extrinsics left to right: {" << params.ex_right_to_left
|
||||
<< "}";
|
||||
return true;
|
||||
} else {
|
||||
@@ -202,7 +199,7 @@ bool DeviceWriter::SaveImgParams(
|
||||
if (params.in_left_map.size() == params.in_right_map.size()) {
|
||||
fs << "version" << info.spec_version.to_string() << "in_left_map"
|
||||
<< params.in_left_map << "in_right_map" << params.in_right_map
|
||||
<< "ex_left_to_right" << params.ex_left_to_right;
|
||||
<< "ex_right_to_left" << params.ex_right_to_left;
|
||||
fs.release();
|
||||
return true;
|
||||
} else {
|
||||
@@ -329,8 +326,8 @@ DeviceWriter::dev_info_t DeviceWriter::LoadDeviceInfo(
|
||||
LOG(FATAL) << "Failed to load file: " << filepath;
|
||||
}
|
||||
DeviceInfo info;
|
||||
info.lens_type = Type(fs["lens_type"].string());
|
||||
info.imu_type = Type(fs["imu_type"].string());
|
||||
info.lens_type = Type(std::string(fs["lens_type"]));
|
||||
info.imu_type = Type(std::string(fs["imu_type"]));
|
||||
fs["nominal_baseline"] >> info.nominal_baseline;
|
||||
fs.release();
|
||||
return info;
|
||||
@@ -369,25 +366,25 @@ DeviceWriter::img_params_t DeviceWriter::LoadImgParams(
|
||||
w, h, m, M1, D1, ¶ms.in_left_map[Resolution::RES_752x480]);
|
||||
to_intrinsics(
|
||||
w, h, m, M2, D2, ¶ms.in_right_map[Resolution::RES_752x480]);
|
||||
to_extrinsics(R, T, ¶ms.ex_left_to_right);
|
||||
to_extrinsics(R, T, ¶ms.ex_right_to_left);
|
||||
} else {
|
||||
fs["in_left"][0] >> params.in_left_map[Resolution::RES_752x480];
|
||||
fs["in_right"][0] >> params.in_right_map[Resolution::RES_752x480];
|
||||
fs["ex_left_to_right"] >> params.ex_left_to_right;
|
||||
fs["ex_right_to_left"] >> params.ex_right_to_left;
|
||||
}
|
||||
} else {
|
||||
// TODO(Kalman): Is there a more reasonable way?
|
||||
if (static_cast<std::string>(fs["version"]) == "1.0") {
|
||||
fs["in_left_map"][0] >> params.in_left_map[Resolution::RES_752x480];
|
||||
fs["in_right_map"][0] >> params.in_right_map[Resolution::RES_752x480];
|
||||
fs["ex_left_to_right"] >> params.ex_left_to_right;
|
||||
fs["ex_right_to_left"] >> params.ex_right_to_left;
|
||||
}
|
||||
if (static_cast<std::string>(fs["version"]) == "1.1") {
|
||||
fs["in_left_map"][0] >> params.in_left_map[Resolution::RES_1280x400];
|
||||
fs["in_left_map"][1] >> params.in_left_map[Resolution::RES_2560x800];
|
||||
fs["in_right_map"][0] >> params.in_right_map[Resolution::RES_1280x400];
|
||||
fs["in_right_map"][1] >> params.in_right_map[Resolution::RES_2560x800];
|
||||
fs["ex_left_to_right"] >> params.ex_left_to_right;
|
||||
fs["ex_right_to_left"] >> params.ex_right_to_left;
|
||||
}
|
||||
}
|
||||
fs.release();
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
#include <string>
|
||||
|
||||
#include "mynteye/mynteye.h"
|
||||
|
||||
#include "internal/channels.h"
|
||||
#include "internal/types.h"
|
||||
#include "mynteye/device/channels.h"
|
||||
#include "mynteye/device/types.h"
|
||||
|
||||
MYNTEYE_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "mynteye/glog_init.h"
|
||||
|
||||
#include "mynteye/device.h"
|
||||
#include "mynteye/utils.h"
|
||||
#include "mynteye/logger.h"
|
||||
#include "mynteye/device/device.h"
|
||||
#include "mynteye/device/utils.h"
|
||||
|
||||
#include "writer/device_writer.h"
|
||||
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "mynteye/glog_init.h"
|
||||
|
||||
#include "mynteye/device.h"
|
||||
#include "mynteye/utils.h"
|
||||
#include "mynteye/logger.h"
|
||||
#include "mynteye/device/device.h"
|
||||
#include "mynteye/device/utils.h"
|
||||
|
||||
#include "writer/device_writer.h"
|
||||
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "mynteye/glog_init.h"
|
||||
|
||||
#include "mynteye/device.h"
|
||||
#include "mynteye/utils.h"
|
||||
#include "mynteye/logger.h"
|
||||
#include "mynteye/device/device.h"
|
||||
#include "mynteye/device/utils.h"
|
||||
|
||||
#include "writer/device_writer.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user