From 4b58449ad9a7de9910e0fc2db3877a0e7aa5cfce Mon Sep 17 00:00:00 2001 From: JustinAJ Date: Tue, 3 Jun 2014 22:35:30 -0400 Subject: [PATCH] Modified to be in a compilable state. Requires testing and further modification. --- Jupiter/IRC_Client.cpp | 573 ++++++++++++++++++++--------------------- Jupiter/IRC_Client.h | 129 +++++----- Release/Jupiter.lib | Bin 205240 -> 215808 bytes 3 files changed, 339 insertions(+), 363 deletions(-) diff --git a/Jupiter/IRC_Client.cpp b/Jupiter/IRC_Client.cpp index 78fc326..5351b49 100644 --- a/Jupiter/IRC_Client.cpp +++ b/Jupiter/IRC_Client.cpp @@ -15,6 +15,7 @@ #include "INIFile.h" #include "TCPSocket.h" #include "CString.h" +#include "String.h" #include "Plugin.h" #include "Base64.h" @@ -61,9 +62,9 @@ struct JUPITER_API Jupiter::IRC::Client::Data Jupiter::CStringS modeD = "psitnm"; Jupiter::ArrayList channels; void delChannel(unsigned int index); - void delChannel(const char *chan); - void addNamesToChannel(unsigned int channelIndex, Jupiter::CStringS &names); - unsigned int addChannel(const char *chan); + void delChannel(const Jupiter::ReadableString &chan); + void addNamesToChannel(unsigned int channelIndex, Jupiter::ReadableString &names); + size_t addChannel(const Jupiter::ReadableString &chan); bool joinOnKick; Jupiter::CStringS autoPartMessage; time_t reconnectDelay; @@ -79,8 +80,8 @@ struct JUPITER_API Jupiter::IRC::Client::Data bool startCAP(); bool registerClient(); Data(Jupiter::IRC::Client *interFace); - Jupiter::IRC::Client::User *findUser(const char *nick) const; - Jupiter::IRC::Client::User *findUserOrAdd(Jupiter::CStringS &nick); + Jupiter::IRC::Client::User *findUser(const Jupiter::ReadableString &nick) const; + Jupiter::IRC::Client::User *findUserOrAdd(const Jupiter::ReadableString &nick); }; Jupiter::IRC::Client::Data::Data(Jupiter::IRC::Client *interFace) @@ -106,12 +107,12 @@ struct Jupiter::IRC::Client::Channel::Data { Jupiter::CStringS channel; Jupiter::ArrayList users; - const char *serverPrefixSetPtr; + Jupiter::ReferenceString serverPrefixSetPtr; int type; bool isAddingNames; }; -Jupiter::IRC::Client::Client(const char *configSection) +Jupiter::IRC::Client::Client(const Jupiter::ReadableString &configSection) { Jupiter::IRC::Client::data_ = new Jupiter::IRC::Client::Data(this); if (Jupiter::IRC::Client::Config == nullptr) @@ -120,43 +121,43 @@ Jupiter::IRC::Client::Client(const char *configSection) Jupiter::IRC::Client::Config->readFile(CONFIG_INI); } Jupiter::IRC::Client::data_->configSectionName = configSection; - Jupiter::IRC::Client::data_->serverHostname = Jupiter::IRC::Client::readConfigValue("Hostname", "irc.tibitek.com"); + Jupiter::IRC::Client::data_->serverHostname = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("Hostname"), STRING_LITERAL_AS_REFERENCE("irc.tibitek.com")); - Jupiter::IRC::Client::data_->logFileName = Jupiter::IRC::Client::readConfigValue("LogFile"); - Jupiter::IRC::Client::data_->nickname = Jupiter::IRC::Client::readConfigValue("Nick", "Jupiter"); + Jupiter::IRC::Client::data_->logFileName = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("LogFile")); + Jupiter::IRC::Client::data_->nickname = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("Nick"), STRING_LITERAL_AS_REFERENCE("Jupiter")); - Jupiter::IRC::Client::data_->realName = Jupiter::IRC::Client::readConfigValue("Realname", "Jupiter IRC Client"); + Jupiter::IRC::Client::data_->realName = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("Realname"), STRING_LITERAL_AS_REFERENCE("Jupiter IRC Client")); - Jupiter::IRC::Client::data_->saslPass = Jupiter::IRC::Client::readConfigValue("SASL.Password"); - if (Jupiter::IRC::Client::data_->saslPass.size() == 0) Jupiter::IRC::Client::data_->saslPass = Jupiter::IRC::Client::readConfigValue("SASL.Pass"); + Jupiter::IRC::Client::data_->saslPass = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("SASL.Password")); + if (Jupiter::IRC::Client::data_->saslPass.size() == 0) Jupiter::IRC::Client::data_->saslPass = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("SASL.Pass")); - Jupiter::IRC::Client::data_->saslAccount = Jupiter::IRC::Client::readConfigValue("SASL.Account"); + Jupiter::IRC::Client::data_->saslAccount = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("SASL.Account")); if (Jupiter::IRC::Client::data_->saslAccount.size() == 0) Jupiter::IRC::Client::data_->saslAccount = Jupiter::IRC::Client::data_->nickname; - Jupiter::IRC::Client::data_->autoPartMessage = Jupiter::IRC::Client::readConfigValue("AutoPartMessage"); + Jupiter::IRC::Client::data_->autoPartMessage = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("AutoPartMessage")); - Jupiter::IRC::Client::data_->ssl = Jupiter::IRC::Client::readConfigBool("SSL"); - Jupiter::IRC::Client::data_->SSLCertificate = Jupiter::IRC::Client::readConfigValue("Certificate"); - Jupiter::IRC::Client::data_->SSLKey = Jupiter::IRC::Client::readConfigValue("Key"); + Jupiter::IRC::Client::data_->ssl = Jupiter::IRC::Client::readConfigBool(STRING_LITERAL_AS_REFERENCE("SSL")); + Jupiter::IRC::Client::data_->SSLCertificate = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("Certificate")); + Jupiter::IRC::Client::data_->SSLKey = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("Key")); if (Jupiter::IRC::Client::data_->SSLCertificate.size() == 0) { - Jupiter::IRC::Client::data_->SSLCertificate = Jupiter::IRC::Client::readConfigValue("Cert"); + Jupiter::IRC::Client::data_->SSLCertificate = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("Cert")); if (Jupiter::IRC::Client::data_->SSLCertificate.size() == 0) Jupiter::IRC::Client::data_->SSLCertificate = Jupiter::IRC::Client::data_->SSLKey; } if (Jupiter::IRC::Client::data_->SSLKey.size() == 0) Jupiter::IRC::Client::data_->SSLKey = Jupiter::IRC::Client::data_->SSLCertificate; - Jupiter::IRC::Client::data_->joinOnKick = Jupiter::IRC::Client::readConfigBool("AutoJoinOnKick"); - Jupiter::IRC::Client::data_->reconnectDelay = Jupiter::IRC::Client::readConfigInt("AutoReconnectDelay"); - Jupiter::IRC::Client::data_->maxReconnectAttempts = Jupiter::IRC::Client::readConfigInt("MaxReconnectAttempts"); - Jupiter::IRC::Client::data_->serverPort = (unsigned short) Jupiter::IRC::Client::readConfigInt("Port"); + Jupiter::IRC::Client::data_->joinOnKick = Jupiter::IRC::Client::readConfigBool(STRING_LITERAL_AS_REFERENCE("AutoJoinOnKick")); + Jupiter::IRC::Client::data_->reconnectDelay = Jupiter::IRC::Client::readConfigInt(STRING_LITERAL_AS_REFERENCE("AutoReconnectDelay")); + Jupiter::IRC::Client::data_->maxReconnectAttempts = Jupiter::IRC::Client::readConfigInt(STRING_LITERAL_AS_REFERENCE("MaxReconnectAttempts")); + Jupiter::IRC::Client::data_->serverPort = (unsigned short)Jupiter::IRC::Client::readConfigInt(STRING_LITERAL_AS_REFERENCE("Port")); if (Jupiter::IRC::Client::data_->serverPort == 0) { if (Jupiter::IRC::Client::data_->ssl) Jupiter::IRC::Client::data_->serverPort = 994; else Jupiter::IRC::Client::data_->serverPort = 194; } - Jupiter::IRC::Client::data_->dChanType = (short) Jupiter::IRC::Client::readConfigInt("Channel.Type"); + Jupiter::IRC::Client::data_->dChanType = (short)Jupiter::IRC::Client::readConfigInt(STRING_LITERAL_AS_REFERENCE("Channel.Type")); - if (Jupiter::IRC::Client::readConfigBool("PrintOutput", true)) Jupiter::IRC::Client::data_->printOutput = stdout; + if (Jupiter::IRC::Client::readConfigBool(STRING_LITERAL_AS_REFERENCE("PrintOutput"), true)) Jupiter::IRC::Client::data_->printOutput = stdout; else Jupiter::IRC::Client::data_->printOutput = nullptr; if (Jupiter::IRC::Client::data_->logFileName.size() != 0) Jupiter::IRC::Client::data_->logFile = fopen(Jupiter::IRC::Client::data_->logFileName.c_str(), "a+b"); else Jupiter::IRC::Client::data_->logFile = nullptr; @@ -166,7 +167,7 @@ Jupiter::IRC::Client::Client(const char *configSection) Jupiter::SecureTCPSocket *t = new Jupiter::SecureTCPSocket(); if (Jupiter::IRC::Client::data_->SSLCertificate.size() != 0) { - t->setCertificate(Jupiter::IRC::Client::data_->SSLCertificate.c_str(), Jupiter::IRC::Client::data_->SSLKey.c_str()); + t->setCertificate(Jupiter::IRC::Client::data_->SSLCertificate, Jupiter::IRC::Client::data_->SSLKey); } Jupiter::IRC::Client::data_->sock = t; } @@ -203,112 +204,112 @@ void Jupiter::IRC::Client::OnReconnectAttempt(bool) return; } -void Jupiter::IRC::Client::OnRaw(const Jupiter::StringType &) +void Jupiter::IRC::Client::OnRaw(const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnNumeric(long int, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnNumeric(long int, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnError(const Jupiter::StringType &) +void Jupiter::IRC::Client::OnError(const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnChat(const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnChat(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnNotice(const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnNotice(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnServerNotice(const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnServerNotice(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnCTCP(const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnCTCP(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnAction(const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnAction(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnInvite(const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnInvite(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnJoin(const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnJoin(const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnPart(const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnPart(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnNick(const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnNick(const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnKick(const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnKick(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnQuit(const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnQuit(const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -void Jupiter::IRC::Client::OnMode(const Jupiter::StringType &, const Jupiter::StringType &, const Jupiter::StringType &) +void Jupiter::IRC::Client::OnMode(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &) { return; } -const Jupiter::StringType &Jupiter::IRC::Client::getConfigSection() const +const Jupiter::ReadableString &Jupiter::IRC::Client::getConfigSection() const { return Jupiter::IRC::Client::data_->configSectionName; } -const Jupiter::StringType &Jupiter::IRC::Client::getLogFile() const +const Jupiter::ReadableString &Jupiter::IRC::Client::getLogFile() const { return Jupiter::IRC::Client::data_->logFileName; } -const Jupiter::StringType &Jupiter::IRC::Client::getPrefixes() const +const Jupiter::ReadableString &Jupiter::IRC::Client::getPrefixes() const { return Jupiter::IRC::Client::data_->prefixes; } -const Jupiter::StringType &Jupiter::IRC::Client::getNickname() const +const Jupiter::ReadableString &Jupiter::IRC::Client::getNickname() const { return Jupiter::IRC::Client::data_->nickname; } -const Jupiter::StringType &Jupiter::IRC::Client::getRealname() const +const Jupiter::ReadableString &Jupiter::IRC::Client::getRealname() const { return Jupiter::IRC::Client::data_->realName; } -const Jupiter::StringType &Jupiter::IRC::Client::getServerName() const +const Jupiter::ReadableString &Jupiter::IRC::Client::getServerName() const { return Jupiter::IRC::Client::data_->serverName; } -const Jupiter::StringType &Jupiter::IRC::Client::getServerHostname() const +const Jupiter::ReadableString &Jupiter::IRC::Client::getServerHostname() const { return Jupiter::IRC::Client::data_->serverHostname; } @@ -358,7 +359,7 @@ inline Jupiter::CStringS getSender(Jupiter::CStringS &line) return line.getWord(0, ":! "); } -int Jupiter::IRC::Client::getAccessLevel(const char *chan, const char *nick) const +int Jupiter::IRC::Client::getAccessLevel(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &nick) const { Jupiter::IRC::Client::getChannelIndex(chan); unsigned int i = 0; @@ -370,18 +371,18 @@ int Jupiter::IRC::Client::getAccessLevel(const char *chan, const char *nick) con { char prefix = channel->getUserPrefix(nick); if (prefix == 0) return 0; - return Jupiter::IRC::Client::data_->prefixes.size() - findSymbol(Jupiter::IRC::Client::data_->prefixes.c_str(), prefix, 0); + return Jupiter::IRC::Client::data_->prefixes.size() - Jupiter::IRC::Client::data_->prefixes.find(prefix); } i++; } return 0; } -void Jupiter::IRC::Client::send(const char *rawMessage) +void Jupiter::IRC::Client::send(const Jupiter::ReadableString &rawMessage) { - char *sentMessage = new char[strlen(rawMessage) + 3]; - sprintf(sentMessage, "%s" ENDL, rawMessage); - Jupiter::IRC::Client::data_->sock->send(sentMessage); + Jupiter::CStringS out = rawMessage; + out += ENDL; + Jupiter::IRC::Client::data_->sock->send(out); } Jupiter::IRC::Client::User *Jupiter::IRC::Client::getUser(unsigned int index) const @@ -389,7 +390,7 @@ Jupiter::IRC::Client::User *Jupiter::IRC::Client::getUser(unsigned int index) co return Jupiter::IRC::Client::data_->users.get(index); } -Jupiter::IRC::Client::User *Jupiter::IRC::Client::getUser(const char *nickname) const +Jupiter::IRC::Client::User *Jupiter::IRC::Client::getUser(const Jupiter::ReadableString &nickname) const { Jupiter::IRC::Client::User *r; for (unsigned int i = 0; i < Jupiter::IRC::Client::data_->users.size(); i++) @@ -400,7 +401,7 @@ Jupiter::IRC::Client::User *Jupiter::IRC::Client::getUser(const char *nickname) return nullptr; } -int Jupiter::IRC::Client::getUserIndex(const char *nickname) const +int Jupiter::IRC::Client::getUserIndex(const Jupiter::ReadableString &nickname) const { for (int i = Jupiter::IRC::Client::data_->users.size() - 1; i >= 0; i--) if (Jupiter::IRC::Client::data_->users.get(i)->getNickname().equalsi(nickname)) return i; return -1; @@ -427,21 +428,22 @@ Jupiter::IRC::Client::Channel *Jupiter::IRC::Client::getChannel(unsigned int ind return Jupiter::IRC::Client::data_->channels.get(index); } -Jupiter::IRC::Client::Channel *Jupiter::IRC::Client::getChannel(const char *chanName) const +Jupiter::IRC::Client::Channel *Jupiter::IRC::Client::getChannel(const Jupiter::ReadableString &chanName) const { int index = Jupiter::IRC::Client::getChannelIndex(chanName); if (index < 0) return nullptr; return Jupiter::IRC::Client::getChannel(index); } -const Jupiter::StringType &Jupiter::IRC::Client::getChannelName(unsigned int index) const +const Jupiter::ReadableString &Jupiter::IRC::Client::getChannelName(unsigned int index) const { return Jupiter::IRC::Client::data_->channels.get(index)->getName(); } -int Jupiter::IRC::Client::getChannelIndex(const char *chanName) const +int Jupiter::IRC::Client::getChannelIndex(const Jupiter::ReadableString &chanName) const { - for (unsigned int i = 0; i < Jupiter::IRC::Client::data_->channels.size(); i++) if (Jupiter::IRC::Client::data_->channels.get(i)->getName().equalsi(chanName)) return i; + for (size_t i = 0; i < Jupiter::IRC::Client::data_->channels.size(); i++) + if (Jupiter::IRC::Client::data_->channels.get(i)->getName().equalsi(chanName)) return i; return -1; } @@ -455,59 +457,41 @@ void Jupiter::IRC::Client::setAutoReconnect(int val) Jupiter::IRC::Client::data_->maxReconnectAttempts = val; } -void Jupiter::IRC::Client::joinChannel(const char *channel) +void Jupiter::IRC::Client::joinChannel(const Jupiter::ReadableString &channel) { - char *msg = new char[strlen(channel) + 8]; - sprintf(msg, "JOIN %s" ENDL, channel); - Jupiter::IRC::Client::data_->sock->send(msg); - delete[] msg; + Jupiter::IRC::Client::data_->sock->send(Jupiter::StringS::Format("JOIN %.*s" ENDL, channel.size(), channel.ptr())); } -void Jupiter::IRC::Client::joinChannel(const char *channel, const char *password) +void Jupiter::IRC::Client::joinChannel(const Jupiter::ReadableString &channel, const Jupiter::ReadableString &password) { - char *msg = new char[strlen(channel) + strlen(password) + 9]; - sprintf(msg, "JOIN %s %s" ENDL, channel, password); - Jupiter::IRC::Client::data_->sock->send(msg); - delete[] msg; + Jupiter::IRC::Client::data_->sock->send(Jupiter::StringS::Format("JOIN %.*s %.*s" ENDL, channel.size(), channel.ptr(), password.size(), password.ptr())); } -void Jupiter::IRC::Client::partChannel(const char *channel) +void Jupiter::IRC::Client::partChannel(const Jupiter::ReadableString &channel) { - char *msg = new char[strlen(channel) + 8]; - sprintf(msg, "PART %s" ENDL, channel); - Jupiter::IRC::Client::data_->sock->send(msg); - delete[] msg; + Jupiter::IRC::Client::data_->sock->send(Jupiter::StringS::Format("PART %.*s" ENDL, channel.size(), channel.ptr())); int index = Jupiter::IRC::Client::getChannelIndex(channel); if (index >= 0) Jupiter::IRC::Client::data_->channels.get(index)->setType(-2); } -void Jupiter::IRC::Client::partChannel(const char *channel, const char *message) +void Jupiter::IRC::Client::partChannel(const Jupiter::ReadableString &channel, const Jupiter::ReadableString &message) { - char *msg = new char[strlen(channel) + strlen(message) + 10]; - sprintf(msg, "PART %s :%s" ENDL, channel, message); - Jupiter::IRC::Client::data_->sock->send(msg); - delete[] msg; + Jupiter::IRC::Client::data_->sock->send(Jupiter::StringS::Format("PART %.*s :%.*s" ENDL, channel.size(), channel.ptr(), message.size(), message.ptr())); int index = Jupiter::IRC::Client::getChannelIndex(channel); if (index >= 0) Jupiter::IRC::Client::data_->channels.get(index)->setType(-2); } -void Jupiter::IRC::Client::sendMessage(const char *dest, const char *message) +void Jupiter::IRC::Client::sendMessage(const Jupiter::ReadableString &dest, const Jupiter::ReadableString &message) { - char *msg = new char[strlen(dest) + strlen(message) + 13]; - sprintf(msg, "PRIVMSG %s :%s" ENDL, dest, message); - Jupiter::IRC::Client::data_->sock->send(msg); - delete[] msg; + Jupiter::IRC::Client::data_->sock->send(Jupiter::StringS::Format("PRIVMSG %.*s :%.*s" ENDL, dest.size(), dest.ptr(), message.size(), message.ptr())); } -void Jupiter::IRC::Client::sendNotice(const char *dest, const char *message) +void Jupiter::IRC::Client::sendNotice(const Jupiter::ReadableString &dest, const Jupiter::ReadableString &message) { - char *msg = new char[strlen(dest) + strlen(message) + 12]; - sprintf(msg, "NOTICE %s :%s" ENDL, dest, message); - Jupiter::IRC::Client::data_->sock->send(msg); - delete[] msg; + Jupiter::IRC::Client::data_->sock->send(Jupiter::StringS::Format("NOTICE %.*s :%.*s" ENDL, dest.size(), dest.ptr(), message.size(), message.ptr())); } -unsigned int Jupiter::IRC::Client::messageChannels(short type, const char *message) +unsigned int Jupiter::IRC::Client::messageChannels(short type, const Jupiter::ReadableString &message) { unsigned int total = 0; Jupiter::IRC::Client::Channel *channel; @@ -516,14 +500,14 @@ unsigned int Jupiter::IRC::Client::messageChannels(short type, const char *messa channel = Jupiter::IRC::Client::data_->channels.get(i); if (channel->getType() == type) { - Jupiter::IRC::Client::sendMessage(channel->getName().c_str(), message); + Jupiter::IRC::Client::sendMessage(channel->getName(), message); total++; } } return total; } -unsigned int Jupiter::IRC::Client::messageChannels(const char *message) +unsigned int Jupiter::IRC::Client::messageChannels(const Jupiter::ReadableString &message) { unsigned int total = 0; Jupiter::IRC::Client::Channel *channel; @@ -532,7 +516,7 @@ unsigned int Jupiter::IRC::Client::messageChannels(const char *message) channel = Jupiter::IRC::Client::data_->channels.get(i); if (channel->getType() >= 0) { - Jupiter::IRC::Client::sendMessage(channel->getName().c_str(), message); + Jupiter::IRC::Client::sendMessage(channel->getName(), message); total++; } } @@ -546,23 +530,22 @@ int Jupiter::IRC::Client::primaryHandler() if (recvVal > 0) { Jupiter::IRC::Client::data_->buffer = Jupiter::IRC::Client::data_->sock->getBuffer(); - unsigned int totalLines = countLines(Jupiter::IRC::Client::data_->buffer.c_str()); + unsigned int totalLines = Jupiter::IRC::Client::data_->buffer.wordCount(ENDL); for (unsigned int currentLine = 0; currentLine < totalLines; currentLine++) { Jupiter::CStringS buff = Jupiter::IRC::Client::data_->buffer.getWord(currentLine, ENDL); if (buff.size() != 0) { - Jupiter::IRC::Client::writeToLogs(buff.c_str()); + Jupiter::IRC::Client::writeToLogs(buff); if (Jupiter::IRC::Client::data_->printOutput != nullptr) { - fputs(buff.c_str(), Jupiter::IRC::Client::data_->printOutput); - fputs(ENDL, Jupiter::IRC::Client::data_->printOutput); + buff.println(Jupiter::IRC::Client::data_->printOutput); } - Jupiter::CStringS w1 = buff.getWord(0, WHITESPACE); + Jupiter::ReferenceString w1 = Jupiter::ReferenceString::getWord(buff, 0, WHITESPACE); if (w1.size() != 0) { - Jupiter::CStringS w2 = buff.getWord(1, WHITESPACE); - long int numeric = strtol(w2.c_str(), nullptr, 10); + Jupiter::ReferenceString w2 = Jupiter::ReferenceString::getWord(buff, 1, WHITESPACE); + int numeric = w2.asInt(10); if (w1[0] == ':') //Messages { if (w2.size() != 0) @@ -571,11 +554,11 @@ int Jupiter::IRC::Client::primaryHandler() { case IRC_RPL_BOUNCE: // 010 { - Jupiter::CStringS portToken = buff.getWord(4, " "); + Jupiter::ReferenceString portToken = Jupiter::ReferenceString::getWord(buff, 4, " "); unsigned short port; if (portToken[0] == '+') // This is most likely not used anywhere. { - port = (unsigned short)strtoul(portToken.c_str() + 1, nullptr, 10); + port = (unsigned short)portToken.asUnsignedInt(10); if (Jupiter::IRC::Client::data_->ssl == false) { Jupiter::IRC::Client::data_->ssl = true; @@ -585,7 +568,7 @@ int Jupiter::IRC::Client::primaryHandler() } else { - port = (unsigned short)strtoul(portToken.c_str(), nullptr, 10); + port = (unsigned short)portToken.asUnsignedInt(10); if (Jupiter::IRC::Client::data_->ssl == true) { Jupiter::IRC::Client::data_->ssl = false; @@ -595,7 +578,7 @@ int Jupiter::IRC::Client::primaryHandler() } if (port != 0) // Don't default -- could be non-compliant input. { - Jupiter::IRC::Client::data_->serverHostname = buff.getWord(3, WHITESPACE); + Jupiter::IRC::Client::data_->serverHostname = Jupiter::ReferenceString::getWord(buff, 3, WHITESPACE); Jupiter::IRC::Client::data_->serverPort = port; puts("Reconnecting due to old bounce."); this->reconnect(); @@ -612,12 +595,12 @@ int Jupiter::IRC::Client::primaryHandler() case IRC_RPL_BOUNCEOLD: // 005 if (buff.matchi("*:Try server *, port *")) { - Jupiter::CStringS portToken = buff.getWord(6, " "); - unsigned short bouncePort = (unsigned short)atoi(buff.getWord(6, " ").c_str()); + Jupiter::ReferenceString portToken = Jupiter::ReferenceString::getWord(buff, 6, " "); + unsigned short bouncePort = (unsigned short)Jupiter::ReferenceString::getWord(buff, 6, " ").asInt(10); if (portToken[0] == '+') // This is almost certainly not used anywhere. { - bouncePort = (unsigned short)strtoul(portToken.c_str() + 1, nullptr, 10); + bouncePort = (unsigned short)portToken.asInt(10); if (Jupiter::IRC::Client::data_->ssl == false) { Jupiter::IRC::Client::data_->ssl = true; @@ -627,7 +610,7 @@ int Jupiter::IRC::Client::primaryHandler() } else { - bouncePort = (unsigned short)strtoul(portToken.c_str(), nullptr, 10); + bouncePort = (unsigned short)portToken.asInt(10); if (Jupiter::IRC::Client::data_->ssl == true) { Jupiter::IRC::Client::data_->ssl = false; @@ -637,7 +620,7 @@ int Jupiter::IRC::Client::primaryHandler() } if (bouncePort != 0) { - Jupiter::IRC::Client::data_->serverHostname = buff.getWord(4, " "); + Jupiter::IRC::Client::data_->serverHostname = Jupiter::ReferenceString::getWord(buff, 4, " "); Jupiter::IRC::Client::data_->serverHostname.truncate(1); // trailing comma Jupiter::IRC::Client::data_->serverPort = bouncePort; puts("Reconnecting due to old bounce."); @@ -648,7 +631,7 @@ int Jupiter::IRC::Client::primaryHandler() break; case IRC_ERR_UNKNOWNCOMMAND: // 421 { - Jupiter::CStringS command = buff.getWord(2, " "); + Jupiter::ReferenceString command = Jupiter::ReferenceString::getWord(buff, 2, " "); if (command.equalsi("STARTTLS")) // Server doesn't support STARTTLS { Jupiter::IRC::Client::data_->startCAP(); @@ -664,7 +647,7 @@ int Jupiter::IRC::Client::primaryHandler() // toggle blocking to prevent error if (Jupiter::IRC::Client::data_->SSLCertificate.size() != 0) { - t->setCertificate(Jupiter::IRC::Client::data_->SSLCertificate.c_str(), Jupiter::IRC::Client::data_->SSLKey.c_str()); + t->setCertificate(Jupiter::IRC::Client::data_->SSLCertificate, Jupiter::IRC::Client::data_->SSLKey); } bool goodSSL; @@ -698,7 +681,7 @@ int Jupiter::IRC::Client::primaryHandler() case 0: if (w2.equalsi("CAP")) { - Jupiter::CStringS w4 = buff.getWord(3, WHITESPACE); + Jupiter::ReferenceString w4 = Jupiter::ReferenceString::getWord(buff, 3, WHITESPACE); if (w4.equals("LS")) { Jupiter::CStringS listParams = buff.gotoWord(4, WHITESPACE); @@ -758,7 +741,7 @@ int Jupiter::IRC::Client::primaryHandler() { // We'll take any of these 4, just in-case any of them are missing. In general, this will trigger on 001. case IRC_RPL_MYINFO: // 004 - Jupiter::IRC::Client::data_->serverName = buff.getWord(3, " "); + Jupiter::IRC::Client::data_->serverName = Jupiter::ReferenceString::getWord(buff, 3, " "); case IRC_RPL_WELCOME: // 001 case IRC_RPL_YOURHOST: // 002 case IRC_RPL_CREATED: // 003 @@ -772,8 +755,8 @@ int Jupiter::IRC::Client::primaryHandler() case IRC_ERR_NICKNAMEINUSE: // 433 case IRC_ERR_NICKCOLLISION: // 436 case IRC_ERR_BANNICKCHANGE: // 437 -- Note: This conflicts with another token. - Jupiter::CStringS altNick = Jupiter::IRC::Client::readConfigValue("AltNick", "Jupiter"); - Jupiter::CStringS configNick = Jupiter::IRC::Client::readConfigValue("Nick", "Jupiter"); + const Jupiter::ReadableString &altNick = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("AltNick"), STRING_LITERAL_AS_REFERENCE("Jupiter")); + const Jupiter::ReadableString &configNick = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("Nick"), STRING_LITERAL_AS_REFERENCE("Jupiter")); /* * Possible Issues: * altNick != nickname after first nick change -- loop initiated? @@ -788,12 +771,7 @@ int Jupiter::IRC::Client::primaryHandler() { Jupiter::IRC::Client::data_->nickname = altNick; if (Jupiter::IRC::Client::data_->nickname.size() != 0) - { - char *messageToSend = new char[Jupiter::IRC::Client::data_->nickname.size() + 8]; - sprintf(messageToSend, "NICK %s" ENDL, Jupiter::IRC::Client::data_->nickname.c_str()); - Jupiter::IRC::Client::data_->sock->send(messageToSend); - delete[] messageToSend; - } + Jupiter::IRC::Client::data_->sock->send(Jupiter::StringS::Format("NICK %.*s" ENDL, Jupiter::IRC::Client::data_->nickname.size(), Jupiter::IRC::Client::data_->nickname.ptr())); } // Note: Add a series of contains() functions to String_Type. else //if (stristr(Jupiter::IRC::Client::data_->nickname.c_str(), configNick.c_str()) == Jupiter::IRC::Client::data_->nickname.c_str()) // We're already adding numbers. @@ -802,8 +780,8 @@ int Jupiter::IRC::Client::primaryHandler() { if (Jupiter::IRC::Client::data_->nickname.size() > configNick.size()) { - int n = atoi(Jupiter::IRC::Client::data_->nickname.c_str() + configNick.size()) + 1; - Jupiter::IRC::Client::data_->nickname.format("%s%d", configNick.c_str(), n); + int n = strtoi_nospace_s(Jupiter::IRC::Client::data_->nickname.ptr() + configNick.size(), Jupiter::IRC::Client::data_->nickname.size() - configNick.size(), 10); + Jupiter::IRC::Client::data_->nickname.format("%.*s%d", configNick.size(), configNick.ptr(), n); } else { @@ -834,9 +812,9 @@ int Jupiter::IRC::Client::primaryHandler() { ptr += 8; int poff = findSymbol(ptr, ')', 0); - Jupiter::IRC::Client::data_->prefixModes = Jupiter::CStringS::getWord(ptr, 0, ")"); + Jupiter::IRC::Client::data_->prefixModes = Jupiter::ReferenceString::getWord(ptr, 0, ")"); ptr += poff + 1; - Jupiter::IRC::Client::data_->prefixes = Jupiter::CStringS::getWord(ptr, 0, " " ENDL); + Jupiter::IRC::Client::data_->prefixes = Jupiter::ReferenceString::getWord(ptr, 0, " " ENDL); ptr = nullptr; } ptr = strstr(buff.c_str(), "CHANMODES="); @@ -846,20 +824,20 @@ int Jupiter::IRC::Client::primaryHandler() int pos = findSymbol(ptr, ',', 0); if (pos >= 0) { - Jupiter::IRC::Client::data_->modeA = Jupiter::CStringS::getWord(ptr, 0, ", "); + Jupiter::IRC::Client::data_->modeA = Jupiter::ReferenceString::getWord(ptr, 0, ", "); ptr += pos + 1; pos = findSymbol(ptr, ',', 0); if (pos >= 0) { - Jupiter::IRC::Client::data_->modeB = Jupiter::CStringS::getWord(ptr, 0, ", "); + Jupiter::IRC::Client::data_->modeB = Jupiter::ReferenceString::getWord(ptr, 0, ", "); ptr += pos + 1; pos = findSymbol(ptr, ',', 0); if (pos >= 0) { - Jupiter::IRC::Client::data_->modeC = Jupiter::CStringS::getWord(ptr, 0, ", "); + Jupiter::IRC::Client::data_->modeC = Jupiter::ReferenceString::getWord(ptr, 0, ", "); ptr += pos + 1; pos = strcspn(ptr, " "); - if (pos >= 0) Jupiter::IRC::Client::data_->modeD = Jupiter::CStringS::getWord(ptr, 0, ", "); + if (pos >= 0) Jupiter::IRC::Client::data_->modeD = Jupiter::ReferenceString::getWord(ptr, 0, ", "); } } } @@ -868,7 +846,7 @@ int Jupiter::IRC::Client::primaryHandler() if (ptr != nullptr) { ptr += 10; - Jupiter::IRC::Client::data_->chanTypes = Jupiter::CStringS::getWord(ptr, 0, " "); + Jupiter::IRC::Client::data_->chanTypes = Jupiter::ReferenceString::getWord(ptr, 0, " "); } } break; @@ -877,15 +855,14 @@ int Jupiter::IRC::Client::primaryHandler() Jupiter::CStringL key = "RawData."; unsigned int offset; - Jupiter::CStringS tVal; unsigned int i = 1; do { offset = key.aformat("%u", i); - tVal = Jupiter::IRC::Client::readConfigValue(key.c_str()); + const Jupiter::ReadableString &tVal = Jupiter::IRC::Client::readConfigValue(key); if (tVal.size() == 0) break; key -= offset; - Jupiter::IRC::Client::send(tVal.c_str()); + Jupiter::IRC::Client::send(tVal); i++; } while (1); key = "Channel."; @@ -893,10 +870,10 @@ int Jupiter::IRC::Client::primaryHandler() do { offset = key.aformat("%u", i); - tVal = Jupiter::IRC::Client::readConfigValue(key.c_str()); + const Jupiter::ReadableString &tVal = Jupiter::IRC::Client::readConfigValue(key); if (tVal.size() == 0) break; key -= offset; - Jupiter::IRC::Client::joinChannel(tVal.c_str()); + Jupiter::IRC::Client::joinChannel(tVal); i++; } while (1); @@ -910,21 +887,21 @@ int Jupiter::IRC::Client::primaryHandler() break; default: // Post-registration. - if (streqli(w2.c_str(), "PRIVMSG")) + if (w2.equalsi("PRIVMSG")) { - Jupiter::CStringS chan = buff.getWord(2, WHITESPACE); + Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(buff, 2, WHITESPACE); if (chan.size() != 0) { Jupiter::CStringS nick = getSender(buff); if (nick.size() != 0) { - const char *premessage = buff.c_str() + findSymbol(buff.c_str(), ':', 1) + 1; + Jupiter::ReferenceString premessage = buff.c_str() + findSymbol(buff.c_str(), ':', 1) + 1; if (premessage[0] == '\001') //CTCP (ACTIONs are included) { - Jupiter::CStringS rawmessage = premessage + 1; - Jupiter::CStringS command = rawmessage.getWord(0, WHITESPACE); + Jupiter::ReferenceString rawmessage(premessage.ptr() + 1, premessage.size() - 1); + Jupiter::ReferenceString command = rawmessage.getWord(0, WHITESPACE); if (command[command.size() - 1] == IRC::CTCP) command.truncate(1); - Jupiter::CStringS message = rawmessage.substring(findSymbol(rawmessage.c_str(), ' ', 0) + 1, findSymbol(rawmessage.c_str(), IRC::CTCP, 0)); + Jupiter::ReferenceString message = rawmessage.substring(rawmessage.find(' ') + 1, rawmessage.find(IRC::CTCP)); if (message[message.size() - 1] == IRC::CTCP) message.truncate(1); if (command.equals("ACTION")) @@ -956,7 +933,7 @@ int Jupiter::IRC::Client::primaryHandler() response += " :Query is unknown"; } response += IRCCTCP ENDL; - Jupiter::IRC::Client::data_->sock->send(response.c_str()); + Jupiter::IRC::Client::data_->sock->send(response); this->OnCTCP(chan, nick, command, message); for (int i = Jupiter::plugins->size() - 1; i >= 0; i--) Jupiter::plugins->get(i)->OnCTCP(this, chan, nick, message); } @@ -970,9 +947,9 @@ int Jupiter::IRC::Client::primaryHandler() } } } - else if (streqli(w2.c_str(), "NOTICE")) + else if (w2.equalsi("NOTICE")) { - CStringS chan = buff.getWord(2, WHITESPACE); + Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(buff, 2, WHITESPACE); if (chan.size() != 0) { int pos = findSymbol(buff.c_str(), '!', 0); @@ -994,7 +971,7 @@ int Jupiter::IRC::Client::primaryHandler() } } } - else if (streqli(w2.c_str(), "NICK")) + else if (w2.equalsi("NICK")) { auto nick = getSender(buff); const char *tnewnick = buff.c_str() + findSymbol(buff.c_str(), ' ', 1) + 1; @@ -1004,7 +981,7 @@ int Jupiter::IRC::Client::primaryHandler() { Jupiter::IRC::Client::data_->nickname = newnick; } - Jupiter::IRC::Client::User *user = Jupiter::IRC::Client::data_->findUser(nick.c_str()); + Jupiter::IRC::Client::User *user = Jupiter::IRC::Client::data_->findUser(nick); if (user != nullptr) { user->data_->nickname = newnick; @@ -1012,73 +989,73 @@ int Jupiter::IRC::Client::primaryHandler() } for (int i = Jupiter::plugins->size() - 1; i >= 0; i--) Jupiter::plugins->get(i)->OnNick(this, nick, newnick); } - else if (streqli(w2.c_str(), "JOIN")) + else if (w2.equalsi("JOIN")) { auto nick = getSender(buff); - CStringS chan = buff.getWord(2, WHITESPACE); + Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(buff, 2, WHITESPACE); if (chan[0] == ':') chan.shiftRight(1); - int i = Jupiter::IRC::Client::getChannelIndex(chan.c_str()); + int i = Jupiter::IRC::Client::getChannelIndex(chan); if (Jupiter::IRC::Client::data_->nickname.equalsi(nick)) { if (i >= 0) Jupiter::IRC::Client::data_->delChannel(i); - Jupiter::IRC::Client::Channel *channel = Jupiter::IRC::Client::data_->channels.get(Jupiter::IRC::Client::data_->addChannel(chan.c_str())); + Jupiter::IRC::Client::Channel *channel = Jupiter::IRC::Client::data_->channels.get(Jupiter::IRC::Client::data_->addChannel(chan)); channel->data_->isAddingNames = true; if (channel->getType() < 0) { - if (Jupiter::IRC::Client::data_->autoPartMessage.size() != 0) Jupiter::IRC::Client::partChannel(chan.c_str(), Jupiter::IRC::Client::data_->autoPartMessage.c_str()); - else Jupiter::IRC::Client::partChannel(chan.c_str()); + if (Jupiter::IRC::Client::data_->autoPartMessage.size() != 0) Jupiter::IRC::Client::partChannel(chan, Jupiter::IRC::Client::data_->autoPartMessage); + else Jupiter::IRC::Client::partChannel(chan); } } else if (i >= 0) Jupiter::IRC::Client::data_->channels.get(i)->addUser(Jupiter::IRC::Client::data_->findUserOrAdd(nick)); this->OnJoin(chan, nick); for (i = Jupiter::plugins->size() - 1; i >= 0; i--) Jupiter::plugins->get(i)->OnJoin(this, chan, nick); } - else if (streqli(w2.c_str(), "PART")) + else if (w2.equalsi("PART")) { auto nick = getSender(buff); if (nick.size() != 0) { - auto chan = buff.getWord(2, WHITESPACE); + Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(buff, 2, WHITESPACE); if (chan.size() != 0) { - int i = Jupiter::IRC::Client::getChannelIndex(chan.c_str()); + int i = Jupiter::IRC::Client::getChannelIndex(chan); if (i >= 0) { - int userIndex = Jupiter::IRC::Client::getUserIndex(nick.c_str()); + int userIndex = Jupiter::IRC::Client::getUserIndex(nick); if (userIndex >= 0) { Jupiter::IRC::Client::User *user = Jupiter::IRC::Client::data_->users.get(userIndex); - Jupiter::IRC::Client::data_->channels.get(i)->delUser(nick.c_str()); + Jupiter::IRC::Client::data_->channels.get(i)->delUser(nick); int pos = findSymbol(buff.c_str(), ':', 1); Jupiter::CStringS reason = buff.c_str() + pos + 1; this->OnPart(chan, nick, reason); for (i = Jupiter::plugins->size() - 1; i >= 0; i--) Jupiter::plugins->get(i)->OnPart(this, chan, nick, reason); - if (nick.equalsi(Jupiter::IRC::Client::data_->nickname)) Jupiter::IRC::Client::data_->delChannel(chan.c_str()); + if (nick.equalsi(Jupiter::IRC::Client::data_->nickname)) Jupiter::IRC::Client::data_->delChannel(chan); if (user->getChannelCount() == 0) Jupiter::IRC::Client::data_->users.remove(userIndex); } } } } } - else if (streqli(w2.c_str(), "KICK")) + else if (w2.equalsi("KICK")) { - auto chan = buff.getWord(2, WHITESPACE); + Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(buff, 2, WHITESPACE); if (chan.size() != 0) { Jupiter::CStringS kicker = getSender(buff); if (kicker.size() != 0) { - auto kicked = buff.getWord(3, WHITESPACE); + Jupiter::ReferenceString kicked = Jupiter::ReferenceString::getWord(buff, 3, WHITESPACE); if (kicked.size() != 0) { - int i = Jupiter::IRC::Client::getChannelIndex(chan.c_str()); + int i = Jupiter::IRC::Client::getChannelIndex(chan); if (i >= 0) { - int userIndex = Jupiter::IRC::Client::getUserIndex(kicked.c_str()); + int userIndex = Jupiter::IRC::Client::getUserIndex(kicked); if (userIndex >= 0) { Jupiter::IRC::Client::User *user = Jupiter::IRC::Client::data_->users.get(userIndex); - Jupiter::IRC::Client::data_->channels.get(i)->delUser(kicked.c_str()); + Jupiter::IRC::Client::data_->channels.get(i)->delUser(kicked); int pos = findSymbol(buff.c_str(), ':', 1); Jupiter::CStringS reason; if (pos >= 0) reason += buff.c_str() + pos + 1; @@ -1086,8 +1063,8 @@ int Jupiter::IRC::Client::primaryHandler() for (i = Jupiter::plugins->size() - 1; i >= 0; i--) Jupiter::plugins->get(i)->OnKick(this, chan, kicker, kicked, reason); if (kicked.equalsi(Jupiter::IRC::Client::data_->nickname)) { - Jupiter::IRC::Client::data_->delChannel(chan.c_str()); - if (Jupiter::IRC::Client::data_->joinOnKick) Jupiter::IRC::Client::joinChannel(chan.c_str()); + Jupiter::IRC::Client::data_->delChannel(chan); + if (Jupiter::IRC::Client::data_->joinOnKick) Jupiter::IRC::Client::joinChannel(chan); } if (user->getChannelCount() == 0) Jupiter::IRC::Client::data_->users.remove(userIndex); } @@ -1096,35 +1073,36 @@ int Jupiter::IRC::Client::primaryHandler() } } } - else if (streqli(w2.c_str(), "QUIT")) + else if (w2.equalsi("QUIT")) { Jupiter::CStringS nick = getSender(buff); Jupiter::CStringS message = buff.substring(findSymbol(buff.c_str(), ':', 1) + 1, buff.size()); - int userIndex = Jupiter::IRC::Client::getUserIndex(nick.c_str()); + int userIndex = Jupiter::IRC::Client::getUserIndex(nick); if (userIndex >= 0) { Jupiter::IRC::Client::User *user = Jupiter::IRC::Client::data_->users.get(userIndex); unsigned int i; - for (i = 0; i < Jupiter::IRC::Client::data_->channels.size(); i++) Jupiter::IRC::Client::data_->channels.get(i)->delUser(nick.c_str()); + for (i = 0; i < Jupiter::IRC::Client::data_->channels.size(); i++) + Jupiter::IRC::Client::data_->channels.get(i)->delUser(nick); this->OnQuit(nick, message); for (i = 0; i < Jupiter::plugins->size(); i++) Jupiter::plugins->get(i)->OnQuit(this, nick, message); if (user->getChannelCount() == 0) Jupiter::IRC::Client::data_->users.remove(userIndex); } } - else if (streqli(w2.c_str(), "INVITE")) + else if (w2.equalsi("INVITE")) { Jupiter::CStringS inviter = getSender(buff); - auto invited = buff.getWord(2, WHITESPACE); + Jupiter::ReferenceString invited = Jupiter::ReferenceString::getWord(buff, 2, WHITESPACE); Jupiter::CStringS chan = buff.c_str() + findSymbol(buff.c_str(), ':', 1) + 1; this->OnInvite(chan, inviter, invited); for (int i = Jupiter::plugins->size() - 1; i >= 0; i--) Jupiter::plugins->get(i)->OnInvite(this, chan, inviter, invited); } - else if (streqli(w2.c_str(), "MODE")) + else if (w2.equalsi("MODE")) { - auto chan = buff.getWord(2, WHITESPACE); + Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(buff, 2, WHITESPACE); if (chan.size() != 0) { - if (containsSymbol(Jupiter::IRC::Client::data_->chanTypes.c_str(), chan[0])) + if (Jupiter::IRC::Client::data_->chanTypes.contains(chan[0])) { auto nick = getSender(buff); if (nick.size() != 0) @@ -1142,8 +1120,9 @@ int Jupiter::IRC::Client::primaryHandler() for (uint8_t z = 0; modes[z] != 0; z++) { if (modes[z] == '+' || modes[z] == '-') symb = modes[z]; - else if (findSymbol(Jupiter::IRC::Client::data_->prefixModes.c_str(), modes[z], 0) >= 0) + else if (Jupiter::IRC::Client::data_->prefixModes.contains(modes[z])) { + tword = getWord(params, g); if (tword != nullptr) { @@ -1151,22 +1130,21 @@ int Jupiter::IRC::Client::primaryHandler() for (unsigned int channelIndex = 0; channelIndex < Jupiter::IRC::Client::data_->channels.size(); channelIndex++) { channel = Jupiter::IRC::Client::data_->channels.get(channelIndex); - if (channel->getName().equalsi(chan.c_str())) + if (channel->getName().equalsi(chan)) { - if (symb == '+') channel->addUserPrefix(tword, Jupiter::IRC::Client::data_->prefixes[findSymbol(Jupiter::IRC::Client::data_->prefixModes.c_str(), modes[z], 0)]); - else channel->delUserPrefix(tword, Jupiter::IRC::Client::data_->prefixes[findSymbol(Jupiter::IRC::Client::data_->prefixModes.c_str(), modes[z], 0)]); + if (symb == '+') channel->addUserPrefix(Jupiter::ReferenceString(tword), Jupiter::IRC::Client::data_->prefixes[Jupiter::IRC::Client::data_->prefixModes.find(modes[z])]); + else channel->delUserPrefix(Jupiter::ReferenceString(tword), Jupiter::IRC::Client::data_->prefixes[Jupiter::IRC::Client::data_->prefixModes.find(modes[z])]); break; } } - free(tword); } g++; } else { - if (containsSymbol(Jupiter::IRC::Client::data_->modeA.c_str(), modes[z])) g++; - else if (containsSymbol(Jupiter::IRC::Client::data_->modeB.c_str(), modes[z])) g++; - else if (containsSymbol(Jupiter::IRC::Client::data_->modeC.c_str(), modes[z]) && symb == '+') g++; + if (Jupiter::IRC::Client::data_->modeA.contains(modes[z])) g++; + else if (Jupiter::IRC::Client::data_->modeB.contains(modes[z])) g++; + else if (Jupiter::IRC::Client::data_->modeC.contains(modes[z]) && symb == '+') g++; } } free(modes); @@ -1183,23 +1161,23 @@ int Jupiter::IRC::Client::primaryHandler() // else if CHGHOST else if (numeric == IRC_RPL_NAMREPLY) // Some names. { - Jupiter::CStringS chan = buff.getWord(4, " "); - Jupiter::CStringS names = buff.c_str() + findSymbol(buff.c_str(), ':', 1) + 1; - int i = Jupiter::IRC::Client::getChannelIndex(chan.c_str()); + Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(buff, 4, " "); + Jupiter::ReferenceString names = Jupiter::ReferenceString::substring(buff, buff.find(':', 1) + 1); + int i = Jupiter::IRC::Client::getChannelIndex(chan); if (i >= 0) { if (Jupiter::IRC::Client::getChannel(i)->data_->isAddingNames == false) { Jupiter::IRC::Client::data_->delChannel(i); - Jupiter::IRC::Client::getChannel(Jupiter::IRC::Client::data_->addChannel(chan.c_str()))->data_->isAddingNames = true; + Jupiter::IRC::Client::getChannel(Jupiter::IRC::Client::data_->addChannel(chan))->data_->isAddingNames = true; } Jupiter::IRC::Client::data_->addNamesToChannel(i, names); } } else if (numeric == IRC_RPL_ENDOFNAMES) // We're done here. { - Jupiter::CStringS chan = buff.getWord(3, " "); - int i = Jupiter::IRC::Client::getChannelIndex(chan.c_str()); + Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(buff, 3, " "); + int i = Jupiter::IRC::Client::getChannelIndex(chan); if (i >= 0) Jupiter::IRC::Client::data_->channels.get(i)->data_->isAddingNames = false; } break; @@ -1210,11 +1188,7 @@ int Jupiter::IRC::Client::primaryHandler() { if (w1.equals("PING")) { - char *tempstr; - tempstr = new char[w2.size() + 8]; - sprintf(tempstr, "PONG %s" ENDL, w2.c_str()); - Jupiter::IRC::Client::data_->sock->send(tempstr); - delete[] tempstr; + Jupiter::IRC::Client::data_->sock->send(Jupiter::StringS::Format("PONG %.*s" ENDL, w2.size(), w2.ptr())); } else if (w1.equals("NICK")) { @@ -1271,20 +1245,18 @@ int Jupiter::IRC::Client::primaryHandler() bool Jupiter::IRC::Client::connect() { - const char *clientAddress = Jupiter::IRC::Client::readConfigValue("ClientAddress").c_str(); - if (*clientAddress == 0) clientAddress = nullptr; - bool r = Jupiter::IRC::Client::data_->sock->connectToHost(Jupiter::IRC::Client::data_->serverHostname.c_str(), Jupiter::IRC::Client::data_->serverPort, clientAddress, (unsigned short) Jupiter::IRC::Client::readConfigLong("ClientPort")); - if (r) + const Jupiter::ReadableString &clientAddress = Jupiter::IRC::Client::readConfigValue(STRING_LITERAL_AS_REFERENCE("ClientAddress")); + if (Jupiter::IRC::Client::data_->sock->connectToHost(Jupiter::IRC::Client::data_->serverHostname.c_str(), Jupiter::IRC::Client::data_->serverPort, clientAddress.size() == 0 ? nullptr : Jupiter::CStringS(clientAddress).c_str(), (unsigned short)Jupiter::IRC::Client::readConfigLong(STRING_LITERAL_AS_REFERENCE("ClientPort"))) == false) + return false; + + Jupiter::IRC::Client::data_->sock->setBlocking(false); + if (Jupiter::IRC::Client::data_->ssl == false) { - Jupiter::IRC::Client::data_->sock->setBlocking(false); - if (Jupiter::IRC::Client::data_->ssl == false) - { - Jupiter::IRC::Client::data_->sock->send("STARTTLS" ENDL); - Jupiter::IRC::Client::data_->connectionStatus = 1; - } - else Jupiter::IRC::Client::data_->startCAP(); + Jupiter::IRC::Client::data_->sock->send("STARTTLS" ENDL); + Jupiter::IRC::Client::data_->connectionStatus = 1; } - return r; + else Jupiter::IRC::Client::data_->startCAP(); + return true; } void Jupiter::IRC::Client::disconnect(bool stayDead) @@ -1298,18 +1270,15 @@ void Jupiter::IRC::Client::disconnect(bool stayDead) for (int i = Jupiter::plugins->size() - 1; i >= 0; i--) Jupiter::plugins->get(i)->OnDisconnect(this); } -void Jupiter::IRC::Client::disconnect(const char *message, bool stayDead) +void Jupiter::IRC::Client::disconnect(const Jupiter::ReadableString &message, bool stayDead) { - char *msg = new char[strlen(message) + 9]; - sprintf(msg, "QUIT :%s" ENDL, message); - Jupiter::IRC::Client::data_->sock->send(msg); - delete[] msg; + Jupiter::IRC::Client::data_->sock->send(Jupiter::StringS::Format("QUIT :%.*s" ENDL, message.size(), message.ptr())); Jupiter::IRC::Client::disconnect(stayDead); } void Jupiter::IRC::Client::reconnect() { - if (Jupiter::IRC::Client::data_->connectionStatus) Jupiter::IRC::Client::disconnect(); + if (Jupiter::IRC::Client::data_->connectionStatus != 0) Jupiter::IRC::Client::disconnect(); Jupiter::IRC::Client::data_->reconnectAttempts++; bool successConnect = Jupiter::IRC::Client::connect(); this->OnReconnectAttempt(successConnect); @@ -1332,43 +1301,46 @@ int Jupiter::IRC::Client::think() return 0; } -Jupiter::CStringS Jupiter::IRC::Client::readConfigValue(const char *key, const char *defaultValue) const +const Jupiter::ReadableString &Jupiter::IRC::Client::readConfigValue(const Jupiter::ReadableString &key, const Jupiter::ReadableString &defaultValue) const { - const char *val = Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName.c_str(), key); - if (val == nullptr) val = Jupiter::IRC::Client::Config->get("Default", key, defaultValue); - return val; + const Jupiter::ReadableString &val = Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName, key); + if (val.size() != 0) return val; + return Jupiter::IRC::Client::Config->get(STRING_LITERAL_AS_REFERENCE("Default"), key, defaultValue); } -bool Jupiter::IRC::Client::readConfigBool(const char *key, bool defaultValue) const +bool Jupiter::IRC::Client::readConfigBool(const Jupiter::ReadableString &key, bool defaultValue) const { - if (Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName.c_str(), key)) return Jupiter::IRC::Client::Config->getBool(Jupiter::IRC::Client::data_->configSectionName.c_str(), key); - return Jupiter::IRC::Client::Config->getBool("Default", key, defaultValue); + const Jupiter::ReadableString &val = Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName, key); + if (val.size() != 0) return val.asBool(); + return Jupiter::IRC::Client::Config->getBool(STRING_LITERAL_AS_REFERENCE("Default"), key, defaultValue); } -int Jupiter::IRC::Client::readConfigInt(const char *key, int defaultValue) const +int Jupiter::IRC::Client::readConfigInt(const Jupiter::ReadableString &key, int defaultValue) const { - if (Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName.c_str(), key)) return Jupiter::IRC::Client::Config->getInt(Jupiter::IRC::Client::data_->configSectionName.c_str(), key); - return Jupiter::IRC::Client::Config->getInt("Default", key, defaultValue); + const Jupiter::ReadableString &val = Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName, key); + if (val.size() != 0) return val.asInt(); + return Jupiter::IRC::Client::Config->getInt(STRING_LITERAL_AS_REFERENCE("Default"), key, defaultValue); } -long Jupiter::IRC::Client::readConfigLong(const char *key, long defaultValue) const +long Jupiter::IRC::Client::readConfigLong(const Jupiter::ReadableString &key, long defaultValue) const { - if (Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName.c_str(), key)) return Jupiter::IRC::Client::Config->getLong(Jupiter::IRC::Client::data_->configSectionName.c_str(), key); - return Jupiter::IRC::Client::Config->getLong("Default", key, defaultValue); + const Jupiter::ReadableString &val = Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName, key); + if (val.size() != 0) return val.asInt(); + return Jupiter::IRC::Client::Config->getInt(STRING_LITERAL_AS_REFERENCE("Default"), key, defaultValue); } -double Jupiter::IRC::Client::readConfigDouble(const char *key, double defaultValue) const +double Jupiter::IRC::Client::readConfigDouble(const Jupiter::ReadableString &key, double defaultValue) const { - if (Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName.c_str(), key)) return Jupiter::IRC::Client::Config->getDouble(Jupiter::IRC::Client::data_->configSectionName.c_str(), key); - return Jupiter::IRC::Client::Config->getDouble("Default", key, defaultValue); + const Jupiter::ReadableString &val = Jupiter::IRC::Client::Config->get(Jupiter::IRC::Client::data_->configSectionName, key); + if (val.size() != 0) return val.asDouble(); + return Jupiter::IRC::Client::Config->getDouble(STRING_LITERAL_AS_REFERENCE("Default"), key, defaultValue); } -void Jupiter::IRC::Client::writeToLogs(const char *message) +void Jupiter::IRC::Client::writeToLogs(const Jupiter::ReadableString &message) { if (Jupiter::IRC::Client::data_->logFile != nullptr) { - fputs(message, Jupiter::IRC::Client::data_->logFile); - fputs(ENDL, Jupiter::IRC::Client::data_->logFile); + message.println(Jupiter::IRC::Client::data_->logFile); fflush(Jupiter::IRC::Client::data_->logFile); } } @@ -1377,7 +1349,7 @@ void Jupiter::IRC::Client::writeToLogs(const char *message) * @brief IRC Client Data Implementation */ -void Jupiter::IRC::Client::Data::delChannel(const char *chan) +void Jupiter::IRC::Client::Data::delChannel(const Jupiter::ReadableString &chan) { Jupiter::IRC::Client::Channel *channel; for (unsigned int i = 0; i < Jupiter::IRC::Client::Data::channels.size(); i++) @@ -1396,7 +1368,7 @@ void Jupiter::IRC::Client::Data::delChannel(unsigned int index) delete Jupiter::IRC::Client::Data::channels.remove(index); } -Jupiter::IRC::Client::User *Jupiter::IRC::Client::Data::findUser(const char *nick) const +Jupiter::IRC::Client::User *Jupiter::IRC::Client::Data::findUser(const Jupiter::ReadableString &nick) const { Jupiter::IRC::Client::User *r; for (unsigned int i = 0; i < Jupiter::IRC::Client::Data::users.size(); i++) @@ -1407,25 +1379,25 @@ Jupiter::IRC::Client::User *Jupiter::IRC::Client::Data::findUser(const char *nic return nullptr; } -Jupiter::IRC::Client::User *Jupiter::IRC::Client::Data::findUserOrAdd(Jupiter::CStringS &name) +Jupiter::IRC::Client::User *Jupiter::IRC::Client::Data::findUserOrAdd(const Jupiter::ReadableString &name) { unsigned int wc = name.wordCount("!@"); - Jupiter::CStringS nick = (wc == 1) ? name : name.getWord(0, "!@"); - Jupiter::IRC::Client::User *r = Jupiter::IRC::Client::Data::findUser(nick.c_str()); + Jupiter::ReferenceString nick = (wc == 1) ? (name) : Jupiter::ReferenceString::getWord(name, 0, "!@"); + Jupiter::IRC::Client::User *r = Jupiter::IRC::Client::Data::findUser(nick); if (r == nullptr) { r = new Jupiter::IRC::Client::User(); switch (wc) { case 3: - r->data_->hostname = name.getWord(2, "!@"); + r->data_->hostname = Jupiter::ReferenceString::getWord(name, 2, "!@"); case 2: // This shouldn't EVER happen. - r->data_->username = name.getWord(1, "!@"); + r->data_->username = Jupiter::ReferenceString::getWord(name, 1, "!@"); case 1: // No user/host is in the string. r->data_->nickname = nick; break; default: - fprintf(stderr, "ERROR: Failed to parse name mask: %s" ENDL, name.c_str()); + fprintf(stderr, "ERROR: Failed to parse name mask: %.*s" ENDL, name.size(), name.ptr()); break; } Jupiter::IRC::Client::Data::users.add(r); @@ -1433,35 +1405,32 @@ Jupiter::IRC::Client::User *Jupiter::IRC::Client::Data::findUserOrAdd(Jupiter::C return r; } -void Jupiter::IRC::Client::Data::addNamesToChannel(unsigned int index, Jupiter::CStringS &names) +void Jupiter::IRC::Client::Data::addNamesToChannel(unsigned int index, Jupiter::ReadableString &names) { - Jupiter::CStringS t; + Jupiter::ReferenceString t; size_t offset; Jupiter::IRC::Client::Channel *channel = Jupiter::IRC::Client::Data::channels.get(index); int nameLen = names.wordCount(" "); for (short i = 0; i < nameLen; i++) { - t = names.getWord(i, " "); + t = Jupiter::ReferenceString::getWord(names, i, " "); if (t.size() != 0) { - offset = strspn(t.c_str(), Jupiter::IRC::Client::Data::prefixes.c_str()); + offset = t.span(Jupiter::IRC::Client::Data::prefixes.c_str()); t.shiftRight(offset); Jupiter::IRC::Client::User *user = Jupiter::IRC::Client::Data::findUserOrAdd(t); t.shiftLeft(offset); unsigned int userIndex = channel->addUser(user); - if (offset > 0) + while (offset > 0) { - while (offset > 0) - { - offset--; - channel->addUserPrefix(userIndex, t[offset]); - } + offset--; + channel->addUserPrefix(userIndex, t[offset]); } } } } -unsigned int Jupiter::IRC::Client::Data::addChannel(const char *chan) +size_t Jupiter::IRC::Client::Data::addChannel(const Jupiter::ReadableString &chan) { Jupiter::IRC::Client::Data::channels.add(new Channel(chan, Jupiter::IRC::Client::Data::iFace)); return Jupiter::IRC::Client::Data::channels.size() - 1; @@ -1472,16 +1441,16 @@ bool Jupiter::IRC::Client::Data::startCAP() Jupiter::IRC::Client::Data::connectionStatus = 2; return Jupiter::IRC::Client::Data::sock->send("CAP LS" ENDL, 8) > 0; } - +//Jupiter::ReferenceString & bool Jupiter::IRC::Client::Data::registerClient() { bool r = true; const char *localHostname = Jupiter::Socket::getLocalHostname(); - Jupiter::CStringL messageToSend; - messageToSend.format("USER %s %s %s :%s" ENDL, Jupiter::IRC::Client::Data::nickname.c_str(), localHostname, Jupiter::IRC::Client::Data::serverHostname.c_str(), Jupiter::IRC::Client::Data::realName.c_str()); - if (Jupiter::IRC::Client::Data::sock->send(messageToSend.c_str(), messageToSend.size()) <= 0) r = false; - messageToSend.format("NICK %s" ENDL, Jupiter::IRC::Client::Data::nickname.c_str()); - if (Jupiter::IRC::Client::Data::sock->send(messageToSend.c_str(), messageToSend.size()) <= 0) r = false; + Jupiter::StringS messageToSend; + messageToSend.format("USER %.*s %s %.*s :%.*s" ENDL, Jupiter::IRC::Client::Data::nickname.size(), Jupiter::IRC::Client::Data::nickname.ptr(), localHostname, Jupiter::IRC::Client::Data::serverHostname.size(), Jupiter::IRC::Client::Data::serverHostname.ptr(), Jupiter::IRC::Client::Data::realName.size(), Jupiter::IRC::Client::Data::realName.ptr()); + if (Jupiter::IRC::Client::Data::sock->send(messageToSend) <= 0) r = false; + messageToSend.format("NICK %.*s" ENDL, Jupiter::IRC::Client::Data::nickname.size(), Jupiter::IRC::Client::Data::nickname.ptr()); + if (Jupiter::IRC::Client::Data::sock->send(messageToSend) <= 0) r = false; Jupiter::IRC::Client::Data::connectionStatus = 3; return r; } @@ -1500,22 +1469,22 @@ Jupiter::IRC::Client::User::~User() delete Jupiter::IRC::Client::User::data_; } -const Jupiter::StringType &Jupiter::IRC::Client::User::getNickname() const +const Jupiter::ReadableString &Jupiter::IRC::Client::User::getNickname() const { return Jupiter::IRC::Client::User::data_->nickname; } -const Jupiter::StringType &Jupiter::IRC::Client::User::getUsername() const +const Jupiter::ReadableString &Jupiter::IRC::Client::User::getUsername() const { return Jupiter::IRC::Client::User::data_->username; } -const Jupiter::StringType &Jupiter::IRC::Client::User::getHostname() const +const Jupiter::ReadableString &Jupiter::IRC::Client::User::getHostname() const { return Jupiter::IRC::Client::User::data_->hostname; } -unsigned int Jupiter::IRC::Client::User::getChannelCount() const +size_t Jupiter::IRC::Client::User::getChannelCount() const { return Jupiter::IRC::Client::User::data_->channelCount; } @@ -1524,50 +1493,51 @@ unsigned int Jupiter::IRC::Client::User::getChannelCount() const * Channel Implementation */ -Jupiter::IRC::Client::Channel::Channel(const char *channelName, Jupiter::IRC::Client *iFace) +Jupiter::IRC::Client::Channel::Channel(const Jupiter::ReadableString &channelName, Jupiter::IRC::Client *iFace) { Jupiter::IRC::Client::Channel::data_ = new Jupiter::IRC::Client::Channel::Data(); unsigned int i = 0; - const char *ptr = nullptr; - const char *section = iFace->getConfigSection().c_str(); - char key[64]; - int offset = sprintf(key, "Channel."); - Jupiter::CStringL channelKeyStr; + const Jupiter::ReadableString *ptr = nullptr; + Jupiter::ReferenceString section = iFace->getConfigSection(); + Jupiter::String key = "Channel."; + size_t offset = 0; // TODO: Make this more efficient -- consider moving responsibility elsewhere. while (1) { i++; - sprintf(key + offset, "%u", i); - ptr = Jupiter::IRC::Client::Config->get(section, key); - if (ptr == nullptr) + offset = key.aformat("%u", i); + ptr = &Jupiter::IRC::Client::Config->get(iFace->getConfigSection(), Jupiter::ReferenceString(key)); + if (ptr->size() == 0) { - if (section != iFace->getConfigSection().c_str()) break; + if (section != iFace->getConfigSection()) break; i = 0; - section = "Default"; + section = STRING_LITERAL_AS_REFERENCE("Default"); + key.truncate(offset); continue; } - channelKeyStr = ptr; - if (channelKeyStr.getWord(0, WHITESPACE).equalsi(channelName)) + if (Jupiter::ReferenceString::getWord(*ptr, 0, WHITESPACE).equalsi(channelName)) { - sprintf(key + offset, "%u.Type", i); - ptr = Jupiter::IRC::Client::Config->get(section, key); - if (ptr != nullptr) + offset += key.aformat(".Type", i); + ptr = &Jupiter::IRC::Client::Config->get(iFace->getConfigSection(), Jupiter::ReferenceString(key)); + if (ptr->size() != 0) { - Jupiter::IRC::Client::Channel::data_->type = atoi(ptr); + Jupiter::IRC::Client::Channel::data_->type = ptr->asInt(); + key.truncate(offset); break; } } + key.truncate(offset); } - if (ptr == nullptr) + if (ptr->size() == 0) { - sprintf(key + offset, "%s.Type", channelName); - ptr = iFace->readConfigValue(key).c_str(); - if (*ptr != 0) Jupiter::IRC::Client::Channel::data_->type = atoi(ptr); + key.aformat("%.*s.Type", channelName.size(), channelName.ptr()); + Jupiter::CStringS val = iFace->readConfigValue(key); + if (val.size() != 0) Jupiter::IRC::Client::Channel::data_->type = val.asInt(); else Jupiter::IRC::Client::Channel::data_->type = iFace->getDefaultChanType(); } Jupiter::IRC::Client::Channel::data_->channel = channelName; - Jupiter::IRC::Client::Channel::data_->serverPrefixSetPtr = iFace->getPrefixes().c_str(); + Jupiter::IRC::Client::Channel::data_->serverPrefixSetPtr = iFace->getPrefixes(); } Jupiter::IRC::Client::Channel::~Channel() @@ -1592,13 +1562,13 @@ unsigned int Jupiter::IRC::Client::Channel::addUser(Jupiter::IRC::Client::User * return r; } -void Jupiter::IRC::Client::Channel::delUser(const char *nickname) +void Jupiter::IRC::Client::Channel::delUser(const Jupiter::ReadableString &nickname) { int index = getUserIndex(nickname); if (index >= 0) Jupiter::IRC::Client::Channel::delUser(index); } -void Jupiter::IRC::Client::Channel::delUser(unsigned int index) +void Jupiter::IRC::Client::Channel::delUser(size_t index) { if (index < Jupiter::IRC::Client::Channel::data_->users.size()) { @@ -1608,7 +1578,7 @@ void Jupiter::IRC::Client::Channel::delUser(unsigned int index) } } -void Jupiter::IRC::Client::Channel::addUserPrefix(unsigned int index, char prefix) +void Jupiter::IRC::Client::Channel::addUserPrefix(size_t index, char prefix) { if (index < Jupiter::IRC::Client::Channel::data_->users.size()) { @@ -1619,7 +1589,7 @@ void Jupiter::IRC::Client::Channel::addUserPrefix(unsigned int index, char prefi } } -void Jupiter::IRC::Client::Channel::addUserPrefix(const char *user, char prefix) +void Jupiter::IRC::Client::Channel::addUserPrefix(const Jupiter::ReadableString &user, char prefix) { int i = Jupiter::IRC::Client::Channel::getUserIndex(user); if (i >= 0) Jupiter::IRC::Client::Channel::addUserPrefix(i, prefix); @@ -1630,13 +1600,13 @@ void Jupiter::IRC::Client::Channel::delUserPrefix(unsigned int index, char prefi if (index < Jupiter::IRC::Client::Channel::data_->users.size()) Jupiter::IRC::Client::Channel::data_->users.get(index)->data_->prefixes.remove(prefix); } -void Jupiter::IRC::Client::Channel::delUserPrefix(const char *user, char prefix) +void Jupiter::IRC::Client::Channel::delUserPrefix(const Jupiter::ReadableString &user, char prefix) { int i = Jupiter::IRC::Client::Channel::getUserIndex(user); if (i >= 0) Jupiter::IRC::Client::Channel::delUserPrefix(i, prefix); } -const Jupiter::StringType &Jupiter::IRC::Client::Channel::getName() const +const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::getName() const { return Jupiter::IRC::Client::Channel::data_->channel; } @@ -1648,7 +1618,7 @@ Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::getUser(unsi return nullptr; } -Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::getUser(const char *nickname) const +Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::getUser(const Jupiter::ReadableString &nickname) const { Jupiter::ArrayList &users = Jupiter::IRC::Client::Channel::data_->users; Jupiter::IRC::Client::Channel::User *user; @@ -1660,15 +1630,19 @@ Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::getUser(cons return nullptr; } -int Jupiter::IRC::Client::Channel::getUserIndex(const char *user) const +int Jupiter::IRC::Client::Channel::getUserIndex(const Jupiter::ReadableString &user) const { - for (unsigned int i = 0; i < Jupiter::IRC::Client::Channel::data_->users.size(); i++) if (Jupiter::IRC::Client::Channel::data_->users[i] && Jupiter::IRC::Client::Channel::data_->users[i]->data_->user->getNickname().equalsi(user)) return i; + for (unsigned int i = 0; i < Jupiter::IRC::Client::Channel::data_->users.size(); i++) + if (Jupiter::IRC::Client::Channel::data_->users[i] && Jupiter::IRC::Client::Channel::data_->users[i]->data_->user->getNickname().equalsi(user)) + return i; return -1; } -int Jupiter::IRC::Client::Channel::getUserIndexByPartName(const char *user) const +int Jupiter::IRC::Client::Channel::getUserIndexByPartName(const Jupiter::ReadableString &user) const { - for (unsigned int i = 0; i < Jupiter::IRC::Client::Channel::data_->users.size(); i++) if (Jupiter::IRC::Client::Channel::data_->users[i] && stristr(Jupiter::IRC::Client::Channel::data_->users[i]->data_->user->getNickname().c_str(), user)) return i; + for (unsigned int i = 0; i < Jupiter::IRC::Client::Channel::data_->users.size(); i++) + if (Jupiter::IRC::Client::Channel::data_->users[i] && Jupiter::IRC::Client::Channel::data_->users[i]->data_->user->getNickname().find(user) != Jupiter::INVALID_INDEX) + return i; return -1; } @@ -1676,11 +1650,12 @@ char Jupiter::IRC::Client::Channel::getUserPrefix(unsigned int index) const { if (index < Jupiter::IRC::Client::Channel::data_->users.size()) for (unsigned char i = 0; Jupiter::IRC::Client::Channel::data_->serverPrefixSetPtr[i]; i++) - if (containsSymbol(Jupiter::IRC::Client::Channel::data_->users.get(index)->data_->prefixes.c_str(), Jupiter::IRC::Client::Channel::data_->serverPrefixSetPtr[i])) return Jupiter::IRC::Client::Channel::data_->serverPrefixSetPtr[i]; + if (containsSymbol(Jupiter::IRC::Client::Channel::data_->users.get(index)->data_->prefixes.c_str(), Jupiter::IRC::Client::Channel::data_->serverPrefixSetPtr[i])) + return Jupiter::IRC::Client::Channel::data_->serverPrefixSetPtr[i]; return 0; } -char Jupiter::IRC::Client::Channel::getUserPrefix(const char *user) const +char Jupiter::IRC::Client::Channel::getUserPrefix(const Jupiter::ReadableString &user) const { int i = Jupiter::IRC::Client::Channel::getUserIndex(user); if (i >= 0) return Jupiter::IRC::Client::Channel::getUserPrefix(i); @@ -1721,22 +1696,22 @@ Jupiter::IRC::Client::User *Jupiter::IRC::Client::Channel::User::getUser() const return Jupiter::IRC::Client::Channel::User::data_->user; } -const Jupiter::StringType &Jupiter::IRC::Client::Channel::User::getPrefixes() const +const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getPrefixes() const { return Jupiter::IRC::Client::Channel::User::data_->prefixes; } -const Jupiter::StringType &Jupiter::IRC::Client::Channel::User::getNickname() const +const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getNickname() const { return Jupiter::IRC::Client::Channel::User::data_->user->getNickname(); } -const Jupiter::StringType &Jupiter::IRC::Client::Channel::User::getUsername() const +const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getUsername() const { return Jupiter::IRC::Client::Channel::User::data_->user->getUsername(); } -const Jupiter::StringType &Jupiter::IRC::Client::Channel::User::getHostname() const +const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getHostname() const { return Jupiter::IRC::Client::Channel::User::data_->user->getHostname(); } diff --git a/Jupiter/IRC_Client.h b/Jupiter/IRC_Client.h index 7226dbb..96d38f4 100644 --- a/Jupiter/IRC_Client.h +++ b/Jupiter/IRC_Client.h @@ -28,7 +28,7 @@ #include "Jupiter.h" #include "Thinker.h" #include "IRC.h" -#include "CString.h" +#include "Reference_String.h" #define CONFIG_INI "Config.ini" /** Default location of the Config file. */ @@ -73,14 +73,14 @@ namespace Jupiter * * @param raw The raw message. */ - virtual void OnRaw(const StringType &raw); + virtual void OnRaw(const Jupiter::ReadableString &raw); /** * @brief This is called after an IRC numeric has been processed. * * @param raw The raw message. */ - virtual void OnNumeric(long int numeric, const StringType &raw); + virtual void OnNumeric(long int numeric, const Jupiter::ReadableString &raw); /** * @brief This is called when an ERROR is received. @@ -88,7 +88,7 @@ namespace Jupiter * * @param message Message sent by the server. */ - virtual void OnError(const StringType &message); + virtual void OnError(const Jupiter::ReadableString &message); /** * @brief This is called when a chat message is received. @@ -97,7 +97,7 @@ namespace Jupiter * @param nick String containing the nickname of the sender. * @param message String containing the message sent. */ - virtual void OnChat(const StringType &channel, const StringType &nick, const StringType &message); + virtual void OnChat(const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString &message); /** * @brief This is called when a notice is received. @@ -106,7 +106,7 @@ namespace Jupiter * @param nick String containing the nickname of the sender. * @param message String containing the message sent. */ - virtual void OnNotice(const StringType &chan, const StringType &sender, const StringType &message); + virtual void OnNotice(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &sender, const Jupiter::ReadableString &message); /** * @brief This is called when a server notice is received. @@ -115,7 +115,7 @@ namespace Jupiter * @param nick String containing the sender. * @param message String containing the message sent. */ - virtual void OnServerNotice(const StringType &chan, const StringType &sender, const StringType &message); + virtual void OnServerNotice(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &sender, const Jupiter::ReadableString &message); /** * @brief This is called when a CTCP message is received. @@ -124,7 +124,7 @@ namespace Jupiter * @param nick String containing the nickname of the sender. * @param message String containing the message sent. */ - virtual void OnCTCP(const StringType &channel, const StringType &nick, const StringType &command, const StringType &message); + virtual void OnCTCP(const Jupiter::ReadableString &channel, const Jupiter::ReadableString &nick, const Jupiter::ReadableString &command, const Jupiter::ReadableString &message); /** * @brief This is called when an action message is received. @@ -133,7 +133,7 @@ namespace Jupiter * @param nick String containing the nickname of the sender. * @param message String containing the message sent. */ - virtual void OnAction(const StringType &chan, const StringType &nick, const StringType &message); + virtual void OnAction(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &nick, const Jupiter::ReadableString &message); /** * @brief This is called when an invite is received. @@ -142,7 +142,7 @@ namespace Jupiter * @param inviter String containing the nickname of the inviter. * @param invited String containing the nickname of the user invited. */ - virtual void OnInvite(const StringType &chan, const StringType &inviter, const StringType &invited); + virtual void OnInvite(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &inviter, const Jupiter::ReadableString &invited); /** * @brief This is called when a chat message is received. @@ -151,7 +151,7 @@ namespace Jupiter * @param nick String containing the nickname of the sender. * @param message String containing the message sent. */ - virtual void OnJoin(const StringType &chan, const StringType &nick); + virtual void OnJoin(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &nick); /** * @brief This is called when a user parts a channel. @@ -160,7 +160,7 @@ namespace Jupiter * @param nick String containing the nickname of the user. * @param reason String containing the reason for parting, or nullptr if none is specified. */ - virtual void OnPart(const StringType &chan, const StringType &nick, const StringType &reason); + virtual void OnPart(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &nick, const Jupiter::ReadableString &reason); /** * @brief This is called when a user changes their nickname. @@ -168,7 +168,7 @@ namespace Jupiter * @param oldnick String containing the old nickname of the user. * @param newnick String containing the new nickname of the user. */ - virtual void OnNick(const StringType &oldnick, const StringType &newnick); + virtual void OnNick(const Jupiter::ReadableString &oldnick, const Jupiter::ReadableString &newnick); /** * @brief This is called when a user is kicked from a channel. @@ -178,7 +178,7 @@ namespace Jupiter * @param kicked String containing the nickname of the user kicked. * @param reason String containing the reason for the kick, or nullptr if none is specified. */ - virtual void OnKick(const StringType &chan, const StringType &kicker, const StringType &kicked, const StringType &reason); + virtual void OnKick(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &kicker, const Jupiter::ReadableString &kicked, const Jupiter::ReadableString &reason); /** * @brief This is called when a user quits the server. @@ -186,7 +186,7 @@ namespace Jupiter * @param nick String containing the nickname of the user. * @param message String containing the reason for quiting. */ - virtual void OnQuit(const StringType &nick, const StringType &message); + virtual void OnQuit(const Jupiter::ReadableString &nick, const Jupiter::ReadableString &message); /** * @brief This is called when a channel mode is changed. @@ -195,7 +195,7 @@ namespace Jupiter * @param nick String containing the nickname of the user. * @param modeString String containing the modes changed. */ - virtual void OnMode(const Jupiter::StringType &chan, const Jupiter::StringType &nick, const Jupiter::StringType &modeString); + virtual void OnMode(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &nick, const Jupiter::ReadableString &modeString); public: static INIFile *Config; /** IRC client config file. This is automatically instantiated upon library initialization. */ @@ -215,21 +215,21 @@ namespace Jupiter * * @return String containing the user's nickname. */ - const Jupiter::StringType &getNickname() const; + const Jupiter::ReadableString &getNickname() const; /** * @brief Fetches the user's username. * * @return String containing the user's username. */ - const Jupiter::StringType &getUsername() const; + const Jupiter::ReadableString &getUsername() const; /** * @brief Fetches the user's hostname. * * @return String containing the user's hostname. */ - const Jupiter::StringType &getHostname() const; + const Jupiter::ReadableString &getHostname() const; /** * @brief Returns the number of channels the user shares with the local client. @@ -275,28 +275,28 @@ namespace Jupiter * * @return String containing the user's channel prefixes. */ - const Jupiter::StringType &getPrefixes() const; + const Jupiter::ReadableString &getPrefixes() const; /** * @brief Fetches the user's nickname. * * @return String containing the user's nickname. */ - const Jupiter::StringType &getNickname() const; + const Jupiter::ReadableString &getNickname() const; /** * @brief Fetches the user's username. * * @return String containing the user's username. */ - const Jupiter::StringType &getUsername() const; + const Jupiter::ReadableString &getUsername() const; /** * @brief Fetches the user's hostname. * * @return String containing the user's hostname. */ - const Jupiter::StringType &getHostname() const; + const Jupiter::ReadableString &getHostname() const; /** * @brief Returns the number of channels the user shares with the local client. @@ -319,7 +319,7 @@ namespace Jupiter * * @return String containing the name of the channel. */ - const StringType &getName() const; + const Jupiter::ReadableString &getName() const; /** * @brief Returns a user at an index. @@ -335,7 +335,7 @@ namespace Jupiter * @param nickname String containing the nickname of the user to find. * @return A user if a match is found, nullptr otherwise. */ - Jupiter::IRC::Client::Channel::User *getUser(const char *nickname) const; + Jupiter::IRC::Client::Channel::User *getUser(const Jupiter::ReadableString &nickname) const; /** * @brief Adds a user to the channel @@ -359,14 +359,14 @@ namespace Jupiter * * @param nickname String containing the nickname of the user. */ - void delUser(const char *nickname); + void delUser(const Jupiter::ReadableString &nickname); /** * @brief Removes a user from the channel. * * @param index Index of a user. */ - void delUser(unsigned int index); + void delUser(size_t index); /** * @brief Adds a prefix to a user. @@ -374,7 +374,7 @@ namespace Jupiter * @param index Index of a user. * @param prefix Prefix to add to the user. */ - void addUserPrefix(unsigned int index, char prefix); + void addUserPrefix(size_t index, char prefix); /** * @brief Adds a prefix to a user. @@ -382,7 +382,7 @@ namespace Jupiter * @param user String containing the nickname of the user. * @param prefix Prefix to add to the user. */ - void addUserPrefix(const char *user, char prefix); + void addUserPrefix(const Jupiter::ReadableString &user, char prefix); /** * @brief Removes a prefix from a user. @@ -398,7 +398,7 @@ namespace Jupiter * @param user String containing the nickname of a user. * @param prefix Prefix to remove from the user. */ - void delUserPrefix(const char *user, char prefix); + void delUserPrefix(const Jupiter::ReadableString &user, char prefix); /** * @brief Returns the index of a user. @@ -406,7 +406,7 @@ namespace Jupiter * @param user String containing the nickname of a user. * @return Index of a user if they're found, -1 otherwise. */ - int getUserIndex(const char *user) const; + int getUserIndex(const Jupiter::ReadableString &user) const; /** * @brief Returns the index of a user. @@ -414,7 +414,7 @@ namespace Jupiter * @param user String containing part of the nickname of a user. * @return Index of a user if they're found, -1 otherwise. */ - int getUserIndexByPartName(const char *user) const; + int getUserIndexByPartName(const Jupiter::ReadableString &user) const; /** * @brief Returns a user's most significant prefix. @@ -430,7 +430,7 @@ namespace Jupiter * @param user String containing the nickname of a user. * @return User's most significant prefix. */ - char getUserPrefix(const char *user) const; + char getUserPrefix(const Jupiter::ReadableString &user) const; /** * @brief Returns the number of users in this channel. @@ -459,7 +459,7 @@ namespace Jupiter * @param channelName String containing the name of a channel. * @param iFace Server in which this channel is located. */ - Channel(const char *channelName, Client *iFace); + Channel(const Jupiter::ReadableString &channelName, Client *iFace); /** * @brief Destructor for Channel @@ -477,42 +477,42 @@ namespace Jupiter * * @return String containing a config section. */ - const StringType &getConfigSection() const; + const Jupiter::ReadableString &getConfigSection() const; /** * @brief Returns the name of the file this logs to. * * @return String containing a log file's name. */ - const StringType &getLogFile() const; + const Jupiter::ReadableString &getLogFile() const; /** * @brief Returns the nickname prefixes supported by the connected server. * * @return String containing nickname prefixes. */ - const StringType &getPrefixes() const; + const Jupiter::ReadableString &getPrefixes() const; /** * @brief Returns the client's current nickname. * * @return String containing a nickame. */ - const StringType &getNickname() const; + const Jupiter::ReadableString &getNickname() const; /** * @brief Returns the client's real name. * * @return String containing a name. */ - const StringType &getRealname() const; + const Jupiter::ReadableString &getRealname() const; /** * @brief Returns the server's name * * @return String containing the server's name. */ - const StringType &getServerName() const; + const Jupiter::ReadableString &getServerName() const; /** * @brief Returns the server's hostname. @@ -520,7 +520,7 @@ namespace Jupiter * * @return String containing a hostname. */ - const StringType &getServerHostname() const; + const Jupiter::ReadableString &getServerHostname() const; /** * @brief Returns the server's port. @@ -595,7 +595,7 @@ namespace Jupiter * @param nickname String containing the nickname of the user to fetch. * @return A User if a match is found, nullptr otherwise. */ - Jupiter::IRC::Client::User *getUser(const char *nickname) const; + Jupiter::IRC::Client::User *getUser(const Jupiter::ReadableString &nickname) const; /** * @brief Fetches a user's index from the user list. @@ -603,7 +603,7 @@ namespace Jupiter * @param nickname String containing the nickname of the user to fetch. * @return The index of a user if a match is found, -1 otherwise. */ - int getUserIndex(const char *nickname) const; + int getUserIndex(const Jupiter::ReadableString &nickname) const; /** * @brief Fetches a user's index from the user list. @@ -641,7 +641,7 @@ namespace Jupiter * @param chanName String containing the name of a channel. * @return The channel at index. */ - Channel *getChannel(const char *chanName) const; + Channel *getChannel(const Jupiter::ReadableString &chanName) const; /** * @brief Returns a channel's name at index. @@ -649,7 +649,7 @@ namespace Jupiter * @param index Index of the channel. * @return Channel's name. */ - const StringType &getChannelName(unsigned int index) const; + const Jupiter::ReadableString &getChannelName(unsigned int index) const; /** * @brief Returns the index of the channel with a given name. @@ -657,14 +657,14 @@ namespace Jupiter * @param chanName String containing the name of a channel. * @return Index of a channel if a match is found, -1 otherwise. */ - int getChannelIndex(const char *chanName) const; + int getChannelIndex(const Jupiter::ReadableString &chanName) const; /** * @brief Sends a join request. * * @param channel Channel to join. */ - void joinChannel(const char *channel); + void joinChannel(const Jupiter::ReadableString &channel); /** * @brief Sends a join request with a password. @@ -672,14 +672,14 @@ namespace Jupiter * @param channel Channel to join. * @param password Password to use. */ - void joinChannel(const char *channel, const char *password); + void joinChannel(const Jupiter::ReadableString &channel, const Jupiter::ReadableString &password); /** * @brief Parts a channel. * * @param channel Channel to part. */ - void partChannel(const char *channel); + void partChannel(const Jupiter::ReadableString &channel); /** * @brief Parts a channel. @@ -687,7 +687,7 @@ namespace Jupiter * @param channel Channel to part. * @param message Reason for parting. */ - void partChannel(const char *channel, const char *message); + void partChannel(const Jupiter::ReadableString &channel, const Jupiter::ReadableString &message); /** * @brief Gets the access level of a user. @@ -696,7 +696,7 @@ namespace Jupiter * @param nick String containing the nickname of the user. * @return Access level of the user. */ - int getAccessLevel(const char *chan, const char *nick) const; + int getAccessLevel(const Jupiter::ReadableString &chan, const Jupiter::ReadableString &nick) const; /** * @brief Sends a message. @@ -704,7 +704,7 @@ namespace Jupiter * @param dest String containing the destination of the message (nickname or channel). * @param message String containing the message to send. */ - void sendMessage(const char *dest, const char *message); + void sendMessage(const Jupiter::ReadableString &dest, const Jupiter::ReadableString &message); /** * @brief Sends a notice. @@ -712,7 +712,7 @@ namespace Jupiter * @param dest String containing the destination of the message (nickname or channel). * @param message String containing the message to send. */ - void sendNotice(const char *dest, const char *message); + void sendNotice(const Jupiter::ReadableString &dest, const Jupiter::ReadableString &message); /** * @brief Sends a message to all channels of a given type. @@ -721,7 +721,7 @@ namespace Jupiter * @param message String containing the message to send. * @return Number of messages sent. */ - unsigned int messageChannels(short type, const char *message); + unsigned int messageChannels(short type, const Jupiter::ReadableString &message); /** * @brief Sends a message to all channels with a type of at least 0. @@ -729,7 +729,7 @@ namespace Jupiter * @param message String containing the message to send. * @return Number of messages sent. */ - unsigned int messageChannels(const char *message); + unsigned int messageChannels(const Jupiter::ReadableString &message); /** * @brief Returns if the client will automatically reconnect upon failure. @@ -751,7 +751,7 @@ namespace Jupiter * * @param rawMessage String containing the data to send. */ - void send(const char *rawMessage); + void send(const Jupiter::ReadableString &rawMessage); /** * @brief Method that is called by think() to handle all of the IRC protocol. @@ -766,9 +766,10 @@ namespace Jupiter * This reads from the client's config section first, then default if it doesn't exist. * * @param key String containing the key name. + * @param defaultValue Optional parameter specifying the default value to return if none is found. * @return String containing the key value if it exists, defaultValue otherwise. */ - Jupiter::CStringS readConfigValue(const char *key, const char *defaultValue = nullptr) const; + const Jupiter::ReadableString &readConfigValue(const Jupiter::ReadableString &key, const Jupiter::ReadableString &defaultValue = Jupiter::ReferenceString::empty) const; /** * @brief Returns a key's value as a boolean. @@ -777,7 +778,7 @@ namespace Jupiter * @param key String containing the key name. * @return Boolean value of the key value if it exists, defaultValue otherwise. */ - bool readConfigBool(const char *key, bool defaultValue = false) const; + bool readConfigBool(const Jupiter::ReadableString &key, bool defaultValue = false) const; /** * @brief Returns a key's value as an integer. @@ -786,7 +787,7 @@ namespace Jupiter * @param key String containing the key name. * @return Integer value of the key value if it exists, defaultValue otherwise. */ - int readConfigInt(const char *key, int defaultValue = 0) const; + int readConfigInt(const Jupiter::ReadableString &key, int defaultValue = 0) const; /** * @brief Returns a key's value as a long integer. @@ -795,7 +796,7 @@ namespace Jupiter * @param key String containing the key name. * @return Long integer value of the key value if it exists, defaultValue otherwise. */ - long readConfigLong(const char *key, long defaultValue = 0) const; + long readConfigLong(const Jupiter::ReadableString &key, long defaultValue = 0) const; /** * @brief Returns a key's value as a double. @@ -804,14 +805,14 @@ namespace Jupiter * @param key String containing the key name. * @return Double value of the key value if it exists, defaultValue otherwise. */ - double readConfigDouble(const char *key, double defaultValue = 0) const; + double readConfigDouble(const Jupiter::ReadableString &key, double defaultValue = 0) const; /** * @brief Writes to the server's log file. * * @param message String containing the text to write to the file. */ - void writeToLogs(const char *message); + void writeToLogs(const Jupiter::ReadableString &message); /** * @brief Connects the client to its server. @@ -833,7 +834,7 @@ namespace Jupiter * * @param message String containing the QUIT message to send prior to disconnecting. */ - void disconnect(const char *message, bool stayDead = false); + void disconnect(const Jupiter::ReadableString &message, bool stayDead = false); /** * @brief Calls disconnect() if the client has not already, then calls connect(). @@ -854,7 +855,7 @@ namespace Jupiter * * @param configSection String containing the config section for the client to read from, before defaulting to "Default". */ - Client(const char *configSection); + Client(const Jupiter::ReadableString &configSection); /** * @brief Destructor for a client. diff --git a/Release/Jupiter.lib b/Release/Jupiter.lib index e741f7271a155721ea558be2ceb8194302d53bb0..642be88c0c9d78cb56b66bd75afa3d803318fe69 100644 GIT binary patch literal 215808 zcmeEvdz@TFm4Dsah`dEWL_`e`9`c+QdGP9<$s}aLWHMwDNKhF%Gd)SeWP0f72?@H2 ztg?uRh^*^_MHV0Hx`>GQLPgg_)(5)CD(fP$ii$4FB8x8;5r5yRx^-{Wy;XIq`gW8* zetbTM&UBwT=Ub;vy&vb$Q>)F1EvN5s;sW)*?!K<>C4EbKdX}o+cSV0L>RYmC5&QS~ zdl0hA4J7#eRV4Vsr%CYaVh~9?ZK&9@z zICZ_3lqmJCoGM=+A*Bxh_oh2ZczzcN$?2SKf=p29pu0J}_%>1kg}d*;>G{x2>3QIzwCj-( zeHovi-7b$P#3$%)kWWSr;}i6r6F9y5BP0Zs_Pc`9{tHQo(g7E6+W!&!4a|=|#Oc3h zNJ#0w4vgr-_yj#V!l-n_^@P!p$B+`EJMalQdN)o-oli=Xj(#_zaLc2FQt5fyI32$a zDS^Uwtm3ryt|SDN4qe44+-Ct{^cJL}bS3Of>8+=7`q)z>q;$(=oIbvSgp{6!JWBs} z4X3A`B_SjH_S6beI^h{c;Xf=QjQ)O zr}c0;@AV|4^qSd-ev41gt8eD?syC64(yL)pO1oUb>3KK8Z$L|K;i_HU___m z6SU|yPUphLjGn+j@rHvEjzx~C%ou63Xd$Oj|n+yFY~Y))t21Afrh zrigxlPte*MB02z{ppj-oDBBUx>RTdOh)>Y)fe~GgPtcibIj#B{2`Qa*HKWoi;g^hV z!6)b#{7or5Fe3PG2r3=S=>+&ADE#GLh*qIJVT9jTfd=>Cv7=XhJ*bTDD4l*kqws4VB#iDv`BD1Pk2rmO zfP|F3wil7QGi{{2Z3GFpdE(EWFF`u-&(1eJCr zoDO&b?KkMy1)Pq#34RVLUB@VVc3;BiW82YQf{wq8(~F>&5q$7P_dpixO6jF{a(dC_ zqy!2dLwy644u2h^@Y}%52tNL8(9iGV^b6D#O5ePh(}|CfkkU(lo6^C<5h2aNKP9CF zH!uo+ek9U^?gCCq$3M;Kz(Eo+`aV8E1JFZhIr2bh8EisnGkpB`cahRw!1=3Rlkl4R zN%&6iOq=dGCQGhx{iJ-hF zeQ=i3O}C@323>Y3r#Ie1LQrX!eHn$HKz=EGbPK0fqJB~;AMnb7{==T|gqg{kj>9AQw;V9Bk`rNgg{^=SLQu^5gobGvq zgp}@E#py>a5>o2@GN+?{K|)aJ6|f^HeDE1gKi-Xmlzw^>r=KA`rJp>>>ET02Na-OG z5$yaB=$m_SdO!LVM$r9!&=s&frMH~R=?2)6(SG;@T>)8?{^|-&#~|O7UT^}ZJB}tH zrLUaK>5(^)kkYr1S4w>=IUPNV@`P;yv?G*`;1s?IJe1yiH>aDwMnXm}$0z7-ui$h& zu!2e_Udbr@{bhvFGf2niNPL2xeu&c_wvZ51!uXF;_{V)X-S}$~Qu@1VIlbr87>j{^ zcPFPOZ^d{L^sBXuO8eeNIHBzK?IYo@FW~f>-AG93@lzv0xjy~?DIItiqws%jBaH5V zY)YTs!09vJCLyKIqP|f2+#Z~M{4SI$=qKlMdiX0SN6>!`M)V7O!XNfRdj|?XiN8Um zLw?ODybpPz^hNjurLX^p(|7T2O5giJL|ymlGKnbVFI2`OC!oRnri$f>@Kgp@A0gVXEpCn2S6 zk8!#Xcqla{Ic*14O0PxUDE$TgO=)JB(^lkx(y@ne+85zgltL&!4{NWGR$f6BWNE^U{u;0Z3Za(<29Uq^I^0tp!Y&9 zsPvL&BRUtKpqDOW6n+CbDSiGaPS-*{rMIIzDP4LSr><%EAn2u&5&Z(6phJL*(G&Ot z)o#SR?_N%i-HtH^=&P^~rDv~YR3d198SRVDeM$IRq+xUvE<%mcb+l+*h*V2%lT@7Fl}+vOyr^usqX zD!uG-!f3$)jKM$$!v{g(o$wJ#-CH;<06(QyT+M00Uih2Rvz(?5KsmyfUN+6?<%EQc zz>j=~uh@svp)C?JLOnPXbl5gdn?uYUKFaBor!mF{opCp(Q{Z=$PR4i?6#jBMqtf$H zhLkX;q7?SPhbS%F6wy!d30iprr^6pXn*}=Zf{0MwM}m&P-;Cg!M}Rg1(@`^=hF*@g z5Y)SZ()jq$>d`f8*NqP@A6vF|Xms70wd1SiXX~w6lZ=m#tREiEGLSb!9Q^lnE7y;l zIX>9GuAh`QRp)Ap`X*}=jmcUi;;K|O_K)@tjt&e~&V|hS*4goVz8sDrS5cJFC~F9q zhDQ6BJ4lmRbLHiO6XFtdwHY^?S@oZ*NAgeONwVBPWE$L(i zCLx2{fZHpbRP$T8Jid5YW9!!H%w$qS7Y$TMd26*bv86Uw$^3fO!1D2t{(-a03)j}F zlhsYrwehi5vp%!AGFa)UBqi6rfb!;AYhAOxd2_9~tT8{+(qb6e5Vs$$?2=rqNHhQ| z68wo&8*{ljIT>Nqu=OwB;9#jDBFg3NObM;;UtUS9V`eCqyE19dLRvuX>Xu3}kIf`U z!k||KhH|-2hoQfpLdXE|;H_<)ZSAO(7cS$@IlgYkYz-b7)ssr4=j`sD%0N^_Xf;?- zpO$(lS_h);3BQ@eu)0$2DlhDBHmf^^>vOFNYDT1!eoVAvt%-iUp$p0>i(I#XW{b*369;D6Gs#Z(MTlKl5gTI>{f|hGyNe9kc zX_9I3#8K8^C zHLLa39IE47YqCPCX?1$KF;Q(bn!M{`U%Oj{!7QdJH#c-l>W(Plc9H5O6wKv`#tckl zsUGNch72Vq4+{#*@jz0naH8hl9dI#qZuvqHCq?H3ji+#v?kk(}({{JGTND%GilJBu zMGoNzwU{o494W4l4=VD5d`8I$+?dOo8?DAUjpn4q4KQmc_tPO4o$Mwa+(t?lZDajh znXx_cM&T-v&N13Fg?B;+U9PYr*Uks;D$oNP9AcPbqv?0XhG*Cl&$2Qj^~I? zlYH{xl%QOl63!YehoqNa&g$={GX@L_5?A$02dqU$W%Iy@4 zR~lChMeP(-Fh^`fwK?TVDHIoAQJKtQ3B5HvgBqV*R*x4gF^a}^%lh$pW7GUpMOvb5 zGj-WH9TsGT`5G8&)v8-7gZgz9zPgfh`8!hu$6v%|zG+=G7PMDBtTq&sFUA~=@2KQ^ zncTU1rz_Vkny*gJ)pN5kKC*D(y2Mv}lSO(Q)bM^Lt;r{$mo8CP3NAr%d$^%2s?t4w zXtCNbBv0k8MHyat7=mJR*P?Mh2XpgOSX0|NTW!)|ti8=%nf5;agkHLexN3z`;Tt(B@<@=ur=TxMAaI zTs7$Gy0Sa$rqn2=Ts}A7=VY&UWG|OD=F63R*^%8zuIkGUl7%ljuy(+^gfIVTv^iNU zoQR13) zD-P31Cez6)g`c$=7EWy!;l%GIS*=)TdU9opn&raV!K(EqQs-thmM??P3fFfAY>?xO zB-3T(7Gc~rl*^;KDlD(JjgQD}x+A-jT-Eg)Bn!`TVC|se{b{s0Su8F$;bU&tM4LY1 zSJsZ~<+1~#TGq}9oMd;ftQ~-LK$~l>)QatfO_cQ-zp{2@FP9w{)v|U@;3T^P))#fh z0aypLx#mhOYd377tXKP$wIh4E?7*m&wQ~X|*&VRHC~F5`9nj{QE48fMu!*u>>Q~l| z?B%ipqgvL^37lki!1|)B9e{N}n`^GrvUbBJ%6f@kSv#_q%MOfcSvx0ilHCF8i?VhA z)&Xs+*`l}`NSxg9eT74>cpCZOXZ+HG_*BDnHiG&S$WFyGx{7#*OY85WqoQxxw|o& zWy-cO%Ho#6Wxv5{tEwwHR#mfJE$>RSnVO!)rFCGWy0wBi}_E)TzsoyJWUZVB3@n|LJjuvM1NL*Se zN%nOp@hkGIcTxFbn}r2h4e9#_)^{npYz~}eX>vvk3R!OY^gm+ll!D1(a^+_$RBha} zn|0WUVM=B8_LE+?~V-dS9;B|TFz z+vTOvTFX5V*I_=&oAFPSMYPwT*~(48FiT~7v1BaQAMN{Q6rcilrDHj;r$}JMjc%Tj zBnfhoX z`Wl~HGX^GflZ}kW|KQ)(=kRt%eQR}^j7$F%zpboor{A*=@f{b#9|Mu3ud8q6()m9) z_txr#HQ*%U@jv+Y;ta{yj;)&-P@VppbI}tmf{3`t@^opN&@e3I|o%oG;2Kz~*qB?39O-I`JzY<;en`>hK zh-GoMIHmkO)1Y$WnF&|||KtA`jcB*`jTc${gcfp8Z(;* z8}oSarZO}#lxpz@maj3+qq^24=gJ^7G*8!vf}(vH6u}Bib6Z+7tTvlr zwF01R5uz-p9kmd~SD7)4uTnrz8STpvNVF&{AhHH~$?^AV+tF@qg85Dt5yD{(hp%?a7?>e_F zg6coBwqs~!vbJ3-#QYkEilBgy2!mFAjv3Td9$;u!2*of~n`qS=GyKIgtswcDqt~U0Gpo2woYl@R5u2K+ z#CXx&;x+`ZS2TRnNwtH%f6-2IzPhhZnXFo|1%4xwO@^{PWf8;q#Hzkdl~kC~dc27X zQmT_|(4*y0Ai1!Xr>5uUwy>o+oj_@wKc5k6Jvtf6dZmd0s|ebk(0-}wb2)4#IZ1gN z6wx)x$i>Yy)lye_rCSSy<x|4H@1|syE8<$ zjaTgs+sZN(LG?33SPf=04u0rMnWz)e3ZhbNQvi^#P)_S%+-~fZT5A}(kQnp_<_fDm z(3s1JcHJtA^%L?Qtuw!aWL-7$(`A&9r(N#1tOlU{7g~GnI!aq%OJ?dr`lQ~h!%~x) z;)v4dt9`1kdS%@%lwzd)O@|S7OeAWSBeYaC^GXHZbm!+4P;ObBgI;jU@+ONVL^7CYkPYV?3+09e$~x#W|l`B^xL}r&2VX5VCCDveC-W+GWXW%Dsc} zQ_k~P5NS@+BPS+~W^G%oi5pU;-)HE%MOaxfD8LrWr18gz#x$OjH6_JU((AU=XD+NY z6X@xerumln`Z@3{o37XB`koBLlu*a37maO{nVH(Om-Nx;`OWniS@+r+MzmY#^Y8Sg zS+tm6#x1m|`ev=@9*iV~Gs81P3Ya7-To_4`%wFM^&PR9~NI6~MZi8}dJMP&}GR?T# zEg^7|(T`_wleVHW!r0LUZzS{#Qi6n@j%Zf|8p`$)OB?Zjdi~O9x9vQzfo|KWSu-q+ zaf%D#kG}WMOb*tjYwS_IcI+yxx3K5mJ0VZ^9KBnufv=_kwNv>bF*Ha+JIQfMXaia; z4P<4Bbtg&R8K{#*)tvyEPLbnxAiaGM#&)pvPLodu-fj5^UX#psk)0#l+&4M&j*cCZ zyQFll`ZhJ2yCFx_x<1G;X-)^^E5+LTxCu+Q^oFj-U6`)l zaZerjgeC}zyNqnx?T|L=Zql6gz9!8bor=NZknz8)ayyIE(!Ue|YU)|sWTJgeGb%RK z^(pBDu`w018YO3Y6BmK3D@ijdP&55Vnp=m{B9?C|h;!PSfsRHVeS|cbN3flSwgjXf zvU1dJ8YbADvg(Lv)m9FMw;0Mjb=pcUDVd4Vj5hnEd3B|35lX#1GBLkO!{u4l8C27> zo1E%hiRWl%=(Q#no#^{?>)|I!^Wsj5r1&VT4&&>XNQ!TyK5=1(@pVij#W&ilP1Uy} z5Mk%aw__qj`8r`kU(wy$mvS|hDVLl{sWHyZPmx;daZP~ntSf6gbaqWZH;LHI5nF3a zXYA4eMV}6>7YbU zbVF^UU@7U$w8OUOphQn}vMu~ja9c#BXm@XTgj6GZl8BPcm2a#D8HXz*N?12f2%=%| zxjk*QBzKEU?47(Vy-C*FQA^i05Tn^PSxOD&9C$H~%i}VXWN(EIHPt=)PROF|djv_I zBWiZIUFL@7WK>UTPN-)#NI5>u zy!LECw2u(aUh-u{(;PD+cCt3(b|pscoQEA$*B!Ee?(vai5a64vJlDd|c3J;u#Z`lQ z0@|91X22%hbW=zk?{z{H#Y0C(bL=iJJA`6`wP6V7h;-{UDO?>B$wCECCtK6($BwZL zo80dhTau(>p!cmiD>%k#ftf7)Iu7au%#O&UV+t4VOO08alQ_$FC?8j-Hc{n^oAp+0 zU1PYhdCt^InNGdRN92l%VHb7yL9FPGueRA5SZ=y1+*^_ENYbl3#f3?j*lk+_BGZ-G z-imZ%HbK$z0?RFWh*Dc>*z1(m_j37=OFWh_gX^POX>>JG?%ExA%airFJT{}v zYkvC!Ny#5b1mvrjP0^% z1SGf1oe<@W$8>|f9Y9uDSe2id9BH)b6E$NMF#4-hyNilpI9Bu0Dh#BMoHAm%iK%KK zB!%S^Lz0X>3jv|)6Bjh3kTo}7$#>$^qGg;bcUzCK0&gb+M&v#S+6RXQBeXWZ6RB~4n}>1qD@CnhkE8OAj;{Vgl3aGRS|X-w4#QM9KTrLo1=%(rIe z&C?wHd+6~%L=cn1IjUNHgH%%)PO&*D;j@8xead+R} zYSHt-hWSMLjEQebs;x~`Uda?a^r1<8jlm#em14M9Np2cN!(eT?y2DpRej=)4tk%Sx z&QbavnW23;L&<>~ef@5v1eJK=0 zyaiRLY>G&sDB?qfg-{fcLQ!DtnLW`|2t)xP6vHxh2Uy%lFNCD9sPdYb)s0DgySCak z5|Cf%DZ(XL-LK@lOqK&w|97-So?F9Q1M`N1~y zOM|gOGJs$e)==6&AX}h)5zs$0vklu*Z6Hu=P)G_;^s|Q=i=rqb1t{1961tYjr$!VJ z0t|czVp)03!6G|G2V?BkO2hCn@zmo;SE6s(7p&-4)a@U z&H989fq9oyhEPZfP^_(9Y(!uj?#ck#6+m^1Wz}e&WdtJcU->43o|_By4DOI99w9#A8Jo|`h1rSeixTZy65c7jHC&d`w`PZ8NT zd0-#9s6_+($UA1<>GJZRQDM)tlmMk_%Y{<3d5o|~doQw>o}KE5G=_@5XJlLWPOj9# zAI*S@2|`JF-cnU-S9_`3(ux|HdU@6#c`PIC8OBvq$5N2q^=M0!6i$)%QUru@0$jW7ql61Fv zE%+Vzkscq5uPR&ePBdnBH0ztUNG+uNdmO?kl9CSf z6ekytK+dw~CFf*q^yI%Z)=2jycyzL#MCU-$zab~mVZjzVD{A1uT#Z?(qWPUY{g!y3 z+z@!Cf)=(4?V<$Tw(iP9Po=wCo?LfG9+0us>0-!aV4V>MTx`L)7%tUhoe~IaY$>`J zHrZyK5eHmsmAe=&#mhP*56IZkbunbJ#X2JnxT5v!V#pMmbxb1AMeE!hMAtEiK*tuq zJBY1A@_?2?(9tD%7i7jkh-|Y?2&0(TL*hDE(jYF6jmeqdtL|dYz$K$O`v=YHCq=ZfYJ|xi({xgNgZuq_*Vp!4g?4 z@_N4EXRN^3(;0rono>5MX z$e1i9*2Vspus@V$0e0mU zo)a^>?`jZ87ckN7O8q#yj-uBtF{4B$wpnB*+0ADx&(>-eI?2js6gS4#HR#!Qvrts8 zfx$Dn&Pb|PG^F=PNPFF7wPve6RiCKhyrbS|C^A$3E6=_5wj9NtdI=alGzaqEHC%#AtZiWObErWtUkM?)?~LJ46cH! zN&|z6O7}G7iRs3iXfX8hQGcajku!gJQ+;M~U4vbDF$(4tN}l9;rYcu)m2H+D>8Iz} z=!TF{7v?hXj>JxFq(tvx6fa56;XPoJ)F;?9>Ebqn(NJr{|b#;QT; z3v5E!yw1jul#e49`o+{vI_nW9rfb!i`PoYP$FY97E6m|y{c4T~+Vz@PX#E|o&b9dJ zT^5S8faJhQd(T>Z8@h~ChT%7oq#Q2R2d`*0wr0ezj=Fz6#(21nIn_Xfj(B~9cE`?X zqFz1)l1fhsm-p{_7S^*nYl{vB(N5kuO*D4UtCs|7O@vIau@O7+s4EI(L4pp9ayWCP zNp&kv9IIcHXN#|ZCxqb z(&{xz1L4TW_^4UqhR7Z(N!mU&2j-`ya1CAqLg|-tIazDen5a(27d+D<$NHf-sid?` za^k0wO-`PcXy>Dncz(xNH2IWm)KwlQUX+DZB3<@TXEJW=iCk^T7=+q*le}lSvSU1x zR|rljjSs%EHdOB#+qkF{J}1gbNtdjhPe@|-anp{6ay8Z`#UG8Xn@-lm}251KJg)lF~MbCK#fF z?Q}(_#*>F?{p*!SJ=;mj_TwxHv27t~O!7we=zNmVe2ulLc(KotO3{UyCaoZ~o7~Hu zX^oyx)pe6>Q=^Q`q!kuDr?OU(WwEc4SozZ{n$YEmg_36C}# ztp=jlXKD;a0MZ20fs;yOkMX4IUPh9Qi}r$MOjtXUnk5%j*8A_6)z0!$vh=Vbl~m4P zZEm7jpT(|n##%!eWDd;KVm7vP3FPzA6}4>1t7~cc-|1>p>KD3xrjEOMQnEZfY7tp(SF!gS^Q0+-W)lWR$g-MD%7nQ4=A6JRTgk6Mf8>>hU*$aJv%oho z>u4rBv58-fUs#`>X1~r6<==dtequ{);zIGW@(2ID)o4}YNmsR;)5RPlipG6YW*OgnSOqzyweDV6h%#ByJ%Y$g3 z*5b6E`ZFh7T20MrC0+ae?|@cVAcclD?%qJxkT^yP`iA^)2mP z!v1~!9_NRIT=n~aeEJUodF5-`_q>oCxob$i47z-`kc6PYzX{31pcCE`l8?MQ zBv}pBIwZ*M#J^pqpPEk~h67B>Uj= zl3hY_BW!cil8_v|G$ao$h7CctEdu6qfeCcmM*If4b3JT!c1WIH2U(zlHy|zO>~lhL z55C_t7Ls3pZdeX0l19XJg8f!3ZGlCP}_$<=3tz7&%CzZ#MY?gsATLvsEBA^GY4A$b6w*Bu8N?}y*; z_dWfP-4~Kuk(VoX56OaKQ1-CFb$i1WD2ppk3CZjB0)_$Deo2WuzM@1{EH9B=mzKzR zXOzh8`1c|B{!)DZz+j2ox)^xy?``<^9;d@6D&X%gkxTG-OSwe$8z_;tO4BpAE_OkHIft*O3>&hM;$Y@6MN& z$mK6WxjY7&9bO_m--gXW_x&8@@(cLUH&ORagzT4uWcXnG2D)KEi5!XF_l5qaA#d=& zkbEC>AMCw-Ij}5)A8!uHyHHOK+^a->{VSB~HTeCVA-QTQB$X=s7IX{ha@PcWY76`i zpVyCvWEap~s2@)p4POd@DL}qa-)BDw*z-qd zKYHQgM*;sUP|gpAWVauq?)((LgYU_ogyfKiVdIB@AG8Gz=i{th;H68VSC z@7uRT`al=_8hQ8)+NQ^mSI}VxqTT!-@B`0=&xhpOpFz2OHY9t%9`8b4&qp4=f;3>rdttwK4jMEb+fPaF<=^`KnPZq1@x zTByfQqW?MuHb3|{)QL-xcjRpZnD0V9S0FF@AkUXILsCIr_d_1fM&7o+0WvOzt*6nx zBcJympI5yOvXTEgk=Of>*E^Bd*Z(WpwR=PI>RVCXpFn=_dG-GS{}Um3FZ~|narp_r zj(WQdK5z&8{u%sz_CaWuk;kq{_+DR$9E5h|X!N_A(C7By??ul?+qE0=a5*sEk9@-a znkNDW(ha`^Z79;60RK2_Z}{XN(J%f6{nLAa^(7^8E@&azjM;CX-G}eob1m}vcKAN> zKHUWyzZ7-_H4lN!KsVN4&v&5g9|Nwh!cU)tKNGY^pc{V+e+Kou0R9M?eIe=_Xvsb$ z@?q${9iPLH|LEN)Q~2EQXJAM4`CaJq@A)*+eFyE`mw^Lx^QS=Y>jO|{uYNiDOVGd@ zVb?v;#_oZ(7Bsv&`gG*`yZF5FcKH3rVZ$Gwe35qTJJBa!gEDv@>L2oY`M;r_{t%xp zLpzH0?#6>l4&C^E0m|VOsQdVQ7IeTAY=wMIzYOid%kdj%AN<}r6y*Wh2Hy!c zqpwGw@-+I0yU_mge@os&-c8<19w)yfVNeQg4n7t<68t*& zP4Ij24EY0jUbt)cd<>`t!{yIT6{%~bD6s`(CAABL$5Uvl;4qp|%I@}nZ z8=e;~4$cZ*92^$hL{+k;O8cLe8z&bR`C?@yOG^V81{u_vPbxmFbI3Y4dfiMj;tqVlUI^s$Z_OYG8z0nSQMTVzJ_cJ zHUwt`D}sSwS@4r!Q!o*{f*cYY6}&V!GWcmQM%I!wWR#pmM#zD|p~0)jtI0XR*}-FE z1v!JPBwgVH!GpmMf(5~`!GDt11}BC+;o;#!=@-X=sc~kJ_;4gz8lJ4+D zVQ@U?lh>`5k$R^pZYu66q#A?=8lQYRGGDOY`UKPA1cy%xy z{5RP$@Tl;}@Q83paB}!8=_khpCj<`%za|^WxnwL@L>7}Jh~5 zU*s3${NSI1vG8bCEp?Ul7A)lk=w|} z$v=>r$+yYB5ftA4Z!dOYd-0;+fZ%0h-(a8M1;Kvg5c0xc|KJzFZ-Zsw?%_bVcW`F- zn(+C-e!+92UD-28T9&;6Tif!bz}UKw|KGl-?aLlg3-gtrQ*F%d!Jn&@*)6z++!@F% z%|8WsZOxYh+S-hUYr?z8>hSaAPV!~)1@bBKMRGs+9{C*kC-PbHY4RB|9Nt0hA>Sn5 zB3~o_LT)FYApb~iA)h3-l8=&)k&*B#$=&3u9hX<4J0r@|O67%PEu2W+ zJWf9l2y-ymO-TMl7yaVZ*|Y@P`(hmz5pAC+S#SrycZQV2#wWuZp*yD6;dV?aKrf35 zifv3w#e~h~3Ld?Ue#K>txmI(YUUnWIsLs{!R2Dr=L`&TyfR?Vh-)iSoJ;5dwoVw?% z+#s>Uo2qm5iE-ozE?OB}UtTz|rP>^CHLG=m-x;jTwI(YS=%`NPbH`~lN8>!0UyxT)Ifn_7kJ=(nnyaFvcpg+6+svASux#u_K; z0JcgwwxvGRia5v9l|<*`xe3%97^JV!*mNm9+MPOdD*|iM3_}E!=Gr0J5ZlJTWvcsso5g^8?K3KsmMa9{9II3(~wdu?L zE|*yLS1xsEWGMTSoKVZa)1Fz|!9rq>R_i!P6kW8_@-u<_Npl#@JssDReh?z^Fuvsq zdAi?u%Iq@*bh8af3f|C$1c&@arJBcSb7N~-o)xg@FL$T9#vH!r)RgGq%-m5|VP=qF z8IFQ5&s8L-dacQ%BQU%ikbOe}1*?H4g3F~wZ#Gma*~U?KtW3z)B#us;QG}Xbxl#in zZXGq72G$6G;nzq@`pMLE{mDGKN*SWG*~0>I9#-wtSV5_Yjmq>XO+(1&Yyu80*w7>y&~=%T zjC7Bj{ABG#dHxLDC;w6H!4kRJzKAFB?1M~?62Ug6KF0Rq2$G@oV;9pc7?lPxZkdwo z@!vIdUt&qMJ;^WDWSJI0N~g96$q$;EBKYh%BsTv~R?Xv5J7Ew=&+`A|&FDyEdby38psVSsmHFHOpg| z%4HdCJub(nmX*Hy)mqHh6YIHCowAlm(?9F^G^6`$-m_!yERUuG*J|XAoqg2H?TNq| z(agV(&xNDt97%M7cvK@ar7PDGT}zXsLX7VbX+q-0UA*ma(8Jpv2S(BMEcME%8+Y-X zI_Tj!bzl@Z?NbqS*2hC)no$yG>+R`V2hlqG zYA;uC<1X$B4tlsNI4}xV81c%f8+Y-XI_Tj!bzl@ZUE`HgH}2v&bcA*+I_i~E zH}2v&bcA*+x-o8$G#e(F4%UrZXS`_2<|?4*jLkt0HLh)7Jc_l8Oe7_YG<3xi1v#RR+hf#LX#)v+ z+cHYt86fRPqo&#DO#BQgDL* z=tX1JcQT?63tZ%FkjSk&7WIgQ!tzJa72)V$BrWz>R2xXR_jWD{8VkYYkAuVLSp2Ri zc8@=fs9-u7`$xo`F@Z5fuMyQ(q<3j8OtScDPZZb81jN{k2zTvV6f+jw&L0Q&l8!~j zqk(t4L2wKmi`f&sE+b;?nBcHG$!LPt)=~*vydp`=-l^9lp%2nPx)PSl1SQu^6e${I z{-YSL(2|;G*|Y}|FrH%PVc33X_L1e(l9Sz) zUMw5JX5^+91k6~|oCct2HXnfkqOhTD?{&!Fe0((z`P45v8v_!>*`e>2&#h~?VAwE( ziIi^C9fPoksGvbC)*qN29A!JA_`$VyX+e*jgRFT5b zW^JmzJ#WXF?(PYIi4*Dny z^6mHhzQUhvqopV4%IvVSW#Ya*eu6gdd3A^9jn#+tOdSq=ZcpXRW`XlGw$4_YHK4bz z(5_s#a2>VcgeyOmbUpcL&GJoBsCIcNi-j`X^bVnfbi0k4v} zAJG+R(>26VQu5IT4ud2gKzRWH%ZNN!opz~_QSal-AJt$Fe$o5*Bq`kcI4g@9U(R25 zXu^cSw$I`&2y^Im9HJkc8FNgN7zb|_OH3YBE*R`F=IKlQk^n=y}bKM~AVARu=2eAj9apv3Z=s1u~6|nW_3_ zabD6_C+#W$o3-+qyH98(1xIbFIzP?ahn=4=C|VJ-o1ZP`PmD9Qjd|R=)m967Qc&l5 zXedS^Thr6A%+RT0vX-VMLbn1Dzgt?htIcXxM{0Loj2vo`IG%}%uN%Og#MbSz!t_3E z5Yi`v49)0GWvUA(A^KiE%?yqmYprZh$r)0=_?3_%7 zXv1~pHwcK!jUEq}!A6ZKug>W^(d@)v(j&xV8z#TL=3G=~LlvcQa2c<(B~;YY^nUF| z#P>;t=mrbNV|ROMRmWf*!8P&D$c|*eWn;flLFC4HG2r+jSIt-*4Dw?ai_>?)MMm+| zN^8x0YZd|03{4f*PRHwwP4iO~(Kwl7v?N0c>%uU>9GX*I0^3{;tGTfvPht<)qsDBpD_g&J{En|PHz~s(~*SX+RWzG7HxMilu|aQ z=Zf>t+*WJGLmz`f1d`wGYrwmzrPr0e&_tMdcP`Sk>P)+BPcoFw8xgTbcg zW4%Qo!4RKhA}C&tdMwbT5a*|HhK!L0op9Sq&bU^|ORYXr&xX4l>*pKn^vAKWVJct$ z1X9E{*FWEC#G@qR2x)|R?*)xIz5g&XV_GUU9~q05iVI1gK4T3bg=MD6^nw6Aa3BqB zsSG0%L>hvY@TioYCpf1c2G@}M%>GM+}I3+k&-CT>x!!XS- zA2s1Fddi{ z*=BufwYg&@c21{hx1#F_gjPE9a@f_R2RZq1p2l3OS*va}J&c*Wg9#KaqEp__Qcch7 zL`W{eQ=pLH$z^P1eSmJQ2H3_?t6Y`qn>!j=f(-LpZ8p*`xQLvHl&th=M4Sc8-uBG5CsyyLO<`)J6KEdtGeSHrMA`7}E1fXxobCU0$=s?jEG)_RX5H zUr1I)Xj5Zh6jn4zqMc}zTw4tMcNzz=t*vKv*g(@kM{5y0Xrd~a4~sSJSF#kw?;E5U z(=tt?KBSJ1%S8ZmS+{g{k^3^Mm`6)ojdl-4ptx?_DVgvGK4O z7S*(x5BmJ=#3~V$V7ZS-+izo65(`+@(2tR1Pm{9c$R6de(79=Z??&ThX^8l?W5Gky z`C8cIHlHmvl5Szs(wt#sGb#+s{wyyg8k^K;L;!>ib3gb*R6XOvH<|K> z560-2aNUld-HW-{@fmZO;gN#z5#buP12?qi(}*5vENjft1G^@tP!ueyHCy$mI!^Cn z1Z0{vn`#J3g||hmf?^^mwm|SwnbJkX2cxbqCg?A1wNY(nR3g! zR7l_xW$gxDP+=1aKhT8wt-j!y&oT^hdekuxJR zkD*C)VsvAoi}soUSUlF0G3rA6o z7drY!t>=CDBx7!V6Q=PrzJS~@~ZIMU0F>aVovX(p8={;@evFJ;j> zYUcQmy|tmhby+JJFf!xa-L z5`W2WeDXW0`ftbQ(%4K$S%wB&G#e; zUqz7rrV~_YdYS$yn@=1fJ5RMlVQDoc(|?c8H0EZj6E)NK za@HXd669~TrLkTtz8D``J-TM?y79r~W6RbKjjmg>R+J+dA0JsiJe*~~5B06H<9I<{ zxq;+*lZwBaNiTxx<=Fb)q!ytk?wlan9u)Y;thOwWj~{)Nub#Prv)LElNv?LHYQP$pR|?JcLx!fRxBe!ZFSN=Yie$WCHH`K%EyfrDCOV? zhtJIv3 zp0<=r=CP+d($?098m>l&ik(o`!^cVZ#93Lsa0$g03%B+BJjfb7hniWba1F~A>rqDq z0)BSd?-HUd7V11!VE$q-uV%6yyO+Aq+?SoVn>cj?3QMMKV+)R5SI+u@hFy(*%wbED z8h%(Dkf$^s7BWD7X3s}^vG=9aO5TbfQ;z(JdA0S9)~ z0vqFokR8SxR9YRw$jmK`u5VJN%&uZOb7;Upn`}r2cGZxMA?!r^JHA+1lhJeo}uH>%m7ksso8}3Yi@Fp0|U_1G(i=vnHfk7EWY8;+GUBu_6`mR zYx29T+G{&K7&VDCZOoKKiWMT(h{;jKaa>eHysR75tb!pQ(^AqNfHhmskV&z`BH7=FRahIV!q3sDNF!O^53a&_s3ow&J zwN;?cT^T_+T8qhWfn<;u#Y&E?-+pLHRYWmJvfbMaQyJswM6k+4n0SrCDP*NNnTvho z!!Y6|M@5s6Uh0W8jn(KoimbvelhOdKH_qEdUX4x>eO;#4}B zl1-T!&g;^2J{F~vmCg&74wB(|6K-corw<(Fg3%Z|%_%om9Tls>6;pBBuAb@jZg$Z$ za(+P6pY$=_N>62wUQO;u7|aAvTyNva-^Tt8@rxY^-@0}~VkRPZ>DiB=r2}IYNG+}1 z!0=SL%QK1QaR3jJsRDA8$bxo>lrE8B&>8Z0HJ*tItuZDuW~V5f${ZUja(N*%qpaj{ zN>$Iq%ED7h#cSuw2+YR2#8Xcqw5Ed6%;_Lhk1{Kg@v&f=LU$e4?;HFnZBrk@V*tt> zupFo}+ka^I8`F~&)6$G{Y|aRBPJ~X0t7&-&BN--4OgH9g(IIF3IvMQ|4E)*L%bbnr zM$?>c*EpR#P?*S1KCeV6mkoEfB*}@e(m&W4a8!OjCDx@Z~B>YT1#*Wz6EJ-APndyW!&? z!|mO!%f zI^jk<4sYm{@g%4kNoL#4AtRF%YveffC7 z2&YO7_7lPM1B25358yk+TTS$^$Gde#GrAp~O_YZ>RAo-= zRY_ZJ1lEMt=5Q!f>Evo&T(fp%N|gt>jPOKpXf)#`fTB<0Wwh}W+{JC{iw?;>wAv%d z7^;N)(nOMF_U5E+lxeP8y)2fNWD4hqtx}qzaa$8nY++k-Egh}4QeuPdFqp6ukeWOp@Co0Uo2d|Ld+Zh?RubHPq*z%7B~--nQ-EISle-GWhv2yL3HBC z@cM05d6aB0H)gFy7d?}%J(`Ar1&eblr?JMbO&D$M6ue#hjHOrASEC==>CKfd?tG4z8rY5)C)ua%q#`-Ha_aCT;<-YMrt5ml7I!KVNrxJ=MXvO4DF) zG>?dts~R9GTl+{!EoQ1ON~W(nS@vk1!LG$LACk8~F*Bv=JF#w&FGns#rC!8II}}e> zEfSZ_&77#ZZ3)b}mNWsj7oEY!Q*&x+Hc6!3c?_abqjIkp8pbiYR;cJCb(2~HI1!Og zagu_OcatLYjArYcP~0>#WC~*hWkU{CF9(Sbh-54luRxL?T^C)65|P(ErO@e^iNeu& zBV@K1y%I})q+Y@75wAB&QYhxGv>i}LPU7*l2)+?weXI(0h-bXs*fc*SAK@`Fv-lp8 zMEjh~;1}||j%wmU)TJR^WZy_{`|*8+fDT0Y^%P}|^&82Wq1&v}#G{p|nYrW$OfNlkcUsH1VUu-|Hb z5@iVQ8;C7!*O0@03Zz-PR2CGRON8Kp@LW`A0XE~ny+uM1N0v&26$wb35!QBC;*6yB zgA->&6%A1=31sbSc3c$)DvntvY~hL%F3Xi_^+a2K=;A~uVjO4Bi%R#uyuujAV*P>{ z$H{adjpHAUU1YMXmQ>KZ@W#1PleNj5P{*;PofPocBA?DMv}AuCpq;#DO%-`For%-w<_D?)YmtT1>Jp^;-=hw#O6 zAYvNZ(I+jBE9{kGz3z;7TOpHGweh}ly2Z$bTh8V(Cvhs9xNtgGGY-sHv|{bflKC>2 zya2`0W8$j`qk#HC!x>A91DrY4Mxwnnt>4Hu0F7ytsiu}o55#n6BMQMBl@}Fg<4onQ zP&j5urR9n+?Vk*D6CTG`65|+aIjKi9yN-#JoIAx?&JI7-0(KJ8ky|c^8k-X&QEH*{ znNu#PJG7A>zBw+oLP4ApDej@1lQiOVUuGZ!r;7qQOU#CIdGJp)WCsi=g=#i;j=22J zgFB~nu%OWCmJ*OGYTN@oC&~)OX_ls`$ZS3Hw9w%Y4LVsrm#U6eI(Z!6kT8GQ-495Bu@!%K6eOmpY!*tBNTW_b}EG!1NbfKgkb4MAPCpnfx1# z;;c(40%ohfO*EoQ%IQSd)JvZEWSjbFjwGtKDpGu(1!9P>ttM~Q=+ahN8DEus%ChTUEusrSZ3Q-_t1Ey6!!wZ%-EQpX$_+aOMLi7WumtU)oFv%h8jRwMOS+I1igJmTBLWuot6gR{TqRblgSItfCnk$jyJhaX~jtwyVw zG6n9VZxw{8KoB_+I=?3ohai|Dw*ozDmkF^F^GD7rj#GyttKumWntkO){PoYg~T(%gEQ? z5RK@^N7fGykFQ&~e&o#Y!TxpqB>Mh@$?5467vR6{zOL>ieM@_KmeRkH|GJ`o_ATv= z{&oHy!$FC>?afz@?HLfV8)5$iCrs8h&2L^f#{VRwAOE;Y{1JUt$i4$7)F-R0>cSrJ z(*gL$w?IFRz9`|dLb|>j@hytJCVSx@e*_6W`hA5g_;QHP{mAb0PqL?!siVmL`#vAv zQF-(~ntt!K`>n1|G#hh`sn&v{*S>PW@X*Ma?AO%)C^Jn+1rV|e``5ns|MS?tBrT*u zU$_C*z1RMb{1N!LI+}w1N5O?eWVu2JgS$n1!!k!xl*BiElm}msnCGPA8~XhM`oHKu zDxHv}(O>i20;eOEUHA zdr-g&S#LE<{W?h)in=1LU-Exa{pu6nQ@-zrKcdf$TG!R0Mo09u=u%=GF;$5a`?Nl<)bp4UFMbYc42Omr5h(p&*tyS9%jRg~V=TCBI$YM^?)KxKMmX^56t z|N1cu;bu0EFKf(T95_GGYBa~`d<&=1QWe14W{VAewgl*Q%R@(-2o}$s2Xm7wBRjv7 zPc1gI5p-O$y9*BN#TG{q4@^@YMB9Ts98u`b_Z2Uv?%tlrjnp=D7RdH=Mur8b0&f!* zDc?ngKB^n|_j18sxOG@;Xtn5|aBmj`eC<~@f`4rjg_!a$I&|8{5kuM#5+J9Vw#YD+ z=>moqxL_#S9$Na`eT9A=-Kp3x%DZ%IJuFW z?5|=fGC1)r#U&@{`&+t-a6ntQQik$IwAe5LpwsOa2}IdbIgyi8DxDjNFENzaX+UzI zK#~_x+|=d!+r`i)oB}j2c1EM^`2DdMyk;@5928^W!!S)u!p_;m&^ppd_)8pcbjBLp zU818>M;mlW=wOb*)&fQjs~ZXRR&d3FKIN4fxcat;w(-PEBZRv9iDC}Kj=V`qiMPir zG1Tg1u+bs82z0h7j%ks>i;oAUmqnN|x4?x-(naEJk&_Jd`6y_AxkY>7_SKMUT6bT; z^|G_0hV!*p<`iuI(BEuZ=IA}hcYtCl6L-W@~qQOj!?2m!&g(ltF#@g53CmCk&3!(W4ljfAE zeRbN}nIpMQ-A#%PttZ;rnWHS)Q_S(!dSd;WD@wE#=ukf#Z+)iv;gf-(*9k*(!6CC`>s=a# zQ7IjZ_vIl;FY5W!Ql9pdBlzarHZxiz>()dCk6l5z%$6w(Z+qBQJ{CJ;;&5nwi`vkadA7!eO>&&(qHek_SIM;^N(_@kAWszQ-FWxD6 zwyj7G8g&niufhd<8hVk1TaX;ge?@Y!A@_9cczG^@(f$pUbGwV9u(jSW8X$%8NSsQi0(C*Pb=gdemdt=0M29AzFi{h}2u!dzEhE0m1`fVp!Rx|zG%85nW zc8=OZ6h>yKq4bp2hz6PC=5Y#^GZmi3Y`uGhM6lyW(L{g%<;I!S+a)1s(m z+n&LCu31&8F}JUO*-H6ru2Z{bP&BW$74mbqUiVe|6c}$CSXQYwa4hK+@=jRZ;OBIe zdL!4mGghe$;}AOAJ(p|Mtx|U&zqY>jRa~=ml{i(%{`K0j5Ay0*zh)hDC+Gb&vTn`H zTch4P@3xhO^CJDJl^u;*-+E;mZ;o@VJ1f7IGY{uSn$z=aO@{sLY^l@LNUu86?SxjF zoi}lqvb(7w>oKewrqH*)~ zrKN`bHF|rnq2eptu=(04*8O8nQ6HngiATI4o{`wo`zwmC&e5n9L&VfIEj#^c0|N zmFaaHg$6+9W?8l!gTLVVb?d2}>>&($ZS)!<0x!vvDSvvyWKGOE8QFZ%NUDhUADtE zv5oQGB;(MmS=yoaTEtdM-W(xGt=8HBc-Io!nc>Shf}L&!TTA*^5r*^{uH6jY%&SJ2gs=qSA;IP6QbtHXa6v!URmde9>MZ`Atd8>@e zHWV~=Y!Wi3brDXC0c;lurxW2q_ z0#BEYx0=;@Ypya_nQKi}DhP>Iot|z?RPpu=zQZj=_I1(KF0q)Nn&Z+Fb630OVW-Z( z-tLN`12Zt2Z(YN1EPW36);m0qJXd||TGu@6RNs21D~b;IR(H1;e5va-$qD)9cb2Cr>tLfOLtU=43a5bJleUIoPO z(jazQ_yycFV+XL>X7GO_u-evuX+&ri(n{(-y?b_Bd-raJV)b*Ny?c)blILoB_g>dL z?9}$|eXb}v(B9d6>w1P`D5f9rwdx$0XtxaMJ}`qukhQS4;jx{={n^BnN4zwiIXjqUeO@Th^IA#&DdQ z@A-x2w6=GIy{q(b9j^3@)B%(U|+Zp_Hq%pmL zzGy(&P)0XctW~hpz|R;Ftcy14((1kQZ}G3sM%ty^M&c`#!ge>Dj-H5;<&Z2Nn-p~a)G7=B)8Pi;k~mHL*k?MC7kBAq)WuVQIAWoddJ z?~6ijdc!%LS$_)~%J*<+y;EpaH<^p;G@O&BFT#E)(y7^4F0R*-*Dq7O%TTV_D5a7E z`Hy03C+Gi(>1@nQ)i-OS?(|@pT^!cJRN}!xZF18alU!h~o6%87#uVM}WFJk#( z;CpVd+XS|A=>JTyteNSbXwh)5y1p8L=uP3tdn;Wu&bwqA`QJ`<>h2PUF4P^K4e-so z6m02!4)@tM&~2P#!=D}X)J+C^D&5@$aV|CZGCgJYRgRN+vjitHOQn)y!L$jz+m!Au z(QKl7gH51HQUL`Z*nw)^*O{a^)ZQe-LsvSzbAvD4YPP7vb{O; zEskh;vx)ONCNIIcBwZt#2^Qduth-AzqG~&}9xcGPWn?a9GN8;nobHX%)?5B7M>#aJ zt=_8n8*r!gmiH>y3YoBYZ)sSkpb@;j!*Q-^)Y}98 z<%GVyy{#YlcaCzTJs(T~^DbFi9sa(AteE|ZqO|oR{}G{VwCWRo9uG9nx*kxl6|-UC zS(m6NsWlpUgZc*%&Uw5fTAwgBg{uq$h0Jiqw|>}Wt`Dl%T#RVKnHkXd;~5xb1|O*WhZ9-ma)u#a+GJy*W0mQ(H6$m4*p0&R?L1y zQQG!9f6P&?tzK-bzlMU%RNppw5mB(J_t7_e9!_u-GG0;J+1|_lNrbT$O>z5Mt=iUE zvmX|JQ`j~l_^APni}{KpvqeJsnLxIsI=7{w!Lu^8EYgN2iR~iQlW3g2N4WN}T60^i zIr3-g@4Lm~n~Lx}ApE%op~gyo!nIc0+W9XyTDHNcE6fbcR2B5?J#8QfW&ssCn3CMU7I z(cf%Vclex<5bOHcr=c@LA^)1%BQ}&(%#*IX5g}yA)PpCu6wEG| z>K1Y{h3xH-UHY285gz%!5vGyq*4o^_I1tr=FJF&u`GRB2_fMNE~dg~S8cQW-%6-Po3*L>_KNU#-QJ3&MEh`Eve-Vl zZJhEuf1E=_@z~zYe2U?j5(glnd!yO2=KZu;#gHj={K4DXyDcwM{+|z)LYEkd=E8Qe z( z|1;|^ZUM1unX&+ln-|y+?DX;vbG6eLSMnh({}Xn$*?EcSug^@bYm7Fqrfi%GkB^`t zoRL}h@f|bRZm{o?#*&=}cL>Ev;#fn5~J7^zIEOgwR zg5y0->h9COg|Y*9Uf_$T(Ac|ZPHY~xuUAfrkN<3MvcHgHnZW~Hwx%Bwcf*2JrqF%s zgKe(0pC7u;U7PjxTwB||zjH2%)@R#{?*L~M#XZh8<9bnq!+6LRJ#D6|_b!hmmX_^6 z3BkI?%Enyou(Ruo!tH@!^i@I2_F@g5Y`=@4XaD-@CnU9<+-;$R)jM<=s8umZcKC5=u{VTz4U zY*B4qN^LM%n-&X&wp|6&`fp~b)w@2~{N)fIgoS65He0yq8Iq%EW8$NI~{T;$8*tqZN65?z66d)%&BRjcU`lM*A8Ra?YC4c z+XlUr;wvbIo|V46dblIH3NU}u#{cTT zJm2<8%@GD{qIK7816jfOTh1^Np||ReG@wiG`p4F?Lh~Mz7)AnpKz0=EdqtU=p6}?P zbI_tav2ZN4#iS=pkB+U=KQlR4o37zTkK$l$7oxAFY|#W?nTN8y!u0kt+n&cU4C9Qc z4aJeH4XFXQuZ3*$?_-(vi{`7-E@R4_yW(@47nb7VTid+ocuy=ld&TDjUp&v*6`vEm za#DQ$Z94_rm0+nmOsTT&@7)sETB~k`X8UY)W|H;P?KG(USe+_5=IZX!pYt0H&VTYl=eg1)1^NJhG**^g7OX1MHBFw2q;T<ma*oQVW62)H- zwZ&;a&4#G(N|7y+(CIeKXgnhmWwP(pBvkD_;_Z~(zkuH zoxC|iATyjk>crVA+j~$e75!uNOKO?!7p0S)X8BscHeMf!5ZKyuK#*GUZXPpOcV;JZ z+1D4T?Iqt;Z6Qr}(Y}amd;4dqh?X_xXY|*4J5YwUTNlGR9K0X1T?@%NmVfIk4i2T- z!qda^q8XZ*tl<`j9*DU+E82J1);rdy2K5 zZ{geNwi(Ge0@ZW_rxSI7kkfg- zX=DJ;FFdcby(RdX2-lgl9a>xlV~K@=^su0fQWclE)b$p6ll(jh8}OZ7ou03aR_kcz zqmEf;NCV&wl&)cQk-q;to*?DpKOHjjiR;2Mb=yqz{0Q4{b*{yqeNA_hWAvswk@_F` z-)`>$8&01tgKerpe|@G_aqou;dzNj-W0Qo5Pp&e+3eOpAC&(v+egx8G{ogm_2fN`WBMBC2VMG z3hx!$R(hIF$kN8~t+Te-+nj=6u-?Q3q|w|V8_8&x)X>`7n`}4iTLKq*Y9YI7a7IeG zw@oZ~Hd`CJEsgEZ+Q!;;nlFx#)@NF4=3BG##*H3qGLP3A zo93q~g-71D`Qr8%QKQws-Tlm}D%QgakIF25wIkAxi~G}mj=tM=rs@ARcb(C395+}| znw=hZ$4z$RZYMn6iIx(_A}LCdY^stjiTxgPCYR(zliqRDN4f;;)~}#^2Ls13e7&Wy+JD zy3{fTaxTmr&b@3dlkkLHVJgyZpNsA9-DQH~e(R8#Pb2&c0}r&|*q(a_={^}g=M=+< zs{a|{h~Sfp*q2@43E$Ub(@%CPFka7h)Rws$m^jQ zD|!a1y73Q|3|GnaFq1=8YvT-KEup4`tN3}iX0dz#j!nL}#&#;irzg=ddI9XnBl0}# zi-Hn7KW>)wBQxwG&N`f+>dzpMFW%%)>KFB>e%S_}WR(HEf#x|f3H$eGgO%St=VV9q z$As70>C~o`ox2z~K1RsV7MN7uxe3~j&2uTJc$I3+xy}}IBCI0Tw>>V$DKkgBK?wF| zIs5o{myKVof?05{us$KjA}g`uWkOx32X}sPKGG9imVQ}L?83i0;+7hFV4hT%UEV^3 zdL@;L4)#rJbr)dtWSi0GGQLDrRF&{1;_p}@zmD4F=X$i?Wrne8K+W49~ycZ<*bU#!7S4=Q;F5ct} zD}IJo1H)%z3{^SIuyL!Qa|*t|WA(T)-pDfzu6@v}qJvTkwu+l{k&)$%>;`#0E1YBS zx5G_wcy`9`%2tdG;nb`Y@Xa@?=Y?>{da%uAY~XW>@tGJ&=@5DcS+5d!a&mjFj3=bMQ1Vjb3QqqSF9E%VY~cA*xX)8UsPyZw!Yg<-t3iF>!& zrA%(+bok|n4BY@Tc3~(gZtlJ_c=d#@d_L^WD_9QUXDL^K_DYTIP9=a4tlNiAoS{z9 zh4_o&zU^0;+{^-5vnZs5lbox*cr`LvtS8g+SY_bJ%#xrpQ7K!ECCYf|F}4%cb%hG2HV_LA5!d|~K~id_`#C!7v=Skk_r5bqs#TD_@J)G+Oy431rJp z`@+?;lj$o1(1a03^~K?_%Qvr|p0CGKNnCFvZFrWioy@>M+4TQrn~YemxhVv17x1QC zqulNm+R@6OP8ge#Y=9)+(PgyI{6CZ>QS~wg%-<4#fAr)U&xXfmTz&NiQU=pe`$lIi!Cs|MqIQQd6wD-E`$HY9y*?t<8V%`&Mkrt2rL^l2zKI2Jr2I*!%e~v zPPhoo$LKO9i@_)`_;Sji-C8)P#vMaW*vSvUGzWP6J3sH(9_%9C7lP47VDy#3j7G;o zd2s!0UoFmqehg0>{cw4fujLqZ`z+kcTYIxYwMU0zmiFL;l&|;4$lf-wl(Gb`B5VpyQ2Q3Hza7CF4Bo()yBY}86wcayyUPmB zp-!ydmd+MFJgjoi?voJW{ouZz@ANoWQ5jqpQz;kcB2KzjT$KJ@mXVtx5MwiO!S_h) zvi5@O)&0Ikr^Z2UFJbjW?OX-Ek{=Yo53Y{me6t^F20PPxSo!B_yN*)r;9iIOk!H86 z1zlG}KP+cUY;xi+nd=|^v1T{vzRi$oZ|+ET6-ms6duiq;LN2yaiFb|org56vPg5>s zJ)kX?6ZDsOZ?|IL_A>#u@}AF@N|!sseqL+^!I37HQ~E_Q4rS;(VLi9PUj9K|21Q#n)kS~ zgVL|yEGai*`)?V$v?R(q!HeSMl-Wvkii@WIu6e~P%zskGygL9Ya38r__kVO5QS+b5 z&~eU=|1)C%6QE|WBE8jdyDQZ3dYL5#@t4N2_*cea0+K+h%YxgDe`hRKmjRav{Eud^ z;$(_4^kRsJ%kU2Nzj-E}lihLn#QIRF_-`Yx0rWL%RYouo^<9EUhzc5~0a$ERG*v63 zd#bF6@CmBT>(vF3 z?@~4cgi6cqFKB5Do+-e2YS(pm**C9UDl93ftcHlZ^Et3{*XwfH+le|+skmG$as4hX zeRR9qAze9_0lI-=01rolmZ0Uw$!(d&LJ@9vCr~NilY+5nmhqQz;cVUwi*qR#X<}BY zTmfJ0jf?VGxtTUlYTWdSo0P{gSejg?^i8Ea;TyCGNv#2Qhkdht_}GNR`o`r@Z>|_E zH>VF{-{dV=4&jwT+$niW4m+?SjjOdes*CGS*}8{;R1b%A1A*n$VW;ZRE1+8o7i%21 z@?#J?nQt`rdvDnAy2yeTubl8_vHtPc9=hGrR0cAU=RFsYkLw{@&CwoUvBbHFfX6H3 zxYJbGIy!j>Jc7M$!T@|ccES@&c8YdSGxowUebYYE4skpmWI2xK3TDe z8%Z?T8gI>!UCmT*>!kAJ`$O2l(_w#3S$o8qsca*r>N7LC=r6w^YvhRf($&(4GXU|_ zJR)4HMnkn3c)?~SG9YuhQAi&+9XyRfoN9+*GOJwYVn)sIRT9?qG?44*Yme;hJ8_YoSDa4Y&6s5jj0bL9qDZ>RlK7$;zsynSnFAN>{yjP8(`vHB<}0a2CTD9EbL3j zRa_ge;x%%%;2am%Yx1OP<>Y#99utE8g{WyPP>QvI`8v*Xu_{BWhIYP-Rvlb5v=QL(8e*$Mdud#`8jbZe&nqS*Nk69@dt(HeyDg})=b&msW*??%^ zjjAxw5TW=xU~J`39%WYxrsdWb1GR(j2v2}DU4&>j4P&weeROfqs%pf|-id&-F~y0d z_bcg{3zF*u@lB(@ut_1cnn}IUY)>pNUfWs-TNNX{+of2YW-<i?{Z9$YYE;B&H zI!$CPjt7jf6a&H{7?ETe9r3)14EJch_W9+~-#K4J>9&;_08MFI$ zM4ZL?{s<25z|}Cjza3EkA-bEnEoH7`M-QVBxDrNQmu4u?g&Qg_#?!ehLs26cjm3y1 z#(Xd1d6ZC@F}uGr!%12uhL`%l6$%L^4u;tvW-V7D!V(bxiPysI&Q%IY-~Sj3lH(9sho1GF6prVxlcO+J f;m$b}^Me&zRYs$))+p{lBwr2V?ObEvnCtl;Qbb@n literal 205240 zcmeEvdz@TFm4Dqkyo`tlhzJOX5%GmH$>fDd_e>@s6Y?UNK#0iDndxL2Cf!3%Paudd zR76BXMMOkJ#5W?cEUPYyEbF?c_+k|m5fu>;5fK#;5r5yRx{s>5RduWG?YR8$ z-RD)OPMvz!dHzwg_SnSHvtDtC{9j*xZ{LD>{fibYlE3eb{yD#|x4)15eab9Cb~={? zKfRg+Kf8kjzu29GTUSKz4SWJ7V_1&A0WJK_0N=L&%^2`ob2;gG+IbP|i%-DQzZ${u z_yp|U&*5oL;P)p;IB*RKzkLpeFJ4MQ2K(R>u;mI4vo??r5d41k2+qgn`6N8}Ob)NQ znS>Sa7@SSQw;jk~*NaIA2<~|zf|K!iG6~;wD2F$!A|Zv^B!^SJOhO7jgFX~4gls@? zABo^Re4aC{A^0uI2?!s*mqGAgn@|W(or(Z9I~8!+Ega6rCxv&QUMO6!Cx<(hl90j=F5vL} z$4SUw5TApjXV(iEgy&vJ7`)|EB&6`xg&fWe@jc)zuqTB#U&LVsHe~P+J^|al$f0vP z2^m0U2e2LbQurHmr*Onk9G(Mu1}NWi0Q+9b;n~oSK@*>V=dFq04txR*L^&uNFdhM9 z9{_mOksOYC83`F&hflyOCpa8gB_RX&>5+g%b0UD=ivSBDi^2lvLZSaG4)X{JDa=J3 zG64U%fcemc!h(}H%-;+D2F!zRP?&R21Xtk`(6^C8?{`T^;pIm}a6LW&FFTdPOMgy6 z3NN{x!%H{d-+-6w!QsVkAt8m{98Fjcm(l+!7O|N{)qMg2%nDn0tA29 zGlGloc@YT@flVmv4c#g1H_0IQ^*w~cGJGy0;r`!e5d8K&_&?ym#~FnC!aBX zis1QcNDqZW@H>V5zZStM_yinsP6Uv72;jLFN6?E;3XgNx^D@#y;hEq?VUK$v=-?CZ z%$qnoYd6wEVUGyV)_NEq4m|rp5?*yDhYwy(LJF5($Km6fNJ!x-_#%amoW;KV>*sLzm(P%p!GZV$T>oVbzqplz6dr58zLaL;&6Y1o%CCkitU`a=7(J zBxC@7w*vltHHXhmk&wb?4vzqB{xg8DUcuqN#z{!wt2=S{pJRuV4WkAz1*1UMf3 zdP!Zn}baO0^Yq_Ef79Co>YgcKeF9|~VWSt#82B!`>tBOwFW=w`rI zZsc&&UL>UOB&6{0EDql| z8Q%lme=~K)0L<{z*qV?{5x#QU=2P2_usb@dpqa0oOjp;X3#Pg)hL5DcsQE@UKUakinh!1YCOxhfhIQ3fJt( z;bSNVg%7kjthUUM4>DI7nG z!?9~gNMY4=98OqDLJAun;cyc8QCJDt6jq$i;c0inFYhM7Ll<&*_ z-yz28-{r8+;UuK+T*w6kzromm!u{JAg!@1z3eWuvgW!Rq(8mLQa}|T|(5n&KFgN)# zBC6R&ixF+QQ%M*>E*C- z4QvWn3%(TAPjEO9bwlB}8#$~&JyIC%a9DmV>JD)7sT_{K5_JbS_I?hlQEmz+piU^f z`dkjLfqzms>3R;U4nZ9QR-(KVuD&n=`ZwUh*&N<^1qm6T-rouM)?*R0@d@}GY(U}9 zXK{GOAPFh_y`RJDZb8fgycswYp7BKn!J}uR&dx@C9l>ES##_%od|_}gJ^{O3#bMUn zuqR;mYZ-*UoFokHZIY0}mP0vQcRAV_;HOm%dw@3}cobs*3V%UA3kZkyAmP{VABATg z&LDVvH^Sipd;!AB@uwkL;+VQ&h5xGVzr z=N|y?eUQWFpf`mN&FAo*dq_y(VSGp7u>(2$gECZ4AP1 zK88LI@XH4n^z3{M;>NMUqzc;%YaYezb0ZGXQmpRdYg=nu3EohMHYd) zA;RFlk1Sii>e$htfsp}H*;JdZ&+i|vkG00@)d;IvJ#k>oz|fk(q3TBPY;2tx&Bx2Z z7^9``skOMan zHJ6`iv#fG4JBk@Qpy+RNBIh#wsH3rwq*5BwgUqip5`-UO?(tVD=k)s+b8Dl?*$%Ph zvZCJH(wR`n3`j8#UVd&Xl~nUvr82r;ack?=T5~*Yo%08)q_VZv8Jnn2S2MpJH@IYU zmDF}!P%B&Noso89%a(e3acid8(efSMki-L5bb+syB@|tndQ!^OhFqzQk4L&{&<2)l zkV@}{T&eVBEV+JQNi{988KF|?&CnhP+JV92d;6+s>GIG_d;}fzf`Cw|^y_pO7@#U- z6!F0wT~L`l&~DeZuV_qns>fGmuj{lM%`Kz!W2{phO8qkZi+X6(alnBqvkQ|hZA=Q? z5_A0enNw&DOrxs5W&`LvQhRoV7hK0*59%MO9wj)yX-Z2k&Y`gMj7t{OA>mW0Z=LFF zA83vb)hFwndI8r!m260>q+9H`UfofrI2Rf+3s55hZdfy*Y4dZc!f;}T@b13GX&~;p z!eCu#*SEH|74bV5Ip4-Rh&%0`i}=N$gUUOCHH$ZkqaJ8v`&3=*e`rjdJ^MJ;<)xKP zEd1N0%QOj8*v>YHhS@(3l<`O@(c@#&;TS)2$ewasy* z7>5f3!|)??erc8X5jo2!HE8hHuBa!J1IWH?SyDN-?BG_DfL+9~Ru9d#=!&8bvU zrMM^-)yWjrbUKqwwD|0}ELyv)RawMwYE;x+H}du97mSsh{mrwFOXB8vwbHxP)V2a3)5FB1BLchw9C1D;*xpy8Dj&` zvdS{Bgzp3jk<%I9jkDA)oOnlV!U>nn_q((3>SCrYh;y?V6O@hK(ypz&U9-HC6;_3}6io|lK(1y6`K!eP*Vf;1L z7&q>cY$}yCIuYW^%jhc6=N!?U_{u)#z&Z9g2h=Y5+&@Q}lf^PV=cZfibF2L7+7Z1{ zaX^&o+L^$KcNgp0L9s4Kb1jwJSGwsI*Y#?@x^_gbR2&fHx^^aT;@t)7$Dz|fu`Wn+ zEtOo?Zo0*Fz0$9)9nmWl2SmB9oe7+HcftB`T{|e&1!=COlIz+{x45ns`PH=}dZprk zDA%C6ae`K&mVnWnyk!dY<}N<~j?sCPGHGf&Yr zMqb=9I0QXZ>(sPWC$h=KqbIdZoLHlm7kO|NHaP)RfRdhIq^)RGZEIcCeQ=3ZURu+I zXsN^%ji#$KAvpLG#1L>4p`bQ&y4Bhv&m;urxYL5o8NY$e3`2daS@rBdhnN=u;BX! zIj2j_)t`4xRH0<0&7;wTo%{o-DG`@pJ}jCPJs!ludU98l4*SFy$Sh?WBij7Zi;k7R zPLUQ@D1|EtN|K4eN=3z79TDlZm`-b^G1_cRPu0fiqtit96?;>F|BywMz7a6NRp5p{ zh2PSj*k8ggsV*5!6b_Nf5n7^!gf-JhxJci}U*nU@M)y33E9hi2`GbGon8xMt##X#< zIV$`a|F*1tCjFj$#NTl?{5HD4eWbCKbLW3>?5(xa>Zk!Sn*71PA8YY57wfif-PD3; z_1_$8bE7#PV~BtAU!wsBD-j(I#k!2q>*Dka)QI>ur%KN5kx}8#SSwJ*0vT!ik3`}L zI5Nm2@;~_ZXwq8=E?m+7kEGBmSR<{)_-Yrh-o2)EM!h|9MvE3(`6suw@Fgvn{7*J=Z#B0JwPtXstvbAFSP89zOIBks zr+0Naf&_yVjue!;g)@Ecp?8(U*#(<&U5aU9N2~5i%5YAIWDCfR%=qL zBzx?mcT}!@7i`K^%Mm(KHRa2Hd6<;jvGwi4&GGt~T3mX!Q)cOe9`V((cyq=bhe6WM6&UKm!>sgVZ-s_ zl~0{0!RXPNr3njMYU8W}(qc#|xu8}yPtHtFu*C=+Lt!m69}#ObIv&yrjR^rWBJEGv zxttx%#3!w9gCM#p6FF$y)O3=R7nnRK+_+=nLP6{m9$%ZBsWaTZIdiL0{4B?$unswiBnIYAUjxxHa zSy$L03OK5ygaj`tc)vS74;Es?FG%erRcwIny3*EI>DNtVFy6%8KP!vi?M}GhXlu)i z^Bm4vicEe~km6iUE^=-pQ>vP7Fj+jZcujS9?c($$)VV{0(Kkc6@k7 zOaYT*na4&FII{i-P zQCxl|z82LYVPt&}*R57jF~Z88?L}NKe!3@dy%R2TE&);7+ebV|U6Zz$m?mJAFaPN$f5qKjC8S0o)4X82;Uv>0-Y-wK?#+ z^T@_e2ihnotC;q9uVP2%QSfkH@|TrwcQv)d_%e!`qPrVU482uE$)>uvt`a21l+0@6 zoQ>!%3|Tl=5hYbKv0TO0>1kmrKYOIWBxVoUYjAB(A8F8a1+%l3 zZRKEii=o`9RV%qrvT~@1Hv6c!M&qc6oGJD8$i)1r2uHKbv}My2C8u(i;i=9hy{6+L z6TOzY-aJp36?Tgq)r+drMZLPhj_S3lF?L!P_38>cs@Ix!eRJbXZRGPG zT(T@(=JBA2>zW5JYZ25da@0W1WU(CXpw%2fa(+YFS&`z0}~4;9-SmJtYnomd7aRtgLYP3ekE>6wBu) zkC!j11H1d7<^+%RA&F}%m%kKxTqQ(DBcgKW$-ry&eEvyWzu*={$>W;xlAFfYB4X+M z8>uO61A1jZ;(&{>NFEjpO$SCe443NfNk!viBu1Q@X!aIe<|Jk^Do2@%=#ldSV<|Rq zzaWh9i|RoGP+>My4`p&tRF6_@lF_tIy5h9FD>fr0qh~XUGHNy>Vz*)o?#*H3$Z^=Q zcilENM$DtD(jl!cS!KF|Vc6nEVO#D+34m5%UcIVI_f?cT)? zgClnj3Rmu_;T@UN`P!+iMl4cK*R-4sD4b=Wpg=M7F%#IqztDcdj(MrGG+`{F+R8B4hEf1YY`U9!%yQ)-7i9q1w5fQ?7Ry|W9CGRT6HmFq(5NsyBrnI@+f%Yw;$q~G zJKWrcC2LQ~Qke^Lfb;?O+*ujvg*iYvyB4d9D6Sq}lmTS(A%JCt%c6r=@g?~{lkz$g z=0NLU0?#~p)`3|5g7lEQq}|5NV=vL7;9}&|-ZNY4?Z%i<@^Wo&B8o1|0n*pj&M->O z6BrRQQa6GZIK2nWlp zIP@Hhh6A<@>zq_aA{ba`dah_Dx0AV5vo zN+DHO9wIDK;F>9_l)Vk1dFY}m+?ZB8DS>TSHNC=QRj3>z)MT9Az*!fu3W`w|l8Q*F zBp&hCJmH~whH*vEu@;1T=Y?1aK2eB1KF|bz=MGVbi%>6a^jcSNC-s+?RA5}-!~q?p zCJbP4^-T{;JIhB!Su{x57-GjVa7nvRy%hY8@(9nJBv->MWpYCYUn~U7wCi}!W?gIS zG~9uAVeUbLh;PJJJLo(_XzQn^6E-x|;HkQqQ4$+^8!(@M^7g2fTvYHgjC1&dNzr>r z;!$5`0(iH9w}z_&D%I6~+L`ODf8@!Z6!LhOaT3}e6$C_*C^A8YfZf)uvG>mmfssa^@5Q|;?Z+f`S1 zK_j;ETU;Yiq4KPt4_nYJu8(Y@ZZLyRY^k@nPNI#7c^o^!^Jfc zEmWQr^oiDsi)$p=s4Lu{RkV)WC9S%`4O+1U<}T^f1zyldT5s->W?ke74WrfQF6q`4 zZnP%pI(L_J>H;rl#22s&t0cyS@~mjRMeE`&8tK-^<=($5+@KX*@^;ZkJ17usRF)Cd zg*_pvQ%4v~<)JY?V|+zBUXOPvV9wgSGYiNU*6CfyL@WA}LSDQk?<>rcj-As`-hDlB z07KMBZlAn3Pfv9?VCQp{&lB2tvQvbc+x2=DP00;oN2(Zq7K)ozoFlf8t58G}D^@a^ zTb!3n&T?m|1|JfZ;5=(NV-=^o(|MClm9&nB8g1OTX|=aY1cO8AoHB763o1Kx$$U$T zBwsa>g88pj&Ze?_Wo&ETjC5yMf8c zxJOaf2s8*Xt(`FaHKxKn+w@DG+fw^e{3V(~S_*a&UR6my6-{SV$*4DPV zQ2Nw)PaF`=?C0V|oZ^CsY!Gqh51{K#y^nLt!KL?`btoHDZn=0g?kE-%^%IJjkBD;8 z2hI)j`XAAjQt>IJ8d)qjXjQsjv6QG;&dbHLa7zQQS)zb5x`6KvsLSEBg;g5OMrYl+ z6*OZI_A*oy=q}wNazbWz+6)ZoVw-erh}{j)3r}$!I10UTK1TPU(y_FZ=a&6O(SIF0ZolqiU*Bhb`1uXR0i}ar2bZp z3Dse7V``$_W@pf4eO%^ z)?;*si*=h@c(*(86E7MjLCZa@T*}ad!g^p|4QXfWOcV9-iWzD7Qw@3Vu18^G76Q zynt3NigG4l%&s(Avj2!%5vR++OMy0!l#^#OtC_u za?Qu398F%Qa2$b;(6&`a!ksUx_cvwDaS zvv#9%T5#xN#R%%9_wFN2PU>C=O9F2DA%QNNG%>1jBSVt2T6MJaI5Iuzqe;C}0s% zw$Ee{h%Es@Vp=x3_vAxH%eAgk!z)%6DoGYvny?yEl-$dnszgs!<&}wSsF6ln!WxDi zQ(BG4qS)6VtoZ60p9$Hrx@RSE;;(lrWf4&;MxmrNyr$jiw2(hF(_+wr3lk&D7wRD4(JF^jNzwg`L%mwT3g?9FVES zY-nl?3Way3tgd-N4{1Z0|)IImqwC+XW%4^>-CDTd7J*HbgG~G zJF*35FNVlTeff%>0WDcM)BK(+`bleoxfX`>vOGC*6t}NUQ&uI+I+7G$;&@F2}|@eU@6B;JTpN z`LSauea<`ubb4hbqo?V}NG_&c%jE82+9Wd~(=B*C4|l`Km{x9r9c-#a90hDWSJ$c) z@hqH}yx!bOW!yBlqYKs#Wo|yQeH3Kr%Kk##Q;bq(6ndXaOK)-;Cu}q{4IUb*sFej} z)+-K?|Lg1T?OQOff6<~v^7p;bKj-)L_045}pE7GCB;@L!2IP*P1!VVM1Z2h5kbHx} zWJs0+Rgk;04 zknH~ZfSeCF^Wc!&{3_s7LNa?WBnQ4NBp2@*k|*v7$jN|1-xQKnZwSd`EhJw)B_!AU z3_LD`a`y$~Jisph6Ou~+NB?(7z75#+wUFHKWJreo5t8o%4h?$9S)_+thtD<3Ap5rg zx%csqv>yz})TxjIxaBm!`6$ynLbB%tAz6AyNG|w6NFM)wNCp8H?%G2xJU1ktdP_(a zzBMEv{yq?YU-agXoIDefhX7yP7LwaLpao2A2mil?>A*mh-+XCh+0&hTbA^0o^$yxm<`#h9!F7N?& z%n!*)_Zo`>%bniG<%02}*4^4;E$9P#pyTn{+)Wg+?bOQGXSU;}*afzP+R7d&oxocKEY< z$a(nt`h$DO!}z=nzuymD%kl5!d!gQ+kAEN1L%z0u4><*J4*ot6aPf0{NH5@Vz-4;^ z@0mU1o;`X<2XGVq-tAcc{QWriUkJGKs*qg%LDUg!u<7HlBmRBXM^LXfpw8Y4J6{AJ z{wRD3-_5x`B%k>g_zB?4`1{shz!nd|wmbEZ8)4@;KZ7s-82$ynJ9_t!bYQA9{Zm zeswzhWg5CH0ev+j^9Rs|@p;K0$^+c}7Q=Us4$1L=o8AV0+zq_$4amj649Kl-3dsX+ z0R1NTBw*9eL$dZ=_&hHpUjyE$zY55=f!jO>e)~qyjl-A5z!P@b1$Nx+36ulv=L&p& z_!Y4GC6NE&kevCSXa}D{Ij;ea8$)vTUT8he}v@9n_xSX^R9nKTmjs2KmPr0_~4&WzRx3eU50vquReAyY;hfI`~~O=e?977 zp&Q^7e7^$r+!OY^`D2J%9|*~1>!90-kh>Q3H-gx_AtZ+#2R^GIXBp~fIrM!EbUPk( zdMs?R3UTiQ_{m1#odo)ou-OXO7`D9dA;kHI(dG|^o$&eHS@5xaK>J+C{7pc%-5-$K z@bAyy-$x-HT!rthJ{0tSh7Ug)kZWELl4UPMOnWB$^Dyw<6MDj5Z^w5J9|YTi|H=3~ z`Eb}9@FU<{9H6WrZ1gPH60!Tq?eI;s@8+x?au{shzjF`SXB57GvaNy6kD{Ct>rpP0 z`9_rUoHek~a7eC2IZr(qHbyz`M>&_F{CA_A=e`=YMftBsSr0+kcSm_Iyc(Z?*%!jU z-U&MZ9{U#T3E1m%h!d!f!Dm4B-%&@e!*_3n&*9%^ql`zOjF&8i?>qxB32+sB=x*qG zE&9;OUn1__3;*4MHh}u8{uKVV2W$ReQKY_mALmPvCUGoU^ z1KjjS$o~Y&0ROqIjrcMJ9Z~+nVbk3n56A_8egB4b3)ls1{kx~bFTnFNABBzJvxmdy zuL0l7Z-*X$!QY|`fRW#!PXR1@0I~rq!28IL!7d*{-NNrCFGhX+0d@sE_+He@=g@}n z+dc2W-w&g_kD=Uu0WP5T6!82t^aosiAL`&&s9%(O7XH5Z-RM6rKy8ab9puGEk5OuL9{{0WM_ zoWBR;I>3GeHUaDp-z^z#coHZ36BBpS^ZL{owa-FZj()ggl=dLY^7y5j;28FF2gMm|RTWOD+pO z5PUfJQ1AgVpIkx~lJ}EJ@R{H}!G7eqckl}wUT$!Vlc#>pl!Mou9$GD==UP9`UjdF0&S=HP9?e+K6V zUkxq_z8SnL_(t%K;J<^n244x@65JHLDfsu`4Z)X!bAlU#w+H_fTo8OMcysU{!5f1w z2k#92C%7>9dT?uSUT{nB#o)2v!0?4+HrYGaD|lXTV6ZHBD|rhU4(<*1C9evO3Kj(m zgGJ;>@=CHR*@f&xb|z0Jv&e4bY2+`#;o(1mXM~RiFA7(Ym1H?NmaHHff`@~bgf9+P zlNG_r;K<;W!Gd6Z@WbHv;Dq1>!HdYVgM))_kyh}6@UZYX;caA}@LA!OU~@1L%nqu-cu)`i z9K1f*Gi(RF;n&EyfGlT8H z8NoNn3&UrVeaOp$mxcYo++b@k8N4_+B4`A2f>VRjg1(?PctvnnFc|!q{FXdO9w09x zFDFNkmynl|Uy*wW34a@m1*ZhHU`comc{8~^_+GF#d3CTcI5`*%ejn@-?i`*N43YtY zgWqIrusS#{SQD%ZeoVq}eeh7QQ`i$O4ekqGPu@V@NPa{PBl`pg1>Yw>BX^T~f~Dav zgXf2bgolO)hX;kv3!A}%!S8~nhr5TnhP#EY2~G;07S0NPKz>Q?A)A8z!oAT*9|`^t zydwN#@C)*D^8H{cczJk0xPSQE@MXaf;h)GK$pW&591+5>c^&y7xr2-Z{}vn*zKJX*tAd{e&mg;#XOW)=&m?=0J;^VEp9Xgaw~()po5+8V zo5_vjKS_YN^Z(;QcjLkV>28mGHRm z?_{^&sT4tiAdVqnpo=2^68!%-;ulAV5J_$bx))3SLH@bXQyoe#HKl*i zRk>vOv@i$0aUw~_y8t*|uTSLRDBhigM!xZ7Cr9Cq^s!_mV`p@)uUe({mA51_srMvY z)J0|XrrLC4Y;+pc*4$DZT3?wxHc@MjcG|TD(rgS>r#s`-D$r_^IJH)z+sH%JIaU5O z&WEsCIuGgK8%Te#(bT!~a>T<49Op;rm?wnH0Uqc)nVWJvpe&s?98gc8$ z#WbKs3K)Kkq^NH(sx2(@nj=MsXuUVal_Lcxe|DEXId|Z-g{^0$Za3?(ifzJ!mu3$* zwGJN&SVpcYs{X}MZtFg2Je-7$ywNzTCz;mPC(B)?hS+C#(`S>El--sw0K4p&t~%Od z$4}P&m+NlpRQu$Dl^8 z8an)4Coyj-sHHJZ@(N9p7TNH@vBlGsRVUo$pI)^W# zMYDnaOeYvK6<6E*)5~xQxf^7h*|d~ri{S(Qehm`M6Cz9&`*mGXQgJ+|2%@KR56bPJ zKA5hV?qy|U`_?RuVG@`{wDq`LN4c)_-LJO7j6Ja)Tj`XwNSgjxkEa>+XUm=)n`dz} z9k^B^4|evxoZAyG`A2I8{gL+>17$2pZCnd=ktPk1^d7L_x^CFzV~>Lz9(x=Ru_1rzUZch%+eOcrC}I&YH;;TjjpS5R1pPs zw%&el$-p3cT%b}}>E#M;*yUZpK@N8X2gKMFR(X}w4ZD0v9pvzmIv~a+UF}s;H|+8y zb&$hL>VO!Rbd6U@-LT7-)Ikm}sRLqM(i4+_q}jvCbg*vNI^#uCHdh8^XKW5~xTzcv zV^eL+Hx*msT-s`H#VhpY$?3X*%E0m1YXRep*aS$jBIpL;_WZOdtvVLPx5o|ED?j->Ja#2zR?&>vC9{se z?rXi0ZtDnKVm-Ub%81$H-x?D75(yBb96x^55q0Jg2aO=VQH57dIn6s<+5-a^+prTY zY%?Ast|6FpRWS{Us%Sn8V-@4V+O}(lqX9oEK)+?n*6R{ykPgdOXi~29_3G)7 zmWwVMhA{`r%p~|yBxKq16VMC>BgjsGDGPMJkdpHnn$+pNzdHpb%SFd7}ho5Rza z7NTRbu1MgTc71c>%)C9-4Z{U!U~EpcIi8Fe_fH0f(LG`|MyFymNAyy2d1pb<{19{D z`uzTJbTs2aZWpA-!0)J&CA1&S!(sk!LgG&k+SqUmfl0lo(Pjg*VOHmY%s5s?sy10R z41>M|f^z%4sxIMY`w8LQGrYHEeKDK;p7Z*x{AQb}E2A&B$(UKiI8JNpRIOb{S7Tp; zT{e662(`_aD?S!&J@ILK@g*tMX1s(&kv4koO}nUpaK@h2QJ<4DRg#dBLM6%87Le6< z=!z`!_UZ^C5sowv z6j|tWYl5rFcw;)pVQ6>B2jUL69I?K2swzCfTOX3r(bid5)RZ}X z!y#tH20L>K_afL-tbk_?U_44Y&bo<JMoSB|rY;>n!SX^-&=0>ApN9ia~nHJ_#F zM^sj{0>ZbijCi~k#$%-gJb68Hiex&OtV7J<=K?ZJ-5i^9)!>@gIygG#sUivtv;M}O z=SQ9KC1;dn011kwr&rXs87@%Lr*J7g9jH)r-{-2mh*CN6EBV%^`YG?h7G46@m6MGS z`IB=D&yW{G%va!$%>fcMb(qe|neW6HeK>i|IFgu%c%{PN0mddhRls)HN{;m z;2OE&Di=^kW4QJh@GfLlf(o$mx@^rEHzTv4Qm+k9beQ*A%<~FDntw~jNDb-(38`o zCqh`F@^m#p#!|Uylb-`A^5DFDOMD@xZfpr!Q^vg64gzS)ddV6*c+gor)0sjFBtu-m zn%-!mwP|K^HI63cEDUKUi>2DhqHVxCSR@2ku&He~6=ZaIWW5BP9<6u4rhCuyeFz@O zllH?Cb<=2L3lx}3#Xn$4T)(6Y@i}Ja43KCCLtSQ#rz|*Xl{_%P)vvG ze2i-Eb=ZLgDqEX+ByB)0EjwORLFDaET+5pXJMX2ndi*OqUA2yCq`cCK$LV>3GU!_dQ8b>G^42JvQ03! zBpGp2fsQ0{WwIDgsqNd@+F`m>y8QfGt7x20 zZoe0NuueG>(;F>WG=^!65qIOOb^U-TFDT`IDA<}`_NNc z4SK%Z_-q^9r-E**8XR$HG_z)8!TQIzI!&g^3*$)2!-&R%ApO}sXpd}~BFa;2?bsdn z6OiEsLvBqc&K5GMW;moYUE5NR>}D9BV;hE!L45Edbev^~R}l4;C)9}}F4cl3sy6N8 zvr&gNm$hf+>~>>ot-XC2cCsdE?AL{Co=3YfMW-0K+hhE^7Y@+inY`9?r(LgYHNBIU zK8xqbTJbzaHQC&OD!DLMltO{W7qbObw$iROD7`TYC*oV|DM7SkV<4dvY(+CApeuC- zY&wcyYjr6$TjepJ({&!U%9En=&dY$0AfD-#=FECNv`tPy8>U3vs*;6jDlx^;L=G*lxjp+_Xu)LYrwmNx`Z`av*XLYLC zt{bCfI!UL&z=9ZC(Zq>%8xgs-8u;%t=~j_FKem@^-1Fo4xn#b!?kioX;fI|yxY3kb z$C-~>HIYkYt0Kxgbynh=V!S4psmy~5+BLF0ZTX-kA6!Ig+o_X=K_v}LPU;TFve}Mf z`ZJEEV~?##B(K!dI^Q` zpb|@yLlzZh8kxcMVV8IKR1bz@4ogu@=VP&%1V_^ZFo})+_k@9Ik1n2WQXw{+gwaYq zsR>66ea>YM2-C+~?bzEnR=Ta({2 zXwfROL}@c(I*7sI3G4nPQguv|7~eprKIbIzG}}AI>d-mwz#8izKR)uEp4o)iAAN;8 zGf_xXOjm=Le|k~y$nHRrzkK8>JfD-dQgFONG@NLAbIf6ZX4-_tXAq{J>HL8GW*iqY zyHVzP49b9~*VRoTY3H6|s4GPBuQVD78Ij{3XPWxC4?7`x29{3wMnm3plXyaUM!V6e zkF;<)!?;uwh4azKgK2`~cz8{cFU4C*`ful`U-K(M>9<(NO`lX_rAU8kOb^!ReX8s? z0^6;PCdV3Lx32h>V@koNrQ*MpDTn$~wv=exll5kb$N$|oU;SpTpcTgvRp;LU(V->l7Ox#%GqQSZY;iI=x@!H36DOo%~N98252S4r3Mm>R(w#MqOMwl6*xRxyV`=_ctI-YjBe5X*J4ndON z3#Zz8@?;^~#`AqtivsS>rqjT&Vs(DXi{QvWmQ6>tE*U+93d8O#&m_mtVToMSDG9tw{5c&72~!%a2bwTNZss{o%u;S6dHBg1IGfP0!;aPq*!`fy8_YCx;^BanRagI(E)T|%IGrX|V!rU{L8d8# zL4Z^YWr3CYy4KzrJXxX!AzFP)Evvy1l`-hc^wHL+fk0BsfFsG(ymYJyR+-!d)L0T9 zc}Ay?8_KkgA}JY95_?%tg}f&=be7wsx{A4a-lPKoQrmOmxMQO84AkPywA zn@c6(#0EIl;ekG{O2Qy-RM1zbUpHl1NyOTF>^@yTtlG%6x1&i~H2s%`9k4VJEQ6>- zR`quW7MbXl;UPyi^=D0s&Y(^w?#Z&)8;HV`w#qy%br z9}CD1e0{UVBr@~^fq?-fcT9qx88akRD6bN`D z4Ja(NU>jR--J>-SahalDKhUs?(T_Q7G|KS9f~pyb*swJ-Gm|;9vn3OzW~gG(frn%J zJcQd{$x4%Wk1?RfQuU46A;n8(S(Xu4$q z2Wg@O9MEM8$mwTX=c-sm&Z6>cF|kw1jBP!SG&BWg4X%x~(fL)rDq@DIZCsP&xQWZ> zkSZqAc-&~Z~ZQ0&X~iQ3{YmB zxmGCuEYH5=-_-ff{6S&z0;d7woGX0bF`iK69`WhJZ%r_540xR?M#E_GBAWqeDx6-%EblNVP-tfQi- zv=Uvqkx(mPRxquWOkdnEeWGQGrPxYTDW7O7W!365#`JGR*)tWY9J*zh860hIjA?r= zs*o}DR;o|L!9^h*H}SYr;WS){HuRO7Zbk57DY+6=$|vSZSQSanB@w$+jyBebt!Qn0 zBYvRMp%3dDokl#wLQn2T7wKa%7iCly>>9gc<|Px0ijs#Zv@8=UOVlNp z)Q*>7n9cl!wizcGle9ErIxy91nPtiFSem0)c7wjVz~8qu^=#|~lw-uX^ zpNbqO5}h2!{!Z*EBMluXAyf$KRA~7*xB&<)La{|@-QSjD_SxGyTU~@@bfQgUPiX4Njv8ylX?ng zDygUNppttEAHpv66wV^0fWfKUv$n;RV9L7Yb(6EdOlJ^hrC z#h%R5jS*2c&F)0Tz|L9c1j%J`&!ueGLZ#;EJJh1&YeVjN=mh5Vyliv=t~u>il9MjQ zrU!|b(d83GdUMYa_7~vJ4*BU)L40zo%v5QEQS4)U0o8`<;@cYcVOb+&6`M2@jWJ~F z&BAg=q-=7t*QKbq@1l9SERO1O@SwPk_hYneMbQ$hcnj6_Ds%y#z89KmnwQm1!1T*) zClm5emGMRT=%9e;l;=*wFO=<0WRREhPR4b~d?!=5p#B@GAhFp|5zg~ADNTN`=2vR6RoyOwg z13QSaiOC5q^Yu~|D`x#qKJ%M4I9j~y5@#Vmh z`SnDFJhSYHq{wtLhTO}UQ3_8LmSW=aPN9r@A_w`zhv7ZTtl)@jC^!3_MixEVt38o| zz{WE6i8S;$i7^vjif9W^@Y?w2C?8*j&fdjJJ#54(FE?LCggHZ>h)R#eBtxsh&Kw=ypMamAxlceYlD{t{H}B@NF&WL`mqCu^W0@=3>THT#X~~%Z3TK%R`}7Z1 zt8K=m=Ypp)v?RMNuQ55USVFEX+GIpscXVhF6pyun?in1%zpu-Nc$vkuvL} zh7;K7ji+Iw3}?L_eAf$GqMKRrF}N-Hl%9of$``10lC&Rl;vrR{E%RVx zB)9y7F|tP%!idB%zo4*!;Yg9%#g>;a(nA0AJ3F%xXSq)K8Ii?xP>SR+;Yrcu1ruGq z!boSAtc5YEU+zLrD#@jqbgymFc(Tbcb)it*judJ2KE0%^d=$F5IUw%jK%G+M2da_+)FuL{2A3yZwD70X0_|dw%3MX%an>~hb{4idX!8=n*w_-LAgbb1}L70bxQk~Fm_1ID4v3)>AZYsdCo*H3L)WNMp&|l zrmmuD(?QB&J!rF~%pq2aiRHfOx^YBB(;aG^n?_Q}KNu#aj`|01BR)Ko-Or%WNIcbye0=!{Dh0;u;80GQ$`su>_oQ58XEL$oT@qKOniWr9 znexclrbWESSz+)$##X&IvPP@eUa+(rGIBKiCZDhLNIK`D}&a%Sr0 zd!`JUa&t0pOy_#J$u?sbv8LRNkUI1^VC^7No?>%6b$LsNqf9zvl$qvuy*)|Ko|!Is z+LCofI@3`zGC8O1TDt1yozOGl>XFuyWs8inO3KMS<)6fRz|nLlArpT??n@nEobFTp zZLAgD^;3zkznDG&$96(hj5H^x%rgEyqlY0ss7&3i(=`!QR%XtsM~JWRtG`Z1c|&DU z{9BqmRQEm2A*%bHW)jtXk9?x?*O6yszSb*~rW~c&L#ZDy-;b%|f3Ircv76e~>G=Dx ziCTN4g&wP&ep4SijnSq^ttPt&x^DZ{O|8iUu{G1|tU&V-@bHa{M6cw?-@q{jaUDM9 zf`3vT!avuv&ZxIX&S<3u1Wx>AYCU{OwG;^Heqa1g?nLRokWv;4-ihvw>1FjZ<6r5< zja=ZZwbSY_bBusL>!&BQ{9g^>$A*l{c1(ny*}p~nPD}aMXtOmvRU1nR1Af4Xza32s z9DOhUdq!q9lh6q&bXw`x3OoFe@awcXHN_N2{jfD=bVk-&k^qlQiH^Q@n4yf;48rq7?tpET5%CZ{1tD2J5&c*CUvKnh|Dw6kU#HAk5%iEVp8d{sPY(#$jj;cMBgX5SX12^; z$Nx#l0RFfj{zvp#C3_AY(HO6FYP09WKkb7*z6JP2^hFOotEBhl2ycG$HQ611`~wi< z(eJC|kefq%?nRzP|4E)M6zWA}?>%?Lca$IfkJ3M5?OrPzW9`;-Yjfw2!`Hs}kQKwL zj%B|p|3{H2A!R_wPVBEe@&7xszXU0yO5Z4euFqKeQ}Pe!$Hh?!`X5y;Byo|egfMj{ z;%`{tC`C{FO+UrK7bL-%mwrRPKZO2Y^dIF;$fD?9^dlr|@&BXQWY+Nj1HT!vU3bq@ z=FE$IhI&fKJmpJFIjSPjddfKaDg8geQ|89sQcwAK{Ez69ddd#*0GE1w9+WWJQ*aWe z_BCh0!c6=60R-?$)?3ZezUIY-qOM5Wm-wI1zWU?uDc<+ue?*^MwXUm0jgIJR(M7RA z4>@HPVh0-MihxF~RjhP7k@A_{1&xUCw^MyDniI!ZS-WM>E8*7PblP3ksZ2oguEmA(^m@^G$1@7)r5MUv zqXh*%Q zf&FK(3k+Vf0J=OY(FK$5=9W>m^EM=R#)b~Z-zM>7TIrAJuzfEFJ-TC!g@#eVQP5&< zu7xcEQisJh1x{(v_cBWMVe<`M(g$7kiFDCj@Q4SN?D5%BzA@k68!v|j&$es8H*0p7 z^nD}gnTu+1;Z@^%`{O)=^HfZQKUJUsMSml@XgZT#gzYLNOqwKF|_}+-%VCtqEK2d#JBYih+D}v9-S!a9z}Ge&cY}SN1$Z z)H@8VV76Iy$r8^qjMiTWsW0SG)q^~!dPS(WAI>+Fl}7l(xYTsFULJaOCF0m(-HYt< zm7@FBvaN?boJ%$zi%J@uI?(ae!WIW!?50KXm|-+O$P7Gvby{E;h0`svmpJH@9eny~ zFyGJ?UI7hW>Y#z*8s4p9fuRScn-ecf~+SvM!IS$&W?%`WQwn#D8LB8T3-nB8`Fk(Iewb38RSFW5S zj*(qH@-4k>^g7QhT{XIYsSWXw&QRu?QUD2^9@ml&cu(jN>)to?`xLc=arFUdOR3cETd}e=E}9Lg&k#)Ub@tV z_1Krf-mi+};*jGGDYI?m^Jt^&;nC&DX+?8puT--!=+goG0Jl1im`h;@%L~ zL6hj4cJXB+fUVD25=mzF$}Q(zx}k?{gtb)E!>}1r)(*CFNyjkxebVD5$#i%fcFo2* zIMfi;xq6O8QOwsfY-b#nY4oyfT%{^@qsA5)=I``u&9Fu@$8GYG_OivZ8&EhjNHMv~R}x2C}UcDA(XS4VQ?8E`kG+U$H1 zm#P`>cSEvmy#Ja=^8fXC|71}Q%}_}*Nb|1uzTSB9FQ0v;7r926{Qg4YeLQ!C1y}8+ zWdR-I04VD?0v%7$=x7_*N@IVElD-k6uQwii$vPef9cvmL-DUw61--4fzz|vJIm}J5 zhL+Rz-PFZ)H)qU8m&)wyiQ3FIi+5eljf0_Fmou=`xSw|2yAuQD_8+ylMv$GcE_qc5ywuN&Qt{cJ4 z+m{v@YLVV;YRLMP4s5=*TWFXU91Y!0jdjaLiAW6Fz35_1E;O{dDzrH*)+X=leHZny zookp(^f8`z@1iD);-IR;qm{7CRu4^_LcX_$_sxx6TyB9KXxH@8u6rThwMWIg4oMK<7j>tVYgbUN3=7E3X>X3md;o@^AGJ@DzRk;kLwa9NwZ-fX*TA+?IxxVG{SORkkN^8>V>_ET zBWNQpVKR%bWA|JQwOV|&u&pv}<63AG=-w>LwqtMxm#QID0_f=s1&W;JmWh z?Y3*%rQgnVQ&(E;O~$*`+V+Rf;u>UEUAtI2w%+BnT)uAowaZqpt-hblwXm(lS_7$X zi?zk`*Co1W)@8eF6WbW?^`ah{HA}lHz80~yk~c(}D66%01-x5{?G(csxduDj3bsi4 zrbq{M4cBf4?|Lxo3(xnjbNQNe-R|mOJIU~tNC$@%-l!w#k4J&* znOvbhyjMhQW1qK*dfA48#zCo|nbXRHEq0vCv{|T|a7AJ;dq#rJRoZ1-4{m*@g!`4Th=URpxIs<#Vs}^0Df!TcPe5S{ur+{z0!$Xs&s&8H3T816! zTkmw$q6@y&*B4I~sQ#IaQ>{^B$8t>lcszn##oz1r{VS2233i#IhJv4c$`qrhcW!Ry< z^#NBccCc?<#`IYI6!5JNdT8=g^{vZY%dkUz>qD+u>|o#eFw`G(UQheMxhB7Jo4C8|~9YX{qlS)Y&P zs>eoDq28sPXE;xHC`x;6Bvn2Zp^Ee^r)>}O3z0;1tAGBWu=R}&TMSzMYlXI(@YfkN z7>TwNRq@{CxA@n;MAC)QM(nHA(snnTgTp!7m9{1^<z?jAa97JE1Tx3P~SSX-H`paNahYHYrF`qSeo7({9-Iu-5OU5>u+I0{k{NF zzZ6TAx5LZJG~BkJFY10dlBwAOFE7_p)_w+FQ(Fq0f>Lgy8AIfv?^*u`9ThKa(WGb9%52j$mpHj7hUgp1-FvW|KDdeM zvbs4i)}a|Ib$#_peTv?>)n1y3TCj`wx08+fdgBgN-iI22jlLr3rS@^Sb+>_THl@cB z=Fl?{>O5mkwXd(FjOQhihT7akJO4g^%ZvQ1{^?zqK+lj5OMjEz|=Lip+m`tZ!@)p{tQ@gaC3i@wZ z0~a%utTEd;malPbh8ojI`RHR3@AhV!o&HZoivnix*T~STFG2gdm20%5-9~O7lb2`$ zX8G6aZFf(05f^DYxLs>5uD0GQnf)&FNUy)O;=!Au4b4CNGlMoRrYog`qkC;fO|yf7w5)Q!;Y9*uSy z3;mPUK5h3~f5|mv8-2P;%&4d|J>TBZ_Lj-LRF~S=SbeIqm@fm-wQT+V99E98aNIYi z?7ObEGtj@%>!a+ObxRZ5ZI1hxCgbDSW*BIYnnbt~_g?Uc(yIr?PH;T>Ii<6{@H*B=i*`h6sQRc&j1dZgu2 zK^ul~nmDtsT>7rK%|;JLTCQ&L(>T@01l8(^0~?SQ14Fu!{r>{P$a^kq^oL0LNV~CR z3lgI&R!@GxZ#HDB$-CdOotk_k(t$^rY&=g40$qmVi-&XOmaY}s?DvmFbt-)}+19@Q zBxtp!UEka|vl@G~Zl{XY-LR^VZwp%(H!x+UL{D=5*~@YqqzM{z~=0#fAF( z{&B1mVAmpv3nvcHjuoL{Ny$iQJ2U#Yi+pvU;q6bhp5kvd4Ui=cHYi(u!?`}1LG+1y z>E%lwPi~Z0L*Kjkdn&)))YSh5)PL#n$5RzWejnsN=_0?p1q{)aW=8ynO@kd?|0GD- zU)KIiI?ZAx9%S=BfoNMb37Gswb9|(=riHb9;~K^2Dl~*+G7E9OvB>roL8$7IU7zTZ z7V|9UKzjn51Kre`9PjcuP+RWUooLC&ChN84%v3c>m7B!jbpxZTlm$p%tJ`{jonzVU z!I{mQF<4dQ)A3G8`LoHJZEhit zp*%S8jR^}3W8+28=UJ}$U|`Y(%f!bD6wA<;^7o1~>C_s{>D*9BR|Lz(CtGHxy?I|T zwH>QV6CI(iK!YjQTi9x2A8Lc~`eeK`Vq1|dKW4S9Mm*a`lWY+2Zo@XK>>KIgvdXq& zt@0cnO}bze+ltzLf-X;m6}9L3>jMjwZNs)R2m5o4PM@jI)T`N-sgW^Q8FKr3tzphf zbITmSq}%T(&|yD}P=3Z|=mBZog##V+$SC1$4O@lxa*#o{ zI11|)sM8)nqny9x3?qi+sK0{^+NnF6(WpSldaSy*@7STQH=f4JW9IeH?2tsWf# zeX@?*6aGgIx?#UQ%U;^^^Rz5n&HlEGo2hI|dhY(vJS~e=x3?$SR&igzbZna9DGvW^ zC^=HK&1+^e>8H=sCS68{J9Z}hLN8s)k5p|loWneI+0irU7y0V*l$}W*?p2cPaL+eB zER2^Yl-UtIXZqq)mxjaSDC_>-k-&Cm_9aZ4GpB0JadyJ2K-eF^j<_=X^0k*ObLdO0 z8oGsijfw@Vs6UUj26g%}tBwu*UPz1XD47WFo2}miJE` zo_YJ1?L=xXlV9{efv+do-uUbD(40>h9r@UFjPR>&bhrCPInC;B;LaoMbeersxvIcif zwF^4ORV?>6^!)K6t^Dfy*_6H;Xj?UYWh8$9*D|K3 zSJb!FC$(3}kh5nQ)kT>udbbbT`y5Bbx|qYH6eaPGxz%N*HHuwHi57Iv^HshYb-_Zm zcT|p!^ckGQ4iwUjunYBSXTs7eDFb!yda}jwN~}ezHCfg9Ejy3Wn^~Upj^maSTGdzw z!|4pxcoZY}%D27nGa$)d*Ep-5>C{mVW#>z_^RR=F2AT*P6_jP#Lcbbg^dTRu8hU+g zVw-&|E~F8niqeFAb+Vl(9g=lg+?r|XuX=W)wha5~^rfFAIz4z_V>^VNbs_JTY#W&_ zHEWeV*(Q3E>d@ZW*!rSlWNn6<<8_=l*DFFhBgJjJb+PS!ER%Ji*E&q9Xm41TZD+Pw z;&7~6V`>7IW2tKT(_!#wn5kqGwC%$zk2PVBH9`sF>x586YbQlH?>e-tejgiY$L8{x zUJ^?UrEO#L<`uE@`sUiqWQPV}b~V7@&`Zl&!q!`@OmvwZYd5AkI8UeAV;BQGMFsCT z94`VXBdLDGzg4jYt(i@eb?vBu9;NMFr8H_^9c(@3>PQEAS&g+C<<^?kMa$nnHmniT z8&PXwjV4=oVNo}fT1kzvQZY(bTgh>e4*aB*akh1}4(_OhI|m*q+)?K^U@ z&0W3#H)Q*yMr zMX%*QakSdk7rR|{hiD?wZcVL$d2qC7q4PSdok}A)x`3+nL?z_C z=~0U<>YZ9fGjvsDt!C@9Pm6V%oY{hhuA?SM-#HOCnpN}owp80L$)uA8Su^-{OlNAwxN(Aw*wIF7)6C{->2bJi*4R!oYIRz;6`Wba z#A;RPQJ%%0rX%^d5{|w zzb=Md;v*3OwyC;|AZ3@cD&CRUGQ&S3(S$yyTEiMRpXUo5Q|TGLEg#I8k^G$DPW&_G zB&GXC%T258vNraWC}o)7TPwB`f@jHktf)7)bSAV@{9)A`-hOK9r(Y}UF|AjjY)e^W zXeso)-Ln%7=!3h-63{4ws$&SFKNaei!s=&>`2G< zvfdkFEhgwNOE;BSN|%O~Dox4Thi$Ley)o9IQ$yAT%TZVP3|ALcnr)VOQ>2yo%|W(D zUfMFYHTQF59ilTRna2;iaMr`NhWO@Ki|teB0_}%R)B%ET%(cx3-XiLuF8g<31ZVTn zw??vE2Hcn@GBiy3`!k)PcgwM@d!JiWtL)^_TQA%Fy|+nv>Eo?nrHqk$y~Z|vInPs< ztZBTpG4z&0=#SnmYUAikeRKOWTg2Wv8O{>W`)210Iz=JI-pEUjH*GQR9a(Mk4pdqT z+djbsf)>$nGP_MQ$I86x$goc^fI50-Rv*1pmWl1EY_DzW6)tqwD6?SaYZ==J?_H`M zgWG8q9hXguZq%7!{gs{pzev!`<<*YCC7ELe{!!WDL+|$2CmRgCHL|T|y+_c9t&6xs zM9rdGCOmp;X*)slUcHw3_NUPvT{(28xZ5?mT-cS5U8 z^N^U*onwSvVToC~kzc^pB0k`zPn>?8wS??rjabLp!FIdMPfutwT>5O4ZOrpQrVm!g zOH`z9i|p%-2g`C~+kh5%xuZTsD$-X^+X&=CR8K6<(i4QXxTei)Q97pC#%LdQ)-3Dl zz813G9R3K^qtQf;K6Tozd5qV)ceJhIToFrNw{C^$bWJzjrL?_i_fe+9^uSD~m7F;; zZY8Ks6Z>1kvU+|c)#Oy-D@Q2FOP~+7DD&9Ua&)_33gf3Up*I}FV zWffdmUTb+u+*_)x=l&eE03H%&x4)XEtMxlRQeWethvE?4_OP9E|2)&9UO&yyi6aG^ zy7k~M->^pdVtB!|seI)qQa2>q?reS`mb|px+L{?ZQR&jQm{JM8t9nhyi+C+POQJ^fYF~AL2zrQrzv2-5*Vo_Mw_slXqBJ)!{r3Mgcb(r&96{W18l;C# zXofg}5FoKF8%PM)#vvpaLW1*NzBxiV+xL)l9o)4#YLyNK!P6sn(W-_o3xX+1*X>OLtZq{)+R+&&V$@Tg51PEC#;8>OAL=qbu4*=bcRRPTm}jR=>V?;B z$O%lW2y=5s{Ly}FykXoQ{TO!|+7t7w&EiGzrs;N-jVws9@Ig9yQ7@Yf-a}F7JDE@J~FWw;YlBin2h?Bsu#-LNj1lG&t_0Fz8;F$ z-~-iqUFpoqIB@R}!-MA5U<0B1NWZ;J^@5+68^lQ!1TJ-y+arBl}b(VZ_989bHXYqH9yy_|ML zW=96pUC`4B2KKukO!A5r#nK4npg3Un)@E)2M9LRC1vj`CN$a?yGq zboc61)$|)ReE8~3gz@ZIDPnK0$Wy0+VXg)!&;Dj}44mI-QBm<*bqwOH*`V*5W|samv-h{f zmhm?0d&whuG-B*Cg!{>Hji~eW4>1E6z)p6n5zemGuEvoO70douV`S@Alf{mr?pA)1 z46rH!U&aQ|!ADOyh|kX+O%3dQO|ke{vN!<8+Sz46t;R2s#q2VmavQ(K3>wzoXJHrA z8S}R!6N5pd0wT6OQ1u|cOLSJH8>qzKTXVgd;c|W2R*O&D1wQSM8S>1)&&3x|S|qg{ zSp6wjjrk+hL2m?KsU5)I!|Dx$RD+mTm}*>;rH=j*Y;gF^j&_lRhleEkja-dP{Za{P z$Xss+sD286r&t-T+?u1swtVX4{vQ$ld26pfy)yU(e!h3)tnhX=_XWV~y@B)bOB-GM!pcoN^9omNNJD?YM7wq!=J7U%RjvR1Zf z0Oo6)h_@h%&t4%9=u zF7WRCEeUH%{%)!Qgo@I;Uk=s(d(KEXGfVlB#dvBU)a$uK~nGNkphu@_KSbn3+-Z6v%`XG_~^7 zJL1JQ#7+e=Qz@6EF}tPEx=BcVna@f}2vfwb_LNS- z3NU*$E#7h^$hjsR`P1-YRST3v2JbF>@k%fBLtH}01s@dm^OiP`}xqOxr^XStV;OT>%z)P8w~C0>-vW3hmsa_m+{- z?4hkq$~I{*$xLNimqeS&1kG}SSOn{K9-=`cBZ7EEg<0C-`XtJ}0D42_$16@~IZMp6 z1Y|lN(Xf(xD1g*)=!Ro?<+T)WHbgjH;gHatDiGf$h;PkCffSUhdB0paFg<=SD7i^R zXm3-51(VhX;e4eE#kGkXp}h-gI0k|E+9M>o5Rpdwa?t?9mdFzQEChS#KpcqeFbYwY zhc69*(kW4JbsSMF@5`5gEL{?1e=y~RLsNnFq2fzKVC6I{?K8#4BDB{nv2e#aYL7ta zkto>2&k@BEy)1w=+KebsOs{~jZQ63;T?`moA`A$rp}mLdblB_CWr-i=1J2e6XSa8Q zA_^OW`Yv3A7}#md;I7#^BUb-n#2L>Y^5Em`C=Idt+Ykj1yzA9v$x@O_>KMMGB!s@U zOBARBbJZ6S>FkgwqQRFU3|nKwe(6o3xay2p{XU6P4O9@eEJW1NU&k0O2bIJ5g6cB4 zSky^uXBunRG4>#AVIYC#h(g%)r8SfZb&>d9&Eh%nS4|A{xCMajHQzZ~8c}k-99qY946t3V{UOvfO+SA