mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
Merge branch 'feature-readNow' into 'develop'
Feature read now See merge request !102
This commit is contained in:
@ -468,6 +468,7 @@ Foam::Time::Time
|
|||||||
(
|
(
|
||||||
args.parRunControl().parRun(),
|
args.parRunControl().parRun(),
|
||||||
args.rootPath(),
|
args.rootPath(),
|
||||||
|
args.distributed(),
|
||||||
args.globalCaseName(),
|
args.globalCaseName(),
|
||||||
args.caseName(),
|
args.caseName(),
|
||||||
systemName,
|
systemName,
|
||||||
@ -943,6 +944,17 @@ bool Foam::Time::run() const
|
|||||||
addProfiling(functionObjects, "functionObjects.execute()");
|
addProfiling(functionObjects, "functionObjects.execute()");
|
||||||
functionObjects_.execute();
|
functionObjects_.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the execution of functionObjects require re-reading
|
||||||
|
// any files. This moves effect of e.g. 'timeActivatedFileUpdate'
|
||||||
|
// one time step forward. Note that we cannot call
|
||||||
|
// readModifiedObjects from within timeActivatedFileUpdate since
|
||||||
|
// it might re-read the functionObjects themselves (and delete
|
||||||
|
// the timeActivatedFileUpdate one)
|
||||||
|
if (functionObjects_.filesModified())
|
||||||
|
{
|
||||||
|
const_cast<Time&>(*this).readModifiedObjects();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the "running" status following the
|
// Update the "running" status following the
|
||||||
|
|||||||
@ -70,6 +70,7 @@ Foam::TimePaths::TimePaths
|
|||||||
:
|
:
|
||||||
processorCase_(false),
|
processorCase_(false),
|
||||||
rootPath_(rootPath),
|
rootPath_(rootPath),
|
||||||
|
distributed_(false),
|
||||||
globalCaseName_(caseName),
|
globalCaseName_(caseName),
|
||||||
case_(caseName),
|
case_(caseName),
|
||||||
system_(systemName),
|
system_(systemName),
|
||||||
@ -84,6 +85,7 @@ Foam::TimePaths::TimePaths
|
|||||||
(
|
(
|
||||||
const bool processorCase,
|
const bool processorCase,
|
||||||
const fileName& rootPath,
|
const fileName& rootPath,
|
||||||
|
const bool distributed,
|
||||||
const fileName& globalCaseName,
|
const fileName& globalCaseName,
|
||||||
const fileName& caseName,
|
const fileName& caseName,
|
||||||
const word& systemName,
|
const word& systemName,
|
||||||
@ -92,6 +94,7 @@ Foam::TimePaths::TimePaths
|
|||||||
:
|
:
|
||||||
processorCase_(processorCase),
|
processorCase_(processorCase),
|
||||||
rootPath_(rootPath),
|
rootPath_(rootPath),
|
||||||
|
distributed_(distributed),
|
||||||
globalCaseName_(globalCaseName),
|
globalCaseName_(globalCaseName),
|
||||||
case_(caseName),
|
case_(caseName),
|
||||||
system_(systemName),
|
system_(systemName),
|
||||||
|
|||||||
@ -53,6 +53,7 @@ class TimePaths
|
|||||||
|
|
||||||
bool processorCase_;
|
bool processorCase_;
|
||||||
const fileName rootPath_;
|
const fileName rootPath_;
|
||||||
|
bool distributed_;
|
||||||
fileName globalCaseName_;
|
fileName globalCaseName_;
|
||||||
fileName case_;
|
fileName case_;
|
||||||
const word system_;
|
const word system_;
|
||||||
@ -84,6 +85,7 @@ public:
|
|||||||
(
|
(
|
||||||
const bool processorCase,
|
const bool processorCase,
|
||||||
const fileName& rootPath,
|
const fileName& rootPath,
|
||||||
|
const bool distributed,
|
||||||
const fileName& globalCaseName,
|
const fileName& globalCaseName,
|
||||||
const fileName& caseName,
|
const fileName& caseName,
|
||||||
const word& systemName,
|
const word& systemName,
|
||||||
@ -139,6 +141,13 @@ public:
|
|||||||
return constant_;
|
return constant_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//- Is case running with parallel distributed directories
|
||||||
|
// (i.e. not NFS mounted)
|
||||||
|
bool distributed() const
|
||||||
|
{
|
||||||
|
return distributed_;
|
||||||
|
}
|
||||||
|
|
||||||
//- Return constant name for the case
|
//- Return constant name for the case
|
||||||
// which for parallel runs returns ../constant()
|
// which for parallel runs returns ../constant()
|
||||||
fileName caseConstant() const;
|
fileName caseConstant() const;
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -146,6 +146,12 @@ bool Foam::functionObject::adjustTimeStep()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::functionObject::filesModified() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::functionObject::updateMesh(const mapPolyMesh&)
|
void Foam::functionObject::updateMesh(const mapPolyMesh&)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -233,6 +233,9 @@ public:
|
|||||||
//- Called at the end of Time::adjustDeltaT() if adjustTime is true
|
//- Called at the end of Time::adjustDeltaT() if adjustTime is true
|
||||||
virtual bool adjustTimeStep();
|
virtual bool adjustTimeStep();
|
||||||
|
|
||||||
|
//- Did any file get changed during execution?
|
||||||
|
virtual bool filesModified() const;
|
||||||
|
|
||||||
//- Update for changes of mesh
|
//- Update for changes of mesh
|
||||||
virtual void updateMesh(const mapPolyMesh& mpm);
|
virtual void updateMesh(const mapPolyMesh& mpm);
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
\\/ M anipulation | Copyright (C) 2015-2016 OpenCFD Ltd.
|
\\/ M anipulation | Copyright (C) 2015-2017 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -819,6 +819,21 @@ bool Foam::functionObjectList::read()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::functionObjectList::filesModified() const
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
if (execution_)
|
||||||
|
{
|
||||||
|
forAll(*this, objectI)
|
||||||
|
{
|
||||||
|
bool changed = operator[](objectI).filesModified();
|
||||||
|
ok = ok || changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::functionObjectList::updateMesh(const mapPolyMesh& mpm)
|
void Foam::functionObjectList::updateMesh(const mapPolyMesh& mpm)
|
||||||
{
|
{
|
||||||
if (execution_)
|
if (execution_)
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
\\/ M anipulation | Copyright (C) 2015-2016 OpenCFD Ltd.
|
\\/ M anipulation | Copyright (C) 2015-2017 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -264,6 +264,9 @@ public:
|
|||||||
//- Called at the end of Time::adjustDeltaT() if adjustTime is true
|
//- Called at the end of Time::adjustDeltaT() if adjustTime is true
|
||||||
bool adjustTimeStep();
|
bool adjustTimeStep();
|
||||||
|
|
||||||
|
//- Did any file get changed during execution?
|
||||||
|
bool filesModified() const;
|
||||||
|
|
||||||
//- Update for changes of mesh
|
//- Update for changes of mesh
|
||||||
void updateMesh(const mapPolyMesh& mpm);
|
void updateMesh(const mapPolyMesh& mpm);
|
||||||
|
|
||||||
|
|||||||
@ -220,6 +220,17 @@ bool Foam::functionObjects::timeControl::read
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::functionObjects::timeControl::filesModified() const
|
||||||
|
{
|
||||||
|
bool mod = false;
|
||||||
|
if (active())
|
||||||
|
{
|
||||||
|
mod = foPtr_->filesModified();
|
||||||
|
}
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::functionObjects::timeControl::updateMesh
|
void Foam::functionObjects::timeControl::updateMesh
|
||||||
(
|
(
|
||||||
const mapPolyMesh& mpm
|
const mapPolyMesh& mpm
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -177,6 +177,9 @@ public:
|
|||||||
//- Called at the end of Time::adjustDeltaT() if adjustTime is true
|
//- Called at the end of Time::adjustDeltaT() if adjustTime is true
|
||||||
virtual bool adjustTimeStep();
|
virtual bool adjustTimeStep();
|
||||||
|
|
||||||
|
//- Did any file get changed during execution?
|
||||||
|
virtual bool filesModified() const;
|
||||||
|
|
||||||
//- Read and set the function object if its data have changed
|
//- Read and set the function object if its data have changed
|
||||||
virtual bool read(const dictionary&);
|
virtual bool read(const dictionary&);
|
||||||
|
|
||||||
|
|||||||
@ -429,7 +429,8 @@ Foam::argList::argList
|
|||||||
)
|
)
|
||||||
:
|
:
|
||||||
args_(argc),
|
args_(argc),
|
||||||
options_(argc)
|
options_(argc),
|
||||||
|
distributed_(false)
|
||||||
{
|
{
|
||||||
// Check if this run is a parallel run by searching for any parallel option
|
// Check if this run is a parallel run by searching for any parallel option
|
||||||
// If found call runPar which might filter argv
|
// If found call runPar which might filter argv
|
||||||
@ -669,6 +670,7 @@ void Foam::argList::parse
|
|||||||
label dictNProcs = -1;
|
label dictNProcs = -1;
|
||||||
if (options_.found("roots"))
|
if (options_.found("roots"))
|
||||||
{
|
{
|
||||||
|
distributed_ = true;
|
||||||
source = "-roots";
|
source = "-roots";
|
||||||
IStringStream is(options_["roots"]);
|
IStringStream is(options_["roots"]);
|
||||||
roots = readList<fileName>(is);
|
roots = readList<fileName>(is);
|
||||||
@ -702,6 +704,7 @@ void Foam::argList::parse
|
|||||||
|
|
||||||
if (decompDict.lookupOrDefault("distributed", false))
|
if (decompDict.lookupOrDefault("distributed", false))
|
||||||
{
|
{
|
||||||
|
distributed_ = true;
|
||||||
decompDict.lookup("roots") >> roots;
|
decompDict.lookup("roots") >> roots;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -771,7 +774,7 @@ void Foam::argList::parse
|
|||||||
options_.set("case", roots[slave-1]/globalCase_);
|
options_.set("case", roots[slave-1]/globalCase_);
|
||||||
|
|
||||||
OPstream toSlave(Pstream::scheduled, slave);
|
OPstream toSlave(Pstream::scheduled, slave);
|
||||||
toSlave << args_ << options_;
|
toSlave << args_ << options_ << roots.size();
|
||||||
}
|
}
|
||||||
options_.erase("case");
|
options_.erase("case");
|
||||||
|
|
||||||
@ -818,7 +821,7 @@ void Foam::argList::parse
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
OPstream toSlave(Pstream::scheduled, slave);
|
OPstream toSlave(Pstream::scheduled, slave);
|
||||||
toSlave << args_ << options_;
|
toSlave << args_ << options_ << roots.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -826,7 +829,7 @@ void Foam::argList::parse
|
|||||||
{
|
{
|
||||||
// Collect the master's argument list
|
// Collect the master's argument list
|
||||||
IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
|
IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
|
||||||
fromMaster >> args_ >> options_;
|
fromMaster >> args_ >> options_ >> distributed_;
|
||||||
|
|
||||||
// Establish rootPath_/globalCase_/case_ for slave
|
// Establish rootPath_/globalCase_/case_ for slave
|
||||||
getRootCase();
|
getRootCase();
|
||||||
|
|||||||
@ -109,6 +109,7 @@ class argList
|
|||||||
|
|
||||||
word executable_;
|
word executable_;
|
||||||
fileName rootPath_;
|
fileName rootPath_;
|
||||||
|
bool distributed_;
|
||||||
fileName globalCase_;
|
fileName globalCase_;
|
||||||
fileName case_;
|
fileName case_;
|
||||||
string argListStr_;
|
string argListStr_;
|
||||||
@ -221,6 +222,10 @@ public:
|
|||||||
//- Return root path
|
//- Return root path
|
||||||
inline const fileName& rootPath() const;
|
inline const fileName& rootPath() const;
|
||||||
|
|
||||||
|
//- Return distributed flag (i.e. are rootPaths different on
|
||||||
|
// different machines)
|
||||||
|
inline bool distributed() const;
|
||||||
|
|
||||||
//- Return case name (parallel run) or global case (serial run)
|
//- Return case name (parallel run) or global case (serial run)
|
||||||
inline const fileName& caseName() const;
|
inline const fileName& caseName() const;
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2013 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -39,6 +39,12 @@ inline const Foam::fileName& Foam::argList::rootPath() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Foam::argList::distributed() const
|
||||||
|
{
|
||||||
|
return distributed_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline const Foam::fileName& Foam::argList::caseName() const
|
inline const Foam::fileName& Foam::argList::caseName() const
|
||||||
{
|
{
|
||||||
return case_;
|
return case_;
|
||||||
|
|||||||
@ -48,11 +48,10 @@ namespace functionObjects
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
void Foam::functionObjects::timeActivatedFileUpdate::updateFile
|
void Foam::functionObjects::timeActivatedFileUpdate::updateFile()
|
||||||
(
|
|
||||||
const bool checkFiles
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
modified_ = false;
|
||||||
|
|
||||||
label i = lastIndex_;
|
label i = lastIndex_;
|
||||||
while
|
while
|
||||||
(
|
(
|
||||||
@ -68,19 +67,15 @@ void Foam::functionObjects::timeActivatedFileUpdate::updateFile
|
|||||||
Log << nl << type() << ": copying file" << nl << timeVsFile_[i].second()
|
Log << nl << type() << ": copying file" << nl << timeVsFile_[i].second()
|
||||||
<< nl << "to:" << nl << fileToUpdate_ << nl << endl;
|
<< nl << "to:" << nl << fileToUpdate_ << nl << endl;
|
||||||
|
|
||||||
fileName destFile(fileToUpdate_ + Foam::name(pid()));
|
if (Pstream::master() || time_.distributed())
|
||||||
cp(timeVsFile_[i].second(), destFile);
|
|
||||||
mv(destFile, fileToUpdate_);
|
|
||||||
lastIndex_ = i;
|
|
||||||
|
|
||||||
if (checkFiles)
|
|
||||||
{
|
{
|
||||||
// Do an early check to avoid an additional iteration before
|
// Slaves do not copy if running non-distributed
|
||||||
// any changes are picked up (see Time::run : does readModified
|
fileName destFile(fileToUpdate_ + Foam::name(pid()));
|
||||||
// before executing FOs). Note we have to protect the read
|
cp(timeVsFile_[i].second(), destFile);
|
||||||
// constructor of *this from triggering this behaviour.
|
mv(destFile, fileToUpdate_);
|
||||||
const_cast<Time&>(time_).Time::readModifiedObjects();
|
|
||||||
}
|
}
|
||||||
|
lastIndex_ = i;
|
||||||
|
modified_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +93,8 @@ Foam::functionObjects::timeActivatedFileUpdate::timeActivatedFileUpdate
|
|||||||
time_(runTime),
|
time_(runTime),
|
||||||
fileToUpdate_("unknown-fileToUpdate"),
|
fileToUpdate_("unknown-fileToUpdate"),
|
||||||
timeVsFile_(),
|
timeVsFile_(),
|
||||||
lastIndex_(-1)
|
lastIndex_(-1),
|
||||||
|
modified_(false)
|
||||||
{
|
{
|
||||||
read(dict);
|
read(dict);
|
||||||
}
|
}
|
||||||
@ -142,8 +138,8 @@ bool Foam::functionObjects::timeActivatedFileUpdate::read
|
|||||||
<< timeVsFile_[i].second() << endl;
|
<< timeVsFile_[i].second() << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy starting files. Avoid recursion by not checking for modified files.
|
// Copy starting files
|
||||||
updateFile(false);
|
updateFile();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -151,7 +147,7 @@ bool Foam::functionObjects::timeActivatedFileUpdate::read
|
|||||||
|
|
||||||
bool Foam::functionObjects::timeActivatedFileUpdate::execute()
|
bool Foam::functionObjects::timeActivatedFileUpdate::execute()
|
||||||
{
|
{
|
||||||
updateFile(true);
|
updateFile();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -163,4 +159,10 @@ bool Foam::functionObjects::timeActivatedFileUpdate::write()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::functionObjects::timeActivatedFileUpdate::filesModified() const
|
||||||
|
{
|
||||||
|
return modified_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
|
|||||||
@ -106,11 +106,14 @@ class timeActivatedFileUpdate
|
|||||||
//- Index of last file copied
|
//- Index of last file copied
|
||||||
label lastIndex_;
|
label lastIndex_;
|
||||||
|
|
||||||
|
//- Has anything been copied?
|
||||||
|
bool modified_;
|
||||||
|
|
||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
//- Update file
|
//- Update file
|
||||||
void updateFile(const bool checkFiles);
|
void updateFile();
|
||||||
|
|
||||||
//- Disallow default bitwise copy construct
|
//- Disallow default bitwise copy construct
|
||||||
timeActivatedFileUpdate(const timeActivatedFileUpdate&);
|
timeActivatedFileUpdate(const timeActivatedFileUpdate&);
|
||||||
@ -150,6 +153,9 @@ public:
|
|||||||
|
|
||||||
//- Do nothing
|
//- Do nothing
|
||||||
virtual bool write();
|
virtual bool write();
|
||||||
|
|
||||||
|
//- Did any file get changed during execution?
|
||||||
|
virtual bool filesModified() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user