mirror of
https://github.com/deepinsight/insightface.git
synced 2026-05-01 03:00:16 +00:00
Update inspireface to 1.2.0
This commit is contained in:
116
cpp-package/inspireface/cpp/sample/source/expansion_load.cpp
Normal file
116
cpp-package/inspireface/cpp/sample/source/expansion_load.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include "inspireface/middleware/model_archive/inspire_archive.h"
|
||||
#include "inspireface/track_module/face_detect/face_detect_adapt.h"
|
||||
#include "inspireface/track_module/landmark/face_landmark_adapt.h"
|
||||
#include "inspireface/track_module/quality/face_pose_quality_adapt.h"
|
||||
#include "inspireface/recognition_module/extract/extract_adapt.h"
|
||||
|
||||
void test_face_detect() {
|
||||
inspire::InspireModel model;
|
||||
INSPIRE_LAUNCH->getMArchive().LoadModel("face_detect_160", model);
|
||||
auto input_size = 160;
|
||||
inspire::FaceDetectAdapt faceDetectAdapt(input_size);
|
||||
faceDetectAdapt.loadData(model, model.modelType);
|
||||
inspirecv::Image image = inspirecv::Image::Create("test_res/data/bulk/kun.jpg");
|
||||
inspire::FaceLocList faces;
|
||||
inspirecv::TimeSpend timeSpend("Face Detect@" + std::to_string(input_size));
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
timeSpend.Start();
|
||||
faces = faceDetectAdapt(image);
|
||||
timeSpend.Stop();
|
||||
}
|
||||
std::cout << timeSpend << std::endl;
|
||||
std::cout << "faces size: " << faces.size() << std::endl;
|
||||
for (auto &face : faces) {
|
||||
inspirecv::Rect2i rect = inspirecv::Rect2i::Create(face.x1, face.y1, face.x2 - face.x1, face.y2 - face.y1);
|
||||
image.DrawRect(rect, {0, 0, 255});
|
||||
}
|
||||
image.Write("im.jpg");
|
||||
}
|
||||
|
||||
void test_landmark() {
|
||||
inspire::InspireModel model;
|
||||
INSPIRE_LAUNCH->getMArchive().LoadModel("landmark", model);
|
||||
auto input_size = 112;
|
||||
inspire::FaceLandmarkAdapt landmarkAdapt(input_size);
|
||||
landmarkAdapt.loadData(model, model.modelType);
|
||||
inspirecv::Image image = inspirecv::Image::Create("test_res/data/crop/crop.png");
|
||||
image = image.Resize(input_size, input_size);
|
||||
std::vector<float> lmk;
|
||||
inspirecv::TimeSpend timeSpend("Landmark@" + std::to_string(input_size));
|
||||
timeSpend.Start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
lmk = landmarkAdapt(image);
|
||||
}
|
||||
timeSpend.Stop();
|
||||
std::cout << timeSpend << std::endl;
|
||||
for (int i = 0; i < inspire::FaceLandmarkAdapt::NUM_OF_LANDMARK; i++) {
|
||||
auto p = inspirecv::Point2i::Create(lmk[i * 2] * input_size, lmk[i * 2 + 1] * input_size);
|
||||
image.DrawCircle(p, 5, {0, 0, 255});
|
||||
}
|
||||
image.Write("lm.jpg");
|
||||
}
|
||||
|
||||
void test_quality() {
|
||||
inspire::InspireModel model;
|
||||
INSPIRE_LAUNCH->getMArchive().LoadModel("pose_quality", model);
|
||||
auto input_size = 96;
|
||||
inspire::FacePoseQualityAdapt poseQualityAdapt;
|
||||
poseQualityAdapt.loadData(model, model.modelType);
|
||||
inspirecv::Image image = inspirecv::Image::Create("test_res/data/crop/crop.png");
|
||||
image = image.Resize(input_size, input_size);
|
||||
inspire::FacePoseQualityAdaptResult quality;
|
||||
inspirecv::TimeSpend timeSpend("Pose Quality@" + std::to_string(input_size));
|
||||
timeSpend.Start();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
quality = poseQualityAdapt(image);
|
||||
}
|
||||
timeSpend.Stop();
|
||||
std::cout << timeSpend << std::endl;
|
||||
std::cout << "quality: " << quality.pitch << ", " << quality.yaw << ", " << quality.roll << std::endl;
|
||||
for (int i = 0; i < quality.lmk.size(); i++) {
|
||||
std::cout << "lmk: " << quality.lmk[i].GetX() << ", " << quality.lmk[i].GetY() << std::endl;
|
||||
auto p = inspirecv::Point2i::Create(quality.lmk[i].GetX(), quality.lmk[i].GetY());
|
||||
image.DrawCircle(p, 3, {0, 0, 255});
|
||||
}
|
||||
image.Write("qu.jpg");
|
||||
}
|
||||
|
||||
void test_feature() {
|
||||
inspire::InspireModel model;
|
||||
INSPIRE_LAUNCH->getMArchive().LoadModel("feature", model);
|
||||
auto input_size = 112;
|
||||
inspire::ExtractAdapt extractAdapt;
|
||||
extractAdapt.loadData(model, model.modelType);
|
||||
inspirecv::Image image = inspirecv::Image::Create("test_res/data/crop/crop.png");
|
||||
image = image.Resize(input_size, input_size);
|
||||
float norm;
|
||||
bool normalize = true;
|
||||
inspirecv::TimeSpend timeSpend("Extract@" + std::to_string(input_size));
|
||||
timeSpend.Start();
|
||||
inspire::Embedded feature;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
feature = extractAdapt(image, norm, normalize);
|
||||
}
|
||||
timeSpend.Stop();
|
||||
std::cout << timeSpend << std::endl;
|
||||
std::cout << "feature: " << feature.size() << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::string archivePath = "test_res/pack/Pikachu_Apple";
|
||||
INSPIRE_LAUNCH->Load(archivePath);
|
||||
// Test face detect
|
||||
test_face_detect();
|
||||
|
||||
// Test landmark
|
||||
// test_landmark();
|
||||
|
||||
// Test quality
|
||||
// test_quality();
|
||||
|
||||
// Test feature
|
||||
// test_feature();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/track_module/face_track_module.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/middleware/inspirecv_image_process.h>
|
||||
#include <inspireface/pipeline_module/face_pipeline_module.h>
|
||||
#include <inspireface/common/face_data/face_serialize_tools.h>
|
||||
#include <inspireface/feature_hub/feature_hub_db.h>
|
||||
|
||||
using namespace inspire;
|
||||
|
||||
static std::vector<float> FT = {
|
||||
0.0706566, 0.00640248, 0.0418103, -0.00597861, 0.0269879, 0.0187478, 0.0486305, 0.0349162, -0.0080779, -0.0550556, 0.0229963,
|
||||
-0.00683422, -0.0338589, 0.0533989, -0.0371725, 0.000972469, 0.0612415, 0.0389846, -0.00126743, -0.0128782, 0.0935529, 0.0588179,
|
||||
0.0164787, -0.00732871, -0.0458209, -0.0100137, -0.0372892, 0.000871123, 0.0245121, -0.0811471, -0.00481095, 0.0266868, 0.0712961,
|
||||
-0.0675362, -0.0117453, 0.0658745, -0.0694139, -0.00704822, -0.0237313, 0.0209365, 0.0131902, 0.00192449, -0.0593105, 0.0191942,
|
||||
-0.00625798, 0.00748682, 0.0533557, 0.0314002, -0.0627113, 0.0827862, 0.00336722, -0.0191575, -0.0180252, 0.0150318, -0.0686462,
|
||||
0.0465634, 0.0627244, 0.0449248, -0.037054, -0.0486668, 0.040752, 0.0143315, -0.0763842, -0.0161973, 0.0319588, 0.0112792,
|
||||
-0.102007, 0.0649219, 0.0630833, 0.0421069, 0.0519043, -0.084082, 0.0249516, 0.023046, 0.071994, -0.0272229, 0.0167103,
|
||||
-0.00694243, 0.0366775, 0.0672882, 0.0122419, -0.0233413, -0.0144258, -0.012853, -0.0202025, 0.000983093, -0.00776073, -0.0268638,
|
||||
0.00682446, 0.0262906, -0.0407654, -0.0144264, -0.0310807, 0.0596711, 0.0238081, -0.0138019, 0.000502882, 0.0496892, 0.0126823,
|
||||
0.0511028, -0.0310699, -0.0322141, 0.00996936, 0.0675392, -0.0164277, 0.0930009, -0.037467, 0.0419618, -0.00358901, -0.0309569,
|
||||
-0.0225608, -0.0332198, 0.00102291, 0.108814, -0.0831313, 0.048208, -0.0277542, -0.061584, 0.0721224, -0.0795082, 0.0340047,
|
||||
0.056139, -0.0166783, -0.0803042, -0.014245, -0.0476374, 0.048495, 0.0378856, 0.0706566, 0.00640248, 0.0418103, -0.00597861,
|
||||
0.0269879, 0.0187478, 0.0486305, 0.0349162, -0.0080779, -0.0550556, 0.0229963, -0.00683422, -0.0338589, 0.0533989, -0.0371725,
|
||||
0.000972469, 0.0612415, 0.0389846, -0.00126743, -0.0128782, 0.0935529, 0.0588179, 0.0164787, -0.00732871, -0.0458209, -0.0100137,
|
||||
-0.0372892, 0.000871123, 0.0245121, -0.0811471, -0.00481095, 0.0266868, 0.0712961, -0.0675362, -0.0117453, 0.0658745, -0.0694139,
|
||||
-0.00704822, -0.0237313, 0.0209365, 0.0131902, 0.00192449, -0.0593105, 0.0191942, -0.00625798, 0.00748682, 0.0533557, 0.0314002,
|
||||
-0.0627113, 0.0827862, 0.00336722, -0.0191575, -0.0180252, 0.0150318, -0.0686462, 0.0465634, 0.0627244, 0.0449248, -0.037054,
|
||||
-0.0486668, 0.040752, 0.0143315, -0.0763842, -0.0161973, 0.0319588, 0.0112792, -0.102007, 0.0649219, 0.0630833, 0.0421069,
|
||||
0.0519043, -0.084082, 0.0249516, 0.023046, 0.071994, -0.0272229, 0.0167103, -0.00694243, 0.0366775, 0.0672882, 0.0122419,
|
||||
-0.0233413, -0.0144258, -0.012853, -0.0202025, 0.000983093, -0.00776073, -0.0268638, 0.00682446, 0.0262906, -0.0407654, -0.0144264,
|
||||
-0.0310807, 0.0596711, 0.0238081, -0.0138019, 0.000502882, 0.0496892, 0.0126823, 0.0511028, -0.0310699, -0.0322141, 0.00996936,
|
||||
0.0675392, -0.0164277, 0.0930009, -0.037467, 0.0419618, -0.00358901, -0.0309569, -0.0225608, -0.0332198, 0.00102291, 0.108814,
|
||||
-0.0831313, 0.048208, -0.0277542, -0.061584, 0.0721224, -0.0795082, 0.0340047, 0.056139, -0.0166783, -0.0803042, -0.014245,
|
||||
-0.0476374, 0.048495, 0.0378856, 0.0706566, 0.00640248, 0.0418103, -0.00597861, 0.0269879, 0.0187478, 0.0486305, 0.0349162,
|
||||
-0.0080779, -0.0550556, 0.0229963, -0.00683422, -0.0338589, 0.0533989, -0.0371725, 0.000972469, 0.0612415, 0.0389846, -0.00126743,
|
||||
-0.0128782, 0.0935529, 0.0588179, 0.0164787, -0.00732871, -0.0458209, -0.0100137, -0.0372892, 0.000871123, 0.0245121, -0.0811471,
|
||||
-0.00481095, 0.0266868, 0.0712961, -0.0675362, -0.0117453, 0.0658745, -0.0694139, -0.00704822, -0.0237313, 0.0209365, 0.0131902,
|
||||
0.00192449, -0.0593105, 0.0191942, -0.00625798, 0.00748682, 0.0533557, 0.0314002, -0.0627113, 0.0827862, 0.00336722, -0.0191575,
|
||||
-0.0180252, 0.0150318, -0.0686462, 0.0465634, 0.0627244, 0.0449248, -0.037054, -0.0486668, 0.040752, 0.0143315, -0.0763842,
|
||||
-0.0161973, 0.0319588, 0.0112792, -0.102007, 0.0649219, 0.0630833, 0.0421069, 0.0519043, -0.084082, 0.0249516, 0.023046,
|
||||
0.071994, -0.0272229, 0.0167103, -0.00694243, 0.0366775, 0.0672882, 0.0122419, -0.0233413, -0.0144258, -0.012853, -0.0202025,
|
||||
0.000983093, -0.00776073, -0.0268638, 0.00682446, 0.0262906, -0.0407654, -0.0144264, -0.0310807, 0.0596711, 0.0238081, -0.0138019,
|
||||
0.000502882, 0.0496892, 0.0126823, 0.0511028, -0.0310699, -0.0322141, 0.00996936, 0.0675392, -0.0164277, 0.0930009, -0.037467,
|
||||
0.0419618, -0.00358901, -0.0309569, -0.0225608, -0.0332198, 0.00102291, 0.108814, -0.0831313, 0.048208, -0.0277542, -0.061584,
|
||||
0.0721224, -0.0795082, 0.0340047, 0.056139, -0.0166783, -0.0803042, -0.014245, -0.0476374, 0.048495, 0.0378856, 0.0706566,
|
||||
0.00640248, 0.0418103, -0.00597861, 0.0269879, 0.0187478, 0.0486305, 0.0349162, -0.0080779, -0.0550556, 0.0229963, -0.00683422,
|
||||
-0.0338589, 0.0533989, -0.0371725, 0.000972469, 0.0612415, 0.0389846, -0.00126743, -0.0128782, 0.0935529, 0.0588179, 0.0164787,
|
||||
-0.00732871, -0.0458209, -0.0100137, -0.0372892, 0.000871123, 0.0245121, -0.0811471, -0.00481095, 0.0266868, 0.0712961, -0.0675362,
|
||||
-0.0117453, 0.0658745, -0.0694139, -0.00704822, -0.0237313, 0.0209365, 0.0131902, 0.00192449, -0.0593105, 0.0191942, -0.00625798,
|
||||
0.00748682, 0.0533557, 0.0314002, -0.0627113, 0.0827862, 0.00336722, -0.0191575, -0.0180252, 0.0150318, -0.0686462, 0.0465634,
|
||||
0.0627244, 0.0449248, -0.037054, -0.0486668, 0.040752, 0.0143315, -0.0763842, -0.0161973, 0.0319588, 0.0112792, -0.102007,
|
||||
0.0649219, 0.0630833, 0.0421069, 0.0519043, -0.084082, 0.0249516, 0.023046, 0.071994, -0.0272229, 0.0167103, -0.00694243,
|
||||
0.0366775, 0.0672882, 0.0122419, -0.0233413, -0.0144258, -0.012853, -0.0202025, 0.000983093, -0.00776073, -0.0268638, 0.00682446,
|
||||
0.0262906, -0.0407654, -0.0144264, -0.0310807, 0.0596711, 0.0238081, -0.0138019, 0.000502882, 0.0496892, 0.0126823, 0.0511028,
|
||||
-0.0310699, -0.0322141, 0.00996936, 0.0675392, -0.0164277, 0.0930009, -0.037467, 0.0419618, -0.00358901, -0.0309569, -0.0225608,
|
||||
-0.0332198, 0.00102291, 0.108814, -0.0831313, 0.048208, -0.0277542, -0.061584, 0.0721224, -0.0795082, 0.0340047, 0.056139,
|
||||
-0.0166783, -0.0803042, -0.014245, -0.0476374, 0.048495, 0.0378856,
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::string expansion_path = "";
|
||||
INSPIRE_LAUNCH->Load("test_res/pack/Pikachu");
|
||||
|
||||
DatabaseConfiguration configuration;
|
||||
configuration.primary_key_mode = PrimaryKeyMode::MANUAL_INPUT;
|
||||
configuration.enable_persistence = false;
|
||||
configuration.recognition_threshold = 0.48f;
|
||||
|
||||
FEATURE_HUB_DB->EnableHub(configuration);
|
||||
|
||||
// std::vector<float> feature(512, 0.0f);
|
||||
|
||||
int64_t result_id = 0;
|
||||
auto ret = FEATURE_HUB_DB->FaceFeatureInsert(FT, 10086, result_id);
|
||||
if (ret != HSUCCEED) {
|
||||
INSPIRE_LOGE("Failed to insert face feature");
|
||||
INSPIRE_LOGI("result id: %lld", result_id);
|
||||
} else {
|
||||
INSPIRE_LOGI("Insert face feature success, result_id: %lld", result_id);
|
||||
}
|
||||
|
||||
// std::vector<float> query_feature(512, 20.0f);
|
||||
FaceSearchResult search_result;
|
||||
ret = FEATURE_HUB_DB->SearchFaceFeature(FT, search_result, true);
|
||||
if (ret != HSUCCEED) {
|
||||
INSPIRE_LOGE("Failed to search face feature");
|
||||
} else {
|
||||
INSPIRE_LOGI("Search face feature success, result_id: %lld", search_result.id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <iostream>
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/middleware/inspirecv_image_process.h>
|
||||
#include "inspireface/track_module/landmark/face_landmark_adapt.h"
|
||||
int main() {
|
||||
std::string expansion_path = "";
|
||||
INSPIRE_LAUNCH->Load("test_res/pack/Pikachu-t4");
|
||||
auto archive = INSPIRE_LAUNCH->getMArchive();
|
||||
|
||||
inspire::InspireModel lmkModel;
|
||||
auto ret = archive.LoadModel("landmark", lmkModel);
|
||||
if (ret != 0) {
|
||||
INSPIRE_LOGE("Load %s error: %d", "landmark", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
inspire::FaceLandmarkAdapt lmk;
|
||||
lmk.loadData(lmkModel, lmkModel.modelType);
|
||||
|
||||
auto image = inspirecv::Image::Create("test_res/data/crop/crop.png");
|
||||
auto data = image.Resize(112, 112);
|
||||
auto lmk_out = lmk(data);
|
||||
std::vector<inspirecv::Point2i> landmarks_output(inspire::FaceLandmarkAdapt::NUM_OF_LANDMARK);
|
||||
for (int i = 0; i < inspire::FaceLandmarkAdapt::NUM_OF_LANDMARK; ++i) {
|
||||
float x = lmk_out[i * 2 + 0] * image.Width();
|
||||
float y = lmk_out[i * 2 + 1] * image.Height();
|
||||
landmarks_output[i] = inspirecv::Point<int>(x, y);
|
||||
}
|
||||
|
||||
for (int i = 0; i < landmarks_output.size(); ++i) {
|
||||
image.DrawCircle(landmarks_output[i], 5, {0, 0, 255});
|
||||
}
|
||||
image.Write("crop_lmk.png");
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/track_module/face_track_module.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/middleware/inspirecv_image_process.h>
|
||||
#include <inspireface/pipeline_module/face_pipeline_module.h>
|
||||
#include <inspireface/common/face_data/face_serialize_tools.h>
|
||||
|
||||
using namespace inspire;
|
||||
|
||||
int main() {
|
||||
std::string expansion_path = "";
|
||||
INSPIRE_LAUNCH->Load("test_res/pack/Pikachu");
|
||||
auto archive = INSPIRE_LAUNCH->getMArchive();
|
||||
auto mode = inspire::DetectModuleMode::DETECT_MODE_LIGHT_TRACK;
|
||||
FaceTrackModule tracker(mode, 10, 20, 320, -1);
|
||||
tracker.Configuration(archive, expansion_path);
|
||||
|
||||
FacePipelineModule pipe(archive, true, true, true, true);
|
||||
|
||||
auto image = inspirecv::Image::Create("test_res/data/bulk/r90.jpg");
|
||||
inspirecv::InspireImageProcess processor;
|
||||
processor.SetDataBuffer(image.Data(), image.Height(), image.Width());
|
||||
processor.SetDataFormat(inspirecv::DATA_FORMAT::BGR);
|
||||
processor.SetRotationMode(inspirecv::ROTATION_MODE::ROTATION_90);
|
||||
std::vector<FaceProcessFunctionOption> methods = {PROCESS_MASK, PROCESS_RGB_LIVENESS, PROCESS_ATTRIBUTE, PROCESS_INTERACTION};
|
||||
for (int i = 0; i < 1; i++) {
|
||||
auto show = image.Clone();
|
||||
tracker.UpdateStream(processor);
|
||||
auto faces = tracker.trackingFace;
|
||||
int index = 0;
|
||||
if (faces.size() > 0) {
|
||||
auto &face = faces[index];
|
||||
auto hyper_face = FaceObjectInternalToHyperFaceData(face);
|
||||
PrintHyperFaceDataDetail(hyper_face);
|
||||
|
||||
std::cout << face.getTransMatrix() << std::endl;
|
||||
|
||||
for (auto method : methods) {
|
||||
pipe.Process(processor, hyper_face, method);
|
||||
}
|
||||
std::cout << "eyes status: " << pipe.eyesStatusCache[0] << " " << pipe.eyesStatusCache[1] << std::endl;
|
||||
}
|
||||
|
||||
// show.Show("faces", );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
39
cpp-package/inspireface/cpp/sample/source/tracker_sample.cpp
Normal file
39
cpp-package/inspireface/cpp/sample/source/tracker_sample.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <inspirecv/inspirecv.h>
|
||||
#include <inspireface/track_module/face_track_module.h>
|
||||
#include "inspireface/initialization_module/launch.h"
|
||||
#include <inspireface/middleware/inspirecv_image_process.h>
|
||||
|
||||
using namespace inspire;
|
||||
|
||||
int main() {
|
||||
std::string expansion_path = "";
|
||||
INSPIRE_LAUNCH->Load("test_res/pack/Pikachu");
|
||||
auto archive = INSPIRE_LAUNCH->getMArchive();
|
||||
auto mode = inspire::DetectModuleMode::DETECT_MODE_ALWAYS_DETECT;
|
||||
FaceTrackModule tracker(mode, 10, 20, 320, -1);
|
||||
tracker.Configuration(archive, expansion_path);
|
||||
|
||||
auto image = inspirecv::Image::Create("test_res/data/bulk/r0.jpg");
|
||||
inspirecv::InspireImageProcess processor;
|
||||
processor.SetDataBuffer(image.Data(), image.Height(), image.Width());
|
||||
processor.SetDataFormat(inspirecv::DATA_FORMAT::BGR);
|
||||
processor.SetRotationMode(inspirecv::ROTATION_MODE::ROTATION_0);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
auto show = image.Clone();
|
||||
tracker.UpdateStream(processor);
|
||||
auto faces = tracker.trackingFace;
|
||||
int index = 0;
|
||||
if (faces.size() > 0) {
|
||||
auto &face = faces[index];
|
||||
for (auto &p : face.high_result.lmk) {
|
||||
show.DrawCircle(p.As<int>(), 5, {0, 255, 0});
|
||||
}
|
||||
for (auto &p : face.landmark_) {
|
||||
show.DrawCircle(p.As<int>(), 5, {0, 0, 255});
|
||||
}
|
||||
}
|
||||
show.Show("faces", 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user