Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
412 lines
15 KiB
C++
412 lines
15 KiB
C++
// PageLightContainer.cpp : implementation file
|
||
//
|
||
|
||
#include "stdafx.h"
|
||
#include "worldcreator.h"
|
||
#include "PageLightContainer.h"
|
||
#include "DlgLightLoad.h"
|
||
#include "SceneManager.h"
|
||
#include "MainFrm.h"
|
||
#include "WorldCreatorView.h"
|
||
|
||
#ifdef _DEBUG
|
||
#define new DEBUG_NEW
|
||
#undef THIS_FILE
|
||
static char THIS_FILE[] = __FILE__;
|
||
#endif
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// CPageLightContainer property page
|
||
|
||
IMPLEMENT_DYNCREATE(CPageLightContainer, CPropertyPage)
|
||
|
||
CPageLightContainer::CPageLightContainer() : CPropertyPage(CPageLightContainer::IDD)
|
||
{
|
||
//{{AFX_DATA_INIT(CPageLightContainer)
|
||
m_bSectorLightView = TRUE;
|
||
//}}AFX_DATA_INIT
|
||
m_SelectCur=-1;
|
||
}
|
||
|
||
CPageLightContainer::~CPageLightContainer()
|
||
{
|
||
/*
|
||
for(int i=0;i<m_LightListNode.num;i++)
|
||
{
|
||
delete m_LightListNode[i];
|
||
}
|
||
*/
|
||
}
|
||
|
||
void CPageLightContainer::DoDataExchange(CDataExchange* pDX)
|
||
{
|
||
CPropertyPage::DoDataExchange(pDX);
|
||
//{{AFX_DATA_MAP(CPageLightContainer)
|
||
DDX_Control(pDX, IDC_LIST_LIGHTSCENE, m_LightObjectListview);
|
||
DDX_Check(pDX, IDC_SectorLgiht, m_bSectorLightView);
|
||
//}}AFX_DATA_MAP
|
||
}
|
||
|
||
|
||
BEGIN_MESSAGE_MAP(CPageLightContainer, CPropertyPage)
|
||
//{{AFX_MSG_MAP(CPageLightContainer)
|
||
ON_NOTIFY(NM_RCLICK, IDC_LIST_LIGHTSCENE, OnRclickListLightscene)
|
||
ON_NOTIFY(NM_CLICK, IDC_LIST_LIGHTSCENE, OnClickListLightscene)
|
||
ON_COMMAND(MENU_LIGHTDELETE, OnLightdelete)
|
||
ON_COMMAND(MENU_LIGHTLOAD, OnLightload)
|
||
ON_NOTIFY(LVN_BEGINDRAG, IDC_LIST_LIGHTSCENE, OnBegindragListLightscene)
|
||
ON_NOTIFY(NM_DBLCLK, IDC_LIST_LIGHTSCENE, OnDblclkListLightscene)
|
||
ON_BN_CLICKED(IDC_LIGHT, OnLight)
|
||
ON_BN_CLICKED(IDC_PICK, OnPick)
|
||
ON_BN_CLICKED(IDC_SectorLgiht, OnSectorLgiht)
|
||
//}}AFX_MSG_MAP
|
||
END_MESSAGE_MAP()
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// CPageLightContainer message handlers
|
||
|
||
BOOL CPageLightContainer::OnInitDialog()
|
||
{
|
||
CPropertyPage::OnInitDialog();
|
||
|
||
DWORD dwStyle;
|
||
dwStyle = m_LightObjectListview.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0 ,0);
|
||
dwStyle |= LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES ;
|
||
m_LightObjectListview.SendMessage( LVM_SETEXTENDEDLISTVIEWSTYLE, 0,dwStyle );
|
||
|
||
m_LightObjectListview.InsertColumn(0,"<EFBFBD≯<EFBFBD>",LVCFMT_LEFT,80);
|
||
m_LightObjectListview.InsertColumn(1,"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ",LVCFMT_LEFT,80);
|
||
m_LightObjectListview.InsertColumn(2,"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>",LVCFMT_LEFT,60);
|
||
m_LightObjectListview.InsertColumn(3,"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",LVCFMT_LEFT,100);
|
||
// TODO: Add extra initialization here
|
||
return TRUE; // return TRUE unless you set the focus to a control
|
||
// EXCEPTION: OCX Property Pages should return FALSE
|
||
}
|
||
|
||
void CPageLightContainer::OnRclickListLightscene(NMHDR* pNMHDR, LRESULT* pResult)
|
||
{
|
||
// TODO: Add your control notification handler code here
|
||
CPoint point;
|
||
GetCursorPos(&point);
|
||
CMenu menu;
|
||
menu.LoadMenu(IDR_MENU_LIGHTOBJECT);
|
||
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,this);
|
||
*pResult = 0;
|
||
}
|
||
|
||
void CPageLightContainer::OnClickListLightscene(NMHDR* pNMHDR, LRESULT* pResult)
|
||
{
|
||
// TODO: Add your control notification handler code here
|
||
|
||
*pResult = 0;
|
||
}
|
||
|
||
void CPageLightContainer::OnLightdelete()
|
||
{
|
||
// TODO: Add your command handler code here
|
||
SelectLightObject();
|
||
m_LightListNode.DelIndex(m_SelectCur);
|
||
UpdateList();
|
||
}
|
||
|
||
void CPageLightContainer::OnLightload()
|
||
{
|
||
// TODO: Add your command handler code here
|
||
CDlgLightLoad dlgLightLoad;
|
||
if(dlgLightLoad.DoModal()!=IDOK)
|
||
return;
|
||
CString strText;
|
||
LightListNode AddNode;
|
||
strcpy(AddNode.m_strLightName,dlgLightLoad.m_strLightname.LockBuffer());
|
||
strcpy(AddNode.m_strObjectFilename,dlgLightLoad.m_strObjectFilename.LockBuffer());
|
||
AddNode.m_fLightRange=dlgLightLoad.m_fLightRange;
|
||
|
||
AddNode.m_iLightSamples = dlgLightLoad.m_iLightSamples;
|
||
AddNode.m_iShadowSamples = dlgLightLoad.m_iShadowSamples;
|
||
AddNode.m_fShadowFactor = dlgLightLoad.m_ShadowFactors;
|
||
AddNode.m_strEffect = dlgLightLoad.m_strEffect;
|
||
|
||
AddNode.m_LightColor.a=0xff;
|
||
AddNode.m_LightColor.r=GetRValue(dlgLightLoad.m_cLightColor);
|
||
AddNode.m_LightColor.g=GetGValue(dlgLightLoad.m_cLightColor);
|
||
AddNode.m_LightColor.b=GetBValue(dlgLightLoad.m_cLightColor);
|
||
AddNode.m_iAmbient = dlgLightLoad.m_iAmbient;
|
||
AddNode.m_fExpose = dlgLightLoad.m_fExpose;
|
||
|
||
|
||
int nInsertItem=m_LightObjectListview.GetItemCount();
|
||
m_LightObjectListview.InsertItem(nInsertItem,dlgLightLoad.m_strLightname);
|
||
m_LightObjectListview.SetItemText(nInsertItem,1,dlgLightLoad.m_strObjectFilename);
|
||
strText.Format("%x",dlgLightLoad.m_cLightColor);
|
||
m_LightObjectListview.SetItemText(nInsertItem,2,strText);
|
||
strText.Format("%7.1f",dlgLightLoad.m_fLightRange);
|
||
m_LightObjectListview.SetItemText(nInsertItem,3,strText);
|
||
m_LightListNode.Add(AddNode);
|
||
}
|
||
|
||
void CPageLightContainer::OnBegindragListLightscene(NMHDR* pNMHDR, LRESULT* pResult)
|
||
{
|
||
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
|
||
// TODO: Add your control notification handler code here
|
||
CMainFrame *mf=(CMainFrame*)AfxGetApp()->m_pMainWnd;
|
||
CWorldCreatorView *av=(CWorldCreatorView *)mf->GetActiveView();
|
||
SelectLightObject();
|
||
av->ChangeMouseInterface(2);
|
||
*pResult = 0;
|
||
}
|
||
|
||
void CPageLightContainer::AddLight(float fXp, float fYp, float fZp)
|
||
{
|
||
if(CSceneManager::m_PickHouseScene && !CSceneManager::m_PickHouseScene->m_HouseObject->m_pBspObject)
|
||
{
|
||
if(m_SelectCur>=0)
|
||
{
|
||
matrix matInvTM,matTM;
|
||
matTM.Translation(vector3(fXp,fYp,fZp));
|
||
matInvTM.Inverse(CSceneManager::m_PickHouseScene->m_AccumulateTM);
|
||
CLightObjectScene *AddLightScene=new CLightObjectScene();
|
||
AddLightScene->m_TM=matTM*matInvTM;
|
||
AddLightScene->m_pLightObject=CSceneManager::m_LightObjectContainer.GetLightObject(m_strObjectName.LockBuffer(),m_fLightRange,m_LightColor);
|
||
|
||
AddLightScene->m_vecMaxBox=AddLightScene->m_pLightObject->m_pLightObject->m_MaxBox;
|
||
AddLightScene->m_vecMinBox=AddLightScene->m_pLightObject->m_pLightObject->m_MinBox;
|
||
AddLightScene->Init();
|
||
|
||
CMainFrame *mf=(CMainFrame*)AfxGetApp()->m_pMainWnd;
|
||
CWorldCreatorView *av=(CWorldCreatorView *)mf->GetActiveView();
|
||
|
||
AddLightScene->m_LightID=av->m_SceneManager->m_MapStorage.m_TotalInHouseLightSceneCount;
|
||
|
||
CSceneManager::m_PickHouseScene->m_HouseObject->m_LightList.Add(AddLightScene);
|
||
|
||
av->m_SceneManager->m_MapStorage.AddInHouseLight(CSceneManager::m_PickHouseScene->m_strOutName,
|
||
CSceneManager::m_PickHouseScene->m_strMedName,
|
||
CSceneManager::m_PickHouseScene->m_strInName,
|
||
CSceneManager::m_PickHouseScene->m_strBSPName,
|
||
m_strObjectName.LockBuffer(),AddLightScene->m_TM,
|
||
m_fLightRange,m_LightColor);
|
||
|
||
CSceneManager::m_PickHouseScene->m_HouseObject->m_pInHouseMap=
|
||
av->m_SceneManager->m_MapStorage.FindInHouseMap(CSceneManager::m_PickHouseScene->m_strOutName,
|
||
CSceneManager::m_PickHouseScene->m_strMedName,
|
||
CSceneManager::m_PickHouseScene->m_strInName,
|
||
CSceneManager::m_PickHouseScene->m_strBSPName);
|
||
CSceneManager::m_PickHouseScene->m_SelfLoadInObject=true;
|
||
}
|
||
}
|
||
else if(CSceneManager::m_pBspScene)
|
||
{
|
||
matrix matInvTM,matTM,matResult;
|
||
matTM.Translation(vector3(fXp,fYp,fZp));
|
||
matInvTM.Inverse(CSceneManager::m_pBspScene->m_AccumulateTM);
|
||
matResult=matTM*matInvTM;
|
||
CSceneManager::m_pBspScene->m_HouseObject->m_pBspObject->AddLight(matResult.GetLoc(),m_fLightRange,m_LightColor);
|
||
}
|
||
}
|
||
|
||
void CPageLightContainer::SelectLightObject()
|
||
{
|
||
m_SelectCur=m_LightObjectListview.GetNextItem(-1,LVNI_SELECTED);
|
||
if(m_SelectCur<0)
|
||
return;
|
||
m_strLightName=m_LightListNode[m_SelectCur].m_strLightName;
|
||
m_strObjectName=m_LightListNode[m_SelectCur].m_strObjectFilename;
|
||
m_fLightRange=m_LightListNode[m_SelectCur].m_fLightRange;
|
||
m_LightColor=m_LightListNode[m_SelectCur].m_LightColor;
|
||
}
|
||
|
||
|
||
|
||
void CPageLightContainer::Save(FILE *fp)
|
||
{
|
||
fwrite(&m_LightListNode.num,sizeof(int),1,fp);
|
||
for(int cLight=0;cLight<m_LightListNode.num;cLight++)
|
||
{
|
||
fwrite(m_LightListNode[cLight].m_strLightName,sizeof(char)*MAX_NAMEBUFFER,1,fp);
|
||
fwrite(m_LightListNode[cLight].m_strObjectFilename,sizeof(char)*MAX_NAMEBUFFER,1,fp);
|
||
fwrite(&m_LightListNode[cLight].m_fLightRange,sizeof(float),1,fp);
|
||
fwrite(&m_LightListNode[cLight].m_LightColor,sizeof(color),1,fp);
|
||
}
|
||
}
|
||
|
||
void CPageLightContainer::Load(FILE *fp,int iType)
|
||
{
|
||
if(!iType)
|
||
DeleteListData();
|
||
int cSavedLight=0;
|
||
fread(&cSavedLight,sizeof(int),1,fp);
|
||
for(int cLight=0;cLight<cSavedLight;cLight++)
|
||
{
|
||
LightListNode AddNode;
|
||
fread(AddNode.m_strLightName,sizeof(char)*MAX_NAMEBUFFER,1,fp);
|
||
fread(AddNode.m_strObjectFilename,sizeof(char)*MAX_NAMEBUFFER,1,fp);
|
||
fread(&AddNode.m_fLightRange,sizeof(float),1,fp);
|
||
fread(&AddNode.m_LightColor,sizeof(color),1,fp);
|
||
AddNode.m_iShadowSamples = 10;
|
||
AddNode.m_iLightSamples = 10;
|
||
AddNode.m_strEffect.Format("");
|
||
AddNode.m_fShadowFactor = 0.95f;
|
||
|
||
m_LightListNode.Add(AddNode);
|
||
}
|
||
}
|
||
|
||
void CPageLightContainer::UpdateList()
|
||
{
|
||
for(int i=0;i<m_LightListNode.num;i++)
|
||
{
|
||
m_LightObjectListview.InsertItem(i,m_LightListNode[i].m_strLightName);
|
||
m_LightObjectListview.SetItemText(i,1,m_LightListNode[i].m_strObjectFilename);
|
||
CString strAdd;
|
||
strAdd.Format("%x",m_LightListNode[i].m_LightColor.c);
|
||
m_LightObjectListview.SetItemText(i,2,strAdd);
|
||
strAdd.Format("%7.1f",m_LightListNode[i].m_fLightRange);
|
||
m_LightObjectListview.SetItemText(i,3,strAdd);
|
||
}
|
||
}
|
||
|
||
void CPageLightContainer::DeleteListData()
|
||
{
|
||
m_LightListNode.num=0;
|
||
m_LightObjectListview.DeleteAllItems();
|
||
}
|
||
|
||
void CPageLightContainer::OnDblclkListLightscene(NMHDR* pNMHDR, LRESULT* pResult)
|
||
{
|
||
// TODO: Add your control notification handler code here
|
||
|
||
int SelectCur=m_LightObjectListview.GetNextItem(-1,LVNI_SELECTED);
|
||
if(SelectCur==-1)
|
||
return;
|
||
|
||
CDlgLightLoad dlgLightLoad;
|
||
dlgLightLoad.m_fLightRange=m_LightListNode[SelectCur].m_fLightRange;
|
||
dlgLightLoad.m_cLightColor=RGB(m_LightListNode[SelectCur].m_LightColor.r,
|
||
m_LightListNode[SelectCur].m_LightColor.g,
|
||
m_LightListNode[SelectCur].m_LightColor.b);
|
||
dlgLightLoad.m_strLightname=m_LightListNode[SelectCur].m_strLightName;
|
||
dlgLightLoad.m_strObjectFilename=m_LightListNode[SelectCur].m_strObjectFilename;
|
||
dlgLightLoad.m_iLightSamples = m_LightListNode[SelectCur].m_iLightSamples;
|
||
dlgLightLoad.m_strEffect = m_LightListNode[SelectCur].m_strEffect;
|
||
|
||
dlgLightLoad.m_iShadowSamples = m_LightListNode[SelectCur].m_iShadowSamples;
|
||
dlgLightLoad.m_ShadowFactors = m_LightListNode[SelectCur].m_fShadowFactor;
|
||
dlgLightLoad.m_iAmbient = m_LightListNode[SelectCur].m_iAmbient;
|
||
dlgLightLoad.m_fExpose = m_LightListNode[SelectCur].m_fExpose;
|
||
|
||
//CDlgLightLoad dlgLightLoad;
|
||
if(dlgLightLoad.DoModal()!=IDOK)
|
||
return;
|
||
|
||
strcpy(m_LightListNode[SelectCur].m_strLightName,dlgLightLoad.m_strLightname.LockBuffer());
|
||
strcpy(m_LightListNode[SelectCur].m_strObjectFilename,dlgLightLoad.m_strObjectFilename.LockBuffer());
|
||
m_LightListNode[SelectCur].m_fLightRange=dlgLightLoad.m_fLightRange;
|
||
|
||
m_LightListNode[SelectCur].m_LightColor.a=0xff;
|
||
m_LightListNode[SelectCur].m_LightColor.r=GetRValue(dlgLightLoad.m_cLightColor);
|
||
m_LightListNode[SelectCur].m_LightColor.g=GetGValue(dlgLightLoad.m_cLightColor);
|
||
m_LightListNode[SelectCur].m_LightColor.b=GetBValue(dlgLightLoad.m_cLightColor);
|
||
|
||
m_LightListNode[SelectCur].m_iLightSamples = dlgLightLoad.m_iLightSamples;
|
||
m_LightListNode[SelectCur].m_strEffect = dlgLightLoad.m_strEffect;
|
||
m_LightListNode[SelectCur].m_iShadowSamples = dlgLightLoad.m_iShadowSamples;
|
||
m_LightListNode[SelectCur].m_fShadowFactor = dlgLightLoad.m_ShadowFactors;
|
||
m_LightListNode[SelectCur].m_iAmbient = dlgLightLoad.m_iAmbient;
|
||
|
||
m_LightListNode[SelectCur].m_fExpose = dlgLightLoad.m_fExpose;
|
||
|
||
m_LightObjectListview.SetItemText(SelectCur,0,dlgLightLoad.m_strLightname);
|
||
m_LightObjectListview.SetItemText(SelectCur,1,dlgLightLoad.m_strObjectFilename);
|
||
CString strText;
|
||
strText.Format("%x",dlgLightLoad.m_cLightColor);
|
||
m_LightObjectListview.SetItemText(SelectCur,2,strText);
|
||
strText.Format("%7.1f",dlgLightLoad.m_fLightRange);
|
||
m_LightObjectListview.SetItemText(SelectCur,3,strText);
|
||
/*
|
||
CString strText;
|
||
LightListNode AddNode;
|
||
strcpy(AddNode.m_strLightName,dlgLightLoad.m_strLightname.LockBuffer());
|
||
strcpy(AddNode.m_strObjectFilename,dlgLightLoad.m_strObjectFilename.LockBuffer());
|
||
AddNode.m_fLightRange=dlgLightLoad.m_fLightRange;
|
||
|
||
AddNode.m_LightColor.a=0xff;
|
||
AddNode.m_LightColor.r=GetRValue(dlgLightLoad.m_cLightColor);
|
||
AddNode.m_LightColor.g=GetGValue(dlgLightLoad.m_cLightColor);
|
||
AddNode.m_LightColor.b=GetBValue(dlgLightLoad.m_cLightColor);
|
||
|
||
int nInsertItem=m_LightObjectListview.GetItemCount();
|
||
m_LightObjectListview.InsertItem(nInsertItem,dlgLightLoad.m_strLightname);
|
||
m_LightObjectListview.SetItemText(nInsertItem,1,dlgLightLoad.m_strObjectFilename);
|
||
strText.Format("%x",dlgLightLoad.m_cLightColor);
|
||
m_LightObjectListview.SetItemText(nInsertItem,2,strText);
|
||
strText.Format("%7.1f",dlgLightLoad.m_fLightRange);
|
||
m_LightObjectListview.SetItemText(nInsertItem,3,strText);
|
||
m_LightListNode.Add(AddNode);
|
||
*/
|
||
|
||
*pResult = 0;
|
||
}
|
||
|
||
void CPageLightContainer::OnLight()
|
||
{
|
||
// TODO: Add your control notification handler code here
|
||
int SelectCur=m_LightObjectListview.GetNextItem(-1,LVNI_SELECTED);
|
||
if(SelectCur==-1)
|
||
return;
|
||
|
||
CMainFrame *mf=(CMainFrame*)AfxGetApp()->m_pMainWnd;
|
||
CWorldCreatorView *av=(CWorldCreatorView *)mf->GetActiveView();
|
||
D3DXMATRIX matView;
|
||
av->m_SceneManager->GetDevice()->GetTransform(D3DTS_VIEW,&matView);
|
||
D3DXMatrixInverse(&matView,NULL,&matView);
|
||
|
||
vector3 vecPos = vector3(matView._41,matView._42,matView._43);
|
||
|
||
D3DXVECTOR3 vecColor = D3DXVECTOR3(m_LightListNode[SelectCur].m_LightColor.r,
|
||
m_LightListNode[SelectCur].m_LightColor.g,
|
||
m_LightListNode[SelectCur].m_LightColor.b);
|
||
|
||
float fRange = m_LightListNode[SelectCur].m_fLightRange;
|
||
|
||
|
||
av->m_SceneManager->m_MapStorage.AddSectorLight(vecPos.x,vecPos.y,vecPos.z,vecColor.x,vecColor.y,vecColor.z,fRange,
|
||
m_LightListNode[SelectCur].m_iLightSamples,m_LightListNode[SelectCur].m_iShadowSamples,m_LightListNode[SelectCur].m_fShadowFactor,
|
||
m_LightListNode[SelectCur].m_iAmbient,m_LightListNode[SelectCur].m_strEffect.LockBuffer(),m_LightListNode[SelectCur].m_fExpose);
|
||
|
||
av->m_SceneManager->m_MapStorage.AddEffectMap(vecPos.x,vecPos.y,vecPos.z,m_LightListNode[SelectCur].m_strEffect.LockBuffer(),0.0f,0.0f,0.0f);
|
||
|
||
for(int cSector=0;cSector<LSIZEX*LSIZEY;cSector++)
|
||
{
|
||
av->m_SceneManager->m_HeightField.m_SectorScene[cSector].GenerateSectorLight();
|
||
}
|
||
|
||
|
||
}
|
||
|
||
void CPageLightContainer::OnPick()
|
||
{
|
||
// TODO: Add your control notification handler code here
|
||
CMainFrame *mf=(CMainFrame*)AfxGetApp()->m_pMainWnd;
|
||
CWorldCreatorView *av=(CWorldCreatorView *)mf->GetActiveView();
|
||
D3DXMATRIX matView;
|
||
av->m_SceneManager->GetDevice()->GetTransform(D3DTS_VIEW,&matView);
|
||
D3DXMatrixInverse(&matView,NULL,&matView);
|
||
|
||
vector3 vecPos = vector3(matView._41,matView._42,matView._43);
|
||
for(int cSector=0;cSector<LSIZEX*LSIZEY;cSector++)
|
||
{
|
||
av->m_SceneManager->m_HeightField.m_SectorScene[cSector].m_SectorLightManager.PickLight(D3DXVECTOR3(vecPos.x,vecPos.y,vecPos.z));
|
||
}
|
||
|
||
}
|
||
|
||
void CPageLightContainer::OnSectorLgiht()
|
||
{
|
||
// TODO: Add your control notification handler code here
|
||
m_bSectorLightView = (m_bSectorLightView == TRUE) ? FALSE : TRUE;
|
||
|
||
CSceneManager::m_bRenderSectorLight = (m_bSectorLightView) ? true : false;
|
||
UpdateData(FALSE);
|
||
|
||
}
|