2001-01-03 16:55:10 +01:00
|
|
|
/*=========================================================================
|
|
|
|
|
|
|
|
saveload.cpp
|
|
|
|
|
|
|
|
Author: PKG
|
|
|
|
Created:
|
|
|
|
Project: SBSP
|
|
|
|
Purpose:
|
|
|
|
|
|
|
|
Copyright (c) 2000 Climax Development Ltd
|
|
|
|
|
|
|
|
===========================================================================*/
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Includes
|
|
|
|
-------- */
|
|
|
|
|
|
|
|
#include "memcard\saveload.h"
|
|
|
|
|
|
|
|
#ifndef __MEMORY_HEADER__
|
|
|
|
#include "mem\memory.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef __MEMCARD_MEMCARD_H__
|
|
|
|
#include "memcard\memcard.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef _FILEIO_HEADER_
|
|
|
|
#include "fileio\fileio.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef __VID_HEADER_
|
|
|
|
#include "system\vid.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef __LOCALE_TEXTDBASE_H__
|
|
|
|
#include "locale\textdbase.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef __FILE_EQUATES_H__
|
|
|
|
#include <biglump.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* Std Lib
|
|
|
|
------- */
|
|
|
|
|
|
|
|
/* Gfx
|
|
|
|
--- */
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Tyepdefs && Defines
|
|
|
|
------------------- */
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Structure defintions
|
|
|
|
-------------------- */
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Positional Vars
|
|
|
|
--------------- */
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function Prototypes
|
|
|
|
------------------- */
|
|
|
|
|
|
|
|
static void callback(int _status);
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Vars
|
|
|
|
---- */
|
|
|
|
|
|
|
|
static int s_callbackEnded=false;
|
|
|
|
static int s_callbackStatus=0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
CSaveLoadDatabase::CSaveLoadDatabase()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
m_saving=false;
|
|
|
|
m_loading=false;
|
|
|
|
m_formatting=false;
|
|
|
|
m_loading=false;
|
|
|
|
m_autoloading=false;
|
|
|
|
m_tempBuffer=NULL;
|
2001-01-03 17:22:08 +01:00
|
|
|
m_memcardHeader=CFileIO::loadFile(MEMCARD_MEMHEAD_BIN);
|
2001-01-03 16:55:10 +01:00
|
|
|
|
|
|
|
gatherData();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
CSaveLoadDatabase::~CSaveLoadDatabase()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
2001-01-03 17:22:08 +01:00
|
|
|
MemFree(m_memcardHeader);
|
2001-01-03 16:55:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
void CSaveLoadDatabase::think()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
MemCard::Handler();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
void CSaveLoadDatabase::gatherData()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
ASSERT(!m_saving);
|
|
|
|
ASSERT(!m_loading);
|
|
|
|
ASSERT(!m_formatting);
|
|
|
|
ASSERT(!m_autoloading);
|
|
|
|
|
|
|
|
createData();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
bool CSaveLoadDatabase::startSave(char *_filename,int _fileNum=-1)
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
char nameBuf[9]="\0";
|
|
|
|
|
|
|
|
ASSERT(!m_saving);
|
|
|
|
ASSERT(!m_loading);
|
|
|
|
ASSERT(!m_formatting);
|
|
|
|
ASSERT(!m_autoloading);
|
|
|
|
|
|
|
|
if(_fileNum!=-1)
|
|
|
|
{
|
|
|
|
strncat(nameBuf,MemCard::GetFileName(0,_fileNum),8);
|
|
|
|
_filename=nameBuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Alloc a buffer and copy everything to it
|
|
|
|
allocateBuffer();
|
2001-01-03 17:22:08 +01:00
|
|
|
memcpy((char*)&m_tempBuffer[0],m_memcardHeader,256); // Memcard header
|
2001-01-03 16:55:10 +01:00
|
|
|
MemCard::FillHeaderDetails(m_tempBuffer,m_bufferSize,_filename); // Setup header
|
|
|
|
memcpy((char*)&m_tempBuffer[256],(char*)&m_dataBuffer,sizeof(m_dataBuffer)); // Data
|
|
|
|
MemCard::GiveCheckSum(&m_tempBuffer[m_bufferSize-MD5_CHECKSUM_SIZE], // Chksum
|
|
|
|
m_tempBuffer,m_bufferSize-MD5_CHECKSUM_SIZE);
|
|
|
|
|
|
|
|
|
|
|
|
// Start write to memcard
|
|
|
|
if(!MemCard::WriteFile(0,_fileNum,(u8*)_filename,(void*)m_tempBuffer,m_bufferSize,&callback))
|
|
|
|
{
|
|
|
|
MEMCARD_DBGMSG("write error");
|
|
|
|
freeBuffer();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
s_callbackEnded=false;
|
|
|
|
m_saving=true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
int CSaveLoadDatabase::getSaveStatus()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
int ret=INACTIVE;
|
|
|
|
|
|
|
|
if(m_saving)
|
|
|
|
{
|
|
|
|
if(MemCard::GetCardStatus(0)==MemCard::CS_NoCard)
|
|
|
|
{
|
|
|
|
MEMCARD_DBGMSG("======= weird card removal - bonus 50 points");
|
|
|
|
// Card removed at weird time..
|
|
|
|
ret=FAILED;
|
|
|
|
s_callbackEnded=false;
|
|
|
|
m_saving=false;
|
|
|
|
freeBuffer();
|
|
|
|
}
|
|
|
|
else if(s_callbackEnded)
|
|
|
|
{
|
|
|
|
ASSERT(m_tempBuffer);
|
|
|
|
|
|
|
|
if(s_callbackStatus==MemCard::CCS_WriteFileOK) ret=FINISHED_OK;
|
|
|
|
else ret=FAILED;
|
|
|
|
freeBuffer();
|
|
|
|
|
|
|
|
s_callbackEnded=false;
|
|
|
|
m_saving=false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret=IN_PROGRESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
bool CSaveLoadDatabase::startLoad(int _file)
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
ASSERT(!m_saving);
|
|
|
|
ASSERT(!m_loading);
|
|
|
|
ASSERT(!m_formatting);
|
|
|
|
|
|
|
|
// Alloc a buffer to load to
|
|
|
|
allocateBuffer();
|
|
|
|
|
|
|
|
// Start read from memcard
|
|
|
|
if(!MemCard::ReadFile(0,_file,(void*)m_tempBuffer,&callback))
|
|
|
|
{
|
|
|
|
MEMCARD_DBGMSG("read error");
|
|
|
|
freeBuffer();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
s_callbackEnded=false;
|
|
|
|
m_loading=true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
int CSaveLoadDatabase::getLoadStatus()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
int ret=INACTIVE;
|
|
|
|
|
|
|
|
if(m_loading)
|
|
|
|
{
|
|
|
|
if(MemCard::GetCardStatus(0)==MemCard::CS_NoCard)
|
|
|
|
{
|
|
|
|
MEMCARD_DBGMSG("======= weird card removal - bonus 50 points");
|
|
|
|
// Card removed at weird time..
|
|
|
|
freeBuffer();
|
|
|
|
|
|
|
|
m_loading=false;
|
|
|
|
m_autoloading=false;
|
|
|
|
s_callbackEnded=false;
|
|
|
|
ret=FAILED;
|
|
|
|
}
|
|
|
|
else if(s_callbackEnded)
|
|
|
|
{
|
|
|
|
ASSERT(m_tempBuffer);
|
|
|
|
|
|
|
|
// Load ok?
|
|
|
|
if(s_callbackStatus==MemCard::CCS_ReadFileOK&&
|
|
|
|
MemCard::TestCheckSum(&m_tempBuffer[m_bufferSize-MD5_CHECKSUM_SIZE],m_tempBuffer,m_bufferSize-MD5_CHECKSUM_SIZE))
|
|
|
|
{
|
|
|
|
memcpy(&m_dataBuffer,&m_tempBuffer[256],sizeof(m_dataBuffer));
|
|
|
|
if(m_dataBuffer.m_headerId!=SAVELOAD_HEADERID)
|
|
|
|
{
|
|
|
|
ASSERT(!"YOUR MEMCARD SAVE IS OUT OF DATE! PLEASE DELETE IT!");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Loaded ok - Copy the data in
|
|
|
|
restoreData();
|
|
|
|
ret=FINISHED_OK;
|
|
|
|
MEMCARD_DBGMSG("load ok :)");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MEMCARD_DBGMSG("load failed!!!");
|
|
|
|
ret=FAILED;
|
|
|
|
}
|
|
|
|
freeBuffer();
|
|
|
|
|
|
|
|
m_loading=false;
|
|
|
|
m_autoloading=false;
|
|
|
|
s_callbackEnded=false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret=IN_PROGRESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
bool CSaveLoadDatabase::startFormat()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
ASSERT(!m_saving);
|
|
|
|
ASSERT(!m_loading);
|
|
|
|
ASSERT(!m_formatting);
|
|
|
|
ASSERT(!m_autoloading);
|
|
|
|
|
|
|
|
if(!MemCard::FormatCard(0,&callback))
|
|
|
|
{
|
|
|
|
MEMCARD_DBGMSG("format error");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
MEMCARD_DBGMSG("======= m_formatting=true");
|
|
|
|
s_callbackEnded=false;
|
|
|
|
m_formatting=true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
int CSaveLoadDatabase::getFormatStatus()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
int ret=INACTIVE;
|
|
|
|
|
|
|
|
if(m_formatting)
|
|
|
|
{
|
|
|
|
if(MemCard::GetCardStatus(0)==MemCard::CS_NoCard)
|
|
|
|
{
|
|
|
|
MEMCARD_DBGMSG("======= weird card removal - bonus 50 points");
|
|
|
|
// Card removed at weird time..
|
|
|
|
ret=FAILED;
|
|
|
|
s_callbackEnded=false;
|
|
|
|
m_formatting=false;
|
|
|
|
}
|
|
|
|
else if(s_callbackEnded)
|
|
|
|
{
|
|
|
|
if(s_callbackStatus==MemCard::CCS_FormatCardOK) ret=FINISHED_OK;
|
|
|
|
else ret=FAILED;
|
|
|
|
|
|
|
|
MEMCARD_DBGMSG("======= m_formatting=false");
|
|
|
|
s_callbackEnded=false;
|
|
|
|
m_formatting=false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MEMCARD_DBGMSG("======= still formatting...");
|
|
|
|
ret=IN_PROGRESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
void CSaveLoadDatabase::startAutoload()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
MEMCARD_DBGMSG("Trying autoload..");
|
|
|
|
m_autoloadFrameCounter=0;
|
|
|
|
m_autoloading=true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
bool CSaveLoadDatabase::monitorAutoload()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
if(m_autoloading)
|
|
|
|
{
|
|
|
|
if(m_loading)
|
|
|
|
{
|
|
|
|
getLoadStatus();
|
|
|
|
}
|
|
|
|
else if(m_autoloading&&
|
|
|
|
m_autoloadFrameCounter>(60*2)&&
|
|
|
|
MemCard::GetCardStatus(0)!=MemCard::CS_CardInserted)
|
|
|
|
{
|
|
|
|
if(MemCard::GetFileCountOnCard(0))
|
|
|
|
{
|
|
|
|
startLoad(0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_autoloading=false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_autoloadFrameCounter++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
void CSaveLoadDatabase::createData()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Header
|
|
|
|
m_dataBuffer.m_headerId=SAVELOAD_HEADERID;
|
|
|
|
|
|
|
|
// System details
|
|
|
|
m_dataBuffer.m_systemDetails.m_screenOffX=VidGetXOfs();
|
|
|
|
m_dataBuffer.m_systemDetails.m_screenOffY=VidGetYOfs();
|
|
|
|
for(i=0;i<CSoundMediator::NUM_VOLUMETYPES;i++)
|
|
|
|
{
|
|
|
|
m_dataBuffer.m_systemDetails.m_volumes[i]=CSoundMediator::getVolume((CSoundMediator::VOLUMETYPE)i);
|
|
|
|
}
|
|
|
|
m_dataBuffer.m_systemDetails.m_language=(char)TranslationDatabase::getLanguage();
|
2001-01-10 23:03:20 +01:00
|
|
|
|
|
|
|
// Game slots
|
|
|
|
for(i=0;i<CGameSlotManager::NUM_GAME_SLOTS;i++)
|
|
|
|
{
|
|
|
|
m_dataBuffer.m_gameSlots[i]=CGameSlotManager::getSlotData(i);
|
|
|
|
}
|
2001-01-03 16:55:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
void CSaveLoadDatabase::restoreData()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// System details
|
|
|
|
VidSetXYOfs(m_dataBuffer.m_systemDetails.m_screenOffX,m_dataBuffer.m_systemDetails.m_screenOffY);
|
|
|
|
for(i=0;i<CSoundMediator::NUM_VOLUMETYPES;i++)
|
|
|
|
{
|
|
|
|
CSoundMediator::setVolume((CSoundMediator::VOLUMETYPE)i,m_dataBuffer.m_systemDetails.m_volumes[i]);
|
|
|
|
}
|
|
|
|
if(!TranslationDatabase::isLoaded())
|
|
|
|
{
|
|
|
|
TranslationDatabase::loadLanguage(m_dataBuffer.m_systemDetails.m_language);
|
|
|
|
}
|
2001-01-10 23:03:20 +01:00
|
|
|
|
|
|
|
// Game slots
|
|
|
|
for(i=0;i<CGameSlotManager::NUM_GAME_SLOTS;i++)
|
|
|
|
{
|
|
|
|
CGameSlotManager::setSlotData(i,&m_dataBuffer.m_gameSlots[i]);
|
|
|
|
}
|
2001-01-03 16:55:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
void CSaveLoadDatabase::allocateBuffer()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
ASSERT(!m_tempBuffer);
|
|
|
|
|
|
|
|
m_bufferSize=MC_HEADER_SIZE+sizeof(m_dataBuffer)+MD5_CHECKSUM_SIZE;
|
|
|
|
m_bufferSize=((m_bufferSize/MemCard::BLOCKSIZE)+1)*MemCard::BLOCKSIZE;
|
|
|
|
m_tempBuffer=(unsigned char*)MemAlloc(m_bufferSize,"MEMCARD");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
2001-01-10 23:03:20 +01:00
|
|
|
void CSaveLoadDatabase::freeBuffer()
|
2001-01-03 16:55:10 +01:00
|
|
|
{
|
|
|
|
ASSERT(m_tempBuffer);
|
|
|
|
|
|
|
|
MemFree(m_tempBuffer);
|
|
|
|
m_tempBuffer=NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
Function:
|
|
|
|
Purpose:
|
|
|
|
Params:
|
|
|
|
Returns:
|
|
|
|
---------------------------------------------------------------------- */
|
|
|
|
static void callback(int _status)
|
|
|
|
{
|
|
|
|
ASSERT(!s_callbackEnded);
|
|
|
|
s_callbackEnded=true;
|
|
|
|
s_callbackStatus=_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*===========================================================================
|
|
|
|
end */
|