mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2025-01-13 18:20:34 +05:00
fix for inlet/outlet
This commit is contained in:
parent
d5d777a7f9
commit
4430578f93
@ -6403,10 +6403,10 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
|
||||
const StdMeshers_ViscousLayers* hypViscousLayers = _hypViscousLayers;
|
||||
_hypViscousLayers = nullptr;
|
||||
|
||||
StdMeshers_Cartesian_VL::ViscousBuilder builder( hypViscousLayers );
|
||||
StdMeshers_Cartesian_VL::ViscousBuilder builder( hypViscousLayers, theMesh, theShape );
|
||||
|
||||
std::string error;
|
||||
TopoDS_Shape offsetShape = builder.MakeOffsetShape( theShape, error );
|
||||
TopoDS_Shape offsetShape = builder.MakeOffsetShape( theShape, theMesh, error );
|
||||
if ( offsetShape.IsNull() )
|
||||
throw SALOME_Exception( error );
|
||||
|
||||
|
@ -85,6 +85,7 @@ namespace
|
||||
TopoDS_Shape _initShape;
|
||||
TopoDS_Shape _offsetShape;
|
||||
int _initShapeID;
|
||||
bool _hasVL;
|
||||
bool _toCheckCoinc; // to check if nodes on shape boundary coincide
|
||||
};
|
||||
|
||||
@ -241,11 +242,8 @@ namespace
|
||||
*/
|
||||
//================================================================================
|
||||
|
||||
bool computeVLHeight( const StdMeshers_ViscousLayers* hyp,
|
||||
SMESHDS_Mesh * mesh,
|
||||
const TopoDS_Shape & shape,
|
||||
std::vector< double > & vlH,
|
||||
std::set< TGeomID > & shapesWVL )
|
||||
void computeVLHeight( const StdMeshers_ViscousLayers* hyp,
|
||||
std::vector< double > & vlH )
|
||||
{
|
||||
const double T = hyp->GetTotalThickness();
|
||||
const double f = hyp->GetStretchFactor();
|
||||
@ -257,35 +255,6 @@ namespace
|
||||
for ( double h = h0 * f; (int)vlH.size() < N-1; h *= f )
|
||||
vlH.push_back( h + vlH.back() );
|
||||
vlH.push_back( T );
|
||||
|
||||
|
||||
TopTools_IndexedMapOfShape faces;
|
||||
TopExp::MapShapes( shape, TopAbs_FACE, faces );
|
||||
|
||||
if ( hyp->IsToIgnoreShapes() )
|
||||
{
|
||||
for ( int i = 1; i <= faces.Size(); ++i )
|
||||
shapesWVL.insert( mesh->ShapeToIndex( faces( i )));
|
||||
|
||||
for ( TGeomID& sID : hyp->GetBndShapes() )
|
||||
shapesWVL.erase( sID );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( TGeomID& sID : hyp->GetBndShapes() )
|
||||
shapesWVL.insert( sID );
|
||||
}
|
||||
|
||||
for ( TGeomID fID : shapesWVL )
|
||||
{
|
||||
const TopoDS_Shape & face = mesh->IndexToShape( fID );
|
||||
for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next() )
|
||||
shapesWVL.insert( mesh->ShapeToIndex( exp.Current() ));
|
||||
for ( TopExp_Explorer exp( face, TopAbs_VERTEX ); exp.More(); exp.Next() )
|
||||
shapesWVL.insert( mesh->ShapeToIndex( exp.Current() ));
|
||||
}
|
||||
|
||||
return !shapesWVL.empty();
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
@ -491,6 +460,75 @@ namespace
|
||||
return true;
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
/*!
|
||||
* \brief Create faces from edges
|
||||
* \param [inout] theEOS - shape to treat
|
||||
* \param [inout] theMesh - offset mesh to fill in
|
||||
* \param [inout] theN2E - map of node to VLEdge
|
||||
* \param [inout] theFaceID - ID of WOVL FACE for new faces to set on
|
||||
* \return bool - ok
|
||||
*/
|
||||
//================================================================================
|
||||
|
||||
bool makeFaces( VLEdgesOnShape & theEOS,
|
||||
SMESH_Mesh* theMesh,
|
||||
TNode2VLEdge & theN2E,
|
||||
const TGeomID theFaceID)
|
||||
{
|
||||
SMESHDS_SubMesh* sm = theMesh->GetMeshDS()->MeshElements( theEOS._offsetShape );
|
||||
if ( !sm || sm->NbElements() == 0 )
|
||||
return true;
|
||||
|
||||
SMESH_MeshEditor editor( theMesh );
|
||||
SMESH_MeshEditor::ElemFeatures elem2D( SMDSAbs_Face );
|
||||
|
||||
std::vector< const SMDS_MeshNode* > fNodes( 4 );
|
||||
std::vector<const SMDS_MeshElement *> foundVolum;
|
||||
std::vector< VLEdge*> edgesVec;
|
||||
for ( SMDS_ElemIteratorPtr eIt = sm->GetElements(); eIt->more(); )
|
||||
{
|
||||
const SMDS_MeshElement* edge = eIt->next();
|
||||
if ( edge->GetType() != SMDSAbs_Edge )
|
||||
continue;
|
||||
|
||||
const int nbNodes = 2; //edge->NbCornerNodes();
|
||||
edgesVec.resize( nbNodes );
|
||||
fNodes.resize( nbNodes * 2 );
|
||||
for ( int i = 0; i < nbNodes; ++i )
|
||||
{
|
||||
const SMDS_MeshNode* n = edge->GetNode( i );
|
||||
if ( !theN2E.IsBound( n ))
|
||||
return false;
|
||||
edgesVec[ i ] = theN2E( n );
|
||||
}
|
||||
size_t nbFaces = edgesVec[0]->_nodes.size() - 1;
|
||||
for ( size_t iF = 0; iF < nbFaces; ++iF )
|
||||
{
|
||||
fNodes[ 0 ] = edgesVec[ 0 ]->_nodes[ iF ].Node();
|
||||
fNodes[ 1 ] = edgesVec[ 1 ]->_nodes[ iF ].Node();
|
||||
fNodes[ 2 ] = edgesVec[ 1 ]->_nodes[ iF + 1 ].Node();
|
||||
fNodes[ 3 ] = edgesVec[ 0 ]->_nodes[ iF + 1 ].Node();
|
||||
|
||||
if ( const SMDS_MeshElement* face = editor.AddElement( fNodes, elem2D ))
|
||||
{
|
||||
theMesh->GetMeshDS()->SetMeshElementOnShape( face, theFaceID );
|
||||
|
||||
if ( SMDS_Mesh::GetElementsByNodes( fNodes, foundVolum, SMDSAbs_Volume ))
|
||||
{
|
||||
TIDSortedElemSet faces = { face }, volumes = { foundVolum[0] };
|
||||
editor.Reorient2DBy3D( faces, volumes, /*outside=*/true );
|
||||
}
|
||||
}
|
||||
}
|
||||
editor.ClearLastCreated();
|
||||
|
||||
// move the face to the top of prisms, on mesh boundary
|
||||
//theMesh->GetMeshDS()->ChangeElementNodes( face, fNodes.data(), nbNodes );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
/*!
|
||||
* \brief Append the offset mesh to the initial one
|
||||
@ -594,12 +632,13 @@ namespace
|
||||
const int nbNodes = offElem->NbCornerNodes();
|
||||
iniNodes.resize( nbNodes );
|
||||
iniNodesBnd.resize( nbNodes );
|
||||
//edgesVec.resize( nbNodes );
|
||||
for ( int i = 0; i < nbNodes; ++i )
|
||||
{
|
||||
const SMDS_MeshNode* nOff = offElem->GetNode( i );
|
||||
const SMDS_MeshNode* nIni = initMDS->FindNode( nOff->GetID() + theNShift );
|
||||
iniNodes[ i ] = nIni;
|
||||
if ( !theN2E.IsBound( nOff ))
|
||||
break;
|
||||
VLEdge* vlEd = theN2E( nOff );
|
||||
const SMDS_MeshNode* nOffBnd = vlEd->_nodes.back().Node();
|
||||
const SMDS_MeshNode* nIniBnd = initMDS->FindNode( nOffBnd->GetID() + theNShift );
|
||||
@ -619,6 +658,80 @@ namespace
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
/*!
|
||||
* \brief set elements of WOVL face to sub-meshes
|
||||
* \param [in] theEOS - vlEdges of a sub-shape
|
||||
* \param [inout] theMesh - the mesh
|
||||
* \param [in] theN2E - map of node to vlEdge
|
||||
* \param [in] theNShift - nb of nodes in the mesh before adding the offset mesh
|
||||
*/
|
||||
//================================================================================
|
||||
|
||||
void setBnd2FVWL( VLEdgesOnShape & theEOS,
|
||||
SMESH_Mesh* theInitMesh,
|
||||
SMESH_Mesh* theOffsMesh,
|
||||
//const TNode2VLEdge & theN2E,
|
||||
const smIdType theNShift )
|
||||
{
|
||||
SMESHDS_Mesh* offsetMDS = theOffsMesh->GetMeshDS();
|
||||
SMESHDS_Mesh* initMDS = theInitMesh->GetMeshDS();
|
||||
|
||||
SMESHDS_SubMesh* sm = offsetMDS->MeshElements( theEOS._offsetShape );
|
||||
if ( !sm || ( sm->NbElements() + sm->NbNodes() == 0 ))
|
||||
return;
|
||||
|
||||
for ( SMDS_NodeIteratorPtr nIt = sm->GetNodes(); nIt->more(); )
|
||||
{
|
||||
const SMDS_MeshNode* offNode = nIt->next();
|
||||
const SMDS_MeshNode* iniNode = initMDS->FindNode( offNode->GetID() + theNShift );
|
||||
initMDS->UnSetNodeOnShape( iniNode );
|
||||
|
||||
switch( theEOS._initShape.ShapeType() ) {
|
||||
case TopAbs_FACE: initMDS->SetNodeOnFace( iniNode, TopoDS::Face( theEOS._initShape ));
|
||||
break;
|
||||
case TopAbs_EDGE: initMDS->SetNodeOnEdge( iniNode, TopoDS::Edge( theEOS._initShape ));
|
||||
break;
|
||||
case TopAbs_VERTEX: initMDS->SetNodeOnVertex( iniNode, TopoDS::Vertex( theEOS._initShape ));
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector< const SMDS_MeshNode* > iniNodes;
|
||||
for ( SMDS_ElemIteratorPtr eIt = sm->GetElements(); eIt->more(); )
|
||||
{
|
||||
const SMDS_MeshElement* offElem = eIt->next();
|
||||
// if ( offElem->GetType() != SMDSAbs_Face )
|
||||
// continue;
|
||||
|
||||
int nbNodes = offElem->NbCornerNodes();
|
||||
iniNodes.resize( nbNodes );
|
||||
for ( int i = 0; i < nbNodes; ++i )
|
||||
{
|
||||
const SMDS_MeshNode* nOff = offElem->GetNode( i );
|
||||
const SMDS_MeshNode* nIni = initMDS->FindNode( nOff->GetID() + theNShift );
|
||||
iniNodes[ i ] = nIni;
|
||||
}
|
||||
if ( const SMDS_MeshElement* iniElem = initMDS->FindElement( iniNodes ))
|
||||
{
|
||||
initMDS->UnSetElementOnShape( iniElem );
|
||||
initMDS->SetMeshElementOnShape( iniElem, theEOS._initShapeID );
|
||||
|
||||
for ( const SMDS_MeshNode* n : iniNodes )
|
||||
if ( n->GetPosition()->GetDim() == 3 )
|
||||
{
|
||||
initMDS->UnSetNodeOnShape( n );
|
||||
if ( theEOS._initShape.ShapeType() == TopAbs_FACE )
|
||||
initMDS->SetNodeOnFace( n, theEOS._initShapeID );
|
||||
else
|
||||
initMDS->SetNodeOnEdge( n, theEOS._initShapeID );
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -639,9 +752,50 @@ SMESH_Mesh* StdMeshers_Cartesian_VL::ViscousBuilder::MakeOffsetMesh()
|
||||
*/
|
||||
//================================================================================
|
||||
|
||||
StdMeshers_Cartesian_VL::ViscousBuilder::ViscousBuilder( const StdMeshers_ViscousLayers* hyp )
|
||||
StdMeshers_Cartesian_VL::ViscousBuilder::ViscousBuilder( const StdMeshers_ViscousLayers* hyp,
|
||||
const SMESH_Mesh & mainMesh,
|
||||
const TopoDS_Shape & mainShape)
|
||||
: _hyp( hyp ), _offsetMesh( new TmpMesh )
|
||||
{
|
||||
// find shapes with viscous layers
|
||||
TopTools_IndexedMapOfShape faces;
|
||||
TopExp::MapShapes( mainShape, TopAbs_FACE, faces );
|
||||
const SMESHDS_Mesh* iniMDS = mainMesh.GetMeshDS();
|
||||
|
||||
if ( hyp->IsToIgnoreShapes() )
|
||||
{
|
||||
for ( int i = 1; i <= faces.Size(); ++i )
|
||||
_shapesWVL.insert( iniMDS->ShapeToIndex( faces( i )));
|
||||
|
||||
for ( TGeomID& sID : hyp->GetBndShapes() )
|
||||
_shapesWVL.erase( sID );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( TGeomID& sID : hyp->GetBndShapes() )
|
||||
_shapesWVL.insert( sID );
|
||||
}
|
||||
|
||||
for ( TGeomID fID : _shapesWVL )
|
||||
{
|
||||
const TopoDS_Shape & face = iniMDS->IndexToShape( fID );
|
||||
for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next() )
|
||||
_shapesWVL.insert( iniMDS->ShapeToIndex( exp.Current() ));
|
||||
for ( TopExp_Explorer exp( face, TopAbs_VERTEX ); exp.More(); exp.Next() )
|
||||
_shapesWVL.insert( iniMDS->ShapeToIndex( exp.Current() ));
|
||||
}
|
||||
|
||||
// find EDGE and adjacent FACEs w/o VL
|
||||
for ( int i = 1; i <= faces.Size(); ++i )
|
||||
{
|
||||
const TopoDS_Shape& face = faces( i );
|
||||
TGeomID fID = iniMDS->ShapeToIndex( face );
|
||||
if ( _shapesWVL.count( fID ))
|
||||
continue;
|
||||
for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next() )
|
||||
_edge2facesWOVL[ iniMDS->ShapeToIndex( exp.Current() )].push_back( fID );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//================================================================================
|
||||
@ -659,6 +813,7 @@ StdMeshers_Cartesian_VL::ViscousBuilder::~ViscousBuilder()
|
||||
/*!
|
||||
* \brief Create an offset shape from a given one
|
||||
* \param [in] theShape - input shape
|
||||
* \param [in] theMesh - main mesh
|
||||
* \param [out] theError - error description
|
||||
* \return TopoDS_Shape - result offset shape
|
||||
*/
|
||||
@ -666,32 +821,30 @@ StdMeshers_Cartesian_VL::ViscousBuilder::~ViscousBuilder()
|
||||
|
||||
TopoDS_Shape
|
||||
StdMeshers_Cartesian_VL::ViscousBuilder::MakeOffsetShape(const TopoDS_Shape & theShape,
|
||||
SMESH_Mesh & theMesh,
|
||||
std::string & theError )
|
||||
{
|
||||
// TopoDS_Shape S = theShape;
|
||||
// BRep_Builder aBuilder;
|
||||
// TopoDS_Compound comp;
|
||||
// aBuilder.MakeCompound( comp );
|
||||
// for ( TopExp_Explorer e( theShape, TopAbs_FACE); e.More(); e.Next() )
|
||||
// {
|
||||
// aBuilder.Add( comp, e.Current());
|
||||
// e.Next();
|
||||
// if ( !e.More() )
|
||||
// break;
|
||||
// }
|
||||
// S = comp;
|
||||
|
||||
double offset = -_hyp->GetTotalThickness();
|
||||
double tol = Precision::Confusion();
|
||||
_makeOffset.Initialize( theShape, offset, tol, BRepOffset_Skin, /*Intersection=*/false,
|
||||
/*selfInter=*/false, GeomAbs_Intersection );
|
||||
// exclude inlet FACEs
|
||||
SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
|
||||
for ( TopExp_Explorer fEx( theShape, TopAbs_FACE ); fEx.More(); fEx.Next() )
|
||||
{
|
||||
TGeomID fID = meshDS->ShapeToIndex( fEx.Current() );
|
||||
if ( !_shapesWVL.count( fID ))
|
||||
_makeOffset.SetOffsetOnFace( TopoDS::Face( fEx.Current()), 0 );
|
||||
}
|
||||
|
||||
_makeOffset.MakeOffsetShape();
|
||||
if ( _makeOffset.IsDone() )
|
||||
{
|
||||
_offsetShape = _makeOffset.Shape();
|
||||
SMESH_MesherHelper::WriteShape( _offsetShape );////
|
||||
|
||||
_offsetMesh->ShapeToMesh( _offsetShape );
|
||||
_offsetMesh->GetSubMesh( _offsetShape )->DependsOn();
|
||||
//SMESH_MesherHelper::WriteShape( _offsetShape );
|
||||
return _offsetShape;
|
||||
}
|
||||
|
||||
@ -752,11 +905,9 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
|
||||
SMESHDS_Mesh* initMDS = theMesh.GetMeshDS();
|
||||
offsetMDS->SetAllCellsNotMarked();
|
||||
|
||||
// Compute heights of viscous layers and finds FACEs with VL
|
||||
// Compute heights of viscous layers
|
||||
std::vector< double > vlH;
|
||||
std::set< int > shapesWVL;
|
||||
if ( !computeVLHeight( _hyp, initMDS, theShape, vlH, shapesWVL ))
|
||||
return false;
|
||||
computeVLHeight( _hyp, vlH );
|
||||
|
||||
std::vector< VLEdgesOnShape > edgesOnShape;
|
||||
edgesOnShape.reserve( offsetMDS->MaxShapeIndex() + 1 );
|
||||
@ -776,7 +927,10 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
|
||||
EOS._initShape = shapes( i );
|
||||
EOS._offsetShape = getOffsetSubShape( EOS._initShape );
|
||||
EOS._initShapeID = initMDS->ShapeToIndex( EOS._initShape );
|
||||
EOS._hasVL = _shapesWVL.count( EOS._initShapeID );
|
||||
EOS._toCheckCoinc = false;
|
||||
if ( !EOS._hasVL )
|
||||
continue;
|
||||
|
||||
// project boundary nodes of offset mesh to boundary of init mesh
|
||||
// (new nodes are created in the offset mesh)
|
||||
@ -809,7 +963,7 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
|
||||
// create nodes of layers
|
||||
if ( _hyp->GetNumberLayers() > 1 )
|
||||
{
|
||||
if ( shapesWVL.count( EOS._initShapeID ))
|
||||
//if ( _shapesWVL.count( EOS._initShapeID ))
|
||||
for ( size_t i = 0; i < EOS._edges.size(); ++i )
|
||||
{
|
||||
divideVLEdge( &EOS._edges[ i ], vlH, offsetMDS );
|
||||
@ -823,12 +977,31 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
|
||||
for ( size_t i = 0; i < edgesOnShape.size(); ++i )
|
||||
{
|
||||
VLEdgesOnShape& EOS = edgesOnShape[ i ];
|
||||
if ( EOS._initShape.ShapeType() == TopAbs_FACE )
|
||||
if ( EOS._initShape.ShapeType() == TopAbs_FACE && EOS._hasVL )
|
||||
{
|
||||
if ( !makePrisms( EOS, _offsetMesh, n2e ))
|
||||
prismsOk = false;
|
||||
}
|
||||
}
|
||||
if ( prismsOk )
|
||||
{
|
||||
// create faces on FACEs WOVL
|
||||
for ( size_t i = 0; i < edgesOnShape.size(); ++i )
|
||||
{
|
||||
VLEdgesOnShape& EOS = edgesOnShape[ i ];
|
||||
if ( EOS._initShape.ShapeType() == TopAbs_EDGE && EOS._hasVL )
|
||||
{
|
||||
auto e2f = _edge2facesWOVL.find( EOS._initShapeID );
|
||||
if ( e2f != _edge2facesWOVL.end() && !e2f->second.empty() )
|
||||
{
|
||||
TopoDS_Shape f = initMDS->IndexToShape( e2f->second[0] );
|
||||
TopoDS_Shape f2 = getOffsetSubShape( f );
|
||||
//cout << e2f->second[0] << " OFF " << offsetMDS->ShapeToIndex( f2 ) << endl;
|
||||
makeFaces( EOS, _offsetMesh, n2e, offsetMDS->ShapeToIndex( f2 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy offset mesh to the main one
|
||||
initMDS->Modified();
|
||||
@ -854,7 +1027,10 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
|
||||
for ( size_t i = 0; i < edgesOnShape.size(); ++i )
|
||||
{
|
||||
VLEdgesOnShape& EOS = edgesOnShape[ i ];
|
||||
if ( EOS._hasVL )
|
||||
setBnd2Sub( EOS, &theMesh, _offsetMesh, n2e, nShift, nodesToCheckCoinc );
|
||||
else
|
||||
setBnd2FVWL( EOS, &theMesh, _offsetMesh, nShift );
|
||||
}
|
||||
|
||||
// merge coincident nodes
|
||||
|
@ -27,6 +27,9 @@
|
||||
#define __StdMeshers_Cartesian_VL_HXX__
|
||||
|
||||
#include <BRepOffset_MakeOffset.hxx>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class StdMeshers_ViscousLayers;
|
||||
class SMESH_Mesh;
|
||||
@ -37,10 +40,13 @@ namespace StdMeshers_Cartesian_VL
|
||||
{
|
||||
public:
|
||||
|
||||
ViscousBuilder( const StdMeshers_ViscousLayers* hypViscousLayers );
|
||||
ViscousBuilder( const StdMeshers_ViscousLayers* hypViscousLayers,
|
||||
const SMESH_Mesh & theMesh,
|
||||
const TopoDS_Shape & theShape);
|
||||
~ViscousBuilder();
|
||||
|
||||
TopoDS_Shape MakeOffsetShape(const TopoDS_Shape & theShape,
|
||||
SMESH_Mesh & theMesh,
|
||||
std::string & theError );
|
||||
|
||||
SMESH_Mesh* MakeOffsetMesh();
|
||||
@ -56,6 +62,8 @@ namespace StdMeshers_Cartesian_VL
|
||||
BRepOffset_MakeOffset _makeOffset;
|
||||
SMESH_Mesh* _offsetMesh;
|
||||
TopoDS_Shape _offsetShape;
|
||||
std::set< int > _shapesWVL; // shapes with viscous layers
|
||||
std::map< int, std::vector< int > > _edge2facesWOVL; // EDGE 2 FACEs w/o VL
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user