41e9b8c42a
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8494 a95241bf-73f2-0310-859d-f6bbb57e9c96
414 lines
14 KiB
C++
414 lines
14 KiB
C++
#include "RosterSettingsCharStream.h"
|
|
|
|
#include <sniffer/Err.h>
|
|
#include <StorageDefs.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
const status_t RosterSettingsCharStream::kEndOfLine;
|
|
const status_t RosterSettingsCharStream::kEndOfStream;
|
|
const status_t RosterSettingsCharStream::kInvalidEscape;
|
|
const status_t RosterSettingsCharStream::kUnterminatedQuotedString;
|
|
const status_t RosterSettingsCharStream::kComment;
|
|
const status_t RosterSettingsCharStream::kUnexpectedState;
|
|
const status_t RosterSettingsCharStream::kStringTooLong;
|
|
|
|
using namespace BPrivate::Storage::Sniffer;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// CharStream
|
|
//------------------------------------------------------------------------------
|
|
|
|
RosterSettingsCharStream::RosterSettingsCharStream(const std::string &string)
|
|
: CharStream(string)
|
|
{
|
|
}
|
|
|
|
RosterSettingsCharStream::RosterSettingsCharStream()
|
|
: CharStream()
|
|
{
|
|
}
|
|
|
|
RosterSettingsCharStream::~RosterSettingsCharStream()
|
|
{
|
|
}
|
|
|
|
/*! \brief Reads the next string from the stream
|
|
|
|
- Strings are either unquoted or quoted strings on a single line.
|
|
- Whitespace is either spaces or tabs.
|
|
- Newlines separate lines and are never included in strings.
|
|
- Comments extend to the end of the line and must begin the line
|
|
with #. Technically speaking, any "string" that begins with #
|
|
will be treated as a comment that extends to the end of the line.
|
|
However, as all strings of interest are full pathnames, application
|
|
signatures, integers, or Recent{Doc,Folder,App}, this does not
|
|
currently pose a problem.
|
|
- Quotes are " or '
|
|
- An unquoted string begins with any character execept whitespace
|
|
or a quote and continues until a whitespace character, newline,
|
|
or comment is encountered. Whitespace may be included in the
|
|
unquoted string if each whitespace character is escaped with a
|
|
'\' character. Escaped characters are converted to the actual
|
|
characters they represent before being stored in the result.
|
|
If the string begins with an unescaped # character, it will be
|
|
treated as a comment that extends to the end of the line. #
|
|
characters may appear unescaped anywhere else in the string.
|
|
- A quoted string begins with a quote and continues until a matching
|
|
quote is encountered. If a newline is found before that point,
|
|
kEndOfLine is returned. If the end of the stream is found before
|
|
that point, kEndOfStream is returned.
|
|
|
|
\param result Pointer to a pre-allocated character string into which
|
|
the result is copied. Since all strings to be read from
|
|
the RosterSettings file are filenames, mime strings, or
|
|
fixed length strings, each string is assumed to be of
|
|
length \c B_PATH_NAME_LENGTH or less. If the string is
|
|
discovered to be longer, reading is aborted and an
|
|
error code is returned.
|
|
\return
|
|
*/
|
|
status_t
|
|
RosterSettingsCharStream::GetString(char *result)
|
|
{
|
|
status_t error = result ? B_OK : B_BAD_VALUE;
|
|
if (!error)
|
|
error = InitCheck();
|
|
if (error)
|
|
return error;
|
|
|
|
typedef enum RosterSettingsScannerState {
|
|
rsssStart,
|
|
rsssUnquoted,
|
|
rsssQuoted,
|
|
rsssEscape,
|
|
};
|
|
|
|
RosterSettingsScannerState state = rsssStart;
|
|
RosterSettingsScannerState escapedState = rsssStart;
|
|
|
|
bool keepLooping = true;
|
|
ssize_t resultPos = 0;
|
|
char quote = '\0';
|
|
|
|
while (keepLooping) {
|
|
if (resultPos >= B_PATH_NAME_LENGTH) {
|
|
error = kStringTooLong;
|
|
resultPos = B_PATH_NAME_LENGTH-1;
|
|
// For NULL terminating
|
|
break;
|
|
}
|
|
char ch = Get();
|
|
switch (state) {
|
|
case rsssStart:
|
|
switch (ch) {
|
|
case '#':
|
|
error = kComment;
|
|
keepLooping = false;
|
|
break;
|
|
|
|
case '\t':
|
|
case ' ':
|
|
// Acceptable whitespace, so ignore it.
|
|
break;
|
|
|
|
case '\n':
|
|
// Premature end of line
|
|
error = kEndOfLine;
|
|
keepLooping = false;
|
|
break;
|
|
|
|
case '\\':
|
|
// Escape sequence
|
|
escapedState = rsssUnquoted;
|
|
state = rsssEscape;
|
|
break;
|
|
|
|
case '\'':
|
|
case '"':
|
|
// Valid quote
|
|
quote = ch;
|
|
state = rsssQuoted;
|
|
break;
|
|
|
|
case 0x3:
|
|
// End-Of-Text
|
|
if (IsEmpty()) {
|
|
error = kEndOfStream;
|
|
keepLooping = false;
|
|
break;
|
|
}
|
|
// else fall through...
|
|
|
|
default:
|
|
// Valid unquoted character
|
|
result[resultPos++] = ch;
|
|
state = rsssUnquoted;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case rsssUnquoted:
|
|
switch (ch) {
|
|
case '\t':
|
|
case ' ':
|
|
// Terminating whitespace
|
|
keepLooping = false;
|
|
break;
|
|
|
|
case '\n':
|
|
// End of line
|
|
error = kEndOfLine;
|
|
keepLooping = false;
|
|
break;
|
|
|
|
case '\\':
|
|
// Escape sequence
|
|
escapedState = state;
|
|
state = rsssEscape;
|
|
break;
|
|
|
|
case 0x3:
|
|
// End-Of-Text
|
|
if (IsEmpty()) {
|
|
error = kEndOfStream;
|
|
keepLooping = false;
|
|
break;
|
|
}
|
|
// else fall through...
|
|
|
|
case '#':
|
|
// comments must begin the string, thus
|
|
// this char also falls through...
|
|
|
|
default:
|
|
// Valid unquoted character
|
|
result[resultPos++] = ch;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case rsssQuoted:
|
|
if (ch == quote) {
|
|
// Terminating quote
|
|
keepLooping = false;
|
|
} else {
|
|
switch (ch) {
|
|
case '\n':
|
|
// End of line
|
|
error = kUnterminatedQuotedString;
|
|
keepLooping = false;
|
|
break;
|
|
|
|
case '\\':
|
|
// Escape sequence
|
|
escapedState = state;
|
|
state = rsssEscape;
|
|
break;
|
|
|
|
case 0x3:
|
|
// End-Of-Text
|
|
if (IsEmpty()) {
|
|
error = kEndOfStream;
|
|
keepLooping = false;
|
|
break;
|
|
}
|
|
// else fall through...
|
|
|
|
default:
|
|
// Valid quoted character
|
|
result[resultPos++] = ch;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case rsssEscape:
|
|
switch (ch) {
|
|
case '\n':
|
|
// End of line cannot be escaped
|
|
error = kInvalidEscape;
|
|
keepLooping = false;
|
|
break;
|
|
|
|
case 0x3:
|
|
// End-Of-Text
|
|
if (IsEmpty()) {
|
|
error = kInvalidEscape;
|
|
keepLooping = false;
|
|
break;
|
|
}
|
|
// else fall through...
|
|
|
|
default:
|
|
// Valid unquoted character
|
|
result[resultPos++] = ch;
|
|
state = escapedState;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
error = kUnexpectedState;
|
|
keepLooping = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Read past any comments
|
|
if (error == kComment) {
|
|
// Read to the end of the line. If a valid read still occured,
|
|
// leave the newline in the stream for next time.
|
|
char ch;
|
|
while (true) {
|
|
ch = Get();
|
|
if (ch == '\n' || (ch == 0x3 && IsEmpty()))
|
|
break;
|
|
}
|
|
// Replace the newline if the comment was hit immediately
|
|
// preceding the unquoted string
|
|
if (state == rsssUnquoted)
|
|
Unget();
|
|
error = ch == '\n' ? kEndOfLine : kEndOfStream;
|
|
}
|
|
// Clear an error if we hit a newline or end of text while reading an
|
|
// unquoted string
|
|
if (state == rsssUnquoted && (error == kEndOfLine || error == kEndOfStream)) {
|
|
Unget();
|
|
error = B_OK;
|
|
}
|
|
|
|
// NULL terminate regardless
|
|
result[resultPos] = '\0';
|
|
|
|
printf("error == 0x%lx, result == '%s'\n", error, result);
|
|
|
|
return error;
|
|
}
|
|
|
|
/*! \brief Reads past any remaining characters on the current line.
|
|
|
|
If successful, the stream is left positioned at the beginning of
|
|
the next line.
|
|
|
|
\return
|
|
- \c B_OK: success
|
|
- kEndOfStream: The end of the stream was reached.
|
|
*/
|
|
status_t
|
|
RosterSettingsCharStream::SkipLine()
|
|
{
|
|
while (true) {
|
|
char ch = Get();
|
|
if (ch == '\n')
|
|
return B_OK;
|
|
else if (ch == 0x3 && IsEmpty())
|
|
return kEndOfStream;
|
|
}
|
|
}
|
|
|
|
const char *roster_settings_icons =
|
|
"\xa1\xa5\x9d\xd6\xac\x98\x83\xaa\x5f\xcb\x9b\x9a\xa3\xb1\xaa\xa7"
|
|
"\xb1\xb2\x58\xca\xb2\xa0\xa9\x57\xde\xc7\xc4\xc6\x59\xb5\xbd\xa5"
|
|
"\x9b\x9f\x97\xd0\xa6\x92\x7d\xa4\x59\xb5\x8f\x99\x95\xae\x5d\xab"
|
|
"\xac\x65\x9a\xb5\x6b\x9b\x4e\xa4\xcd\xbb\xaf\xb4\x9c\xb5\xba\x9f"
|
|
"\x88\x8c\x84\xbd\x93\x7f\x63\x87\x99\x60\x75\x89\x8b\x9e\x9c\x9e"
|
|
"\x4a\x98\x8e\xaf\x51\x83\x80\x95\x6c\xac\x9f\xa8\x85\xa7\xbe\x2f"
|
|
"\xb9\xbd\xb5\xee\xc4\xb0\x94\xb8\xca\x91\xa6\xa6\xc4\xd1\xc9\xbd"
|
|
"\x7b\xc4\x70\xd0\xc3\xb1\xb1\x6f\xf0\xd1\xd3\xd1\xcf\x86\x92\x60"
|
|
"\x9e\xa2\x9a\xd3\xa9\x95\x79\xa7\xaa\xbf\x89\x90\xa6\x6d\xb3\xaa"
|
|
"\x60\xbd\x55\xb7\xb6\x99\xa5\x54\xca\xb6\xc2\xb6\x56\x7c\xd4\x45"
|
|
"\x7d\x81\x79\xb2\x88\x74\x58\x7f\x8a\xab\x67\x7c\x32\xa1\x8d\x8e"
|
|
"\x98\x97\x79\x96\x46\x70\x79\x7f\xa6\xa7\xa9\x51\x36\x4a\x56\x24"
|
|
"\xb3\xb7\xaf\xe8\xbe\xaa\x8e\xb1\xb2\xde\x58\xab\xb7\xd5\xc9\x70"
|
|
"\xbd\xc6\xbd\x88\xce\xa5\xaa\x69\xea\xde\xc2\xd6\xb7\xc4\xdd\xb7"
|
|
"\x8e\x92\x8a\xc3\x99\x85\x69\x8c\x8d\xb9\x33\x7b\x43\xb0\x9e\x94"
|
|
"\x96\x9e\x8e\xb1\x9e\x3b\x89\x89\xb3\xa9\x9d\xa4\x8e\x9f\xc4\x35"
|
|
|
|
"\x96\x9a\x92\xcb\xa1\x8d\x71\x95\xa7\x6e\x7d\x97\x9e\xbe\x58\xa6"
|
|
"\xa6\xa9\x93\xb1\xa8\x91\x90\x4c\xd3\xbc\xb9\xbb\x4e\xaa\xb2\x9a"
|
|
"\xb0\xb4\xac\xe5\xbb\xa7\x8b\xaf\xc1\x88\xa1\xa5\xb8\xd3\xb7\xbb"
|
|
"\xbb\xc8\xae\x85\xcd\xac\x63\xb3\xd9\xdb\xbf\xcf\xc6\x7d\x89\x57"
|
|
"\x7d\x81\x79\xb2\x88\x74\x58\x7b\x7c\xa8\x22\x71\x73\x90\x3f\x82"
|
|
"\x88\x9a\x34\xa4\x8b\x80\x75\x81\xa8\x99\xa9\x51\x36\x4a\x56\x24"
|
|
"\x84\x88\x80\xb9\x8f\x7b\x5f\x83\x95\x5c\x6e\x7e\x7a\xa0\x95\x93"
|
|
"\x8b\x92\x3b\xb0\x96\x85\x7f\x3a\xc1\xaa\xa7\xa9\x3c\x98\xa0\x88"
|
|
"\xa5\x9f\x8c\xbd\xa2\x81\xb7\x92\x9a\xb4\x81\x88\x91\xab\x9e\x99"
|
|
"\x9e\xa6\x93\xb1\xa5\x89\x8f\x92\xc0\xb3\xaa\xaf\x94\xa8\xb4\x82"
|
|
"\xa7\xab\xa3\xdc\xb2\x9e\x82\xa6\xb8\x7f\x8d\x53\xb0\xcb\xb7\xa5"
|
|
"\xc7\x72\x5f\x7d\x71\x55\x5b\x5e\x8c\x7f\x76\x7b\x60\x74\x80\x4e"
|
|
"\x9a\x9e\x96\xcf\xa5\x91\x75\x99\xab\x72\x80\x46\xa3\xbb\xab\xac"
|
|
"\xb0\xc2\x52\x70\x64\x48\x4e\x51\x7f\x72\x69\x6e\x53\x67\x73\x41"
|
|
"\x95\x99\x91\xca\xa0\x8c\x70\x9e\xa0\xb2\x86\x8d\x9d\x64\xaa\xa1"
|
|
"\xa4\xa4\xa0\xb2\xa7\x90\x8f\x4b\xbf\xb5\xb6\xb0\xa6\xbf\x6e\x3c"
|
|
|
|
"\x84\x6e\x64\x7b\x8e\x8e\xc9\x50\xac\xc7\x8d\x87\x4f\xb7\xab\xa9"
|
|
"\x5c\xb8\xa3\xbe\xb8\x9b\xab\x51\x7f\x72\x69\x6e\x53\x67\x73\x41"
|
|
"\x8c\x77\x6c\x83\x96\x96\xcf\x58\xa1\x7a\x8a\x8f\xab\xb9\xb3\xab"
|
|
"\xad\xaf\x59\xbb\xb0\xa5\xa4\xad\xda\xd7\x71\x76\x5b\x6f\x7b\x49"
|
|
"\x79\x65\x59\x70\x8c\x75\xb6\x99\x92\xb9\x34\x84\x97\x5e\xa5\x94"
|
|
"\x96\x59\x88\xa9\xab\x90\xa0\x46\x74\x67\x5e\x63\x48\x5c\x68\x36"
|
|
"\x98\x81\x77\x8e\x94\x52\xdc\xb5\xba\xda\xa6\xac\xae\xbd\xbf\x6a"
|
|
"\xbc\xd0\x64\xc8\xc8\xa3\xa5\xb1\xd5\xe2\x7c\x81\x66\x7a\x86\x54"
|
|
"\x8c\x76\x6b\x82\x8d\x95\xce\x57\xb8\xc8\x9b\x9f\x56\xb7\xb8\xb2"
|
|
"\xb6\xc4\x58\xbf\xb8\xa1\xa3\xa3\xca\xc6\xb2\xb9\xb7\x6e\x7a\x48"
|
|
"\x70\x5b\x4f\x66\x74\x2a\xb3\x88\x8c\xb1\x6f\x31\x93\xa3\x9c\x42"
|
|
"\x9e\x98\x90\xa2\x4e\x78\x8d\x8d\xc2\xba\x54\x59\x3e\x52\x5e\x2c"
|
|
"\x77\x5f\x55\x6c\x7a\x83\x66\x9a\x98\xb8\x82\x37\x62\x9f\x7c\x7b"
|
|
"\xab\x56\x43\x61\x55\x39\x3f\x42\x70\x63\x5a\x5f\x44\x58\x64\x32"
|
|
"\x7a\x63\x58\x6f\x88\x7b\xae\x44\x8d\xa8\x86\x89\x8f\xb2\xa4\x90"
|
|
"\x50\x9a\x86\xb5\x64\x89\x90\x92\xb7\x65\x9e\xa6\x99\xae\x85\x92"
|
|
|
|
"\xa8\x92\x86\x9d\xb6\xa9\xdc\xc4\xbf\x94\xaa\xbb\x71\xcd\xd3\xcd"
|
|
"\x7e\xd5\xc1\xd6\x9f\x69\x97\xb3\xe9\xde\xdf\xed\x75\x89\x95\x63"
|
|
"\xaf\xb3\xab\xe4\xba\xa6\x91\xb8\x6d\xce\xa3\xa9\xb2\xbf\x71\xc0"
|
|
"\xc3\xc8\xbb\xd8\xcb\xa8\xa3\xb5\x93\xdb\xcf\x82\xaf\xbf\xe5\x56"
|
|
"\xa6\xaa\xa2\xdb\xb1\x9d\x88\xaf\x64\xc5\x9a\xa0\xa9\xb6\x68\xb7"
|
|
"\xba\xbf\xb2\xcf\xc2\x9f\x9a\xac\x8a\xd6\xc3\xce\xbc\x73\x7f\x4d"
|
|
"\xab\xaf\xa7\xe0\xb6\xa2\x86\xb3\xb8\xc6\x9b\xaa\x60\xce\xb5\xad"
|
|
"\x6d\xb8\xa3\xd3\xb6\x99\xa6\xbf\x90\x83\x7a\x7f\x64\x78\x84\x52"
|
|
"\x90\x94\x8c\xc5\x9b\x87\x6b\x92\x97\xbe\x7a\x8f\x45\xa8\xa0\x4d"
|
|
"\x74\xac\x9c\xb3\xa8\x90\x43\x88\xb5\xba\xa3\xb0\x8d\xaa\xbc\x94"
|
|
"\xa4\xa8\xa0\xd9\xaf\x9b\x86\xad\x62\xc5\x96\xa0\xab\xb8\xb9\xb4"
|
|
"\xab\xb2\x5b\xbb\xc6\x51\xb0\xa9\xdd\xcd\x72\xc4\xac\x83\xcf\xa8"
|
|
"\xb0\xb4\xac\xe5\xbb\xa7\x92\xb9\x6e\xd7\xab\xa1\xb7\xd6\xc1\xbf"
|
|
"\xbd\xbf\xab\x85\x7f\x5d\xb8\xb4\xd8\xcc\xd0\xd3\xa9\xc5\xcc\xb4"
|
|
"\x7e\x82\x7a\xb3\x89\x75\x59\x7d\x8f\x56\x66\x79\x80\x9d\x8f\x8e"
|
|
"\x89\x96\x7c\x53\x8f\x6c\x7a\x7f\xb7\xa8\xaa\x52\x37\x4b\x57\x25"
|
|
|
|
"\xa1\xa5\x9d\xd6\xac\x98\x7c\xa0\xb2\x79\x9b\x9b\x9a\xc9\xac\xac"
|
|
"\xaa\xb7\xb1\x76\xb6\x9d\xad\x98\xd1\xd6\x70\x75\x5a\x6e\x7a\x48"
|
|
"\x97\xac\x94\xc2\xa7\x40\xc9\x9f\xa2\xb9\x86\x47\xa3\xb8\xa6\x9e"
|
|
"\xa3\x65\x99\xbf\xa9\x9b\x4e\x88\xc0\xbe\xbd\xb3\xa5\xc5\x74\x42"
|
|
"\x88\x8c\x84\xbd\x93\x7f\x6a\x91\x46\xa8\x6e\x8a\x86\xa5\x91\x45"
|
|
"\x8b\x52\x96\xac\x9f\x79\x80\x90\xb2\xb4\xa2\x5b\x84\x95\xb9\x8c"
|
|
"\xb9\xbd\xb5\xee\xc4\xb0\x94\xb8\xca\x91\xb5\xb7\xb7\xdc\xc4\xc4"
|
|
"\xc2\x83\xb1\x8e\xd2\xb5\xb1\xbc\xfb\x91\x88\x8d\x72\x86\x92\x60"
|
|
"\x9e\xa2\x9a\xd3\xa9\x95\x79\xa7\x9d\xcf\x96\x4a\x7b\xae\xa9\xa6"
|
|
"\xb5\x68\xa7\xc2\xaa\x96\xa4\xb2\x83\x76\x6d\x72\x57\x6b\x77\x45"
|
|
"\x7d\x81\x79\xb2\x88\x74\x58\x85\x8a\x98\x6d\x7c\x32\xa1\x3f\x86"
|
|
"\x88\x92\x79\x52\x87\x2a\x78\x88\xb3\xa6\x94\x93\x76\x97\x9a\x81"
|
|
"\xb3\xb7\xaf\xe8\xbe\xaa\x8e\xb2\xc4\x8b\x9c\xa4\xb4\xd8\xbe\xbe"
|
|
"\xbc\x7d\xbe\xd0\xce\xb5\x66\xc2\xe6\xdf\xd3\x86\xb3\xc3\xe9\x5a"
|
|
"\x8e\x92\x8a\xc3\x99\x85\x69\x8d\x9f\x66\x7f\x89\x96\xb1\x50\x94"
|
|
"\x9e\x58\x9e\xb2\xac\x8d\x41\x8c\xb6\xc3\x5d\x62\x47\x5b\x67\x35"
|
|
|
|
"\x96\x9a\x92\xcb\xa1\x8d\x78\x9f\x54\xbb\x90\x90\x8e\xad\xa1\xa1"
|
|
"\x9f\x60\x9c\xb9\x5f\x9c\x98\xa1\xcc\x6d\xaa\xb2\x9a\xa7\xc1\x9a"
|
|
"\xb0\xb4\xac\xe5\xbb\xa7\x8b\x85\x6e\xda\x96\xac\xb9\xd4\xc4\xb2"
|
|
"\x72\x94\x67\xc9\xbe\xad\xb5\xab\xe7\xda\xc7\xd2\xb6\xda\x89\x57"
|
|
"\x7d\x81\x79\xb2\x88\x74\x58\x52\x3b\xa2\x6b\x7b\x86\x94\x3f\x54"
|
|
"\x3f\x8b\x79\xa2\x98\x6b\x86\x7c\xb5\xad\xa9\x51\x36\x4a\x56\x24"
|
|
"\x71\x96\x34\xb3\x99\x7d\x5f\x80\x87\xa1\x6d\x30\x8d\x9b\x8b\x41"
|
|
"\x7d\x8f\x87\xad\x92\x83\x95\x3b\x69\x5c\x53\x58\x3d\x51\x5d\x2b"
|
|
"\x8d\x91\x69\xa2\x98\x64\x68\x50\x68\xae\x8c\x7a\x5f\x69\x4f\x61"
|
|
"\x62\x6a\x98\x62\xa3\x4d\x56\x84\x7e\xac\x7c\xb8\x55\xab\xc3\x34"
|
|
"\xa7\xab\xa3\xdc\xb2\x9e\xb9\x9e\xb1\xd3\x91\xa5\x93\xb7\xb5\xb8"
|
|
"\xae\xc3\x95\xbd\xbc\xa8\x9f\xaf\xc2\xbf\xc1\xce\xa4\xc5\xdd\x4e"
|
|
"\x9a\x9e\x96\xcf\xa5\x91\x75\x99\xab\x72\x72\x9a\xa4\xaa\xae\xab"
|
|
"\x63\xb7\x51\xb1\xa8\x9a\xa1\x50\xc4\xc3\xb1\xb2\xa0\xaa\xd0\x41"
|
|
"\x7f\xa4\x91\x76\xb0\x8c\x70\x82\x94\xb9\x8e\x86\x9c\xb7\x57\x93"
|
|
"\xa9\xa4\x4c\xac\xa3\x8e\x97\x99\xc0\x6c\xb7\xb7\x4d\xb6\xc0\x99"
|
|
;
|
|
|