mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
Move GKernelPackage to cv namespace
This commit is contained in:
@@ -62,7 +62,7 @@ void cv::gapi::GBackend::Priv::addMetaSensitiveBackendPasses(ade::ExecutionEngin
|
||||
// which are sensitive to metadata
|
||||
}
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::GBackend::Priv::auxiliaryKernels() const
|
||||
cv::GKernelPackage cv::gapi::GBackend::Priv::auxiliaryKernels() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
// they are called when meta information becomes available.
|
||||
virtual void addMetaSensitiveBackendPasses(ade::ExecutionEngineSetupContext &);
|
||||
|
||||
virtual cv::gapi::GKernelPackage auxiliaryKernels() const;
|
||||
virtual cv::GKernelPackage auxiliaryKernels() const;
|
||||
|
||||
// Ask backend if it has a custom control over island fusion process
|
||||
// This method is quite redundant but there's nothing better fits
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "api/gbackend_priv.hpp"
|
||||
|
||||
// GKernelPackage public implementation ////////////////////////////////////////
|
||||
void cv::gapi::GKernelPackage::remove(const cv::gapi::GBackend& backend)
|
||||
void cv::GKernelPackage::remove(const cv::gapi::GBackend& backend)
|
||||
{
|
||||
std::vector<std::string> id_deleted_kernels;
|
||||
for (const auto& p : m_id_kernels)
|
||||
@@ -35,27 +35,38 @@ void cv::gapi::GKernelPackage::remove(const cv::gapi::GBackend& backend)
|
||||
}
|
||||
}
|
||||
|
||||
bool cv::gapi::GKernelPackage::includesAPI(const std::string &id) const
|
||||
void cv::GKernelPackage::include(const cv::gapi::GFunctor& functor)
|
||||
{
|
||||
m_id_kernels[functor.id()] = std::make_pair(functor.backend(), functor.impl());
|
||||
}
|
||||
|
||||
void cv::GKernelPackage::include(const cv::gapi::GBackend& backend, const std::string& kernel_id)
|
||||
{
|
||||
removeAPI(kernel_id);
|
||||
m_id_kernels[kernel_id] = std::make_pair(backend, GKernelImpl{{}, {}});
|
||||
}
|
||||
|
||||
bool cv::GKernelPackage::includesAPI(const std::string &id) const
|
||||
{
|
||||
return ade::util::contains(m_id_kernels, id);
|
||||
}
|
||||
|
||||
void cv::gapi::GKernelPackage::removeAPI(const std::string &id)
|
||||
void cv::GKernelPackage::removeAPI(const std::string &id)
|
||||
{
|
||||
m_id_kernels.erase(id);
|
||||
}
|
||||
|
||||
std::size_t cv::gapi::GKernelPackage::size() const
|
||||
std::size_t cv::GKernelPackage::size() const
|
||||
{
|
||||
return m_id_kernels.size();
|
||||
}
|
||||
|
||||
const std::vector<cv::GTransform> &cv::gapi::GKernelPackage::get_transformations() const
|
||||
const std::vector<cv::GTransform> &cv::GKernelPackage::get_transformations() const
|
||||
{
|
||||
return m_transformations;
|
||||
}
|
||||
|
||||
std::vector<std::string> cv::gapi::GKernelPackage::get_kernel_ids() const
|
||||
std::vector<std::string> cv::GKernelPackage::get_kernel_ids() const
|
||||
{
|
||||
std::vector<std::string> ids;
|
||||
for (auto &&id : m_id_kernels)
|
||||
@@ -65,13 +76,13 @@ std::vector<std::string> cv::gapi::GKernelPackage::get_kernel_ids() const
|
||||
return ids;
|
||||
}
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::combine(const GKernelPackage &lhs,
|
||||
const GKernelPackage &rhs)
|
||||
cv::GKernelPackage cv::gapi::combine(const cv::GKernelPackage &lhs,
|
||||
const cv::GKernelPackage &rhs)
|
||||
{
|
||||
|
||||
// If there is a collision, prefer RHS to LHS
|
||||
// since RHS package has a precedense, start with its copy
|
||||
GKernelPackage result(rhs);
|
||||
cv::GKernelPackage result(rhs);
|
||||
// now iterate over LHS package and put kernel if and only
|
||||
// if there's no such one
|
||||
for (const auto& kernel : lhs.m_id_kernels)
|
||||
@@ -88,7 +99,7 @@ cv::gapi::GKernelPackage cv::gapi::combine(const GKernelPackage &lhs,
|
||||
}
|
||||
|
||||
std::pair<cv::gapi::GBackend, cv::GKernelImpl>
|
||||
cv::gapi::GKernelPackage::lookup(const std::string &id) const
|
||||
cv::GKernelPackage::lookup(const std::string &id) const
|
||||
{
|
||||
auto kernel_it = m_id_kernels.find(id);
|
||||
if (kernel_it != m_id_kernels.end())
|
||||
@@ -99,7 +110,7 @@ cv::gapi::GKernelPackage::lookup(const std::string &id) const
|
||||
util::throw_error(std::logic_error("Kernel " + id + " was not found"));
|
||||
}
|
||||
|
||||
std::vector<cv::gapi::GBackend> cv::gapi::GKernelPackage::backends() const
|
||||
std::vector<cv::gapi::GBackend> cv::GKernelPackage::backends() const
|
||||
{
|
||||
using kernel_type = std::pair<std::string, std::pair<cv::gapi::GBackend, cv::GKernelImpl>>;
|
||||
std::unordered_set<cv::gapi::GBackend> unique_set;
|
||||
|
||||
@@ -113,6 +113,6 @@ struct InGraphMetaKernel final: public cv::detail::KernelTag {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
cv::gapi::GKernelPackage cv::gimpl::meta::kernels() {
|
||||
cv::GKernelPackage cv::gimpl::meta::kernels() {
|
||||
return cv::gapi::kernels<InGraphMetaKernel>();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace cv {
|
||||
namespace gimpl {
|
||||
namespace meta {
|
||||
|
||||
cv::gapi::GKernelPackage kernels();
|
||||
cv::GKernelPackage kernels();
|
||||
|
||||
} // namespace meta
|
||||
} // namespace gimpl
|
||||
|
||||
@@ -720,7 +720,7 @@ GAPI_OCV_KERNEL(GCPUSizeMF, cv::gapi::streaming::GSizeMF)
|
||||
}
|
||||
};
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels()
|
||||
cv::GKernelPackage cv::gapi::core::cpu::kernels()
|
||||
{
|
||||
static auto pkg = cv::gapi::kernels
|
||||
< GCPUAdd
|
||||
|
||||
@@ -613,7 +613,7 @@ GAPI_OCV_KERNEL(GCPUNV12toBGRp, cv::gapi::imgproc::GNV12toBGRp)
|
||||
}
|
||||
};
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels()
|
||||
cv::GKernelPackage cv::gapi::imgproc::cpu::kernels()
|
||||
{
|
||||
static auto pkg = cv::gapi::kernels
|
||||
< GCPUFilter2D
|
||||
|
||||
@@ -70,14 +70,14 @@ GAPI_OCV_KERNEL_ST(GCPUStereo, cv::gapi::calib3d::GStereo, StereoSetup)
|
||||
}
|
||||
};
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::calib3d::cpu::kernels() {
|
||||
cv::GKernelPackage cv::gapi::calib3d::cpu::kernels() {
|
||||
static auto pkg = cv::gapi::kernels<GCPUStereo>();
|
||||
return pkg;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::calib3d::cpu::kernels()
|
||||
cv::GKernelPackage cv::gapi::calib3d::cpu::kernels()
|
||||
{
|
||||
return GKernelPackage();
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ GAPI_OCV_KERNEL_ST(GCPUKalmanFilterNoControl, cv::gapi::video::GKalmanFilterNoCo
|
||||
}
|
||||
};
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::video::cpu::kernels()
|
||||
cv::GKernelPackage cv::gapi::video::cpu::kernels()
|
||||
{
|
||||
static auto pkg = cv::gapi::kernels
|
||||
< GCPUBuildOptFlowPyramid
|
||||
@@ -189,7 +189,7 @@ cv::gapi::GKernelPackage cv::gapi::video::cpu::kernels()
|
||||
|
||||
#else
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::video::cpu::kernels()
|
||||
cv::GKernelPackage cv::gapi::video::cpu::kernels()
|
||||
{
|
||||
return GKernelPackage();
|
||||
}
|
||||
|
||||
@@ -3079,7 +3079,7 @@ GAPI_FLUID_KERNEL(GFluidSqrt, cv::gapi::core::GSqrt, false)
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::core::fluid::kernels()
|
||||
cv::GKernelPackage cv::gapi::core::fluid::kernels()
|
||||
{
|
||||
using namespace cv::gapi::fluid;
|
||||
|
||||
|
||||
@@ -1825,7 +1825,7 @@ GAPI_FLUID_KERNEL(GFluidBayerGR2RGB, cv::gapi::imgproc::GBayerGR2RGB, false)
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::imgproc::fluid::kernels()
|
||||
cv::GKernelPackage cv::gapi::imgproc::fluid::kernels()
|
||||
{
|
||||
using namespace cv::gapi::fluid;
|
||||
|
||||
|
||||
@@ -1456,7 +1456,7 @@ namespace {
|
||||
return EPtr{new cv::gimpl::ie::GIEExecutable(graph, nodes)};
|
||||
}
|
||||
|
||||
virtual cv::gapi::GKernelPackage auxiliaryKernels() const override {
|
||||
virtual cv::GKernelPackage auxiliaryKernels() const override {
|
||||
return cv::gapi::kernels< cv::gimpl::ie::Infer
|
||||
, cv::gimpl::ie::InferROI
|
||||
, cv::gimpl::ie::InferList
|
||||
|
||||
@@ -531,7 +531,7 @@ GAPI_OCL_KERNEL(GOCLTranspose, cv::gapi::core::GTranspose)
|
||||
}
|
||||
};
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::core::ocl::kernels()
|
||||
cv::GKernelPackage cv::gapi::core::ocl::kernels()
|
||||
{
|
||||
static auto pkg = cv::gapi::kernels
|
||||
< GOCLAdd
|
||||
|
||||
@@ -266,7 +266,7 @@ GAPI_OCL_KERNEL(GOCLRGB2GrayCustom, cv::gapi::imgproc::GRGB2GrayCustom)
|
||||
};
|
||||
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::imgproc::ocl::kernels()
|
||||
cv::GKernelPackage cv::gapi::imgproc::ocl::kernels()
|
||||
{
|
||||
static auto pkg = cv::gapi::kernels
|
||||
< GOCLFilter2D
|
||||
|
||||
@@ -1147,7 +1147,7 @@ namespace {
|
||||
return EPtr{new cv::gimpl::onnx::GONNXExecutable(graph, nodes)};
|
||||
}
|
||||
|
||||
virtual cv::gapi::GKernelPackage auxiliaryKernels() const override {
|
||||
virtual cv::GKernelPackage auxiliaryKernels() const override {
|
||||
return cv::gapi::kernels< cv::gimpl::onnx::Infer
|
||||
, cv::gimpl::onnx::InferROI
|
||||
, cv::gimpl::onnx::InferList
|
||||
|
||||
@@ -47,7 +47,7 @@ GAPI_PLAIDML_LOGICAL_OP(GPlaidMLOr , cv::gapi::core::GOr , |)
|
||||
GAPI_PLAIDML_ARITHMETIC_OP(GPlaidMLAdd, cv::gapi::core::GAdd, +);
|
||||
GAPI_PLAIDML_ARITHMETIC_OP(GPlaidMLSub, cv::gapi::core::GSub, -);
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::core::plaidml::kernels()
|
||||
cv::GKernelPackage cv::gapi::core::plaidml::kernels()
|
||||
{
|
||||
static auto pkg = cv::gapi::kernels<GPlaidMLAdd, GPlaidMLSub, GPlaidMLAnd, GPlaidMLXor, GPlaidMLOr>();
|
||||
return pkg;
|
||||
@@ -55,7 +55,7 @@ cv::gapi::GKernelPackage cv::gapi::core::plaidml::kernels()
|
||||
|
||||
#else // HAVE_PLAIDML
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::core::plaidml::kernels()
|
||||
cv::GKernelPackage cv::gapi::core::plaidml::kernels()
|
||||
{
|
||||
// Still provide this symbol to avoid linking issues
|
||||
util::throw_error(std::runtime_error("G-API has been compiled without PlaidML2 support"));
|
||||
|
||||
@@ -193,7 +193,7 @@ GAPI_OCV_KERNEL_ST(RenderFrameOCVImpl, cv::gapi::wip::draw::GRenderFrame, Render
|
||||
};
|
||||
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::render::ocv::kernels()
|
||||
cv::GKernelPackage cv::gapi::render::ocv::kernels()
|
||||
{
|
||||
const static auto pkg = cv::gapi::kernels<RenderBGROCVImpl, RenderNV12OCVImpl, RenderFrameOCVImpl>();
|
||||
return pkg;
|
||||
|
||||
@@ -193,7 +193,7 @@ void Copy::Actor::run(cv::gimpl::GIslandExecutable::IInput &in,
|
||||
out.post(std::move(out_arg));
|
||||
}
|
||||
|
||||
cv::gapi::GKernelPackage cv::gimpl::streaming::kernels()
|
||||
cv::GKernelPackage cv::gimpl::streaming::kernels()
|
||||
{
|
||||
return cv::gapi::kernels<Copy>();
|
||||
}
|
||||
@@ -414,14 +414,14 @@ void GOCVUV::Actor::extractRMat(const cv::MediaFrame& frame, cv::RMat& rmat)
|
||||
}
|
||||
}
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::streaming::kernels()
|
||||
cv::GKernelPackage cv::gapi::streaming::kernels()
|
||||
{
|
||||
return cv::gapi::kernels<GOCVBGR, GOCVY, GOCVUV>();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::streaming::kernels()
|
||||
cv::GKernelPackage cv::gapi::streaming::kernels()
|
||||
{
|
||||
// Still provide this symbol to avoid linking issues
|
||||
util::throw_error(std::runtime_error("cv::gapi::streaming::kernels() isn't supported in standalone"));
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace cv {
|
||||
namespace gimpl {
|
||||
namespace streaming {
|
||||
|
||||
cv::gapi::GKernelPackage kernels();
|
||||
cv::GKernelPackage kernels();
|
||||
|
||||
struct GCopy final : public cv::detail::NoTag
|
||||
{
|
||||
|
||||
@@ -53,18 +53,18 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
cv::gapi::GKernelPackage getKernelPackage(cv::GCompileArgs &args)
|
||||
cv::GKernelPackage getKernelPackage(cv::GCompileArgs &args)
|
||||
{
|
||||
auto withAuxKernels = [](const cv::gapi::GKernelPackage& pkg) {
|
||||
cv::gapi::GKernelPackage aux_pkg;
|
||||
auto withAuxKernels = [](const cv::GKernelPackage& pkg) {
|
||||
cv::GKernelPackage aux_pkg;
|
||||
for (const auto &b : pkg.backends()) {
|
||||
aux_pkg = combine(aux_pkg, b.priv().auxiliaryKernels());
|
||||
aux_pkg = cv::gapi::combine(aux_pkg, b.priv().auxiliaryKernels());
|
||||
}
|
||||
// Always include built-in meta<> and copy implementation
|
||||
return combine(pkg,
|
||||
aux_pkg,
|
||||
cv::gimpl::meta::kernels(),
|
||||
cv::gimpl::streaming::kernels());
|
||||
return cv::gapi::combine(pkg,
|
||||
aux_pkg,
|
||||
cv::gimpl::meta::kernels(),
|
||||
cv::gimpl::streaming::kernels());
|
||||
};
|
||||
|
||||
auto has_use_only = cv::gapi::getCompileArg<cv::gapi::use_only>(args);
|
||||
@@ -73,18 +73,18 @@ namespace
|
||||
|
||||
static auto ocv_pkg =
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
combine(cv::gapi::core::cpu::kernels(),
|
||||
cv::gapi::imgproc::cpu::kernels(),
|
||||
cv::gapi::video::cpu::kernels(),
|
||||
cv::gapi::render::ocv::kernels(),
|
||||
cv::gapi::streaming::kernels());
|
||||
cv::gapi::combine(cv::gapi::core::cpu::kernels(),
|
||||
cv::gapi::imgproc::cpu::kernels(),
|
||||
cv::gapi::video::cpu::kernels(),
|
||||
cv::gapi::render::ocv::kernels(),
|
||||
cv::gapi::streaming::kernels());
|
||||
#else
|
||||
cv::gapi::GKernelPackage();
|
||||
cv::GKernelPackage();
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
|
||||
auto user_pkg = cv::gapi::getCompileArg<cv::gapi::GKernelPackage>(args);
|
||||
auto user_pkg_with_aux = withAuxKernels(user_pkg.value_or(cv::gapi::GKernelPackage{}));
|
||||
return combine(ocv_pkg, user_pkg_with_aux);
|
||||
auto user_pkg = cv::gapi::getCompileArg<cv::GKernelPackage>(args);
|
||||
auto user_pkg_with_aux = withAuxKernels(user_pkg.value_or(cv::GKernelPackage{}));
|
||||
return cv::gapi::combine(ocv_pkg, user_pkg_with_aux);
|
||||
}
|
||||
|
||||
cv::gapi::GNetPackage getNetworkPackage(cv::GCompileArgs &args)
|
||||
@@ -110,8 +110,8 @@ namespace
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
cv::gapi::GKernelPackage auxKernelsFrom(const C& c) {
|
||||
cv::gapi::GKernelPackage result;
|
||||
cv::GKernelPackage auxKernelsFrom(const C& c) {
|
||||
cv::GKernelPackage result;
|
||||
for (const auto &b : c) {
|
||||
result = cv::gapi::combine(result, b.priv().auxiliaryKernels());
|
||||
}
|
||||
@@ -121,7 +121,7 @@ namespace
|
||||
using adeGraphs = std::vector<std::unique_ptr<ade::Graph>>;
|
||||
|
||||
// Creates ADE graphs (patterns and substitutes) from pkg's transformations
|
||||
void makeTransformationGraphs(const cv::gapi::GKernelPackage& pkg,
|
||||
void makeTransformationGraphs(const cv::GKernelPackage& pkg,
|
||||
adeGraphs& patterns,
|
||||
adeGraphs& substitutes) {
|
||||
const auto& transforms = pkg.get_transformations();
|
||||
@@ -142,7 +142,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void checkTransformations(const cv::gapi::GKernelPackage& pkg,
|
||||
void checkTransformations(const cv::GKernelPackage& pkg,
|
||||
const adeGraphs& patterns,
|
||||
const adeGraphs& substitutes) {
|
||||
const auto& transforms = pkg.get_transformations();
|
||||
|
||||
@@ -26,7 +26,7 @@ class GAPI_EXPORTS GCompiler
|
||||
GCompileArgs m_args;
|
||||
ade::ExecutionEngine m_e;
|
||||
|
||||
cv::gapi::GKernelPackage m_all_kernels;
|
||||
cv::GKernelPackage m_all_kernels;
|
||||
cv::gapi::GNetPackage m_all_networks;
|
||||
|
||||
// Patterns built from transformations
|
||||
|
||||
@@ -157,7 +157,7 @@ void cv::gimpl::passes::bindNetParams(ade::passes::PassContext &ctx,
|
||||
// kernels, but if not, they are handled by the framework itself in
|
||||
// its optimization/execution passes.
|
||||
void cv::gimpl::passes::resolveKernels(ade::passes::PassContext &ctx,
|
||||
const gapi::GKernelPackage &kernels)
|
||||
const GKernelPackage &kernels)
|
||||
{
|
||||
std::unordered_set<cv::gapi::GBackend> active_backends;
|
||||
|
||||
@@ -220,7 +220,7 @@ void cv::gimpl::passes::resolveKernels(ade::passes::PassContext &ctx,
|
||||
gr.metadata().set(ActiveBackends{active_backends});
|
||||
}
|
||||
|
||||
void cv::gimpl::passes::expandKernels(ade::passes::PassContext &ctx, const gapi::GKernelPackage &kernels)
|
||||
void cv::gimpl::passes::expandKernels(ade::passes::PassContext &ctx, const GKernelPackage &kernels)
|
||||
{
|
||||
GModel::Graph gr(ctx.graph);
|
||||
|
||||
|
||||
@@ -23,11 +23,11 @@ namespace ade {
|
||||
}
|
||||
}
|
||||
|
||||
namespace cv {
|
||||
|
||||
// Forward declarations - internal
|
||||
namespace gapi {
|
||||
namespace cv {
|
||||
class GKernelPackage;
|
||||
|
||||
namespace gapi {
|
||||
struct GNetPackage;
|
||||
} // namespace gapi
|
||||
|
||||
@@ -52,20 +52,20 @@ void inferMeta(ade::passes::PassContext &ctx, bool meta_is_initialized);
|
||||
void storeResultingMeta(ade::passes::PassContext &ctx);
|
||||
|
||||
void expandKernels(ade::passes::PassContext &ctx,
|
||||
const gapi::GKernelPackage& kernels);
|
||||
const GKernelPackage& kernels);
|
||||
|
||||
void bindNetParams(ade::passes::PassContext &ctx,
|
||||
const gapi::GNetPackage &networks);
|
||||
|
||||
void resolveKernels(ade::passes::PassContext &ctx,
|
||||
const gapi::GKernelPackage &kernels);
|
||||
const GKernelPackage &kernels);
|
||||
|
||||
void fuseIslands(ade::passes::PassContext &ctx);
|
||||
void syncIslandTags(ade::passes::PassContext &ctx);
|
||||
void topoSortIslands(ade::passes::PassContext &ctx);
|
||||
|
||||
void applyTransformations(ade::passes::PassContext &ctx,
|
||||
const gapi::GKernelPackage &pkg,
|
||||
const GKernelPackage &pkg,
|
||||
const std::vector<std::unique_ptr<ade::Graph>> &preGeneratedPatterns);
|
||||
|
||||
void addStreaming(ade::passes::PassContext &ctx);
|
||||
|
||||
@@ -99,7 +99,7 @@ bool tryToSubstitute(ade::Graph& main,
|
||||
} // anonymous namespace
|
||||
|
||||
void applyTransformations(ade::passes::PassContext& ctx,
|
||||
const gapi::GKernelPackage& pkg,
|
||||
const GKernelPackage& pkg,
|
||||
const std::vector<std::unique_ptr<ade::Graph>>& patterns)
|
||||
{
|
||||
const auto& transforms = pkg.get_transformations();
|
||||
|
||||
Reference in New Issue
Block a user