2026-10-04 00:04:20 +08:00
|
|
|
#include "stdafx.h"
|
2026-09-28 15:28:50 +08:00
|
|
|
#include "CoreTools.h"
|
|
|
|
|
#include "AecDbWell.h"
|
|
|
|
|
#include "GiDrawUtility.h"
|
|
|
|
|
#include "AecDb3dRoadAxisLine.h"
|
|
|
|
|
#include "AcDbX3dSolid.h"
|
|
|
|
|
#include "AecDbX3dPart.h"
|
|
|
|
|
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _T_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _H_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _D_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _TOP_PT_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _Type_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _W_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _L_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _pipe_count_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _pipe_name_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _well_cover_thick_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _well_name_);
|
|
|
|
|
IMP_XDATA_KEY(AecDbWell, _well_draw_lable_);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
AcDbRegion* makeRectReg(const AcGePoint3d &pt, const double &dL, const double &dW)
|
|
|
|
|
{
|
|
|
|
|
AcGeVector3d X(AcGeVector3d::kXAxis), Y(AcGeVector3d::kYAxis), Z(AcGeVector3d::kZAxis);
|
|
|
|
|
AcGePoint3d pt1(pt);
|
|
|
|
|
pt1 -= X * dL * .5;
|
|
|
|
|
pt1 += Y * dW * .5;
|
|
|
|
|
AcGePoint3d pt2 = pt1;
|
|
|
|
|
pt2 += X * dL;
|
|
|
|
|
AcGePoint3d pt3 = pt2;
|
|
|
|
|
pt3 -= Y * dW;
|
|
|
|
|
AcGePoint3d pt4 = pt3;
|
|
|
|
|
pt4 -= X * dL;
|
|
|
|
|
AcDbVoidPtrArray ar;
|
|
|
|
|
ar.append(new AcDbLine(pt1, pt2));
|
|
|
|
|
ar.append(new AcDbLine(pt2, pt3));
|
|
|
|
|
ar.append(new AcDbLine(pt3, pt4));
|
|
|
|
|
ar.append(new AcDbLine(pt4, pt1));
|
|
|
|
|
|
|
|
|
|
AcDbRegion *pReg = CoreTools::createRegion(ar);
|
|
|
|
|
deleteArrayVoidPtrs<AcDbLine>(ar);
|
|
|
|
|
return pReg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AcDbRegion* makeCircleReg(const AcGePoint3d &pt, const double &dR)
|
|
|
|
|
{
|
|
|
|
|
return CoreTools::createRegion(new AcDbCircle(pt, AcGeVector3d::kZAxis, dR));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ACRX_DXF_DEFINE_MEMBERS(AecDbWell, AecDbBDPipeBase,
|
|
|
|
|
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
|
|
|
|
|
AcDbProxyEntity::kNoOperation | AcDbProxyEntity::kDisableProxyWarning,
|
|
|
|
|
AEC_DBWELL,
|
|
|
|
|
"AecDbWell"
|
|
|
|
|
"|Product Desc: shanghua earthworm app obj"
|
|
|
|
|
"|Company: shanghua inc"
|
|
|
|
|
"|WEB Address: www.shanghuasoft.com")
|
|
|
|
|
|
|
|
|
|
Adesk::UInt32 AecDbWell::kCurrentVersionNumber = 1;
|
|
|
|
|
|
|
|
|
|
AecDbWell::AecDbWell()
|
|
|
|
|
{
|
2026-10-04 00:04:20 +08:00
|
|
|
m_mapSpecXData.SetAt(KEY_NAME, _T("槽型池壁"));
|
2026-09-28 15:28:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AecDbWell::~AecDbWell() { }
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::subExplode(AcDbVoidPtrArray & entitySet) const
|
|
|
|
|
{
|
|
|
|
|
return Acad::eNotImplementedYet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AecDbWell::subList() const
|
|
|
|
|
{
|
|
|
|
|
assertReadEnabled();
|
2026-10-04 00:04:20 +08:00
|
|
|
acutPrintf(_T("\n名称:槽型池壁"));
|
2026-09-28 15:28:50 +08:00
|
|
|
AecDbBDPipeBase::subList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::copyFrom(const AcRxObject * pSrc)
|
|
|
|
|
{
|
|
|
|
|
return AecDbBDPipeBase::copyFrom(pSrc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::subTransformBy(const AcGeMatrix3d & xform)
|
|
|
|
|
{
|
|
|
|
|
return AecDbBDPipeBase::subTransformBy(xform);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::dwgInFields(AcDbDwgFiler * pFiler)
|
|
|
|
|
{
|
|
|
|
|
AssertWriteEnabled();
|
|
|
|
|
|
|
|
|
|
//----- Read parent class information first.
|
|
|
|
|
Acad::ErrorStatus es = Acad::eOk;
|
|
|
|
|
es = AecDbBDPipeBase::dwgInFields(pFiler);
|
|
|
|
|
if (es != Acad::eOk)
|
|
|
|
|
return (es);
|
|
|
|
|
|
|
|
|
|
//----- Object version number needs to be read first
|
|
|
|
|
Adesk::UInt32 version(0);
|
|
|
|
|
if ((es = pFiler->readUInt32(&version)) != Acad::eOk)
|
|
|
|
|
return (es);
|
|
|
|
|
|
|
|
|
|
if (version > AecDbWell::kCurrentVersionNumber)
|
|
|
|
|
return Acad::eMakeMeProxy;
|
|
|
|
|
|
|
|
|
|
return Acad::eOk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::dwgOutFields(AcDbDwgFiler * pFiler) const
|
|
|
|
|
{
|
|
|
|
|
assertReadEnabled();
|
|
|
|
|
|
|
|
|
|
//----- Save parent class information first.
|
|
|
|
|
Acad::ErrorStatus es = Acad::eOk;
|
|
|
|
|
es = AecDbBDPipeBase::dwgOutFields(pFiler);
|
|
|
|
|
if (es != Acad::eOk)
|
|
|
|
|
return (es);
|
|
|
|
|
|
|
|
|
|
//----- Object version number needs to be saved first
|
|
|
|
|
if ((es = pFiler->writeUInt32(AecDbWell::kCurrentVersionNumber)) != Acad::eOk)
|
|
|
|
|
return (es);
|
|
|
|
|
|
|
|
|
|
return Acad::eOk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::dxfInFields(AcDbDxfFiler * pFiler)
|
|
|
|
|
{
|
|
|
|
|
return AecDbBDPipeBase::dxfInFields(pFiler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::dxfOutFields(AcDbDxfFiler * pFiler) const
|
|
|
|
|
{
|
|
|
|
|
return AecDbBDPipeBase::dxfOutFields(pFiler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AecDbWell::GetGripText(int nPos, CString & sText)
|
|
|
|
|
{
|
|
|
|
|
switch (nPos)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
2026-10-04 00:04:20 +08:00
|
|
|
sText = _T("移动起点");
|
2026-09-28 15:28:50 +08:00
|
|
|
break;
|
|
|
|
|
case 1:
|
2026-10-04 00:04:20 +08:00
|
|
|
sText = _T("平移");
|
2026-09-28 15:28:50 +08:00
|
|
|
break;
|
|
|
|
|
case 2:
|
2026-10-04 00:04:20 +08:00
|
|
|
sText = _T("移动终点");
|
2026-09-28 15:28:50 +08:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::subGetGripPoints(AcDbGripDataPtrArray & grips, const double curViewUnitSize, const int gripSize, const AcGeVector3d & curViewDir, const int bitflags) const
|
|
|
|
|
{
|
|
|
|
|
return Acad::eNotImplementedYet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::subGetGripPoints(AcGePoint3dArray & gripPoints, AcDbIntArray & osnapModes, AcDbIntArray & geomIds) const
|
|
|
|
|
{
|
|
|
|
|
return AecDbBDPipeBase::subGetGripPoints(gripPoints, osnapModes, geomIds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::subMoveGripPointsAt(const AcDbIntArray & indices, const AcGeVector3d & offset)
|
|
|
|
|
{
|
|
|
|
|
AssertWriteEnabled();
|
|
|
|
|
AcGeMatrix3d mat;
|
|
|
|
|
mat.setToTranslation(offset);
|
|
|
|
|
subTransformBy(mat);
|
|
|
|
|
return Acad::eOk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::Draw2d(AcGiDraw & dc) const
|
|
|
|
|
{
|
|
|
|
|
assertReadEnabled();
|
|
|
|
|
if (Has2DBuffer())
|
|
|
|
|
{
|
|
|
|
|
Draw2DBuffers(dc);
|
|
|
|
|
return Acad::eOk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AcGeVector3d X(AcGeVector3d::kXAxis), Y(AcGeVector3d::kYAxis), Z(AcGeVector3d::kZAxis);
|
|
|
|
|
AcGePoint3d pt(GetTopPt());
|
|
|
|
|
int nType = GetType();
|
|
|
|
|
if (nType == eRect)
|
|
|
|
|
{
|
|
|
|
|
double dL(GetL()), dW(GetW());
|
|
|
|
|
AcGePoint3d pt1(pt);
|
|
|
|
|
pt1 -= X * dL * .5;
|
|
|
|
|
pt1 += Y * dW * .5;
|
|
|
|
|
AcGePoint3d pt2 = pt1;
|
|
|
|
|
pt2 += X * dL;
|
|
|
|
|
AcGePoint3d pt3 = pt2;
|
|
|
|
|
pt3 -= Y * dW;
|
|
|
|
|
AcGePoint3d pt4 = pt3;
|
|
|
|
|
pt4 -= X * dL;
|
|
|
|
|
AcDbVoidPtrArray ar;
|
|
|
|
|
Add2DBuffer(new AcDbLine(pt1, pt2));
|
|
|
|
|
Add2DBuffer(new AcDbLine(pt2, pt3));
|
|
|
|
|
Add2DBuffer(new AcDbLine(pt3, pt4));
|
|
|
|
|
Add2DBuffer(new AcDbLine(pt4, pt1));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Add2DBuffer(new AcDbCircle(pt, AcGeVector3d::kZAxis, GetDia() * .5));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Draw2DBuffers(dc);
|
|
|
|
|
return Acad::eOk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Acad::ErrorStatus AecDbWell::Draw3d(AcGiDraw & dc) const
|
|
|
|
|
{
|
|
|
|
|
return AecDbBDPipeBase::Draw3d(dc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SHJson::WValue& AecDbWell::ToJson(bool bExprotGeo) const
|
|
|
|
|
{
|
|
|
|
|
using namespace SHJson;
|
|
|
|
|
return AecDbBDPipeBase::ToJson(bExprotGeo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AecDbWell::ByJson(const SHJson::WValue &v)
|
|
|
|
|
{
|
|
|
|
|
AssertWriteEnabled();
|
|
|
|
|
return AecDbBDPipeBase::ByJson(v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AecDbWell::initWell()
|
|
|
|
|
{
|
|
|
|
|
AssertWriteEnabled();
|
|
|
|
|
AcGeVector3d X(AcGeVector3d::kXAxis), Y(AcGeVector3d::kYAxis), Z(AcGeVector3d::kZAxis);
|
|
|
|
|
double dT(GetThick()), dCT(GetCoverThick());
|
|
|
|
|
AcGePoint3d ptOrg(GetTopPt());
|
|
|
|
|
AcDbLine *pPath(new AcDbLine(ptOrg - Z * dCT, ptOrg - Z * GetHeight()));
|
|
|
|
|
int nType = GetType();
|
|
|
|
|
if (nType == eRect)
|
|
|
|
|
{
|
|
|
|
|
double dL(GetL()), dW(GetW());
|
|
|
|
|
AcDbRegion *pReg1 = makeRectReg(ptOrg, dL, dW);
|
|
|
|
|
if (pReg1)
|
|
|
|
|
{
|
|
|
|
|
AcDbRegion *pReg2 = makeRectReg(ptOrg, dL - 2 * dT, dW - 2 * dT);
|
|
|
|
|
if (pReg2)
|
|
|
|
|
{
|
|
|
|
|
if (pReg1->booleanOper(AcDb::kBoolSubtract, pReg2) == Acad::eOk)
|
|
|
|
|
{
|
|
|
|
|
SetBaseCurve(pPath);
|
|
|
|
|
SetSection(pReg1, GetTopPt());
|
|
|
|
|
addCover();
|
|
|
|
|
}
|
|
|
|
|
DELETE_PTR(pReg2);
|
|
|
|
|
}
|
|
|
|
|
DELETE_PTR(pReg1);
|
|
|
|
|
}
|
|
|
|
|
DELETE_PTR(pPath);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
double dR(GetDia() * .5);
|
|
|
|
|
AcDbRegion *pReg1(makeCircleReg(ptOrg, dR));
|
|
|
|
|
AcDbRegion *pReg2(makeCircleReg(ptOrg, dR - dT));
|
|
|
|
|
if (pReg1)
|
|
|
|
|
{
|
|
|
|
|
if (pReg2)
|
|
|
|
|
{
|
|
|
|
|
if (pReg1->booleanOper(AcDb::kBoolSubtract, pReg2) == Acad::eOk)
|
|
|
|
|
{
|
|
|
|
|
SetSection(pReg1, ptOrg);
|
|
|
|
|
SetBaseCurve(pPath);
|
|
|
|
|
addCover();
|
|
|
|
|
}
|
|
|
|
|
DELETE_PTR(pReg2);
|
|
|
|
|
}
|
|
|
|
|
DELETE_PTR(pReg1);
|
|
|
|
|
}
|
|
|
|
|
DELETE_PTR(pPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AecDbWell::addCover()
|
|
|
|
|
{
|
|
|
|
|
AssertWriteEnabled();
|
|
|
|
|
AcGeVector3d X(AcGeVector3d::kXAxis), Y(AcGeVector3d::kYAxis), Z(AcGeVector3d::kZAxis);
|
|
|
|
|
AcDbRegion *pReg(NULL);
|
|
|
|
|
AcGePoint3d ptOrg(GetTopPt());
|
|
|
|
|
double dCT(GetCoverThick());
|
|
|
|
|
int nType = GetType();
|
|
|
|
|
if (nType == eRect)
|
|
|
|
|
{
|
|
|
|
|
pReg = makeRectReg(ptOrg, GetL(), GetW());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pReg = makeCircleReg(ptOrg, GetDia() * .5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pReg) return;
|
|
|
|
|
|
|
|
|
|
RemoveAllX3dPart();
|
|
|
|
|
AcDbX3dSolid *pSolid = new AcDbX3dSolid();
|
|
|
|
|
if (pSolid->CreateExtrude(pReg, AcDbLine(ptOrg, ptOrg - Z * dCT)))
|
|
|
|
|
{
|
|
|
|
|
AecDbX3dPart *pPart = new AecDbX3dPart();
|
2026-10-04 00:04:20 +08:00
|
|
|
pPart->GetSpecialtyData()->SetAt(_T("DTYG_TYPE"), _T("拉伸体"));
|
2026-09-28 15:28:50 +08:00
|
|
|
{
|
|
|
|
|
CString s(_T(""));
|
|
|
|
|
SH_BIM_BLOCK bims;
|
2026-10-04 00:04:20 +08:00
|
|
|
bims.push_back(std::make_pair(_T("名称"), _T("井盖")));
|
|
|
|
|
bims.push_back(std::make_pair(_T("颜色"), _T("ByLayer")));
|
2026-09-28 15:28:50 +08:00
|
|
|
|
2026-10-04 00:04:20 +08:00
|
|
|
bims.push_back(std::make_pair(_T("材料"), _T("铸铁")));
|
|
|
|
|
bims.push_back(std::make_pair(_T("统计类型"), _T("其它")));
|
2026-09-28 15:28:50 +08:00
|
|
|
|
|
|
|
|
CoreTools::setBimDatas(*pPart->GetSpecialtyData(), bims);
|
|
|
|
|
}
|
2026-10-04 00:04:20 +08:00
|
|
|
pPart->SetName(_T("井盖"));
|
2026-09-28 15:28:50 +08:00
|
|
|
pPart->AddX3dSolid(pSolid);
|
|
|
|
|
ptOrg = pSolid->GetCentoridPoint();
|
|
|
|
|
pPart->SetOrgPoint(ptOrg);
|
|
|
|
|
pPart->SetAxis(0, X);
|
|
|
|
|
pPart->SetAxis(1, Y);
|
|
|
|
|
pPart->SetAxis(2, Z);
|
|
|
|
|
AddX3dPart(pPart, AcDb::kBoolUnite);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DELETE_PTR(pSolid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DELETE_PTR(pReg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AecDbWell::SetRectWellData(const AcGePoint3d &ptTop
|
|
|
|
|
, const double &t
|
|
|
|
|
, const double &ct
|
|
|
|
|
, const double &h
|
|
|
|
|
, const double &l
|
|
|
|
|
, const double &w)
|
|
|
|
|
{
|
|
|
|
|
AssertWriteEnabled();
|
|
|
|
|
SetType(eRect);
|
|
|
|
|
SetTopPt(ptTop);
|
|
|
|
|
SetThick(t);
|
|
|
|
|
SetHeight(h);
|
|
|
|
|
SetL(l);
|
|
|
|
|
SetW(w);
|
|
|
|
|
SetCoverThick(ct);
|
|
|
|
|
|
|
|
|
|
initWell();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AecDbWell::SetCircleWellData(const AcGePoint3d &ptTop
|
|
|
|
|
, const double &t
|
|
|
|
|
, const double &ct
|
|
|
|
|
, const double &h
|
|
|
|
|
, const double &d)
|
|
|
|
|
{
|
|
|
|
|
AssertWriteEnabled();
|
|
|
|
|
SetType(eCircle);
|
|
|
|
|
SetTopPt(ptTop);
|
|
|
|
|
SetThick(t);
|
|
|
|
|
SetHeight(h);
|
|
|
|
|
SetDia(d);
|
|
|
|
|
SetCoverThick(ct);
|
|
|
|
|
|
|
|
|
|
initWell();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AecDbWell::SetPipes(const std::vector<AcDbObjectId>& ids)
|
|
|
|
|
{
|
|
|
|
|
AssertWriteEnabled();
|
|
|
|
|
AecDbObjXDataMap *pObjMap = GetSpecialtyData(AcDb::kForWrite);
|
|
|
|
|
if (!pObjMap) return;
|
|
|
|
|
|
2026-10-04 00:04:20 +08:00
|
|
|
// 先清空
|
2026-09-28 15:28:50 +08:00
|
|
|
int count(0);
|
|
|
|
|
pObjMap->GetAt(_pipe_count_, count);
|
|
|
|
|
int nvt(0);
|
|
|
|
|
CString str(_T(""));
|
|
|
|
|
for (int i(0); i < count; ++i)
|
|
|
|
|
{
|
|
|
|
|
str.Format(_T("%s%d"), _pipe_name_, i);
|
|
|
|
|
pObjMap->RemoveAt(str, nvt);
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-04 00:04:20 +08:00
|
|
|
// 再赋值
|
2026-09-28 15:28:50 +08:00
|
|
|
count = (int)ids.size();
|
|
|
|
|
pObjMap->SetAt(_pipe_count_, count);
|
|
|
|
|
for (int i(0); i < count; ++i)
|
|
|
|
|
{
|
|
|
|
|
str.Format(_T("%s%d"), _pipe_name_, i);
|
|
|
|
|
pObjMap->SetAt(str, ids[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AecDbWell::GetPipes(std::vector<AcDbObjectId>& ids)
|
|
|
|
|
{
|
|
|
|
|
assertReadEnabled();
|
|
|
|
|
const AecDbObjXDataMap *pObjMap = GetSpecialtyData();
|
|
|
|
|
if (!pObjMap) return;
|
|
|
|
|
|
|
|
|
|
int count(0);
|
|
|
|
|
pObjMap->GetAt(_pipe_count_, count);
|
|
|
|
|
|
|
|
|
|
AcDbObjectId id(AcDbObjectId::kNull);
|
|
|
|
|
CString str(_T(""));
|
|
|
|
|
for (int i(0); i < count; ++i)
|
|
|
|
|
{
|
|
|
|
|
str.Format(_T("%s%d"), _pipe_name_, i);
|
|
|
|
|
if (pObjMap->GetAt(str, id))
|
|
|
|
|
ids.push_back(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|