feat(xml-logs): finish tests

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers
2025-04-18 15:22:39 -07:00
parent bfdc77665d
commit 21570a03fb
15 changed files with 2006 additions and 91 deletions

View File

@ -62,3 +62,7 @@ ecm_add_test(MetaComponentParse_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VE
ecm_add_test(CatPack_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME CatPack)
ecm_add_test(XmlLogs_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME XmlLogs)

View File

@ -23,9 +23,11 @@
#include <QList>
#include <QObject>
#include <QRegularExpression>
#include <QString>
#include <optional>
#include <algorithm>
#include <iterator>
#include <FileSystem.h>
#include <MessageLevel.h>
@ -42,16 +44,62 @@ class XmlLogParseTest : public QObject {
QString shortXml = QString::fromUtf8(FS::read(FS::PathCombine(source, "vanilla-1.21.5.xml.log")));
QString shortText = QString::fromUtf8(FS::read(FS::PathCombine(source, "vanilla-1.21.5.text.log")));
QStringList shortTextLevels_s = QString::fromUtf8(FS::read(FS::PathCombine(source, "vanilla-1.21.5-levels.txt")))
.split(QRegularExpression("\n|\r\n|\r"), Qt::SkipEmptyParts);
QList<MessageLevel::Enum> shortTextLevels;
shortTextLevels.reserve(24);
std::transform(shortTextLevels_s.cbegin(), shortTextLevels_s.cend(), std::back_inserter(shortTextLevels),
[](const QString& line) { return MessageLevel::getLevel(line.trimmed()); });
QString longXml = QString::fromUtf8(FS::read(FS::PathCombine(source, "TerraFirmaGreg-Modern-forge.xml.log")));
QString longText = QString::fromUtf8(FS::read(FS::PathCombine(source, "TerraFirmaGreg-Modern-forge.text.log")));
QTest::addColumn<QString>("text");
QTest::addColumn<QString>("xml");
QTest::newRow("short-vanilla") << shortText << shortXml;
QTest::newRow("long-forge") << longText << longXml;
QStringList longTextLevels_s = QString::fromUtf8(FS::read(FS::PathCombine(source, "TerraFirmaGreg-Modern-levels.txt")))
.split(QRegularExpression("\n|\r\n|\r"), Qt::SkipEmptyParts);
QStringList longTextLevelsXml_s = QString::fromUtf8(FS::read(FS::PathCombine(source, "TerraFirmaGreg-Modern-xml-levels.txt")))
.split(QRegularExpression("\n|\r\n|\r"), Qt::SkipEmptyParts);
QList<MessageLevel::Enum> longTextLevelsPlain;
longTextLevelsPlain.reserve(974);
std::transform(longTextLevels_s.cbegin(), longTextLevels_s.cend(), std::back_inserter(longTextLevelsPlain),
[](const QString& line) { return MessageLevel::getLevel(line.trimmed()); });
QList<MessageLevel::Enum> longTextLevelsXml;
longTextLevelsXml.reserve(896);
std::transform(longTextLevelsXml_s.cbegin(), longTextLevelsXml_s.cend(), std::back_inserter(longTextLevelsXml),
[](const QString& line) { return MessageLevel::getLevel(line.trimmed()); });
QTest::addColumn<QString>("log");
QTest::addColumn<int>("num_entries");
QTest::addColumn<QList<MessageLevel::Enum>>("entry_levels");
QTest::newRow("short-vanilla-plain") << shortText << 25 << shortTextLevels;
QTest::newRow("short-vanilla-xml") << shortXml << 25 << shortTextLevels;
QTest::newRow("long-forge-plain") << longText << 945 << longTextLevelsPlain;
QTest::newRow("long-forge-xml") << longXml << 869 << longTextLevelsXml;
}
void parseXml() { QFETCH(QString, ) }
void parseXml()
{
QFETCH(QString, log);
QFETCH(int, num_entries);
QFETCH(QList<MessageLevel::Enum>, entry_levels);
QList<std::pair<MessageLevel::Enum, QString>> entries = {};
QBENCHMARK
{
entries = parseLines(log.split(QRegularExpression("\n|\r\n|\r")));
}
QCOMPARE(entries.length(), num_entries);
QList<MessageLevel::Enum> levels = {};
std::transform(entries.cbegin(), entries.cend(), std::back_inserter(levels),
[](std::pair<MessageLevel::Enum, QString> entry) { return entry.first; });
QCOMPARE(levels, entry_levels);
}
private:
LogParser m_parser;
@ -59,27 +107,35 @@ class XmlLogParseTest : public QObject {
QList<std::pair<MessageLevel::Enum, QString>> parseLines(const QStringList& lines)
{
QList<std::pair<MessageLevel::Enum, QString>> out;
for (const auto& line : lines)
MessageLevel::Enum last = MessageLevel::Unknown;
for (const auto& line : lines) {
m_parser.appendLine(line);
auto items = m_parser.parseAvailable();
for (const auto& item : items) {
if (std::holds_alternative<LogParser::LogEntry>(item)) {
auto entry = std::get<LogParser::LogEntry>(item);
auto msg = QString("[%1] [%2/%3] [%4]: %5")
.arg(entry.timestamp.toString("HH:mm:ss"))
.arg(entry.thread)
.arg(entry.levelText)
.arg(entry.logger)
.arg(entry.message);
msg = censorPrivateInfo(msg);
out.append(std::make_pair(entry.level, msg));
} else if (std::holds_alternative<LogParser::PlainText>(item)) {
auto msg = std::get<LogParser::PlainText>(item).message;
level = m_instance->guessLevel(msg, level);
msg = censorPrivateInfo(msg);
out.append(std::make_pair(entry.level, msg));
auto items = m_parser.parseAvailable();
for (const auto& item : items) {
if (std::holds_alternative<LogParser::LogEntry>(item)) {
auto entry = std::get<LogParser::LogEntry>(item);
auto msg = QString("[%1] [%2/%3] [%4]: %5")
.arg(entry.timestamp.toString("HH:mm:ss"))
.arg(entry.thread)
.arg(entry.levelText)
.arg(entry.logger)
.arg(entry.message);
out.append(std::make_pair(entry.level, msg));
last = entry.level;
} else if (std::holds_alternative<LogParser::PlainText>(item)) {
auto msg = std::get<LogParser::PlainText>(item).message;
auto level = LogParser::guessLevel(msg, last);
out.append(std::make_pair(level, msg));
last = level;
}
}
}
return out;
}
};
QTEST_GUILESS_MAIN(XmlLogParseTest)
#include "XmlLogs_test.moc"

View File

@ -0,0 +1,945 @@
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
WARN
WARN
WARN
INFO
ERROR
INFO
ERROR
ERROR
ERROR
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
WARN
WARN
INFO
WARN
WARN
WARN
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
INFO
INFO
WARN
WARN
WARN
INFO
WARN
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
INFO
INFO
WARN
INFO
WARN
WARN
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
WARN
INFO
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
WARN
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
INFO
INFO
WARN
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
INFO
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
ERROR
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
INFO
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
ERROR
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
INFO
INFO
INFO
ERROR
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
ERROR
ERROR
ERROR
ERROR
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN

View File

@ -0,0 +1,869 @@
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
ERROR
INFO
ERROR
ERROR
ERROR
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
WARN
WARN
INFO
WARN
WARN
WARN
WARN
WARN
INFO
WARN
WARN
INFO
INFO
WARN
WARN
WARN
INFO
WARN
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
WARN
INFO
INFO
WARN
INFO
WARN
WARN
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
WARN
INFO
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
WARN
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
INFO
INFO
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
ERROR
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
WARN
WARN
INFO
INFO
INFO
INFO
ERROR
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
WARN
WARN
WARN
WARN
INFO
INFO
INFO
ERROR
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
WARN
WARN
WARN
WARN
WARN
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
ERROR
ERROR
ERROR
ERROR
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO

View File

@ -0,0 +1,25 @@
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
WARN
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO
INFO