706 lines
17 KiB
C++
Executable File
706 lines
17 KiB
C++
Executable File
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <common/string.hpp>
|
|
#include <common/block.hpp>
|
|
#include <common/array.hpp>
|
|
|
|
String::String(const char *npStr)
|
|
: mnpStr(0), mLengthBytes(0)
|
|
{
|
|
DWORD stringLength;
|
|
|
|
if(!npStr)return;
|
|
try{stringLength=::strlen(npStr);}
|
|
catch(...){{stringLength=0;}}
|
|
if(!stringLength)return;
|
|
stringLength++;
|
|
reserve(stringLength,FALSE);
|
|
::strcpy(mnpStr,npStr);
|
|
}
|
|
|
|
String::String(const wchar_t* npWideString, int length)
|
|
: mnpStr(0), mLengthBytes(0)
|
|
{
|
|
if (!npWideString || 0 == length)return;
|
|
reserve(length);
|
|
for (wchar_t index = 0;index < length;index++)
|
|
{
|
|
char character = (char)((npWideString[index]<<8)>>8);
|
|
operator[](index) = character;
|
|
}
|
|
}
|
|
|
|
String::String(const String &newString)
|
|
: mnpStr(0), mLengthBytes(0)
|
|
{
|
|
DWORD stringLength;
|
|
|
|
if(!newString.mnpStr)return;
|
|
if(!(stringLength=newString.length()))return;
|
|
stringLength++;
|
|
reserve(stringLength,FALSE);
|
|
::strcpy(mnpStr,newString.mnpStr);
|
|
}
|
|
|
|
String &String::operator=(const String &someString)
|
|
{
|
|
int stringLength;
|
|
|
|
if(this==&someString)return *this;
|
|
if(someString.isNull()){removeData();return *this;}
|
|
if(!(stringLength=::strlen(someString.mnpStr)))return *this;
|
|
stringLength++;
|
|
if(lengthBytes()>=stringLength)::strcpy(mnpStr,someString.mnpStr);
|
|
else {reserve(stringLength,FALSE);::strcpy(mnpStr,someString.mnpStr);}
|
|
return *this;
|
|
}
|
|
|
|
int String::operator=(const char *someCharStar)
|
|
{
|
|
int stringLength;
|
|
|
|
if(!someCharStar)return 0;
|
|
if(!(stringLength=::strlen(someCharStar)))return 0;
|
|
stringLength++;
|
|
if(lengthBytes()>=stringLength)::strcpy(mnpStr,someCharStar);
|
|
else {reserve(stringLength,FALSE);::strcpy(mnpStr,someCharStar);}
|
|
return 1;
|
|
}
|
|
|
|
void String::operator+=(char someChar)
|
|
{
|
|
DWORD strLength(length());
|
|
if(strLength+2>mLengthBytes)
|
|
{
|
|
String tmpString(someChar);
|
|
*this+=tmpString;
|
|
return;
|
|
}
|
|
*(mnpStr+strLength)=someChar;
|
|
*(mnpStr+strLength+1)=0;
|
|
}
|
|
|
|
int String::operator+=(const String &someString)
|
|
{
|
|
char *lpString;
|
|
DWORD currLength;
|
|
DWORD stringLength;
|
|
|
|
if(!someString.mnpStr)return 0;
|
|
stringLength=someString.length();
|
|
stringLength++;
|
|
if(!mnpStr)
|
|
{
|
|
reserve(stringLength,FALSE);
|
|
::strcpy(mnpStr,someString.mnpStr);
|
|
return 1;
|
|
}
|
|
currLength=::strlen(mnpStr);
|
|
if(lengthBytes()-currLength>=stringLength)
|
|
{
|
|
::strcat(mnpStr,someString.mnpStr);
|
|
return 1;
|
|
}
|
|
lpString=mnpStr;
|
|
mnpStr=::new char[currLength+stringLength+MaxString];
|
|
mLengthBytes=currLength+stringLength+MaxString;
|
|
::strcpy(mnpStr,lpString);
|
|
::strcpy(mnpStr+currLength,someString.mnpStr);
|
|
::delete[] lpString;
|
|
return 1;
|
|
}
|
|
|
|
int String::operator+=(const char *someStr)
|
|
{
|
|
char *lpString;
|
|
DWORD currLength;
|
|
DWORD stringLength;
|
|
|
|
if(!someStr)return 0;
|
|
stringLength=::strlen(someStr);
|
|
stringLength++;
|
|
if(!mnpStr)
|
|
{
|
|
reserve(stringLength,FALSE);
|
|
::strcpy(mnpStr,someStr);
|
|
return 1;
|
|
}
|
|
currLength=::strlen(mnpStr);
|
|
if(lengthBytes()-currLength>=stringLength)
|
|
{
|
|
::strcat(mnpStr,someStr);
|
|
return 1;
|
|
}
|
|
lpString=mnpStr;
|
|
mnpStr=::new char[currLength+stringLength+MaxString];
|
|
mLengthBytes=currLength+stringLength+MaxString;
|
|
::strcpy(mnpStr,lpString);
|
|
::strcpy(mnpStr+currLength,someStr);
|
|
::delete[] lpString;
|
|
return 1;
|
|
}
|
|
|
|
String String::operator+(const String &someString)const
|
|
{
|
|
String tmpString(*this);
|
|
tmpString+=someString;
|
|
return tmpString;
|
|
}
|
|
|
|
int String::token(const char *tokenString)
|
|
{
|
|
if(!tokenString||!mnpStr)return 0;
|
|
if(::strtok(mnpStr,tokenString))return 1;
|
|
return 0;
|
|
}
|
|
|
|
long String::strchr(char someChar)const
|
|
{
|
|
long pos;
|
|
if(!mnpStr)return -1;
|
|
pos=(long)::strchr(mnpStr,someChar);
|
|
if(!pos)return -1;
|
|
return pos-(long)mnpStr;
|
|
}
|
|
|
|
long String::strpos(const char *string)const
|
|
{
|
|
long stringPosition;
|
|
if(!mnpStr)return -1;
|
|
stringPosition=(long)::strstr(mnpStr,string);
|
|
if(!stringPosition)return -1;
|
|
return stringPosition-(long)mnpStr;
|
|
}
|
|
|
|
int String::strncmp(const char *string)const
|
|
{
|
|
int srcLength;
|
|
int dstLength;
|
|
|
|
if(!mnpStr)return -1;
|
|
srcLength=::strlen(string);
|
|
dstLength=::strlen(mnpStr);
|
|
return ::strncmp(mnpStr,string,srcLength<dstLength?srcLength:dstLength);
|
|
}
|
|
|
|
void String::upper(void)
|
|
{
|
|
char *string=mnpStr;
|
|
|
|
if(!mnpStr)return;
|
|
while(*string)
|
|
{
|
|
*string=::toupper(*string);
|
|
string++;
|
|
}
|
|
}
|
|
|
|
void String::lower(void)
|
|
{
|
|
char *string=mnpStr;
|
|
|
|
if(!mnpStr)return;
|
|
while(*string)
|
|
{
|
|
*string=::tolower(*string);
|
|
string++;
|
|
}
|
|
}
|
|
|
|
String String::betweenString(char beginToken,char endToken)const
|
|
{
|
|
char nullString[MaxString]={0};
|
|
short stringLength;
|
|
char *lpBegin;
|
|
char *lpEnd;
|
|
|
|
if(!mnpStr)return String(nullString);
|
|
stringLength=length();
|
|
if(1>=stringLength)return String(nullString);
|
|
if(beginToken)
|
|
{
|
|
if(0==(lpBegin=::strchr(mnpStr,beginToken)))return String(nullString);
|
|
if(++lpBegin-mnpStr>=stringLength)return String(nullString);
|
|
}
|
|
else lpBegin=mnpStr;
|
|
if(0==(lpEnd=::strchr(lpBegin,endToken)))return *this;
|
|
if(lpBegin==lpEnd)return String(nullString);
|
|
if(sizeof(nullString)<=(lpEnd-lpBegin)+1)
|
|
{
|
|
String nullString;
|
|
nullString.reserve((lpEnd-lpBegin)+1,FALSE);
|
|
::memcpy(nullString,lpBegin,lpEnd-lpBegin);
|
|
*((char*)nullString+(lpEnd-lpBegin))=0;
|
|
return nullString;
|
|
}
|
|
::memcpy(nullString,lpBegin,lpEnd-lpBegin);
|
|
*(nullString+(lpEnd-lpBegin))=0;
|
|
return String(nullString);
|
|
}
|
|
|
|
Block<String> String::split(char delimeter)const
|
|
{
|
|
Block<String> stringList = Block<String>();
|
|
String strDelimeter = String(delimeter);
|
|
String runningString = String(*this);
|
|
|
|
int position = runningString.strpos(strDelimeter);
|
|
while (-1 != position)
|
|
{
|
|
stringList.insert(new String(runningString.substr(0, position - 1)));
|
|
runningString = runningString.substr(position + 1);
|
|
position = runningString.strpos(strDelimeter);
|
|
}
|
|
if (runningString.length())stringList.insert(new String(runningString));
|
|
return stringList;
|
|
}
|
|
|
|
WORD String::makeBlock(Block<String> &receiveStrings,const String &tokenString)const
|
|
{
|
|
String stringData(*this);
|
|
String workString;
|
|
LONG stringPos;
|
|
LONG lengthToken;
|
|
|
|
receiveStrings.remove();
|
|
if(!(lengthToken=tokenString.length()))return FALSE;
|
|
if(stringData.isNull())return FALSE;
|
|
while(TRUE)
|
|
{
|
|
if(-1==(stringPos=stringData.strpos(tokenString)))
|
|
{
|
|
if(!stringData.isNull())receiveStrings.insert(&stringData);
|
|
return receiveStrings.size();
|
|
}
|
|
else if(stringData.length()!=stringPos+lengthToken)
|
|
{
|
|
if(stringPos)
|
|
{
|
|
workString=stringData.substr(0,stringPos-lengthToken);
|
|
receiveStrings.insert(&workString);
|
|
}
|
|
stringData=stringData.substr(stringPos+lengthToken,stringData.length());
|
|
}
|
|
else stringData.removeTokens(tokenString);
|
|
}
|
|
}
|
|
|
|
String String::extractDigits(void)const
|
|
{
|
|
String tempString;
|
|
String nullString;
|
|
char *lpClampOne;
|
|
char *lpClampTwo;
|
|
|
|
if(!mnpStr)return nullString;
|
|
tempString=mnpStr;
|
|
lpClampOne=(char*)tempString;
|
|
while(*lpClampOne&&!isdigit(*lpClampOne))lpClampOne++;
|
|
if(!*lpClampOne)return nullString;
|
|
lpClampTwo=lpClampOne;
|
|
while(*lpClampTwo&&isdigit(*lpClampTwo))lpClampTwo++;
|
|
*lpClampTwo=0;
|
|
return lpClampOne;
|
|
}
|
|
|
|
String String::extractAlpha(void)const
|
|
{
|
|
String tempString;
|
|
String nullString;
|
|
char *lpClampOne;
|
|
char *lpClampTwo;
|
|
|
|
if(!mnpStr)return nullString;
|
|
tempString=mnpStr;
|
|
lpClampOne=(char*)tempString;
|
|
while(*lpClampOne&&!isalpha(*lpClampOne))lpClampOne++;
|
|
if(!*lpClampOne)return nullString;
|
|
lpClampTwo=lpClampOne;
|
|
while(*lpClampTwo&&isalpha(*lpClampTwo))lpClampTwo++;
|
|
*lpClampTwo=0;
|
|
return lpClampOne;
|
|
}
|
|
|
|
int String::hex(void)const
|
|
{
|
|
String workString(*this);
|
|
DWORD stringLength;
|
|
DWORD multiplier(0x01);
|
|
DWORD value(0L);
|
|
char *ptrString;
|
|
|
|
if(workString.isNull())return FALSE;
|
|
if(workString.strstr(" "))workString.removeTokens(" ");
|
|
if(!(stringLength=workString.length()))return FALSE;
|
|
workString.upper();
|
|
if(0!=(ptrString=(char*)workString.strstr("0X")))
|
|
{
|
|
ptrString+=2;
|
|
stringLength=::strlen(ptrString);
|
|
ptrString+=(stringLength-1);
|
|
}
|
|
else if('H'==*((char*)workString+(stringLength-1)))
|
|
{
|
|
stringLength--;
|
|
ptrString=(char*)workString+(stringLength-1);
|
|
}
|
|
else ptrString=(char*)workString+(stringLength-1);
|
|
for(LONG stringIndex=stringLength-1;stringIndex>=0;stringIndex--)
|
|
{
|
|
switch(*(ptrString--))
|
|
{
|
|
case '0' : break;
|
|
case '1' : {value+=multiplier;break;}
|
|
case '2' : {value+=multiplier*2;break;}
|
|
case '3' : {value+=multiplier*3;break;}
|
|
case '4' : {value+=multiplier*4;break;}
|
|
case '5' : {value+=multiplier*5;break;}
|
|
case '6' : {value+=multiplier*6;break;}
|
|
case '7' : {value+=multiplier*7;break;}
|
|
case '8' : {value+=multiplier*8;break;}
|
|
case '9' : {value+=multiplier*9;break;}
|
|
case 'A' : {value+=multiplier*10;break;}
|
|
case 'B' : {value+=multiplier*11;break;}
|
|
case 'C' : {value+=multiplier*12;break;}
|
|
case 'D' : {value+=multiplier*13;break;}
|
|
case 'E' : {value+=multiplier*14;break;}
|
|
case 'F' : {value+=multiplier*15;break;}
|
|
case '-' : {value*=-1;break;}
|
|
default : return value;
|
|
}
|
|
multiplier*=16;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
void String::spaceTerm(void)
|
|
{
|
|
size_t strLen;
|
|
|
|
if(isNull()||(0==(strLen=length())))return;
|
|
for(short index=0;index<strLen;index++)if(Blank==*(mnpStr+index)){*(mnpStr+index)=0;return;}
|
|
}
|
|
|
|
BOOL String::endsWidth(char ch)const
|
|
{
|
|
int strLength = length();
|
|
if(isNull()||strLength)return FALSE;
|
|
return ch == charAt(strLength-1);
|
|
}
|
|
|
|
String& String::trim(void)
|
|
{
|
|
String str = trimRight();
|
|
str=trimLeft();
|
|
*this = str;
|
|
return *this;
|
|
}
|
|
|
|
String &String::trimRight(void)
|
|
{
|
|
size_t strLen;
|
|
|
|
if(isNull()||(0==(strLen=length())))return *this;
|
|
for(short index=strLen-1;index>=0;index--)
|
|
{
|
|
char ch = mnpStr[index];
|
|
if (Blank == ch || CarriageReturn==ch || LineFeed==ch)mnpStr[index] = 0;
|
|
else break;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
String &String::trimLeft(void)
|
|
{
|
|
size_t strLen;
|
|
|
|
if(isNull()||(0==(strLen=length())))return *this;
|
|
short index=0;
|
|
for (index = 0;index < strLen;index++)
|
|
{
|
|
char ch = mnpStr[index];
|
|
if (Blank != ch && CarriageReturn != ch && LineFeed != ch)break;
|
|
}
|
|
if(!index)return *this;
|
|
*this=substr(index);
|
|
return *this;
|
|
}
|
|
|
|
void String::removeTokens(String someTokens)
|
|
{
|
|
int length(this->length());
|
|
int tokens(someTokens.length());
|
|
String tempString;
|
|
|
|
if(!length||!tokens)return;
|
|
for(int token=0;token<tokens;token++)
|
|
for (int pos = 0;pos < length;pos++)
|
|
{
|
|
if (*(mnpStr + pos) == *(someTokens.mnpStr + token))*(mnpStr + pos) = 0;
|
|
}
|
|
for(int pos=0;pos<length;pos++)
|
|
if((mnpStr+pos))tempString+=*(mnpStr+pos);
|
|
*this=tempString;
|
|
}
|
|
|
|
void String::replaceToken(BYTE tokenFind,BYTE tokenReplace)
|
|
{
|
|
int length(this->length());
|
|
String tempString;
|
|
|
|
if(!length)return;
|
|
int pos=0;
|
|
for(pos=0;pos<length;pos++)if(*(mnpStr+pos)==tokenFind)*(mnpStr+pos)=tokenReplace;
|
|
for(pos=0;pos<length;pos++){if((mnpStr+pos))tempString+=*(mnpStr+pos);}
|
|
*this=tempString;
|
|
}
|
|
|
|
void String::length(short newLength)
|
|
{
|
|
short currLength(length());
|
|
|
|
if(currLength==newLength)return;
|
|
if(currLength>newLength)
|
|
{
|
|
String tempString;
|
|
tempString.reserve(newLength+1);
|
|
::memcpy(tempString,*this,newLength);
|
|
*this=tempString;
|
|
}
|
|
else while(length()<newLength)*this+=" ";
|
|
}
|
|
|
|
void String::convert(double doubleValue,const char *formatString)
|
|
{
|
|
if(!formatString)return;
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,formatString,doubleValue);
|
|
return;
|
|
}
|
|
|
|
void String::convert(int integerValue,const char *formatString)
|
|
{
|
|
if(!formatString)return;
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,formatString,integerValue);
|
|
return;
|
|
}
|
|
|
|
void String::convert(long longValue,const char *formatString)
|
|
{
|
|
if(!formatString)return;
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,formatString,longValue);
|
|
return;
|
|
}
|
|
|
|
WORD String::remove(WORD removePosition)
|
|
{
|
|
WORD stringLength(length());
|
|
String tempString;
|
|
|
|
if(!mnpStr)return FALSE;
|
|
if(stringLength<=removePosition)return FALSE;
|
|
if(!removePosition&&1==stringLength){*(mnpStr)='\0';return TRUE;}
|
|
if(!removePosition){*this=(mnpStr+1);return TRUE;}
|
|
*(mnpStr+removePosition)=0;
|
|
tempString=mnpStr;
|
|
tempString+=String((mnpStr+removePosition+1));
|
|
*this=tempString;
|
|
return TRUE;
|
|
}
|
|
|
|
String String::substr(WORD startPosition,WORD endPosition)const
|
|
{
|
|
WORD stringLength(length());
|
|
String resultString;
|
|
|
|
if(!stringLength)return resultString;
|
|
if(startPosition>endPosition)return resultString;
|
|
if(endPosition>stringLength)endPosition=stringLength;
|
|
resultString.reserve(endPosition-startPosition+2);
|
|
::memcpy(resultString,mnpStr+startPosition,(endPosition-startPosition)+1);
|
|
return resultString;
|
|
}
|
|
|
|
WORD String::insert(const String &insertString,WORD insertPosition)
|
|
{
|
|
WORD insertLength(insertString.length());
|
|
|
|
if(!insertLength)return FALSE;
|
|
if(!mnpStr)
|
|
{
|
|
reserve(insertLength+insertPosition+1);
|
|
::memset(mnpStr,Blank,insertLength+insertPosition);
|
|
::memcpy(mnpStr+insertPosition,insertString,insertLength);
|
|
}
|
|
else
|
|
{
|
|
WORD currentLength(length());
|
|
String tempString;
|
|
|
|
if(insertLength+insertPosition>currentLength)
|
|
{
|
|
tempString.reserve(insertLength+insertPosition+currentLength+1);
|
|
::memset(tempString,Blank,insertLength+insertPosition+currentLength);
|
|
}
|
|
else
|
|
{
|
|
tempString.reserve(currentLength+insertLength+1);
|
|
::memset(tempString,Blank,currentLength+insertLength);
|
|
}
|
|
::memcpy(tempString,mnpStr,currentLength);
|
|
if(!(insertPosition>currentLength))shiftRight(tempString,insertPosition,currentLength+insertLength-1,insertLength,currentLength);
|
|
::memcpy(((char*)tempString)+insertPosition,insertString,insertLength);
|
|
*this=tempString;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
WORD String::insert(char *lpInsertString,WORD insertPosition)
|
|
{
|
|
WORD insertLength;
|
|
|
|
if(!lpInsertString||!(insertLength=::strlen(lpInsertString)))return FALSE;
|
|
if(!mnpStr)
|
|
{
|
|
reserve(insertLength+insertPosition+1);
|
|
::memset(mnpStr,Blank,insertLength+insertPosition);
|
|
::memcpy(mnpStr+insertPosition,lpInsertString,insertLength);
|
|
}
|
|
else
|
|
{
|
|
WORD currentLength(length());
|
|
String tempString;
|
|
|
|
if(insertLength+insertPosition>currentLength)
|
|
{
|
|
tempString.reserve(insertLength+insertPosition+currentLength+1);
|
|
::memset(tempString,Blank,insertLength+insertPosition+currentLength);
|
|
}
|
|
else
|
|
{
|
|
tempString.reserve(currentLength+insertLength+1);
|
|
::memset(tempString,Blank,currentLength+insertLength);
|
|
}
|
|
::memcpy(tempString,mnpStr,currentLength);
|
|
if(!(insertPosition>currentLength))shiftRight(tempString,insertPosition,currentLength+insertLength-1,insertLength,currentLength);
|
|
::memcpy(((char*)tempString)+insertPosition,lpInsertString,insertLength);
|
|
*this=tempString;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void String::shiftRight(String &shiftString,WORD startPos,WORD endPos,WORD insertLength,WORD originalLength)
|
|
{
|
|
WORD shiftLength(originalLength-startPos);
|
|
for(WORD shiftIndex=0;shiftIndex<shiftLength;shiftIndex++,endPos--)
|
|
*((char*)shiftString+endPos)=*((char*)shiftString+endPos-insertLength);
|
|
}
|
|
|
|
int String::toInt(void)const
|
|
{
|
|
if(isNull())return 0;
|
|
return ::atoi(str());
|
|
}
|
|
|
|
short String::toShort(void)const
|
|
{
|
|
if(isNull())return 0;
|
|
return short(::atoi(str()));
|
|
}
|
|
|
|
unsigned short String::toUShort(void)const
|
|
{
|
|
if (isNull())return 0;
|
|
return (unsigned short)(::atoi(str()));
|
|
}
|
|
|
|
float String::toFloat(void)const
|
|
{
|
|
if(isNull())return 0.00;
|
|
return ::atof(str());
|
|
}
|
|
|
|
double String::toDouble(void)const
|
|
{
|
|
if(isNull())return 0.00;
|
|
return ::atof(str());
|
|
}
|
|
|
|
long String::toLong(void)const
|
|
{
|
|
if(isNull())return 0;
|
|
return ::atol(str());
|
|
}
|
|
|
|
unsigned long String::toULong(void)const
|
|
{
|
|
if(isNull())return 0;
|
|
return (unsigned long)::atol(str());
|
|
}
|
|
|
|
|
|
String &String::fromInt(int value)
|
|
{
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,"%d",value);
|
|
return *this;
|
|
}
|
|
|
|
String &String::fromShort(short value)
|
|
{
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,"%d",value);
|
|
return *this;
|
|
}
|
|
|
|
String &String::fromUShort(unsigned short value)
|
|
{
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,"%d",value);
|
|
return *this;
|
|
}
|
|
|
|
String &String::fromFloat(float value)
|
|
{
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,"%9.2lf",value);
|
|
return *this;
|
|
}
|
|
|
|
String &String::fromDouble(double value)
|
|
{
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,"%9.2lf",value);
|
|
return *this;
|
|
}
|
|
|
|
String &String::fromLong(long value)
|
|
{
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,"%ld",value);
|
|
return *this;
|
|
}
|
|
|
|
String &String::fromULong(unsigned long value)
|
|
{
|
|
reserve(MaxString);
|
|
::sprintf(mnpStr,"%lu",value);
|
|
return *this;
|
|
}
|
|
|
|
|
|
String &String::fromBool(bool boolValue)
|
|
{
|
|
*this=boolValue?"T":"F";
|
|
return *this;
|
|
}
|
|
|
|
// non-member
|
|
|
|
String operator+(const char *str,const String &string)
|
|
{
|
|
return String(str)+string;
|
|
}
|