mirror of
https://github.com/tesseract-ocr/tesseract.git
synced 2024-11-24 11:09:06 +08:00
Replace malloc / free by new / delete for FEATURE_STRUCT, FEATURE_SET_STRUCT
Signed-off-by: Stefan Weil <sw@weilnetz.de>
This commit is contained in:
parent
aa8dda89a3
commit
b15b5d1de7
@ -39,7 +39,7 @@
|
||||
#include "mfoutline.h" // for baseline, character, MF_SCALE_FACTOR
|
||||
#include "normalis.h" // for DENORM, kBlnBaselineOffset, kBlnXHeight
|
||||
#include "normfeat.h" // for ActualOutlineLength, CharNormLength
|
||||
#include "ocrfeatures.h" // for FEATURE_STRUCT, FreeFeatureSet, FEATURE
|
||||
#include "ocrfeatures.h" // for FEATURE_STRUCT, FEATURE
|
||||
#include "oldlist.h" // for push, delete_d
|
||||
#include "outfeat.h" // for OutlineFeatDir, OutlineFeatLength
|
||||
#include "pageres.h" // for WERD_RES
|
||||
@ -68,7 +68,6 @@
|
||||
#include <cmath> // for fabs
|
||||
#include <cstdint> // for INT32_MAX, UINT8_MAX
|
||||
#include <cstdio> // for fflush, fclose, fopen, stdout, FILE
|
||||
#include <cstdlib> // for malloc
|
||||
#include <cstring> // for strstr, memset, strcmp
|
||||
|
||||
namespace tesseract {
|
||||
@ -693,7 +692,7 @@ void Classify::InitAdaptedClass(TBLOB *Blob, CLASS_ID ClassId, int FontinfoId, A
|
||||
Features = ExtractOutlineFeatures(Blob);
|
||||
NumFeatures = Features->NumFeatures;
|
||||
if (NumFeatures > UNLIKELY_NUM_FEAT || NumFeatures <= 0) {
|
||||
FreeFeatureSet(Features);
|
||||
delete Features;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -732,7 +731,7 @@ void Classify::InitAdaptedClass(TBLOB *Blob, CLASS_ID ClassId, int FontinfoId, A
|
||||
|
||||
Class->TempProtos = push(Class->TempProtos, TempProto);
|
||||
}
|
||||
FreeFeatureSet(Features);
|
||||
delete Features;
|
||||
|
||||
AddIntConfig(IClass);
|
||||
ConvertConfig(AllProtosOn, 0, IClass);
|
||||
@ -781,7 +780,7 @@ int Classify::GetAdaptiveFeatures(TBLOB *Blob, INT_FEATURE_ARRAY IntFeatures,
|
||||
|
||||
NumFeatures = Features->NumFeatures;
|
||||
if (NumFeatures == 0 || NumFeatures > UNLIKELY_NUM_FEAT) {
|
||||
FreeFeatureSet(Features);
|
||||
delete Features;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -885,7 +884,7 @@ void Classify::AdaptToChar(TBLOB *Blob, CLASS_ID ClassId, int FontinfoId, float
|
||||
tprintf("Found good match to perm config %d = %4.1f%%.\n", int_result.config,
|
||||
int_result.rating * 100.0);
|
||||
}
|
||||
FreeFeatureSet(FloatFeatures);
|
||||
delete FloatFeatures;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -927,7 +926,7 @@ void Classify::AdaptToChar(TBLOB *Blob, CLASS_ID ClassId, int FontinfoId, float
|
||||
}
|
||||
#endif
|
||||
}
|
||||
FreeFeatureSet(FloatFeatures);
|
||||
delete FloatFeatures;
|
||||
}
|
||||
} /* AdaptToChar */
|
||||
|
||||
@ -1611,7 +1610,7 @@ bool Classify::LooksLikeGarbage(TBLOB *blob) {
|
||||
*/
|
||||
int Classify::GetCharNormFeature(const INT_FX_RESULT_STRUCT &fx_info, INT_TEMPLATES_STRUCT *templates,
|
||||
uint8_t *pruner_norm_array, uint8_t *char_norm_array) {
|
||||
FEATURE norm_feature = NewFeature(&CharNormDesc);
|
||||
auto norm_feature = new FEATURE_STRUCT(&CharNormDesc);
|
||||
float baseline = kBlnBaselineOffset;
|
||||
float scale = MF_SCALE_FACTOR;
|
||||
norm_feature->Params[CharNormY] = (fx_info.Ymean - baseline) * scale;
|
||||
@ -1649,7 +1648,7 @@ void Classify::ComputeCharNormArrays(FEATURE_STRUCT *norm_feature, INT_TEMPLATES
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeFeature(norm_feature);
|
||||
delete norm_feature;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -57,7 +57,7 @@ struct CHAR_DESC_STRUCT {
|
||||
/// description and all of the features in that description.
|
||||
~CHAR_DESC_STRUCT() {
|
||||
for (size_t i = 0; i < NumFeatureSets; i++) {
|
||||
FreeFeatureSet(FeatureSets[i]);
|
||||
delete FeatureSets[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
** Filename: mf.c
|
||||
** Purpose: Micro-feature interface to flexible feature extractor.
|
||||
** Author: Dan Johnson
|
||||
** History: Thu May 24 09:08:38 1990, DSJ, Created.
|
||||
**
|
||||
** (c) Copyright Hewlett-Packard Company, 1988.
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -42,8 +41,6 @@ namespace tesseract {
|
||||
FEATURE_SET ExtractMicros(TBLOB *Blob, const DENORM &cn_denorm) {
|
||||
int NumFeatures;
|
||||
MICROFEATURES Features, OldFeatures;
|
||||
FEATURE_SET FeatureSet;
|
||||
FEATURE Feature;
|
||||
MICROFEATURE OldFeature;
|
||||
|
||||
OldFeatures = BlobMicroFeatures(Blob, cn_denorm);
|
||||
@ -51,12 +48,12 @@ FEATURE_SET ExtractMicros(TBLOB *Blob, const DENORM &cn_denorm) {
|
||||
return nullptr;
|
||||
}
|
||||
NumFeatures = count(OldFeatures);
|
||||
FeatureSet = NewFeatureSet(NumFeatures);
|
||||
auto FeatureSet = new FEATURE_SET_STRUCT(NumFeatures);
|
||||
|
||||
Features = OldFeatures;
|
||||
iterate(Features) {
|
||||
OldFeature = reinterpret_cast<MICROFEATURE> first_node(Features);
|
||||
Feature = NewFeature(&MicroFeatureDesc);
|
||||
auto Feature = new FEATURE_STRUCT(&MicroFeatureDesc);
|
||||
Feature->Params[MFDirection] = OldFeature[ORIENTATION];
|
||||
Feature->Params[MFXPosition] = OldFeature[XPOSITION];
|
||||
Feature->Params[MFYPosition] = OldFeature[YPOSITION];
|
||||
|
@ -2,7 +2,6 @@
|
||||
** Filename: normfeat.c
|
||||
** Purpose: Definition of char normalization features.
|
||||
** Author: Dan Johnson
|
||||
** History: 12/14/90, DSJ, Created.
|
||||
**
|
||||
** (c) Copyright Hewlett-Packard Company, 1988.
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -55,8 +54,8 @@ float ActualOutlineLength(FEATURE Feature) {
|
||||
* - English: [0.011, 0.31]
|
||||
*/
|
||||
FEATURE_SET ExtractCharNormFeatures(const INT_FX_RESULT_STRUCT &fx_info) {
|
||||
FEATURE_SET feature_set = NewFeatureSet(1);
|
||||
FEATURE feature = NewFeature(&CharNormDesc);
|
||||
auto feature_set = new FEATURE_SET_STRUCT(1);
|
||||
auto feature = new FEATURE_STRUCT(&CharNormDesc);
|
||||
|
||||
feature->Params[CharNormY] = MF_SCALE_FACTOR * (fx_info.Ymean - kBlnBaselineOffset);
|
||||
feature->Params[CharNormLength] = MF_SCALE_FACTOR * fx_info.Length / LENGTH_COMPRESSION;
|
||||
|
@ -38,7 +38,7 @@ namespace tesseract {
|
||||
*/
|
||||
bool AddFeature(FEATURE_SET FeatureSet, FEATURE Feature) {
|
||||
if (FeatureSet->NumFeatures >= FeatureSet->MaxNumFeatures) {
|
||||
FreeFeature(Feature);
|
||||
delete Feature;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -46,64 +46,6 @@ bool AddFeature(FEATURE_SET FeatureSet, FEATURE Feature) {
|
||||
return true;
|
||||
} /* AddFeature */
|
||||
|
||||
/**
|
||||
* Release the memory consumed by the specified feature.
|
||||
* @param Feature feature to be deallocated.
|
||||
*/
|
||||
void FreeFeature(FEATURE Feature) {
|
||||
free(Feature);
|
||||
} /* FreeFeature */
|
||||
|
||||
/**
|
||||
* Release the memory consumed by the specified feature
|
||||
* set. This routine also frees the memory consumed by the
|
||||
* features contained in the set.
|
||||
* @param FeatureSet set of features to be freed
|
||||
*/
|
||||
void FreeFeatureSet(FEATURE_SET FeatureSet) {
|
||||
int i;
|
||||
|
||||
if (FeatureSet) {
|
||||
for (i = 0; i < FeatureSet->NumFeatures; i++) {
|
||||
FreeFeature(FeatureSet->Features[i]);
|
||||
}
|
||||
free(FeatureSet);
|
||||
}
|
||||
} /* FreeFeatureSet */
|
||||
|
||||
/**
|
||||
* Allocate and return a new feature of the specified
|
||||
* type.
|
||||
* @param FeatureDesc description of feature to be created.
|
||||
* @return New #FEATURE.
|
||||
*/
|
||||
FEATURE NewFeature(const FEATURE_DESC_STRUCT *FeatureDesc) {
|
||||
FEATURE Feature;
|
||||
|
||||
Feature = static_cast<FEATURE>(
|
||||
malloc(sizeof(FEATURE_STRUCT) + (FeatureDesc->NumParams - 1) * sizeof(float)));
|
||||
Feature->Type = FeatureDesc;
|
||||
return (Feature);
|
||||
|
||||
} /* NewFeature */
|
||||
|
||||
/**
|
||||
* Allocate and return a new feature set large enough to
|
||||
* hold the specified number of features.
|
||||
* @param NumFeatures maximum # of features to be put in feature set
|
||||
* @return New #FEATURE_SET.
|
||||
*/
|
||||
FEATURE_SET NewFeatureSet(int NumFeatures) {
|
||||
FEATURE_SET FeatureSet;
|
||||
|
||||
FeatureSet = static_cast<FEATURE_SET>(
|
||||
malloc(sizeof(FEATURE_SET_STRUCT) + (NumFeatures - 1) * sizeof(FEATURE)));
|
||||
FeatureSet->MaxNumFeatures = NumFeatures;
|
||||
FeatureSet->NumFeatures = 0;
|
||||
return (FeatureSet);
|
||||
|
||||
} /* NewFeatureSet */
|
||||
|
||||
/**
|
||||
* Create a new feature of the specified type and read in
|
||||
* the value of its parameters from File. The extra penalty
|
||||
@ -116,11 +58,8 @@ FEATURE_SET NewFeatureSet(int NumFeatures) {
|
||||
* @return New #FEATURE read from File.
|
||||
*/
|
||||
static FEATURE ReadFeature(FILE *File, const FEATURE_DESC_STRUCT *FeatureDesc) {
|
||||
FEATURE Feature;
|
||||
int i;
|
||||
|
||||
Feature = NewFeature(FeatureDesc);
|
||||
for (i = 0; i < Feature->Type->NumParams; i++) {
|
||||
auto Feature = new FEATURE_STRUCT(FeatureDesc);
|
||||
for (int i = 0; i < Feature->Type->NumParams; i++) {
|
||||
ASSERT_HOST(tfscanf(File, "%f", &(Feature->Params[i])) == 1);
|
||||
#ifndef _WIN32
|
||||
assert(!std::isnan(Feature->Params[i]));
|
||||
@ -144,7 +83,7 @@ FEATURE_SET ReadFeatureSet(FILE *File, const FEATURE_DESC_STRUCT *FeatureDesc) {
|
||||
ASSERT_HOST(tfscanf(File, "%d", &NumFeatures) == 1);
|
||||
ASSERT_HOST(NumFeatures >= 0);
|
||||
|
||||
FEATURE_SET FeatureSet = NewFeatureSet(NumFeatures);
|
||||
auto FeatureSet = new FEATURE_SET_STRUCT(NumFeatures);
|
||||
for (int i = 0; i < NumFeatures; i++) {
|
||||
AddFeature(FeatureSet, ReadFeature(File, FeatureDesc));
|
||||
}
|
||||
|
@ -56,15 +56,33 @@ struct FEATURE_DESC_STRUCT {
|
||||
using FEATURE_DESC = FEATURE_DESC_STRUCT *;
|
||||
|
||||
struct FEATURE_STRUCT {
|
||||
/// Constructor for a new feature of the specified type.
|
||||
/// @param FeatureDesc description of feature to be created.
|
||||
FEATURE_STRUCT(const FEATURE_DESC_STRUCT *FeatureDesc) : Type(FeatureDesc), Params(FeatureDesc->NumParams) {
|
||||
}
|
||||
~FEATURE_STRUCT() {
|
||||
}
|
||||
const FEATURE_DESC_STRUCT *Type; // points to description of feature type
|
||||
float Params[1]; // variable size array - params for feature
|
||||
std::vector<float> Params; // variable size array - params for feature
|
||||
};
|
||||
using FEATURE = FEATURE_STRUCT *;
|
||||
|
||||
struct FEATURE_SET_STRUCT {
|
||||
/// Creator for a new feature set large enough to
|
||||
/// hold the specified number of features.
|
||||
/// @param NumFeatures maximum # of features to be put in feature set
|
||||
FEATURE_SET_STRUCT(int numFeatures) : NumFeatures(0), MaxNumFeatures(numFeatures), Features(numFeatures) {
|
||||
}
|
||||
|
||||
~FEATURE_SET_STRUCT() {
|
||||
for (uint16_t i = 0; i < NumFeatures; i++) {
|
||||
delete Features[i];
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t NumFeatures; // number of features in set
|
||||
uint16_t MaxNumFeatures; // maximum size of feature set
|
||||
FEATURE Features[1]; // variable size array of features
|
||||
std::vector<FEATURE_STRUCT *> Features; // variable size array of features
|
||||
};
|
||||
using FEATURE_SET = FEATURE_SET_STRUCT *;
|
||||
|
||||
@ -105,17 +123,6 @@ DefineFeature (Name, NumLinear, NumCircular, ShortName, ParamName)
|
||||
----------------------------------------------------------------------*/
|
||||
bool AddFeature(FEATURE_SET FeatureSet, FEATURE Feature);
|
||||
|
||||
TESS_API
|
||||
void FreeFeature(FEATURE Feature);
|
||||
|
||||
TESS_API
|
||||
void FreeFeatureSet(FEATURE_SET FeatureSet);
|
||||
|
||||
TESS_API
|
||||
FEATURE NewFeature(const FEATURE_DESC_STRUCT *FeatureDesc);
|
||||
|
||||
FEATURE_SET NewFeatureSet(int NumFeatures);
|
||||
|
||||
FEATURE_SET ReadFeatureSet(FILE *File, const FEATURE_DESC_STRUCT *FeatureDesc);
|
||||
|
||||
void WriteFeatureSet(FEATURE_SET FeatureSet, std::string &str);
|
||||
|
@ -41,10 +41,9 @@ FEATURE_SET Classify::ExtractOutlineFeatures(TBLOB *Blob) {
|
||||
LIST Outlines;
|
||||
LIST RemainingOutlines;
|
||||
MFOUTLINE Outline;
|
||||
FEATURE_SET FeatureSet;
|
||||
float XScale, YScale;
|
||||
|
||||
FeatureSet = NewFeatureSet(MAX_OUTLINE_FEATURES);
|
||||
auto FeatureSet = new FEATURE_SET_STRUCT(MAX_OUTLINE_FEATURES);
|
||||
if (Blob == nullptr) {
|
||||
return (FeatureSet);
|
||||
}
|
||||
@ -81,9 +80,7 @@ FEATURE_SET Classify::ExtractOutlineFeatures(TBLOB *Blob) {
|
||||
* @param FeatureSet set to add outline-feature to
|
||||
*/
|
||||
void AddOutlineFeatureToSet(FPOINT *Start, FPOINT *End, FEATURE_SET FeatureSet) {
|
||||
FEATURE Feature;
|
||||
|
||||
Feature = NewFeature(&OutlineFeatDesc);
|
||||
auto Feature = new FEATURE_STRUCT(&OutlineFeatDesc);
|
||||
Feature->Params[OutlineFeatDir] = NormalizedAngleFrom(Start, End, 1.0);
|
||||
Feature->Params[OutlineFeatX] = AverageOf(Start->x, End->x);
|
||||
Feature->Params[OutlineFeatY] = AverageOf(Start->y, End->y);
|
||||
|
@ -61,10 +61,9 @@ FEATURE_SET Classify::ExtractPicoFeatures(TBLOB *Blob) {
|
||||
LIST Outlines;
|
||||
LIST RemainingOutlines;
|
||||
MFOUTLINE Outline;
|
||||
FEATURE_SET FeatureSet;
|
||||
float XScale, YScale;
|
||||
|
||||
FeatureSet = NewFeatureSet(MAX_PICO_FEATURES);
|
||||
auto FeatureSet = new FEATURE_SET_STRUCT(MAX_PICO_FEATURES);
|
||||
Outlines = ConvertBlob(Blob);
|
||||
NormalizeOutlines(Outlines, &XScale, &YScale);
|
||||
RemainingOutlines = Outlines;
|
||||
@ -98,7 +97,6 @@ FEATURE_SET Classify::ExtractPicoFeatures(TBLOB *Blob) {
|
||||
* @param FeatureSet set to add pico-feature to
|
||||
*/
|
||||
void ConvertSegmentToPicoFeat(FPOINT *Start, FPOINT *End, FEATURE_SET FeatureSet) {
|
||||
FEATURE Feature;
|
||||
float Angle;
|
||||
float Length;
|
||||
int NumFeatures;
|
||||
@ -123,7 +121,7 @@ void ConvertSegmentToPicoFeat(FPOINT *Start, FPOINT *End, FEATURE_SET FeatureSet
|
||||
|
||||
/* compute each pico feature in segment and add to feature set */
|
||||
for (i = 0; i < NumFeatures; i++) {
|
||||
Feature = NewFeature(&PicoFeatDesc);
|
||||
auto Feature = new FEATURE_STRUCT(&PicoFeatDesc);
|
||||
Feature->Params[PicoFeatDir] = Angle;
|
||||
Feature->Params[PicoFeatX] = Center.x;
|
||||
Feature->Params[PicoFeatY] = Center.y;
|
||||
@ -218,10 +216,9 @@ FEATURE_SET Classify::ExtractIntCNFeatures(const TBLOB &blob, const INT_FX_RESUL
|
||||
|
||||
uint32_t num_features = sample->num_features();
|
||||
const INT_FEATURE_STRUCT *features = sample->features();
|
||||
FEATURE_SET feature_set = NewFeatureSet(num_features);
|
||||
auto feature_set = new FEATURE_SET_STRUCT(num_features);
|
||||
for (uint32_t f = 0; f < num_features; ++f) {
|
||||
FEATURE feature = NewFeature(&IntFeatDesc);
|
||||
|
||||
auto feature = new FEATURE_STRUCT(&IntFeatDesc);
|
||||
feature->Params[IntX] = features[f].X;
|
||||
feature->Params[IntY] = features[f].Y;
|
||||
feature->Params[IntDir] = features[f].Theta;
|
||||
@ -248,8 +245,8 @@ FEATURE_SET Classify::ExtractIntGeoFeatures(const TBLOB &blob,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FEATURE_SET feature_set = NewFeatureSet(1);
|
||||
FEATURE feature = NewFeature(&IntFeatDesc);
|
||||
auto feature_set = new FEATURE_SET_STRUCT(1);
|
||||
auto feature = new FEATURE_STRUCT(&IntFeatDesc);
|
||||
|
||||
feature->Params[GeoBottom] = sample->geo_feature(GeoBottom);
|
||||
feature->Params[GeoTop] = sample->geo_feature(GeoTop);
|
||||
|
@ -183,7 +183,7 @@ TrainingSample *TrainingSample::CopyFromFeatures(const INT_FX_RESULT_STRUCT &fx_
|
||||
|
||||
// Returns the cn_feature as a FEATURE_STRUCT* needed by cntraining.
|
||||
FEATURE_STRUCT *TrainingSample::GetCNFeature() const {
|
||||
FEATURE feature = NewFeature(&CharNormDesc);
|
||||
auto feature = new FEATURE_STRUCT(&CharNormDesc);
|
||||
for (int i = 0; i < kNumCNParams; ++i) {
|
||||
feature->Params[i] = cn_feature_[i];
|
||||
}
|
||||
|
@ -413,11 +413,11 @@ void ReadTrainingSamples(const FEATURE_DEFS_STRUCT &feature_definitions, const c
|
||||
char_sample->SampleCount++;
|
||||
char_sample->font_sample_count++;
|
||||
} else {
|
||||
FreeFeatureSet(feature_samples);
|
||||
delete feature_samples;
|
||||
}
|
||||
for (size_t i = 0; i < char_desc->NumFeatureSets; i++) {
|
||||
if (feature_type != i) {
|
||||
FreeFeatureSet(char_desc->FeatureSets[i]);
|
||||
delete char_desc->FeatureSets[i];
|
||||
}
|
||||
}
|
||||
free(char_desc);
|
||||
@ -441,7 +441,7 @@ void FreeTrainingSamples(LIST CharList) {
|
||||
FeatureList = char_sample->List;
|
||||
iterate(FeatureList) { /* iterate through all of the classes */
|
||||
FeatureSet = reinterpret_cast<FEATURE_SET> first_node(FeatureList);
|
||||
FreeFeatureSet(FeatureSet);
|
||||
delete FeatureSet;
|
||||
}
|
||||
FreeLabeledList(char_sample);
|
||||
}
|
||||
|
@ -64,7 +64,6 @@ static double_VAR(training_angle_pad, 45.0, "Angle pad ...");
|
||||
* @return Worst possible result when matching p1 to p2.
|
||||
*/
|
||||
float CompareProtos(PROTO_STRUCT *p1, PROTO_STRUCT *p2) {
|
||||
FEATURE Feature;
|
||||
float WorstEvidence = WORST_EVIDENCE;
|
||||
float Evidence;
|
||||
float Angle, Length;
|
||||
@ -76,7 +75,7 @@ float CompareProtos(PROTO_STRUCT *p1, PROTO_STRUCT *p2) {
|
||||
}
|
||||
|
||||
/* create a dummy pico-feature to be used for comparisons */
|
||||
Feature = NewFeature(&PicoFeatDesc);
|
||||
auto Feature = new FEATURE_STRUCT(&PicoFeatDesc);
|
||||
Feature->Params[PicoFeatDir] = p1->Angle;
|
||||
|
||||
/* convert angle to radians */
|
||||
@ -97,7 +96,7 @@ float CompareProtos(PROTO_STRUCT *p1, PROTO_STRUCT *p2) {
|
||||
WorstEvidence = Evidence;
|
||||
}
|
||||
} else {
|
||||
FreeFeature(Feature);
|
||||
delete Feature;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
@ -110,11 +109,11 @@ float CompareProtos(PROTO_STRUCT *p1, PROTO_STRUCT *p2) {
|
||||
WorstEvidence = Evidence;
|
||||
}
|
||||
} else {
|
||||
FreeFeature(Feature);
|
||||
delete Feature;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
FreeFeature(Feature);
|
||||
delete Feature;
|
||||
return (WorstEvidence);
|
||||
|
||||
} /* CompareProtos */
|
||||
|
Loading…
Reference in New Issue
Block a user