znc-1.7.5/0000755000175000017500000000000013542151642012545 5ustar somebodysomebodyznc-1.7.5/src/0000755000175000017500000000000013542151642013334 5ustar somebodysomebodyznc-1.7.5/src/FileUtils.cpp0000644000175000017500000004146313542151610015743 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #ifndef HAVE_LSTAT #define lstat(a, b) stat(a, b) #endif #ifndef O_BINARY #define O_BINARY 0 #endif CString CFile::m_sHomePath; CFile::CFile() : CFile("") {} CFile::CFile(const CString& sLongName) : m_sBuffer(""), m_iFD(-1), m_bHadError(false), m_sLongName(""), m_sShortName("") { SetFileName(sLongName); } CFile::~CFile() { Close(); } void CFile::SetFileName(const CString& sLongName) { if (sLongName.StartsWith("~/")) { m_sLongName = CFile::GetHomePath() + sLongName.substr(1); } else m_sLongName = sLongName; m_sShortName = sLongName; m_sShortName.TrimRight("/"); CString::size_type uPos = m_sShortName.rfind('/'); if (uPos != CString::npos) { m_sShortName = m_sShortName.substr(uPos + 1); } } bool CFile::IsDir(const CString& sLongName, bool bUseLstat) { if (sLongName.Equals("/")) return CFile::FType(sLongName, FT_DIRECTORY, bUseLstat); // Some OS don't like trailing slashes for directories return CFile::FType(sLongName.TrimRight_n("/"), FT_DIRECTORY, bUseLstat); } bool CFile::IsReg(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_REGULAR, bUseLstat); } bool CFile::IsChr(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_CHARACTER, bUseLstat); } bool CFile::IsBlk(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_BLOCK, bUseLstat); } bool CFile::IsFifo(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_FIFO, bUseLstat); } bool CFile::IsLnk(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_LINK, bUseLstat); } bool CFile::IsSock(const CString& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_SOCK, bUseLstat); } bool CFile::IsReg(bool bUseLstat) const { return CFile::IsReg(m_sLongName, bUseLstat); } bool CFile::IsDir(bool bUseLstat) const { return CFile::IsDir(m_sLongName, bUseLstat); } bool CFile::IsChr(bool bUseLstat) const { return CFile::IsChr(m_sLongName, bUseLstat); } bool CFile::IsBlk(bool bUseLstat) const { return CFile::IsBlk(m_sLongName, bUseLstat); } bool CFile::IsFifo(bool bUseLstat) const { return CFile::IsFifo(m_sLongName, bUseLstat); } bool CFile::IsLnk(bool bUseLstat) const { return CFile::IsLnk(m_sLongName, bUseLstat); } bool CFile::IsSock(bool bUseLstat) const { return CFile::IsSock(m_sLongName, bUseLstat); } // for gettin file types, using fstat instead bool CFile::FType(const CString& sFileName, EFileTypes eType, bool bUseLstat) { struct stat st; if (!bUseLstat) { if (stat(sFileName.c_str(), &st) != 0) { return false; } } else { if (lstat(sFileName.c_str(), &st) != 0) { return false; } } switch (eType) { case FT_REGULAR: return S_ISREG(st.st_mode); case FT_DIRECTORY: return S_ISDIR(st.st_mode); case FT_CHARACTER: return S_ISCHR(st.st_mode); case FT_BLOCK: return S_ISBLK(st.st_mode); case FT_FIFO: return S_ISFIFO(st.st_mode); case FT_LINK: return S_ISLNK(st.st_mode); case FT_SOCK: return S_ISSOCK(st.st_mode); default: break; } return false; } // // Functions to retrieve file information // bool CFile::Exists() const { return CFile::Exists(m_sLongName); } off_t CFile::GetSize() const { return CFile::GetSize(m_sLongName); } time_t CFile::GetATime() const { return CFile::GetATime(m_sLongName); } time_t CFile::GetMTime() const { return CFile::GetMTime(m_sLongName); } time_t CFile::GetCTime() const { return CFile::GetCTime(m_sLongName); } uid_t CFile::GetUID() const { return CFile::GetUID(m_sLongName); } gid_t CFile::GetGID() const { return CFile::GetGID(m_sLongName); } bool CFile::Exists(const CString& sFile) { struct stat st; return (stat(sFile.c_str(), &st) == 0); } off_t CFile::GetSize(const CString& sFile) { struct stat st; if (stat(sFile.c_str(), &st) != 0) { return 0; } return (S_ISREG(st.st_mode)) ? st.st_size : 0; } time_t CFile::GetATime(const CString& sFile) { struct stat st; return (stat(sFile.c_str(), &st) != 0) ? 0 : st.st_atime; } time_t CFile::GetMTime(const CString& sFile) { struct stat st; return (stat(sFile.c_str(), &st) != 0) ? 0 : st.st_mtime; } time_t CFile::GetCTime(const CString& sFile) { struct stat st; return (stat(sFile.c_str(), &st) != 0) ? 0 : st.st_ctime; } uid_t CFile::GetUID(const CString& sFile) { struct stat st; return (stat(sFile.c_str(), &st) != 0) ? -1 : (int)st.st_uid; } gid_t CFile::GetGID(const CString& sFile) { struct stat st; return (stat(sFile.c_str(), &st) != 0) ? -1 : (int)st.st_gid; } int CFile::GetInfo(const CString& sFile, struct stat& st) { return stat(sFile.c_str(), &st); } // // Functions to manipulate the file on the filesystem // bool CFile::Delete() { if (CFile::Delete(m_sLongName)) return true; m_bHadError = true; return false; } bool CFile::Move(const CString& sNewFileName, bool bOverwrite) { if (CFile::Move(m_sLongName, sNewFileName, bOverwrite)) return true; m_bHadError = true; return false; } bool CFile::Copy(const CString& sNewFileName, bool bOverwrite) { if (CFile::Copy(m_sLongName, sNewFileName, bOverwrite)) return true; m_bHadError = true; return false; } bool CFile::Delete(const CString& sFileName) { return (unlink(sFileName.c_str()) == 0) ? true : false; } bool CFile::Move(const CString& sOldFileName, const CString& sNewFileName, bool bOverwrite) { if (CFile::Exists(sNewFileName)) { if (!bOverwrite) { errno = EEXIST; return false; } #ifdef _WIN32 // rename() never overwrites files on Windows. DWORD dFlags = MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING; return (::MoveFileExA(sOldFileName.c_str(), sNewFileName.c_str(), dFlags) != 0); #endif } return (rename(sOldFileName.c_str(), sNewFileName.c_str()) == 0); } bool CFile::Copy(const CString& sOldFileName, const CString& sNewFileName, bool bOverwrite) { if ((!bOverwrite) && (CFile::Exists(sNewFileName))) { errno = EEXIST; return false; } CFile OldFile(sOldFileName); CFile NewFile(sNewFileName); if (!OldFile.Open()) { return false; } if (!NewFile.Open(O_WRONLY | O_CREAT | O_TRUNC)) { return false; } char szBuf[8192]; ssize_t len = 0; while ((len = OldFile.Read(szBuf, 8192))) { if (len < 0) { DEBUG("CFile::Copy() failed: " << strerror(errno)); OldFile.Close(); // That file is only a partial copy, get rid of it NewFile.Close(); NewFile.Delete(); return false; } NewFile.Write(szBuf, len); } OldFile.Close(); NewFile.Close(); struct stat st; GetInfo(sOldFileName, st); Chmod(sNewFileName, st.st_mode); return true; } bool CFile::Chmod(mode_t mode) { if (m_iFD == -1) { errno = EBADF; return false; } if (fchmod(m_iFD, mode) != 0) { m_bHadError = true; return false; } return true; } bool CFile::Chmod(const CString& sFile, mode_t mode) { return (chmod(sFile.c_str(), mode) == 0); } bool CFile::Seek(off_t uPos) { /* This sets errno in case m_iFD == -1 */ errno = EBADF; if (m_iFD != -1 && lseek(m_iFD, uPos, SEEK_SET) == uPos) { ClearBuffer(); return true; } m_bHadError = true; return false; } bool CFile::Truncate() { /* This sets errno in case m_iFD == -1 */ errno = EBADF; if (m_iFD != -1 && ftruncate(m_iFD, 0) == 0) { ClearBuffer(); return true; } m_bHadError = true; return false; } bool CFile::Sync() { /* This sets errno in case m_iFD == -1 */ errno = EBADF; if (m_iFD != -1 && fsync(m_iFD) == 0) return true; m_bHadError = true; return false; } bool CFile::Open(const CString& sFileName, int iFlags, mode_t iMode) { SetFileName(sFileName); return Open(iFlags, iMode); } bool CFile::Open(int iFlags, mode_t iMode) { if (m_iFD != -1) { errno = EEXIST; m_bHadError = true; return false; } // We never want to get a controlling TTY through this -> O_NOCTTY iFlags |= O_NOCTTY; // Some weird OS from MS needs O_BINARY or else it generates fake EOFs // when reading ^Z from a file. iFlags |= O_BINARY; m_iFD = open(m_sLongName.c_str(), iFlags, iMode); if (m_iFD < 0) { m_bHadError = true; return false; } /* Make sure this FD isn't given to childs */ SetFdCloseOnExec(m_iFD); return true; } ssize_t CFile::Read(char* pszBuffer, int iBytes) { if (m_iFD == -1) { errno = EBADF; return -1; } ssize_t res = read(m_iFD, pszBuffer, iBytes); if (res != iBytes) m_bHadError = true; return res; } bool CFile::ReadLine(CString& sData, const CString& sDelimiter) { char buff[4096]; ssize_t iBytes; if (m_iFD == -1) { errno = EBADF; return false; } do { CString::size_type iFind = m_sBuffer.find(sDelimiter); if (iFind != CString::npos) { // We found a line, return it sData = m_sBuffer.substr(0, iFind + sDelimiter.length()); m_sBuffer.erase(0, iFind + sDelimiter.length()); return true; } iBytes = read(m_iFD, buff, sizeof(buff)); if (iBytes > 0) { m_sBuffer.append(buff, iBytes); } } while (iBytes > 0); // We are at the end of the file or an error happened if (!m_sBuffer.empty()) { // ..but there is still some partial line in the buffer sData = m_sBuffer; m_sBuffer.clear(); return true; } // Nothing left for reading :( return false; } bool CFile::ReadFile(CString& sData, size_t iMaxSize) { char buff[4096]; size_t iBytesRead = 0; sData.clear(); while (iBytesRead < iMaxSize) { ssize_t iBytes = Read(buff, sizeof(buff)); if (iBytes < 0) // Error return false; if (iBytes == 0) // EOF return true; sData.append(buff, iBytes); iBytesRead += iBytes; } // Buffer limit reached return false; } ssize_t CFile::Write(const char* pszBuffer, size_t iBytes) { if (m_iFD == -1) { errno = EBADF; return -1; } ssize_t res = write(m_iFD, pszBuffer, iBytes); if (-1 == res) m_bHadError = true; return res; } ssize_t CFile::Write(const CString& sData) { return Write(sData.data(), sData.size()); } void CFile::Close() { if (m_iFD >= 0) { if (close(m_iFD) < 0) { m_bHadError = true; DEBUG("CFile::Close(): close() failed with [" << strerror(errno) << "]"); } } m_iFD = -1; ClearBuffer(); } void CFile::ClearBuffer() { m_sBuffer.clear(); } bool CFile::TryExLock(const CString& sLockFile, int iFlags) { return Open(sLockFile, iFlags) && TryExLock(); } bool CFile::TryExLock() { return Lock(F_WRLCK, false); } bool CFile::ExLock() { return Lock(F_WRLCK, true); } bool CFile::UnLock() { return Lock(F_UNLCK, true); } bool CFile::Lock(short iType, bool bBlocking) { struct flock fl; if (m_iFD == -1) { return false; } fl.l_type = iType; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; return (fcntl(m_iFD, (bBlocking ? F_SETLKW : F_SETLK), &fl) != -1); } bool CFile::IsOpen() const { return (m_iFD != -1); } CString CFile::GetLongName() const { return m_sLongName; } CString CFile::GetShortName() const { return m_sShortName; } CString CFile::GetDir() const { CString sDir(m_sLongName); while (!sDir.empty() && !sDir.EndsWith("/") && !sDir.EndsWith("\\")) { sDir.RightChomp(); } return sDir; } void CFile::InitHomePath(const CString& sFallback) { const char* home = getenv("HOME"); m_sHomePath.clear(); if (home) { m_sHomePath = home; } if (m_sHomePath.empty()) { const struct passwd* pUserInfo = getpwuid(getuid()); if (pUserInfo) { m_sHomePath = pUserInfo->pw_dir; } } if (m_sHomePath.empty()) { m_sHomePath = sFallback; } } CString CDir::ChangeDir(const CString& sPath, const CString& sAdd, const CString& sHome) { CString sHomeDir(sHome); if (sHomeDir.empty()) { sHomeDir = CFile::GetHomePath(); } if (sAdd == "~") { return sHomeDir; } CString sAddDir(sAdd); if (sAddDir.StartsWith("~/")) { sAddDir.LeftChomp(); sAddDir = sHomeDir + sAddDir; } CString sRet = ((sAddDir.size()) && (sAddDir[0] == '/')) ? "" : sPath; sAddDir += "/"; CString sCurDir; sRet.TrimSuffix("/"); for (unsigned int a = 0; a < sAddDir.size(); a++) { switch (sAddDir[a]) { case '/': if (sCurDir == "..") { sRet = sRet.substr(0, sRet.rfind('/')); } else if ((sCurDir != "") && (sCurDir != ".")) { sRet += "/" + sCurDir; } sCurDir = ""; break; default: sCurDir += sAddDir[a]; break; } } return (sRet.empty()) ? "/" : sRet; } CString CDir::CheckPathPrefix(const CString& sPath, const CString& sAdd, const CString& sHomeDir) { CString sPrefix = sPath.Replace_n("//", "/").TrimRight_n("/") + "/"; CString sAbsolutePath = ChangeDir(sPrefix, sAdd, sHomeDir); if (!sAbsolutePath.StartsWith(sPrefix)) return ""; return sAbsolutePath; } bool CDir::MakeDir(const CString& sPath, mode_t iMode) { CString sDir; VCString dirs; VCString::iterator it; // Just in case someone tries this... if (sPath.empty()) { errno = ENOENT; return false; } // If this is an absolute path, we need to handle this now! if (sPath.StartsWith("/")) sDir = "/"; // For every single subpath, do... sPath.Split("/", dirs, false); for (it = dirs.begin(); it != dirs.end(); ++it) { // Add this to the path we already created sDir += *it; int i = mkdir(sDir.c_str(), iMode); if (i != 0) { // All errors except EEXIST are fatal if (errno != EEXIST) return false; // If it's EEXIST we have to make sure it's a dir if (!CFile::IsDir(sDir)) return false; } sDir += "/"; } // All went well return true; } int CExecSock::popen2(int& iReadFD, int& iWriteFD, const CString& sCommand) { int rpipes[2] = {-1, -1}; int wpipes[2] = {-1, -1}; iReadFD = -1; iWriteFD = -1; if (pipe(rpipes) < 0) return -1; if (pipe(wpipes) < 0) { close(rpipes[0]); close(rpipes[1]); return -1; } int iPid = fork(); if (iPid == -1) { close(rpipes[0]); close(rpipes[1]); close(wpipes[0]); close(wpipes[1]); return -1; } if (iPid == 0) { close(wpipes[1]); close(rpipes[0]); dup2(wpipes[0], 0); dup2(rpipes[1], 1); dup2(rpipes[1], 2); close(wpipes[0]); close(rpipes[1]); const char* pArgv[] = {"sh", "-c", sCommand.c_str(), nullptr}; execvp("sh", (char* const*)pArgv); // if execvp returns, there was an error perror("execvp"); exit(1); } close(wpipes[0]); close(rpipes[1]); iWriteFD = wpipes[1]; iReadFD = rpipes[0]; return iPid; } void CExecSock::close2(int iPid, int iReadFD, int iWriteFD) { close(iReadFD); close(iWriteFD); time_t iNow = time(nullptr); while (waitpid(iPid, nullptr, WNOHANG) == 0) { if ((time(nullptr) - iNow) > 5) break; // giveup usleep(100); } return; } znc-1.7.5/src/Buffer.cpp0000644000175000017500000001214413542151610015246 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include CBufLine::CBufLine(const CMessage& Format, const CString& sText) : m_Message(Format), m_sText(sText) {} CBufLine::CBufLine(const CString& sFormat, const CString& sText, const timeval* ts, const MCString& mssTags) : m_sText(sText) { m_Message.Parse(sFormat); m_Message.SetTags(mssTags); if (ts == nullptr) UpdateTime(); else m_Message.SetTime(*ts); } CBufLine::~CBufLine() {} void CBufLine::UpdateTime() { m_Message.SetTime(CUtils::GetTime()); } CMessage CBufLine::ToMessage(const CClient& Client, const MCString& mssParams) const { CMessage Line = m_Message; CString sSender = Line.GetNick().GetNickMask(); Line.SetNick(CNick(CString::NamedFormat(sSender, mssParams))); MCString mssThisParams = mssParams; if (Client.HasServerTime()) { mssThisParams["text"] = m_sText; } else { mssThisParams["text"] = Client.GetUser()->AddTimestamp(Line.GetTime(), m_sText); } // make a copy of params, because the following loop modifies the original VCString vsParams = Line.GetParams(); for (unsigned int uIdx = 0; uIdx < vsParams.size(); ++uIdx) { Line.SetParam(uIdx, CString::NamedFormat(vsParams[uIdx], mssThisParams)); } return Line; } CString CBufLine::GetLine(const CClient& Client, const MCString& mssParams) const { CMessage Line = ToMessage(Client, mssParams); // Note: Discard all tags (except the time tag, conditionally) to // keep the same behavior as ZNC versions 1.6 and earlier had. See // CClient::PutClient(CMessage) documentation for more details. Line.SetTags(MCString::EmptyMap); if (Client.HasServerTime()) { CString sTime = m_Message.GetTag("time"); if (sTime.empty()) { sTime = CUtils::FormatServerTime(m_Message.GetTime()); } Line.SetTag("time", sTime); } return Line.ToString(); } CBuffer::CBuffer(unsigned int uLineCount) : m_uLineCount(uLineCount) {} CBuffer::~CBuffer() {} CBuffer::size_type CBuffer::AddLine(const CMessage& Format, const CString& sText) { if (!m_uLineCount) { return 0; } while (size() >= m_uLineCount) { erase(begin()); } push_back(CBufLine(Format, sText)); return size(); } CBuffer::size_type CBuffer::UpdateLine(const CString& sCommand, const CMessage& Format, const CString& sText) { for (CBufLine& Line : *this) { if (Line.GetCommand().Equals(sCommand)) { Line = CBufLine(Format, sText); return size(); } } return AddLine(Format, sText); } CBuffer::size_type CBuffer::UpdateExactLine(const CMessage& Format, const CString& sText) { for (CBufLine& Line : *this) { if (Line.Equals(Format)) { return size(); } } return AddLine(Format, sText); } CBuffer::size_type CBuffer::AddLine(const CString& sFormat, const CString& sText, const timeval* ts, const MCString& mssTags) { CMessage Message(sFormat); if (ts) { Message.SetTime(*ts); } Message.SetTags(mssTags); return AddLine(Message, sText); } CBuffer::size_type CBuffer::UpdateLine(const CString& sMatch, const CString& sFormat, const CString& sText) { return UpdateLine(CMessage(sMatch).GetCommand(), CMessage(sFormat), sText); } CBuffer::size_type CBuffer::UpdateExactLine(const CString& sFormat, const CString& sText) { return UpdateExactLine(CMessage(sFormat, sText)); } const CBufLine& CBuffer::GetBufLine(unsigned int uIdx) const { return (*this)[uIdx]; } CString CBuffer::GetLine(size_type uIdx, const CClient& Client, const MCString& msParams) const { return (*this)[uIdx].GetLine(Client, msParams); } bool CBuffer::SetLineCount(unsigned int u, bool bForce) { if (!bForce && u > CZNC::Get().GetMaxBufferSize()) { return false; } m_uLineCount = u; // We may need to shrink the buffer if the allowed size got smaller while (size() > m_uLineCount) { erase(begin()); } return true; } znc-1.7.5/src/WebModules.cpp0000644000175000017500000010234013542151610016101 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include using std::pair; using std::vector; /// @todo Do we want to make this a configure option? #define _SKINDIR_ _DATADIR_ "/webskins" const unsigned int CWebSock::m_uiMaxSessions = 5; // We need this class to make sure the contained maps and their content is // destroyed in the order that we want. struct CSessionManager { // Sessions are valid for a day, (24h, ...) CSessionManager() : m_mspSessions(24 * 60 * 60 * 1000), m_mIPSessions() {} ~CSessionManager() { // Make sure all sessions are destroyed before any of our maps // are destroyed m_mspSessions.Clear(); } CWebSessionMap m_mspSessions; std::multimap m_mIPSessions; }; typedef std::multimap::iterator mIPSessionsIterator; static CSessionManager Sessions; class CWebAuth : public CAuthBase { public: CWebAuth(CWebSock* pWebSock, const CString& sUsername, const CString& sPassword, bool bBasic); ~CWebAuth() override {} CWebAuth(const CWebAuth&) = delete; CWebAuth& operator=(const CWebAuth&) = delete; void SetWebSock(CWebSock* pWebSock) { m_pWebSock = pWebSock; } void AcceptedLogin(CUser& User) override; void RefusedLogin(const CString& sReason) override; void Invalidate() override; private: protected: CWebSock* m_pWebSock; bool m_bBasic; }; void CWebSock::FinishUserSessions(const CUser& User) { Sessions.m_mspSessions.FinishUserSessions(User); } CWebSession::~CWebSession() { // Find our entry in mIPSessions pair p = Sessions.m_mIPSessions.equal_range(m_sIP); mIPSessionsIterator it = p.first; mIPSessionsIterator end = p.second; while (it != end) { if (it->second == this) { Sessions.m_mIPSessions.erase(it++); } else { ++it; } } } CZNCTagHandler::CZNCTagHandler(CWebSock& WebSock) : CTemplateTagHandler(), m_WebSock(WebSock) {} bool CZNCTagHandler::HandleTag(CTemplate& Tmpl, const CString& sName, const CString& sArgs, CString& sOutput) { if (sName.Equals("URLPARAM")) { // sOutput = CZNC::Get() sOutput = m_WebSock.GetParam(sArgs.Token(0), false); return true; } return false; } CWebSession::CWebSession(const CString& sId, const CString& sIP) : m_sId(sId), m_sIP(sIP), m_pUser(nullptr), m_vsErrorMsgs(), m_vsSuccessMsgs(), m_tmLastActive() { Sessions.m_mIPSessions.insert(make_pair(sIP, this)); UpdateLastActive(); } void CWebSession::UpdateLastActive() { time(&m_tmLastActive); } bool CWebSession::IsAdmin() const { return IsLoggedIn() && m_pUser->IsAdmin(); } CWebAuth::CWebAuth(CWebSock* pWebSock, const CString& sUsername, const CString& sPassword, bool bBasic) : CAuthBase(sUsername, sPassword, pWebSock), m_pWebSock(pWebSock), m_bBasic(bBasic) {} void CWebSession::ClearMessageLoops() { m_vsErrorMsgs.clear(); m_vsSuccessMsgs.clear(); } void CWebSession::FillMessageLoops(CTemplate& Tmpl) { for (const CString& sMessage : m_vsErrorMsgs) { CTemplate& Row = Tmpl.AddRow("ErrorLoop"); Row["Message"] = sMessage; } for (const CString& sMessage : m_vsSuccessMsgs) { CTemplate& Row = Tmpl.AddRow("SuccessLoop"); Row["Message"] = sMessage; } } size_t CWebSession::AddError(const CString& sMessage) { m_vsErrorMsgs.push_back(sMessage); return m_vsErrorMsgs.size(); } size_t CWebSession::AddSuccess(const CString& sMessage) { m_vsSuccessMsgs.push_back(sMessage); return m_vsSuccessMsgs.size(); } void CWebSessionMap::FinishUserSessions(const CUser& User) { iterator it = m_mItems.begin(); while (it != m_mItems.end()) { if (it->second.second->GetUser() == &User) { m_mItems.erase(it++); } else { ++it; } } } void CWebAuth::AcceptedLogin(CUser& User) { if (m_pWebSock) { std::shared_ptr spSession = m_pWebSock->GetSession(); spSession->SetUser(&User); m_pWebSock->SetLoggedIn(true); m_pWebSock->UnPauseRead(); if (m_bBasic) { m_pWebSock->ReadLine(""); } else { m_pWebSock->Redirect("/?cookie_check=true"); } DEBUG("Successful login attempt ==> USER [" + User.GetUserName() + "] ==> SESSION [" + spSession->GetId() + "]"); } } void CWebAuth::RefusedLogin(const CString& sReason) { if (m_pWebSock) { std::shared_ptr spSession = m_pWebSock->GetSession(); spSession->AddError("Invalid login!"); spSession->SetUser(nullptr); m_pWebSock->SetLoggedIn(false); m_pWebSock->UnPauseRead(); if (m_bBasic) { m_pWebSock->AddHeader("WWW-Authenticate", "Basic realm=\"ZNC\""); m_pWebSock->CHTTPSock::PrintErrorPage( 401, "Unauthorized", "HTTP Basic authentication attempted with invalid credentials"); // Why CWebSock makes this function protected?.. } else { m_pWebSock->Redirect("/?cookie_check=true"); } DEBUG("UNSUCCESSFUL login attempt ==> REASON [" + sReason + "] ==> SESSION [" + spSession->GetId() + "]"); } } void CWebAuth::Invalidate() { CAuthBase::Invalidate(); m_pWebSock = nullptr; } CWebSock::CWebSock(const CString& sURIPrefix) : CHTTPSock(nullptr, sURIPrefix), m_bPathsSet(false), m_Template(), m_spAuth(), m_sModName(""), m_sPath(""), m_sPage(""), m_spSession() { m_Template.AddTagHandler(std::make_shared(*this)); } CWebSock::~CWebSock() { if (m_spAuth) { m_spAuth->Invalidate(); } // we have to account for traffic here because CSocket does // not have a valid CModule* pointer. CUser* pUser = GetSession()->GetUser(); if (pUser) { pUser->AddBytesWritten(GetBytesWritten()); pUser->AddBytesRead(GetBytesRead()); } else { CZNC::Get().AddBytesWritten(GetBytesWritten()); CZNC::Get().AddBytesRead(GetBytesRead()); } // bytes have been accounted for, so make sure they don't get again: ResetBytesWritten(); ResetBytesRead(); } void CWebSock::GetAvailSkins(VCString& vRet) const { vRet.clear(); CString sRoot(GetSkinPath("_default_")); sRoot.TrimRight("/"); sRoot.TrimRight("_default_"); sRoot.TrimRight("/"); if (!sRoot.empty()) { sRoot += "/"; } if (!sRoot.empty() && CFile::IsDir(sRoot)) { CDir Dir(sRoot); for (const CFile* pSubDir : Dir) { if (pSubDir->IsDir() && pSubDir->GetShortName() == "_default_") { vRet.push_back(pSubDir->GetShortName()); break; } } for (const CFile* pSubDir : Dir) { if (pSubDir->IsDir() && pSubDir->GetShortName() != "_default_" && pSubDir->GetShortName() != ".svn") { vRet.push_back(pSubDir->GetShortName()); } } } } VCString CWebSock::GetDirs(CModule* pModule, bool bIsTemplate) { CString sHomeSkinsDir(CZNC::Get().GetZNCPath() + "/webskins/"); CString sSkinName(GetSkinName()); VCString vsResult; // Module specific paths if (pModule) { const CString& sModName(pModule->GetModName()); // 1. ~/.znc/webskins//mods// // if (!sSkinName.empty()) { vsResult.push_back(GetSkinPath(sSkinName) + "/mods/" + sModName + "/"); } // 2. ~/.znc/webskins/_default_/mods// // vsResult.push_back(GetSkinPath("_default_") + "/mods/" + sModName + "/"); // 3. ./modules//tmpl/ // vsResult.push_back(pModule->GetModDataDir() + "/tmpl/"); // 4. ~/.znc/webskins//mods// // if (!sSkinName.empty()) { vsResult.push_back(GetSkinPath(sSkinName) + "/mods/" + sModName + "/"); } // 5. ~/.znc/webskins/_default_/mods// // vsResult.push_back(GetSkinPath("_default_") + "/mods/" + sModName + "/"); } // 6. ~/.znc/webskins// // if (!sSkinName.empty()) { vsResult.push_back(GetSkinPath(sSkinName) + CString(bIsTemplate ? "/tmpl/" : "/")); } // 7. ~/.znc/webskins/_default_/ // vsResult.push_back(GetSkinPath("_default_") + CString(bIsTemplate ? "/tmpl/" : "/")); return vsResult; } CString CWebSock::FindTmpl(CModule* pModule, const CString& sName) { VCString vsDirs = GetDirs(pModule, true); CString sFile = pModule->GetModName() + "_" + sName; for (const CString& sDir : vsDirs) { if (CFile::Exists(CDir::ChangeDir(sDir, sFile))) { m_Template.AppendPath(sDir); return sFile; } } return sName; } void CWebSock::SetPaths(CModule* pModule, bool bIsTemplate) { m_Template.ClearPaths(); VCString vsDirs = GetDirs(pModule, bIsTemplate); for (const CString& sDir : vsDirs) { m_Template.AppendPath(sDir); } m_bPathsSet = true; } void CWebSock::SetVars() { m_Template["SessionUser"] = GetUser(); m_Template["SessionIP"] = GetRemoteIP(); m_Template["Tag"] = CZNC::GetTag(GetSession()->GetUser() != nullptr, true); m_Template["Version"] = CZNC::GetVersion(); m_Template["SkinName"] = GetSkinName(); m_Template["_CSRF_Check"] = GetCSRFCheck(); m_Template["URIPrefix"] = GetURIPrefix(); if (GetSession()->IsAdmin()) { m_Template["IsAdmin"] = "true"; } GetSession()->FillMessageLoops(m_Template); GetSession()->ClearMessageLoops(); // Global Mods CModules& vgMods = CZNC::Get().GetModules(); for (CModule* pgMod : vgMods) { AddModLoop("GlobalModLoop", *pgMod); } // User Mods if (IsLoggedIn()) { CModules& vMods = GetSession()->GetUser()->GetModules(); for (CModule* pMod : vMods) { AddModLoop("UserModLoop", *pMod); } vector vNetworks = GetSession()->GetUser()->GetNetworks(); for (CIRCNetwork* pNetwork : vNetworks) { CModules& vnMods = pNetwork->GetModules(); CTemplate& Row = m_Template.AddRow("NetworkModLoop"); Row["NetworkName"] = pNetwork->GetName(); for (CModule* pnMod : vnMods) { AddModLoop("ModLoop", *pnMod, &Row); } } } if (IsLoggedIn()) { m_Template["LoggedIn"] = "true"; } } bool CWebSock::AddModLoop(const CString& sLoopName, CModule& Module, CTemplate* pTemplate) { if (!pTemplate) { pTemplate = &m_Template; } CString sTitle(Module.GetWebMenuTitle()); if (!sTitle.empty() && (IsLoggedIn() || (!Module.WebRequiresLogin() && !Module.WebRequiresAdmin())) && (GetSession()->IsAdmin() || !Module.WebRequiresAdmin())) { CTemplate& Row = pTemplate->AddRow(sLoopName); bool bActiveModule = false; Row["ModName"] = Module.GetModName(); Row["ModPath"] = Module.GetWebPath(); Row["Title"] = sTitle; if (m_sModName == Module.GetModName()) { CString sModuleType = GetPath().Token(1, false, "/"); if (sModuleType == "global" && Module.GetType() == CModInfo::GlobalModule) { bActiveModule = true; } else if (sModuleType == "user" && Module.GetType() == CModInfo::UserModule) { bActiveModule = true; } else if (sModuleType == "network" && Module.GetType() == CModInfo::NetworkModule) { CIRCNetwork* Network = Module.GetNetwork(); if (Network) { CString sNetworkName = GetPath().Token(2, false, "/"); if (sNetworkName == Network->GetName()) { bActiveModule = true; } } else { bActiveModule = true; } } } if (bActiveModule) { Row["Active"] = "true"; } if (Module.GetUser()) { Row["Username"] = Module.GetUser()->GetUserName(); } VWebSubPages& vSubPages = Module.GetSubPages(); for (TWebSubPage& SubPage : vSubPages) { // bActive is whether or not the current url matches this subpage // (params will be checked below) bool bActive = (m_sModName == Module.GetModName() && m_sPage == SubPage->GetName() && bActiveModule); if (SubPage->RequiresAdmin() && !GetSession()->IsAdmin()) { // Don't add admin-only subpages to requests from non-admin // users continue; } CTemplate& SubRow = Row.AddRow("SubPageLoop"); SubRow["ModName"] = Module.GetModName(); SubRow["ModPath"] = Module.GetWebPath(); SubRow["PageName"] = SubPage->GetName(); SubRow["Title"] = SubPage->GetTitle().empty() ? SubPage->GetName() : SubPage->GetTitle(); CString& sParams = SubRow["Params"]; const VPair& vParams = SubPage->GetParams(); for (const pair& ssNV : vParams) { if (!sParams.empty()) { sParams += "&"; } if (!ssNV.first.empty()) { if (!ssNV.second.empty()) { sParams += ssNV.first.Escape_n(CString::EURL); sParams += "="; sParams += ssNV.second.Escape_n(CString::EURL); } if (bActive && GetParam(ssNV.first, false) != ssNV.second) { bActive = false; } } } if (bActive) { SubRow["Active"] = "true"; } } return true; } return false; } CWebSock::EPageReqResult CWebSock::PrintStaticFile(const CString& sPath, CString& sPageRet, CModule* pModule) { SetPaths(pModule); CString sFile = m_Template.ExpandFile(sPath.TrimLeft_n("/")); DEBUG("About to print [" + sFile + "]"); // Either PrintFile() fails and sends an error page or it succeeds and // sends a result. In both cases we don't have anything more to do. PrintFile(sFile); return PAGE_DONE; } CWebSock::EPageReqResult CWebSock::PrintTemplate(const CString& sPageName, CString& sPageRet, CModule* pModule) { SetVars(); m_Template["PageName"] = sPageName; if (pModule) { m_Template["ModName"] = pModule->GetModName(); if (m_Template.find("Title") == m_Template.end()) { m_Template["Title"] = pModule->GetWebMenuTitle(); } std::vector* breadcrumbs = m_Template.GetLoop("BreadCrumbs"); if (breadcrumbs->size() == 1 && m_Template["Title"] != pModule->GetModName()) { // Module didn't add its own breadcrumbs, so add a generic one... // But it'll be useless if it's the same as module name CTemplate& bread = m_Template.AddRow("BreadCrumbs"); bread["Text"] = m_Template["Title"]; } } if (!m_bPathsSet) { SetPaths(pModule, true); } if (m_Template.GetFileName().empty() && !m_Template.SetFile(sPageName + ".tmpl")) { return PAGE_NOTFOUND; } if (m_Template.PrintString(sPageRet)) { return PAGE_PRINT; } else { return PAGE_NOTFOUND; } } CString CWebSock::GetSkinPath(const CString& sSkinName) { const CString sSkin = sSkinName.Replace_n("/", "_").Replace_n(".", "_"); CString sRet = CZNC::Get().GetZNCPath() + "/webskins/" + sSkin; if (!CFile::IsDir(sRet)) { sRet = CZNC::Get().GetCurPath() + "/webskins/" + sSkin; if (!CFile::IsDir(sRet)) { sRet = CString(_SKINDIR_) + "/" + sSkin; } } return sRet + "/"; } bool CWebSock::ForceLogin() { if (GetSession()->IsLoggedIn()) { return true; } GetSession()->AddError("You must login to view that page"); Redirect("/"); return false; } CString CWebSock::GetRequestCookie(const CString& sKey) { const CString sPrefixedKey = CString(GetLocalPort()) + "-" + sKey; CString sRet; if (!m_sModName.empty()) { sRet = CHTTPSock::GetRequestCookie("Mod-" + m_sModName + "-" + sPrefixedKey); } if (sRet.empty()) { return CHTTPSock::GetRequestCookie(sPrefixedKey); } return sRet; } bool CWebSock::SendCookie(const CString& sKey, const CString& sValue) { const CString sPrefixedKey = CString(GetLocalPort()) + "-" + sKey; if (!m_sModName.empty()) { return CHTTPSock::SendCookie("Mod-" + m_sModName + "-" + sPrefixedKey, sValue); } return CHTTPSock::SendCookie(sPrefixedKey, sValue); } void CWebSock::OnPageRequest(const CString& sURI) { CString sPageRet; EPageReqResult eRet = OnPageRequestInternal(sURI, sPageRet); switch (eRet) { case PAGE_PRINT: PrintPage(sPageRet); break; case PAGE_DEFERRED: // Something else will later call Close() break; case PAGE_DONE: // Redirect or something like that, it's done, just make sure // the connection will be closed Close(CLT_AFTERWRITE); break; case PAGE_NOTFOUND: default: PrintNotFound(); break; } } CWebSock::EPageReqResult CWebSock::OnPageRequestInternal(const CString& sURI, CString& sPageRet) { // Check that their session really belongs to their IP address. IP-based // authentication is bad, but here it's just an extra layer that makes // stealing cookies harder to pull off. // // When their IP is wrong, we give them an invalid cookie. This makes // sure that they will get a new cookie on their next request. if (CZNC::Get().GetProtectWebSessions() && GetSession()->GetIP() != GetRemoteIP()) { DEBUG("Expected IP: " << GetSession()->GetIP()); DEBUG("Remote IP: " << GetRemoteIP()); SendCookie("SessionId", "WRONG_IP_FOR_SESSION"); PrintErrorPage(403, "Access denied", "This session does not belong to your IP."); return PAGE_DONE; } // For pages *not provided* by modules, a CSRF check is performed which involves: // Ensure that they really POSTed from one our forms by checking if they // know the "secret" CSRF check value. Don't do this for login since // CSRF against the login form makes no sense and the login form does a // cookies-enabled check which would break otherwise. // Don't do this, if user authenticated using http-basic auth, because: // 1. they obviously know the password, // 2. it's easier to automate some tasks e.g. user creation, without need to // care about cookies and CSRF if (IsPost() && !m_bBasicAuth && !sURI.StartsWith("/mods/") && !ValidateCSRFCheck(sURI)) { DEBUG("Expected _CSRF_Check: " << GetCSRFCheck()); DEBUG("Actual _CSRF_Check: " << GetParam("_CSRF_Check")); PrintErrorPage( 403, "Access denied", "POST requests need to send " "a secret token to prevent cross-site request forgery attacks."); return PAGE_DONE; } SendCookie("SessionId", GetSession()->GetId()); if (GetSession()->IsLoggedIn()) { m_sUser = GetSession()->GetUser()->GetUserName(); m_bLoggedIn = true; } CLanguageScope user_language( m_bLoggedIn ? GetSession()->GetUser()->GetLanguage() : ""); // Handle the static pages that don't require a login if (sURI == "/") { if (!m_bLoggedIn && GetParam("cookie_check", false).ToBool() && GetRequestCookie("SessionId").empty()) { GetSession()->AddError( "Your browser does not have cookies enabled for this site!"); } return PrintTemplate("index", sPageRet); } else if (sURI == "/favicon.ico") { return PrintStaticFile("/pub/favicon.ico", sPageRet); } else if (sURI == "/robots.txt") { return PrintStaticFile("/pub/robots.txt", sPageRet); } else if (sURI == "/logout") { GetSession()->SetUser(nullptr); SetLoggedIn(false); Redirect("/"); // We already sent a reply return PAGE_DONE; } else if (sURI == "/login") { if (GetParam("submitted").ToBool()) { m_sUser = GetParam("user"); m_sPass = GetParam("pass"); m_bLoggedIn = OnLogin(m_sUser, m_sPass, false); // AcceptedLogin()/RefusedLogin() will call Redirect() return PAGE_DEFERRED; } Redirect("/"); // the login form is here return PAGE_DONE; } else if (sURI.StartsWith("/pub/")) { return PrintStaticFile(sURI, sPageRet); } else if (sURI.StartsWith("/skinfiles/")) { CString sSkinName = sURI.substr(11); CString::size_type uPathStart = sSkinName.find("/"); if (uPathStart != CString::npos) { CString sFilePath = sSkinName.substr(uPathStart + 1); sSkinName.erase(uPathStart); m_Template.ClearPaths(); m_Template.AppendPath(GetSkinPath(sSkinName) + "pub"); if (PrintFile(m_Template.ExpandFile(sFilePath))) { return PAGE_DONE; } else { return PAGE_NOTFOUND; } } return PAGE_NOTFOUND; } else if (sURI.StartsWith("/mods/") || sURI.StartsWith("/modfiles/")) { // Make sure modules are treated as directories if (!sURI.EndsWith("/") && !sURI.Contains(".") && !sURI.TrimLeft_n("/mods/").TrimLeft_n("/").Contains("/")) { Redirect(sURI + "/"); return PAGE_DONE; } // The URI looks like: // /mods/[type]/([network]/)?[module][/page][?arg1=val1&arg2=val2...] m_sPath = GetPath().TrimLeft_n("/"); m_sPath.TrimPrefix("mods/"); m_sPath.TrimPrefix("modfiles/"); CString sType = m_sPath.Token(0, false, "/"); m_sPath = m_sPath.Token(1, true, "/"); CModInfo::EModuleType eModType; if (sType.Equals("global")) { eModType = CModInfo::GlobalModule; } else if (sType.Equals("user")) { eModType = CModInfo::UserModule; } else if (sType.Equals("network")) { eModType = CModInfo::NetworkModule; } else { PrintErrorPage(403, "Forbidden", "Unknown module type [" + sType + "]"); return PAGE_DONE; } if ((eModType != CModInfo::GlobalModule) && !ForceLogin()) { // Make sure we have a valid user return PAGE_DONE; } CIRCNetwork* pNetwork = nullptr; if (eModType == CModInfo::NetworkModule) { CString sNetwork = m_sPath.Token(0, false, "/"); m_sPath = m_sPath.Token(1, true, "/"); pNetwork = GetSession()->GetUser()->FindNetwork(sNetwork); if (!pNetwork) { PrintErrorPage(404, "Not Found", "Network [" + sNetwork + "] not found."); return PAGE_DONE; } } m_sModName = m_sPath.Token(0, false, "/"); m_sPage = m_sPath.Token(1, true, "/"); if (m_sPage.empty()) { m_sPage = "index"; } DEBUG("Path [" + m_sPath + "], Module [" + m_sModName + "], Page [" + m_sPage + "]"); CModule* pModule = nullptr; switch (eModType) { case CModInfo::GlobalModule: pModule = CZNC::Get().GetModules().FindModule(m_sModName); break; case CModInfo::UserModule: pModule = GetSession()->GetUser()->GetModules().FindModule( m_sModName); break; case CModInfo::NetworkModule: pModule = pNetwork->GetModules().FindModule(m_sModName); break; } if (!pModule) return PAGE_NOTFOUND; // Pass CSRF check to module. // Note that the normal CSRF checks are not applied to /mods/ URLs. if (IsPost() && !m_bBasicAuth && !pModule->ValidateWebRequestCSRFCheck(*this, m_sPage)) { DEBUG("Expected _CSRF_Check: " << GetCSRFCheck()); DEBUG("Actual _CSRF_Check: " << GetParam("_CSRF_Check")); PrintErrorPage( 403, "Access denied", "POST requests need to send " "a secret token to prevent cross-site request forgery attacks."); return PAGE_DONE; } m_Template["ModPath"] = pModule->GetWebPath(); m_Template["ModFilesPath"] = pModule->GetWebFilesPath(); if (pModule->WebRequiresLogin() && !ForceLogin()) { return PAGE_PRINT; } else if (pModule->WebRequiresAdmin() && !GetSession()->IsAdmin()) { PrintErrorPage(403, "Forbidden", "You need to be an admin to access this module"); return PAGE_DONE; } else if (pModule->GetType() != CModInfo::GlobalModule && pModule->GetUser() != GetSession()->GetUser()) { PrintErrorPage(403, "Forbidden", "You must login as " + pModule->GetUser()->GetUserName() + " in order to view this page"); return PAGE_DONE; } else if (pModule->OnWebPreRequest(*this, m_sPage)) { return PAGE_DEFERRED; } VWebSubPages& vSubPages = pModule->GetSubPages(); for (TWebSubPage& SubPage : vSubPages) { bool bActive = (m_sModName == pModule->GetModName() && m_sPage == SubPage->GetName()); if (bActive && SubPage->RequiresAdmin() && !GetSession()->IsAdmin()) { PrintErrorPage(403, "Forbidden", "You need to be an admin to access this page"); return PAGE_DONE; } } if (pModule && pModule->GetType() != CModInfo::GlobalModule && (!IsLoggedIn() || pModule->GetUser() != GetSession()->GetUser())) { AddModLoop("UserModLoop", *pModule); } if (sURI.StartsWith("/modfiles/")) { m_Template.AppendPath(GetSkinPath(GetSkinName()) + "/mods/" + m_sModName + "/files/"); m_Template.AppendPath(pModule->GetModDataDir() + "/files/"); if (PrintFile(m_Template.ExpandFile(m_sPage.TrimLeft_n("/")))) { return PAGE_PRINT; } else { return PAGE_NOTFOUND; } } else { SetPaths(pModule, true); CTemplate& breadModule = m_Template.AddRow("BreadCrumbs"); breadModule["Text"] = pModule->GetModName(); breadModule["URL"] = pModule->GetWebPath(); /* if a module returns false from OnWebRequest, it does not want the template to be printed, usually because it did a redirect. */ if (pModule->OnWebRequest(*this, m_sPage, m_Template)) { // If they already sent a reply, let's assume // they did what they wanted to do. if (SentHeader()) { return PAGE_DONE; } return PrintTemplate(m_sPage, sPageRet, pModule); } if (!SentHeader()) { PrintErrorPage( 404, "Not Implemented", "The requested module does not acknowledge web requests"); } return PAGE_DONE; } } else { CString sPage(sURI.Trim_n("/")); if (sPage.length() < 32) { for (unsigned int a = 0; a < sPage.length(); a++) { unsigned char c = sPage[a]; if ((c < '0' || c > '9') && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_') { return PAGE_NOTFOUND; } } return PrintTemplate(sPage, sPageRet); } } return PAGE_NOTFOUND; } void CWebSock::PrintErrorPage(const CString& sMessage) { m_Template.SetFile("Error.tmpl"); m_Template["Action"] = "error"; m_Template["Title"] = "Error"; m_Template["Error"] = sMessage; } static inline bool compareLastActive( const std::pair& first, const std::pair& second) { return first.second->GetLastActive() < second.second->GetLastActive(); } std::shared_ptr CWebSock::GetSession() { if (m_spSession) { return m_spSession; } const CString sCookieSessionId = GetRequestCookie("SessionId"); std::shared_ptr* pSession = Sessions.m_mspSessions.GetItem(sCookieSessionId); if (pSession != nullptr) { // Refresh the timeout Sessions.m_mspSessions.AddItem((*pSession)->GetId(), *pSession); (*pSession)->UpdateLastActive(); m_spSession = *pSession; DEBUG("Found existing session from cookie: [" + sCookieSessionId + "] IsLoggedIn(" + CString((*pSession)->IsLoggedIn() ? "true, " + ((*pSession)->GetUser()->GetUserName()) : "false") + ")"); return *pSession; } if (Sessions.m_mIPSessions.count(GetRemoteIP()) > m_uiMaxSessions) { pair p = Sessions.m_mIPSessions.equal_range(GetRemoteIP()); mIPSessionsIterator it = std::min_element(p.first, p.second, compareLastActive); DEBUG("Remote IP: " << GetRemoteIP() << "; discarding session [" << it->second->GetId() << "]"); Sessions.m_mspSessions.RemItem(it->second->GetId()); } CString sSessionID; do { sSessionID = CString::RandomString(32); sSessionID += ":" + GetRemoteIP() + ":" + CString(GetRemotePort()); sSessionID += ":" + GetLocalIP() + ":" + CString(GetLocalPort()); sSessionID += ":" + CString(time(nullptr)); sSessionID = sSessionID.SHA256(); DEBUG("Auto generated session: [" + sSessionID + "]"); } while (Sessions.m_mspSessions.HasItem(sSessionID)); std::shared_ptr spSession( new CWebSession(sSessionID, GetRemoteIP())); Sessions.m_mspSessions.AddItem(spSession->GetId(), spSession); m_spSession = spSession; return spSession; } CString CWebSock::GetCSRFCheck() { std::shared_ptr pSession = GetSession(); return pSession->GetId().MD5(); } bool CWebSock::ValidateCSRFCheck(const CString& sURI) { return sURI == "/login" || GetParam("_CSRF_Check") == GetCSRFCheck(); } bool CWebSock::OnLogin(const CString& sUser, const CString& sPass, bool bBasic) { DEBUG("=================== CWebSock::OnLogin(), basic auth? " << std::boolalpha << bBasic); m_spAuth = std::make_shared(this, sUser, sPass, bBasic); // Some authentication module could need some time, block this socket // until then. CWebAuth will UnPauseRead(). PauseRead(); CZNC::Get().AuthUser(m_spAuth); // If CWebAuth already set this, don't change it. return IsLoggedIn(); } Csock* CWebSock::GetSockObj(const CString& sHost, unsigned short uPort) { // All listening is done by CListener, thus CWebSock should never have // to listen, but since GetSockObj() is pure virtual... DEBUG("CWebSock::GetSockObj() called - this should never happen!"); return nullptr; } CString CWebSock::GetSkinName() { std::shared_ptr spSession = GetSession(); if (spSession->IsLoggedIn() && !spSession->GetUser()->GetSkinName().empty()) { return spSession->GetUser()->GetSkinName(); } return CZNC::Get().GetSkinName(); } znc-1.7.5/src/Modules.cpp0000644000175000017500000020703313542151610015450 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include using std::map; using std::set; using std::vector; bool ZNC_NO_NEED_TO_DO_ANYTHING_ON_MODULE_CALL_EXITER; #ifndef RTLD_LOCAL #define RTLD_LOCAL 0 #warning "your crap box doesn't define RTLD_LOCAL !?" #endif #define MODUNLOADCHK(func) \ for (CModule * pMod : *this) { \ try { \ CClient* pOldClient = pMod->GetClient(); \ pMod->SetClient(m_pClient); \ CUser* pOldUser = nullptr; \ if (m_pUser) { \ pOldUser = pMod->GetUser(); \ pMod->SetUser(m_pUser); \ } \ CIRCNetwork* pNetwork = nullptr; \ if (m_pNetwork) { \ pNetwork = pMod->GetNetwork(); \ pMod->SetNetwork(m_pNetwork); \ } \ pMod->func; \ if (m_pUser) pMod->SetUser(pOldUser); \ if (m_pNetwork) pMod->SetNetwork(pNetwork); \ pMod->SetClient(pOldClient); \ } catch (const CModule::EModException& e) { \ if (e == CModule::UNLOAD) { \ UnloadModule(pMod->GetModName()); \ } \ } \ } #define MODHALTCHK(func) \ bool bHaltCore = false; \ for (CModule * pMod : *this) { \ try { \ CModule::EModRet e = CModule::CONTINUE; \ CClient* pOldClient = pMod->GetClient(); \ pMod->SetClient(m_pClient); \ CUser* pOldUser = nullptr; \ if (m_pUser) { \ pOldUser = pMod->GetUser(); \ pMod->SetUser(m_pUser); \ } \ CIRCNetwork* pNetwork = nullptr; \ if (m_pNetwork) { \ pNetwork = pMod->GetNetwork(); \ pMod->SetNetwork(m_pNetwork); \ } \ e = pMod->func; \ if (m_pUser) pMod->SetUser(pOldUser); \ if (m_pNetwork) pMod->SetNetwork(pNetwork); \ pMod->SetClient(pOldClient); \ if (e == CModule::HALTMODS) { \ break; \ } else if (e == CModule::HALTCORE) { \ bHaltCore = true; \ } else if (e == CModule::HALT) { \ bHaltCore = true; \ break; \ } \ } catch (const CModule::EModException& e) { \ if (e == CModule::UNLOAD) { \ UnloadModule(pMod->GetModName()); \ } \ } \ } \ return bHaltCore; /////////////////// Timer /////////////////// CTimer::CTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CCron(), m_pModule(pModule), m_sDescription(sDescription) { SetName(sLabel); // Make integration test faster char* szDebugTimer = getenv("ZNC_DEBUG_TIMER"); if (szDebugTimer && *szDebugTimer == '1') { uInterval = std::max(1u, uInterval / 4u); } if (uCycles) { StartMaxCycles(uInterval, uCycles); } else { Start(uInterval); } } CTimer::~CTimer() { m_pModule->UnlinkTimer(this); } void CTimer::SetModule(CModule* p) { m_pModule = p; } void CTimer::SetDescription(const CString& s) { m_sDescription = s; } CModule* CTimer::GetModule() const { return m_pModule; } const CString& CTimer::GetDescription() const { return m_sDescription; } /////////////////// !Timer /////////////////// CModule::CModule(ModHandle pDLL, CUser* pUser, CIRCNetwork* pNetwork, const CString& sModName, const CString& sDataDir, CModInfo::EModuleType eType) : m_eType(eType), m_sDescription(""), m_sTimers(), m_sSockets(), #ifdef HAVE_PTHREAD m_sJobs(), #endif m_pDLL(pDLL), m_pManager(&(CZNC::Get().GetManager())), m_pUser(pUser), m_pNetwork(pNetwork), m_pClient(nullptr), m_sModName(sModName), m_sDataDir(sDataDir), m_sSavePath(""), m_sArgs(""), m_sModPath(""), m_Translation("znc-" + sModName), m_mssRegistry(), m_vSubPages(), m_mCommands() { if (m_pNetwork) { m_sSavePath = m_pNetwork->GetNetworkPath() + "/moddata/" + m_sModName; } else if (m_pUser) { m_sSavePath = m_pUser->GetUserPath() + "/moddata/" + m_sModName; } else { m_sSavePath = CZNC::Get().GetZNCPath() + "/moddata/" + m_sModName; } LoadRegistry(); } CModule::~CModule() { while (!m_sTimers.empty()) { RemTimer(*m_sTimers.begin()); } while (!m_sSockets.empty()) { RemSocket(*m_sSockets.begin()); } SaveRegistry(); #ifdef HAVE_PTHREAD CancelJobs(m_sJobs); #endif } void CModule::SetUser(CUser* pUser) { m_pUser = pUser; } void CModule::SetNetwork(CIRCNetwork* pNetwork) { m_pNetwork = pNetwork; } void CModule::SetClient(CClient* pClient) { m_pClient = pClient; } CString CModule::ExpandString(const CString& sStr) const { CString sRet; return ExpandString(sStr, sRet); } CString& CModule::ExpandString(const CString& sStr, CString& sRet) const { sRet = sStr; if (m_pNetwork) { return m_pNetwork->ExpandString(sRet, sRet); } if (m_pUser) { return m_pUser->ExpandString(sRet, sRet); } return sRet; } const CString& CModule::GetSavePath() const { if (!CFile::Exists(m_sSavePath)) { CDir::MakeDir(m_sSavePath); } return m_sSavePath; } CString CModule::GetWebPath() { switch (m_eType) { case CModInfo::GlobalModule: return "/mods/global/" + GetModName() + "/"; case CModInfo::UserModule: return "/mods/user/" + GetModName() + "/"; case CModInfo::NetworkModule: return "/mods/network/" + m_pNetwork->GetName() + "/" + GetModName() + "/"; default: return "/"; } } CString CModule::GetWebFilesPath() { switch (m_eType) { case CModInfo::GlobalModule: return "/modfiles/global/" + GetModName() + "/"; case CModInfo::UserModule: return "/modfiles/user/" + GetModName() + "/"; case CModInfo::NetworkModule: return "/modfiles/network/" + m_pNetwork->GetName() + "/" + GetModName() + "/"; default: return "/"; } } bool CModule::LoadRegistry() { // CString sPrefix = (m_pUser) ? m_pUser->GetUserName() : ".global"; return (m_mssRegistry.ReadFromDisk(GetSavePath() + "/.registry") == MCString::MCS_SUCCESS); } bool CModule::SaveRegistry() const { // CString sPrefix = (m_pUser) ? m_pUser->GetUserName() : ".global"; return (m_mssRegistry.WriteToDisk(GetSavePath() + "/.registry", 0600) == MCString::MCS_SUCCESS); } bool CModule::MoveRegistry(const CString& sPath) { if (m_sSavePath != sPath) { CFile fOldNVFile = CFile(m_sSavePath + "/.registry"); if (!fOldNVFile.Exists()) { return false; } if (!CFile::Exists(sPath) && !CDir::MakeDir(sPath)) { return false; } fOldNVFile.Copy(sPath + "/.registry"); m_sSavePath = sPath; return true; } return false; } bool CModule::SetNV(const CString& sName, const CString& sValue, bool bWriteToDisk) { m_mssRegistry[sName] = sValue; if (bWriteToDisk) { return SaveRegistry(); } return true; } CString CModule::GetNV(const CString& sName) const { MCString::const_iterator it = m_mssRegistry.find(sName); if (it != m_mssRegistry.end()) { return it->second; } return ""; } bool CModule::DelNV(const CString& sName, bool bWriteToDisk) { MCString::iterator it = m_mssRegistry.find(sName); if (it != m_mssRegistry.end()) { m_mssRegistry.erase(it); } else { return false; } if (bWriteToDisk) { return SaveRegistry(); } return true; } bool CModule::ClearNV(bool bWriteToDisk) { m_mssRegistry.clear(); if (bWriteToDisk) { return SaveRegistry(); } return true; } bool CModule::AddTimer(CTimer* pTimer) { if ((!pTimer) || (!pTimer->GetName().empty() && FindTimer(pTimer->GetName()))) { delete pTimer; return false; } if (!m_sTimers.insert(pTimer).second) // Was already added return true; m_pManager->AddCron(pTimer); return true; } bool CModule::AddTimer(FPTimer_t pFBCallback, const CString& sLabel, u_int uInterval, u_int uCycles, const CString& sDescription) { CFPTimer* pTimer = new CFPTimer(this, uInterval, uCycles, sLabel, sDescription); pTimer->SetFPCallback(pFBCallback); return AddTimer(pTimer); } bool CModule::RemTimer(CTimer* pTimer) { if (m_sTimers.erase(pTimer) == 0) return false; m_pManager->DelCronByAddr(pTimer); return true; } bool CModule::RemTimer(const CString& sLabel) { CTimer* pTimer = FindTimer(sLabel); if (!pTimer) return false; return RemTimer(pTimer); } bool CModule::UnlinkTimer(CTimer* pTimer) { return m_sTimers.erase(pTimer); } CTimer* CModule::FindTimer(const CString& sLabel) { if (sLabel.empty()) { return nullptr; } for (CTimer* pTimer : m_sTimers) { if (pTimer->GetName().Equals(sLabel)) { return pTimer; } } return nullptr; } void CModule::ListTimers() { if (m_sTimers.empty()) { PutModule("You have no timers running."); return; } CTable Table; Table.AddColumn("Name"); Table.AddColumn("Secs"); Table.AddColumn("Cycles"); Table.AddColumn("Description"); for (const CTimer* pTimer : m_sTimers) { unsigned int uCycles = pTimer->GetCyclesLeft(); timeval Interval = pTimer->GetInterval(); Table.AddRow(); Table.SetCell("Name", pTimer->GetName()); Table.SetCell( "Secs", CString(Interval.tv_sec) + "seconds" + (Interval.tv_usec ? " " + CString(Interval.tv_usec) + " microseconds" : "")); Table.SetCell("Cycles", ((uCycles) ? CString(uCycles) : "INF")); Table.SetCell("Description", pTimer->GetDescription()); } PutModule(Table); } bool CModule::AddSocket(CSocket* pSocket) { if (!pSocket) { return false; } m_sSockets.insert(pSocket); return true; } bool CModule::RemSocket(CSocket* pSocket) { if (m_sSockets.erase(pSocket)) { m_pManager->DelSockByAddr(pSocket); return true; } return false; } bool CModule::RemSocket(const CString& sSockName) { for (CSocket* pSocket : m_sSockets) { if (pSocket->GetSockName().Equals(sSockName)) { m_sSockets.erase(pSocket); m_pManager->DelSockByAddr(pSocket); return true; } } return false; } bool CModule::UnlinkSocket(CSocket* pSocket) { return m_sSockets.erase(pSocket); } CSocket* CModule::FindSocket(const CString& sSockName) { for (CSocket* pSocket : m_sSockets) { if (pSocket->GetSockName().Equals(sSockName)) { return pSocket; } } return nullptr; } void CModule::ListSockets() { if (m_sSockets.empty()) { PutModule("You have no open sockets."); return; } CTable Table; Table.AddColumn("Name"); Table.AddColumn("State"); Table.AddColumn("LocalPort"); Table.AddColumn("SSL"); Table.AddColumn("RemoteIP"); Table.AddColumn("RemotePort"); for (const CSocket* pSocket : m_sSockets) { Table.AddRow(); Table.SetCell("Name", pSocket->GetSockName()); if (pSocket->GetType() == CSocket::LISTENER) { Table.SetCell("State", "Listening"); } else { Table.SetCell("State", (pSocket->IsConnected() ? "Connected" : "")); } Table.SetCell("LocalPort", CString(pSocket->GetLocalPort())); Table.SetCell("SSL", (pSocket->GetSSL() ? "yes" : "no")); Table.SetCell("RemoteIP", pSocket->GetRemoteIP()); Table.SetCell("RemotePort", (pSocket->GetRemotePort()) ? CString(pSocket->GetRemotePort()) : CString("")); } PutModule(Table); } #ifdef HAVE_PTHREAD CModuleJob::~CModuleJob() { m_pModule->UnlinkJob(this); } void CModule::AddJob(CModuleJob* pJob) { CThreadPool::Get().addJob(pJob); m_sJobs.insert(pJob); } void CModule::CancelJob(CModuleJob* pJob) { if (pJob == nullptr) return; // Destructor calls UnlinkJob and removes the job from m_sJobs CThreadPool::Get().cancelJob(pJob); } bool CModule::CancelJob(const CString& sJobName) { for (CModuleJob* pJob : m_sJobs) { if (pJob->GetName().Equals(sJobName)) { CancelJob(pJob); return true; } } return false; } void CModule::CancelJobs(const std::set& sJobs) { set sPlainJobs(sJobs.begin(), sJobs.end()); // Destructor calls UnlinkJob and removes the jobs from m_sJobs CThreadPool::Get().cancelJobs(sPlainJobs); } bool CModule::UnlinkJob(CModuleJob* pJob) { return 0 != m_sJobs.erase(pJob); } #endif bool CModule::AddCommand(const CModCommand& Command) { if (Command.GetFunction() == nullptr) return false; if (Command.GetCommand().Contains(" ")) return false; if (FindCommand(Command.GetCommand()) != nullptr) return false; m_mCommands[Command.GetCommand()] = Command; return true; } bool CModule::AddCommand(const CString& sCmd, CModCommand::ModCmdFunc func, const CString& sArgs, const CString& sDesc) { CModCommand cmd(sCmd, this, func, sArgs, sDesc); return AddCommand(cmd); } bool CModule::AddCommand(const CString& sCmd, const COptionalTranslation& Args, const COptionalTranslation& Desc, std::function func) { CModCommand cmd(sCmd, std::move(func), Args, Desc); return AddCommand(std::move(cmd)); } void CModule::AddHelpCommand() { AddCommand("Help", t_d("", "modhelpcmd"), t_d("Generate this output", "modhelpcmd"), [=](const CString& sLine) { HandleHelpCommand(sLine); }); } bool CModule::RemCommand(const CString& sCmd) { return m_mCommands.erase(sCmd) > 0; } const CModCommand* CModule::FindCommand(const CString& sCmd) const { for (const auto& it : m_mCommands) { if (!it.first.Equals(sCmd)) continue; return &it.second; } return nullptr; } bool CModule::HandleCommand(const CString& sLine) { const CString& sCmd = sLine.Token(0); const CModCommand* pCmd = FindCommand(sCmd); if (pCmd) { pCmd->Call(sLine); return true; } OnUnknownModCommand(sLine); return false; } void CModule::HandleHelpCommand(const CString& sLine) { CString sFilter = sLine.Token(1).AsLower(); CTable Table; CModCommand::InitHelp(Table); for (const auto& it : m_mCommands) { CString sCmd = it.second.GetCommand().AsLower(); if (sFilter.empty() || (sCmd.StartsWith(sFilter, CString::CaseSensitive)) || sCmd.WildCmp(sFilter)) { it.second.AddHelp(Table); } } if (Table.empty()) { PutModule(t_f("No matches for '{1}'")(sFilter)); } else { PutModule(Table); } } CString CModule::GetModNick() const { return ((m_pUser) ? m_pUser->GetStatusPrefix() : "*") + m_sModName; } // Webmods bool CModule::OnWebPreRequest(CWebSock& WebSock, const CString& sPageName) { return false; } bool CModule::OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) { return false; } bool CModule::ValidateWebRequestCSRFCheck(CWebSock& WebSock, const CString& sPageName) { return WebSock.ValidateCSRFCheck(WebSock.GetURI()); } bool CModule::OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) { return false; } // !Webmods bool CModule::OnLoad(const CString& sArgs, CString& sMessage) { sMessage = ""; return true; } bool CModule::OnBoot() { return true; } void CModule::OnPreRehash() {} void CModule::OnPostRehash() {} void CModule::OnIRCDisconnected() {} void CModule::OnIRCConnected() {} CModule::EModRet CModule::OnIRCConnecting(CIRCSock* IRCSock) { return CONTINUE; } void CModule::OnIRCConnectionError(CIRCSock* IRCSock) {} CModule::EModRet CModule::OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { return CONTINUE; } CModule::EModRet CModule::OnBroadcast(CString& sMessage) { return CONTINUE; } void CModule::OnChanPermission3(const CNick* pOpNick, const CNick& Nick, CChan& Channel, char cMode, bool bAdded, bool bNoChange) { OnChanPermission2(pOpNick, Nick, Channel, cMode, bAdded, bNoChange); } void CModule::OnChanPermission2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) { if (pOpNick) OnChanPermission(*pOpNick, Nick, Channel, uMode, bAdded, bNoChange); } void CModule::OnOp2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { if (pOpNick) OnOp(*pOpNick, Nick, Channel, bNoChange); } void CModule::OnDeop2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { if (pOpNick) OnDeop(*pOpNick, Nick, Channel, bNoChange); } void CModule::OnVoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { if (pOpNick) OnVoice(*pOpNick, Nick, Channel, bNoChange); } void CModule::OnDevoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { if (pOpNick) OnDevoice(*pOpNick, Nick, Channel, bNoChange); } void CModule::OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) { if (pOpNick) OnRawMode(*pOpNick, Channel, sModes, sArgs); } void CModule::OnMode2(const CNick* pOpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) { if (pOpNick) OnMode(*pOpNick, Channel, uMode, sArg, bAdded, bNoChange); } void CModule::OnChanPermission(const CNick& pOpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) {} void CModule::OnOp(const CNick& pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {} void CModule::OnDeop(const CNick& pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {} void CModule::OnVoice(const CNick& pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {} void CModule::OnDevoice(const CNick& pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {} void CModule::OnRawMode(const CNick& pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) {} void CModule::OnMode(const CNick& pOpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) {} CModule::EModRet CModule::OnRaw(CString& sLine) { return CONTINUE; } CModule::EModRet CModule::OnRawMessage(CMessage& Message) { return CONTINUE; } CModule::EModRet CModule::OnNumericMessage(CNumericMessage& Message) { return CONTINUE; } CModule::EModRet CModule::OnStatusCommand(CString& sCommand) { return CONTINUE; } void CModule::OnModNotice(const CString& sMessage) {} void CModule::OnModCTCP(const CString& sMessage) {} void CModule::OnModCommand(const CString& sCommand) { HandleCommand(sCommand); } void CModule::OnUnknownModCommand(const CString& sLine) { if (m_mCommands.empty()) // This function is only called if OnModCommand wasn't // overriden, so no false warnings for modules which don't use // CModCommand for command handling. PutModule(t_s("This module doesn't implement any commands.")); else PutModule(t_s("Unknown command!")); } void CModule::OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) {} void CModule::OnQuitMessage(CQuitMessage& Message, const vector& vChans) { OnQuit(Message.GetNick(), Message.GetReason(), vChans); } void CModule::OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans) {} void CModule::OnNickMessage(CNickMessage& Message, const vector& vChans) { OnNick(Message.GetNick(), Message.GetNewNick(), vChans); } void CModule::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) {} void CModule::OnKickMessage(CKickMessage& Message) { OnKick(Message.GetNick(), Message.GetKickedNick(), *Message.GetChan(), Message.GetReason()); } CModule::EModRet CModule::OnJoining(CChan& Channel) { return CONTINUE; } void CModule::OnJoin(const CNick& Nick, CChan& Channel) {} void CModule::OnJoinMessage(CJoinMessage& Message) { OnJoin(Message.GetNick(), *Message.GetChan()); } void CModule::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) {} void CModule::OnPartMessage(CPartMessage& Message) { OnPart(Message.GetNick(), *Message.GetChan(), Message.GetReason()); } CModule::EModRet CModule::OnInvite(const CNick& Nick, const CString& sChan) { return CONTINUE; } CModule::EModRet CModule::OnChanBufferStarting(CChan& Chan, CClient& Client) { return CONTINUE; } CModule::EModRet CModule::OnChanBufferEnding(CChan& Chan, CClient& Client) { return CONTINUE; } CModule::EModRet CModule::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { return CONTINUE; } CModule::EModRet CModule::OnPrivBufferStarting(CQuery& Query, CClient& Client) { return CONTINUE; } CModule::EModRet CModule::OnPrivBufferEnding(CQuery& Query, CClient& Client) { return CONTINUE; } CModule::EModRet CModule::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { return CONTINUE; } CModule::EModRet CModule::OnChanBufferPlayLine2(CChan& Chan, CClient& Client, CString& sLine, const timeval& tv) { return OnChanBufferPlayLine(Chan, Client, sLine); } CModule::EModRet CModule::OnPrivBufferPlayLine2(CClient& Client, CString& sLine, const timeval& tv) { return OnPrivBufferPlayLine(Client, sLine); } CModule::EModRet CModule::OnChanBufferPlayMessage(CMessage& Message) { CString sOriginal, sModified; sOriginal = sModified = Message.ToString(CMessage::ExcludeTags); EModRet ret = OnChanBufferPlayLine2( *Message.GetChan(), *Message.GetClient(), sModified, Message.GetTime()); if (sOriginal != sModified) { Message.Parse(sModified); } return ret; } CModule::EModRet CModule::OnPrivBufferPlayMessage(CMessage& Message) { CString sOriginal, sModified; sOriginal = sModified = Message.ToString(CMessage::ExcludeTags); EModRet ret = OnPrivBufferPlayLine2(*Message.GetClient(), sModified, Message.GetTime()); if (sOriginal != sModified) { Message.Parse(sModified); } return ret; } void CModule::OnClientLogin() {} void CModule::OnClientDisconnect() {} CModule::EModRet CModule::OnUserRaw(CString& sLine) { return CONTINUE; } CModule::EModRet CModule::OnUserRawMessage(CMessage& Message) { return CONTINUE; } CModule::EModRet CModule::OnUserCTCPReply(CString& sTarget, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnUserCTCPReplyMessage(CCTCPMessage& Message) { CString sTarget = Message.GetTarget(); CString sText = Message.GetText(); EModRet ret = OnUserCTCPReply(sTarget, sText); Message.SetTarget(sTarget); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnUserCTCP(CString& sTarget, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnUserCTCPMessage(CCTCPMessage& Message) { CString sTarget = Message.GetTarget(); CString sText = Message.GetText(); EModRet ret = OnUserCTCP(sTarget, sText); Message.SetTarget(sTarget); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnUserAction(CString& sTarget, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnUserActionMessage(CActionMessage& Message) { CString sTarget = Message.GetTarget(); CString sText = Message.GetText(); EModRet ret = OnUserAction(sTarget, sText); Message.SetTarget(sTarget); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnUserMsg(CString& sTarget, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnUserTextMessage(CTextMessage& Message) { CString sTarget = Message.GetTarget(); CString sText = Message.GetText(); EModRet ret = OnUserMsg(sTarget, sText); Message.SetTarget(sTarget); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnUserNotice(CString& sTarget, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnUserNoticeMessage(CNoticeMessage& Message) { CString sTarget = Message.GetTarget(); CString sText = Message.GetText(); EModRet ret = OnUserNotice(sTarget, sText); Message.SetTarget(sTarget); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnUserJoin(CString& sChannel, CString& sKey) { return CONTINUE; } CModule::EModRet CModule::OnUserJoinMessage(CJoinMessage& Message) { CString sChan = Message.GetTarget(); CString sKey = Message.GetKey(); EModRet ret = OnUserJoin(sChan, sKey); Message.SetTarget(sChan); Message.SetKey(sKey); return ret; } CModule::EModRet CModule::OnUserPart(CString& sChannel, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnUserPartMessage(CPartMessage& Message) { CString sChan = Message.GetTarget(); CString sReason = Message.GetReason(); EModRet ret = OnUserPart(sChan, sReason); Message.SetTarget(sChan); Message.SetReason(sReason); return ret; } CModule::EModRet CModule::OnUserTopic(CString& sChannel, CString& sTopic) { return CONTINUE; } CModule::EModRet CModule::OnUserTopicMessage(CTopicMessage& Message) { CString sChan = Message.GetTarget(); CString sTopic = Message.GetTopic(); EModRet ret = OnUserTopic(sChan, sTopic); Message.SetTarget(sChan); Message.SetTopic(sTopic); return ret; } CModule::EModRet CModule::OnUserTopicRequest(CString& sChannel) { return CONTINUE; } CModule::EModRet CModule::OnUserQuit(CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnUserQuitMessage(CQuitMessage& Message) { CString sReason = Message.GetReason(); EModRet ret = OnUserQuit(sReason); Message.SetReason(sReason); return ret; } CModule::EModRet CModule::OnCTCPReply(CNick& Nick, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnCTCPReplyMessage(CCTCPMessage& Message) { CString sText = Message.GetText(); EModRet ret = OnCTCPReply(Message.GetNick(), sText); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnPrivCTCP(CNick& Nick, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnPrivCTCPMessage(CCTCPMessage& Message) { CString sText = Message.GetText(); EModRet ret = OnPrivCTCP(Message.GetNick(), sText); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnChanCTCPMessage(CCTCPMessage& Message) { CString sText = Message.GetText(); EModRet ret = OnChanCTCP(Message.GetNick(), *Message.GetChan(), sText); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnPrivAction(CNick& Nick, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnPrivActionMessage(CActionMessage& Message) { CString sText = Message.GetText(); EModRet ret = OnPrivAction(Message.GetNick(), sText); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnChanActionMessage(CActionMessage& Message) { CString sText = Message.GetText(); EModRet ret = OnChanAction(Message.GetNick(), *Message.GetChan(), sText); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnPrivMsg(CNick& Nick, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnPrivTextMessage(CTextMessage& Message) { CString sText = Message.GetText(); EModRet ret = OnPrivMsg(Message.GetNick(), sText); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnChanTextMessage(CTextMessage& Message) { CString sText = Message.GetText(); EModRet ret = OnChanMsg(Message.GetNick(), *Message.GetChan(), sText); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnPrivNotice(CNick& Nick, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnPrivNoticeMessage(CNoticeMessage& Message) { CString sText = Message.GetText(); EModRet ret = OnPrivNotice(Message.GetNick(), sText); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; } CModule::EModRet CModule::OnChanNoticeMessage(CNoticeMessage& Message) { CString sText = Message.GetText(); EModRet ret = OnChanNotice(Message.GetNick(), *Message.GetChan(), sText); Message.SetText(sText); return ret; } CModule::EModRet CModule::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { return CONTINUE; } CModule::EModRet CModule::OnTopicMessage(CTopicMessage& Message) { CString sTopic = Message.GetTopic(); EModRet ret = OnTopic(Message.GetNick(), *Message.GetChan(), sTopic); Message.SetTopic(sTopic); return ret; } CModule::EModRet CModule::OnTimerAutoJoin(CChan& Channel) { return CONTINUE; } CModule::EModRet CModule::OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet) { return CONTINUE; } CModule::EModRet CModule::OnDeleteNetwork(CIRCNetwork& Network) { return CONTINUE; } CModule::EModRet CModule::OnSendToClient(CString& sLine, CClient& Client) { return CONTINUE; } CModule::EModRet CModule::OnSendToClientMessage(CMessage& Message) { return CONTINUE; } CModule::EModRet CModule::OnSendToIRC(CString& sLine) { return CONTINUE; } CModule::EModRet CModule::OnSendToIRCMessage(CMessage& Message) { return CONTINUE; } bool CModule::OnServerCapAvailable(const CString& sCap) { return false; } void CModule::OnServerCapResult(const CString& sCap, bool bSuccess) {} bool CModule::PutIRC(const CString& sLine) { return m_pNetwork ? m_pNetwork->PutIRC(sLine) : false; } bool CModule::PutIRC(const CMessage& Message) { return m_pNetwork ? m_pNetwork->PutIRC(Message) : false; } bool CModule::PutUser(const CString& sLine) { return m_pNetwork ? m_pNetwork->PutUser(sLine, m_pClient) : false; } bool CModule::PutStatus(const CString& sLine) { return m_pNetwork ? m_pNetwork->PutStatus(sLine, m_pClient) : false; } unsigned int CModule::PutModule(const CTable& table) { if (!m_pUser) return 0; unsigned int idx = 0; CString sLine; while (table.GetLine(idx++, sLine)) PutModule(sLine); return idx - 1; } bool CModule::PutModule(const CString& sLine) { if (m_pClient) { m_pClient->PutModule(GetModName(), sLine); return true; } if (m_pNetwork) { return m_pNetwork->PutModule(GetModName(), sLine); } if (m_pUser) { return m_pUser->PutModule(GetModName(), sLine); } return false; } bool CModule::PutModNotice(const CString& sLine) { if (!m_pUser) return false; if (m_pClient) { m_pClient->PutModNotice(GetModName(), sLine); return true; } return m_pUser->PutModNotice(GetModName(), sLine); } /////////////////// // Global Module // /////////////////// CModule::EModRet CModule::OnAddUser(CUser& User, CString& sErrorRet) { return CONTINUE; } CModule::EModRet CModule::OnDeleteUser(CUser& User) { return CONTINUE; } void CModule::OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) {} CModule::EModRet CModule::OnLoginAttempt(std::shared_ptr Auth) { return CONTINUE; } void CModule::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) {} CModule::EModRet CModule::OnUnknownUserRaw(CClient* pClient, CString& sLine) { return CONTINUE; } CModule::EModRet CModule::OnUnknownUserRawMessage(CMessage& Message) { return CONTINUE; } void CModule::OnClientCapLs(CClient* pClient, SCString& ssCaps) {} bool CModule::IsClientCapSupported(CClient* pClient, const CString& sCap, bool bState) { return false; } void CModule::OnClientCapRequest(CClient* pClient, const CString& sCap, bool bState) {} CModule::EModRet CModule::OnModuleLoading(const CString& sModName, const CString& sArgs, CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) { return CONTINUE; } CModule::EModRet CModule::OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) { return CONTINUE; } CModule::EModRet CModule::OnGetModInfo(CModInfo& ModInfo, const CString& sModule, bool& bSuccess, CString& sRetMsg) { return CONTINUE; } void CModule::OnGetAvailableMods(set& ssMods, CModInfo::EModuleType eType) {} CModules::CModules() : m_pUser(nullptr), m_pNetwork(nullptr), m_pClient(nullptr) {} CModules::~CModules() { UnloadAll(); } void CModules::UnloadAll() { while (size()) { CString sRetMsg; CString sModName = back()->GetModName(); UnloadModule(sModName, sRetMsg); } } bool CModules::OnBoot() { for (CModule* pMod : *this) { try { if (!pMod->OnBoot()) { return true; } } catch (const CModule::EModException& e) { if (e == CModule::UNLOAD) { UnloadModule(pMod->GetModName()); } } } return false; } bool CModules::OnPreRehash() { MODUNLOADCHK(OnPreRehash()); return false; } bool CModules::OnPostRehash() { MODUNLOADCHK(OnPostRehash()); return false; } bool CModules::OnIRCConnected() { MODUNLOADCHK(OnIRCConnected()); return false; } bool CModules::OnIRCConnecting(CIRCSock* pIRCSock) { MODHALTCHK(OnIRCConnecting(pIRCSock)); } bool CModules::OnIRCConnectionError(CIRCSock* pIRCSock) { MODUNLOADCHK(OnIRCConnectionError(pIRCSock)); return false; } bool CModules::OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { MODHALTCHK(OnIRCRegistration(sPass, sNick, sIdent, sRealName)); } bool CModules::OnBroadcast(CString& sMessage) { MODHALTCHK(OnBroadcast(sMessage)); } bool CModules::OnIRCDisconnected() { MODUNLOADCHK(OnIRCDisconnected()); return false; } bool CModules::OnChanPermission3(const CNick* pOpNick, const CNick& Nick, CChan& Channel, char cMode, bool bAdded, bool bNoChange) { MODUNLOADCHK( OnChanPermission3(pOpNick, Nick, Channel, cMode, bAdded, bNoChange)); return false; } bool CModules::OnChanPermission2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) { MODUNLOADCHK( OnChanPermission2(pOpNick, Nick, Channel, uMode, bAdded, bNoChange)); return false; } bool CModules::OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) { MODUNLOADCHK( OnChanPermission(OpNick, Nick, Channel, uMode, bAdded, bNoChange)); return false; } bool CModules::OnOp2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnOp2(pOpNick, Nick, Channel, bNoChange)); return false; } bool CModules::OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnOp(OpNick, Nick, Channel, bNoChange)); return false; } bool CModules::OnDeop2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDeop2(pOpNick, Nick, Channel, bNoChange)); return false; } bool CModules::OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDeop(OpNick, Nick, Channel, bNoChange)); return false; } bool CModules::OnVoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnVoice2(pOpNick, Nick, Channel, bNoChange)); return false; } bool CModules::OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnVoice(OpNick, Nick, Channel, bNoChange)); return false; } bool CModules::OnDevoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDevoice2(pOpNick, Nick, Channel, bNoChange)); return false; } bool CModules::OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDevoice(OpNick, Nick, Channel, bNoChange)); return false; } bool CModules::OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) { MODUNLOADCHK(OnRawMode2(pOpNick, Channel, sModes, sArgs)); return false; } bool CModules::OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) { MODUNLOADCHK(OnRawMode(OpNick, Channel, sModes, sArgs)); return false; } bool CModules::OnMode2(const CNick* pOpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) { MODUNLOADCHK(OnMode2(pOpNick, Channel, uMode, sArg, bAdded, bNoChange)); return false; } bool CModules::OnMode(const CNick& OpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) { MODUNLOADCHK(OnMode(OpNick, Channel, uMode, sArg, bAdded, bNoChange)); return false; } bool CModules::OnRaw(CString& sLine) { MODHALTCHK(OnRaw(sLine)); } bool CModules::OnRawMessage(CMessage& Message) { MODHALTCHK(OnRawMessage(Message)); } bool CModules::OnNumericMessage(CNumericMessage& Message) { MODHALTCHK(OnNumericMessage(Message)); } bool CModules::OnClientLogin() { MODUNLOADCHK(OnClientLogin()); return false; } bool CModules::OnClientDisconnect() { MODUNLOADCHK(OnClientDisconnect()); return false; } bool CModules::OnUserRaw(CString& sLine) { MODHALTCHK(OnUserRaw(sLine)); } bool CModules::OnUserRawMessage(CMessage& Message) { MODHALTCHK(OnUserRawMessage(Message)); } bool CModules::OnUserCTCPReply(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCPReply(sTarget, sMessage)); } bool CModules::OnUserCTCPReplyMessage(CCTCPMessage& Message) { MODHALTCHK(OnUserCTCPReplyMessage(Message)); } bool CModules::OnUserCTCP(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCP(sTarget, sMessage)); } bool CModules::OnUserCTCPMessage(CCTCPMessage& Message) { MODHALTCHK(OnUserCTCPMessage(Message)); } bool CModules::OnUserAction(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserAction(sTarget, sMessage)); } bool CModules::OnUserActionMessage(CActionMessage& Message) { MODHALTCHK(OnUserActionMessage(Message)); } bool CModules::OnUserMsg(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserMsg(sTarget, sMessage)); } bool CModules::OnUserTextMessage(CTextMessage& Message) { MODHALTCHK(OnUserTextMessage(Message)); } bool CModules::OnUserNotice(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserNotice(sTarget, sMessage)); } bool CModules::OnUserNoticeMessage(CNoticeMessage& Message) { MODHALTCHK(OnUserNoticeMessage(Message)); } bool CModules::OnUserJoin(CString& sChannel, CString& sKey) { MODHALTCHK(OnUserJoin(sChannel, sKey)); } bool CModules::OnUserJoinMessage(CJoinMessage& Message) { MODHALTCHK(OnUserJoinMessage(Message)); } bool CModules::OnUserPart(CString& sChannel, CString& sMessage) { MODHALTCHK(OnUserPart(sChannel, sMessage)); } bool CModules::OnUserPartMessage(CPartMessage& Message) { MODHALTCHK(OnUserPartMessage(Message)); } bool CModules::OnUserTopic(CString& sChannel, CString& sTopic) { MODHALTCHK(OnUserTopic(sChannel, sTopic)); } bool CModules::OnUserTopicMessage(CTopicMessage& Message) { MODHALTCHK(OnUserTopicMessage(Message)); } bool CModules::OnUserTopicRequest(CString& sChannel) { MODHALTCHK(OnUserTopicRequest(sChannel)); } bool CModules::OnUserQuit(CString& sMessage) { MODHALTCHK(OnUserQuit(sMessage)); } bool CModules::OnUserQuitMessage(CQuitMessage& Message) { MODHALTCHK(OnUserQuitMessage(Message)); } bool CModules::OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) { MODUNLOADCHK(OnQuit(Nick, sMessage, vChans)); return false; } bool CModules::OnQuitMessage(CQuitMessage& Message, const vector& vChans) { MODUNLOADCHK(OnQuitMessage(Message, vChans)); return false; } bool CModules::OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans) { MODUNLOADCHK(OnNick(Nick, sNewNick, vChans)); return false; } bool CModules::OnNickMessage(CNickMessage& Message, const vector& vChans) { MODUNLOADCHK(OnNickMessage(Message, vChans)); return false; } bool CModules::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnKick(Nick, sKickedNick, Channel, sMessage)); return false; } bool CModules::OnKickMessage(CKickMessage& Message) { MODUNLOADCHK(OnKickMessage(Message)); return false; } bool CModules::OnJoining(CChan& Channel) { MODHALTCHK(OnJoining(Channel)); } bool CModules::OnJoin(const CNick& Nick, CChan& Channel) { MODUNLOADCHK(OnJoin(Nick, Channel)); return false; } bool CModules::OnJoinMessage(CJoinMessage& Message) { MODUNLOADCHK(OnJoinMessage(Message)); return false; } bool CModules::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnPart(Nick, Channel, sMessage)); return false; } bool CModules::OnPartMessage(CPartMessage& Message) { MODUNLOADCHK(OnPartMessage(Message)); return false; } bool CModules::OnInvite(const CNick& Nick, const CString& sChan) { MODHALTCHK(OnInvite(Nick, sChan)); } bool CModules::OnChanBufferStarting(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferStarting(Chan, Client)); } bool CModules::OnChanBufferEnding(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferEnding(Chan, Client)); } bool CModules::OnChanBufferPlayLine2(CChan& Chan, CClient& Client, CString& sLine, const timeval& tv) { MODHALTCHK(OnChanBufferPlayLine2(Chan, Client, sLine, tv)); } bool CModules::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { MODHALTCHK(OnChanBufferPlayLine(Chan, Client, sLine)); } bool CModules::OnPrivBufferStarting(CQuery& Query, CClient& Client) { MODHALTCHK(OnPrivBufferStarting(Query, Client)); } bool CModules::OnPrivBufferEnding(CQuery& Query, CClient& Client) { MODHALTCHK(OnPrivBufferEnding(Query, Client)); } bool CModules::OnPrivBufferPlayLine2(CClient& Client, CString& sLine, const timeval& tv) { MODHALTCHK(OnPrivBufferPlayLine2(Client, sLine, tv)); } bool CModules::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { MODHALTCHK(OnPrivBufferPlayLine(Client, sLine)); } bool CModules::OnChanBufferPlayMessage(CMessage& Message) { MODHALTCHK(OnChanBufferPlayMessage(Message)); } bool CModules::OnPrivBufferPlayMessage(CMessage& Message) { MODHALTCHK(OnPrivBufferPlayMessage(Message)); } bool CModules::OnCTCPReply(CNick& Nick, CString& sMessage) { MODHALTCHK(OnCTCPReply(Nick, sMessage)); } bool CModules::OnCTCPReplyMessage(CCTCPMessage& Message) { MODHALTCHK(OnCTCPReplyMessage(Message)); } bool CModules::OnPrivCTCP(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivCTCP(Nick, sMessage)); } bool CModules::OnPrivCTCPMessage(CCTCPMessage& Message) { MODHALTCHK(OnPrivCTCPMessage(Message)); } bool CModules::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanCTCP(Nick, Channel, sMessage)); } bool CModules::OnChanCTCPMessage(CCTCPMessage& Message) { MODHALTCHK(OnChanCTCPMessage(Message)); } bool CModules::OnPrivAction(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivAction(Nick, sMessage)); } bool CModules::OnPrivActionMessage(CActionMessage& Message) { MODHALTCHK(OnPrivActionMessage(Message)); } bool CModules::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanAction(Nick, Channel, sMessage)); } bool CModules::OnChanActionMessage(CActionMessage& Message) { MODHALTCHK(OnChanActionMessage(Message)); } bool CModules::OnPrivMsg(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivMsg(Nick, sMessage)); } bool CModules::OnPrivTextMessage(CTextMessage& Message) { MODHALTCHK(OnPrivTextMessage(Message)); } bool CModules::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanMsg(Nick, Channel, sMessage)); } bool CModules::OnChanTextMessage(CTextMessage& Message) { MODHALTCHK(OnChanTextMessage(Message)); } bool CModules::OnPrivNotice(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivNotice(Nick, sMessage)); } bool CModules::OnPrivNoticeMessage(CNoticeMessage& Message) { MODHALTCHK(OnPrivNoticeMessage(Message)); } bool CModules::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanNotice(Nick, Channel, sMessage)); } bool CModules::OnChanNoticeMessage(CNoticeMessage& Message) { MODHALTCHK(OnChanNoticeMessage(Message)); } bool CModules::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { MODHALTCHK(OnTopic(Nick, Channel, sTopic)); } bool CModules::OnTopicMessage(CTopicMessage& Message) { MODHALTCHK(OnTopicMessage(Message)); } bool CModules::OnTimerAutoJoin(CChan& Channel) { MODHALTCHK(OnTimerAutoJoin(Channel)); } bool CModules::OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet) { MODHALTCHK(OnAddNetwork(Network, sErrorRet)); } bool CModules::OnDeleteNetwork(CIRCNetwork& Network) { MODHALTCHK(OnDeleteNetwork(Network)); } bool CModules::OnSendToClient(CString& sLine, CClient& Client) { MODHALTCHK(OnSendToClient(sLine, Client)); } bool CModules::OnSendToClientMessage(CMessage& Message) { MODHALTCHK(OnSendToClientMessage(Message)); } bool CModules::OnSendToIRC(CString& sLine) { MODHALTCHK(OnSendToIRC(sLine)); } bool CModules::OnSendToIRCMessage(CMessage& Message) { MODHALTCHK(OnSendToIRCMessage(Message)); } bool CModules::OnStatusCommand(CString& sCommand) { MODHALTCHK(OnStatusCommand(sCommand)); } bool CModules::OnModCommand(const CString& sCommand) { MODUNLOADCHK(OnModCommand(sCommand)); return false; } bool CModules::OnModNotice(const CString& sMessage) { MODUNLOADCHK(OnModNotice(sMessage)); return false; } bool CModules::OnModCTCP(const CString& sMessage) { MODUNLOADCHK(OnModCTCP(sMessage)); return false; } // Why MODHALTCHK works only with functions returning EModRet ? :( bool CModules::OnServerCapAvailable(const CString& sCap) { bool bResult = false; for (CModule* pMod : *this) { try { CClient* pOldClient = pMod->GetClient(); pMod->SetClient(m_pClient); if (m_pUser) { CUser* pOldUser = pMod->GetUser(); pMod->SetUser(m_pUser); bResult |= pMod->OnServerCapAvailable(sCap); pMod->SetUser(pOldUser); } else { // WTF? Is that possible? bResult |= pMod->OnServerCapAvailable(sCap); } pMod->SetClient(pOldClient); } catch (const CModule::EModException& e) { if (CModule::UNLOAD == e) { UnloadModule(pMod->GetModName()); } } } return bResult; } bool CModules::OnServerCapResult(const CString& sCap, bool bSuccess) { MODUNLOADCHK(OnServerCapResult(sCap, bSuccess)); return false; } //////////////////// // Global Modules // //////////////////// bool CModules::OnAddUser(CUser& User, CString& sErrorRet) { MODHALTCHK(OnAddUser(User, sErrorRet)); } bool CModules::OnDeleteUser(CUser& User) { MODHALTCHK(OnDeleteUser(User)); } bool CModules::OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) { MODUNLOADCHK(OnClientConnect(pClient, sHost, uPort)); return false; } bool CModules::OnLoginAttempt(std::shared_ptr Auth) { MODHALTCHK(OnLoginAttempt(Auth)); } bool CModules::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) { MODUNLOADCHK(OnFailedLogin(sUsername, sRemoteIP)); return false; } bool CModules::OnUnknownUserRaw(CClient* pClient, CString& sLine) { MODHALTCHK(OnUnknownUserRaw(pClient, sLine)); } bool CModules::OnUnknownUserRawMessage(CMessage& Message) { MODHALTCHK(OnUnknownUserRawMessage(Message)); } bool CModules::OnClientCapLs(CClient* pClient, SCString& ssCaps) { MODUNLOADCHK(OnClientCapLs(pClient, ssCaps)); return false; } // Maybe create new macro for this? bool CModules::IsClientCapSupported(CClient* pClient, const CString& sCap, bool bState) { bool bResult = false; for (CModule* pMod : *this) { try { CClient* pOldClient = pMod->GetClient(); pMod->SetClient(m_pClient); if (m_pUser) { CUser* pOldUser = pMod->GetUser(); pMod->SetUser(m_pUser); bResult |= pMod->IsClientCapSupported(pClient, sCap, bState); pMod->SetUser(pOldUser); } else { // WTF? Is that possible? bResult |= pMod->IsClientCapSupported(pClient, sCap, bState); } pMod->SetClient(pOldClient); } catch (const CModule::EModException& e) { if (CModule::UNLOAD == e) { UnloadModule(pMod->GetModName()); } } } return bResult; } bool CModules::OnClientCapRequest(CClient* pClient, const CString& sCap, bool bState) { MODUNLOADCHK(OnClientCapRequest(pClient, sCap, bState)); return false; } bool CModules::OnModuleLoading(const CString& sModName, const CString& sArgs, CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) { MODHALTCHK(OnModuleLoading(sModName, sArgs, eType, bSuccess, sRetMsg)); } bool CModules::OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) { MODHALTCHK(OnModuleUnloading(pModule, bSuccess, sRetMsg)); } bool CModules::OnGetModInfo(CModInfo& ModInfo, const CString& sModule, bool& bSuccess, CString& sRetMsg) { MODHALTCHK(OnGetModInfo(ModInfo, sModule, bSuccess, sRetMsg)); } bool CModules::OnGetAvailableMods(set& ssMods, CModInfo::EModuleType eType) { MODUNLOADCHK(OnGetAvailableMods(ssMods, eType)); return false; } CModule* CModules::FindModule(const CString& sModule) const { for (CModule* pMod : *this) { if (sModule.Equals(pMod->GetModName())) { return pMod; } } return nullptr; } bool CModules::ValidateModuleName(const CString& sModule, CString& sRetMsg) { for (unsigned int a = 0; a < sModule.length(); a++) { if (((sModule[a] < '0') || (sModule[a] > '9')) && ((sModule[a] < 'a') || (sModule[a] > 'z')) && ((sModule[a] < 'A') || (sModule[a] > 'Z')) && (sModule[a] != '_')) { sRetMsg = t_f("Module names can only contain letters, numbers and " "underscores, [{1}] is invalid")(sModule); return false; } } return true; } bool CModules::LoadModule(const CString& sModule, const CString& sArgs, CModInfo::EModuleType eType, CUser* pUser, CIRCNetwork* pNetwork, CString& sRetMsg) { sRetMsg = ""; if (!ValidateModuleName(sModule, sRetMsg)) { return false; } if (FindModule(sModule) != nullptr) { sRetMsg = t_f("Module {1} already loaded.")(sModule); return false; } bool bSuccess; bool bHandled = false; _GLOBALMODULECALL(OnModuleLoading(sModule, sArgs, eType, bSuccess, sRetMsg), pUser, pNetwork, nullptr, &bHandled); if (bHandled) return bSuccess; CString sModPath, sDataPath; CModInfo Info; if (!FindModPath(sModule, sModPath, sDataPath)) { sRetMsg = t_f("Unable to find module {1}")(sModule); return false; } Info.SetName(sModule); Info.SetPath(sModPath); ModHandle p = OpenModule(sModule, sModPath, Info, sRetMsg); if (!p) return false; if (!Info.SupportsType(eType)) { dlclose(p); sRetMsg = t_f("Module {1} does not support module type {2}.")( sModule, CModInfo::ModuleTypeToString(eType)); return false; } if (!pUser && eType == CModInfo::UserModule) { dlclose(p); sRetMsg = t_f("Module {1} requires a user.")(sModule); return false; } if (!pNetwork && eType == CModInfo::NetworkModule) { dlclose(p); sRetMsg = t_f("Module {1} requires a network.")(sModule); return false; } CModule* pModule = Info.GetLoader()(p, pUser, pNetwork, sModule, sDataPath, eType); pModule->SetDescription(Info.GetDescription()); pModule->SetArgs(sArgs); pModule->SetModPath(CDir::ChangeDir(CZNC::Get().GetCurPath(), sModPath)); push_back(pModule); bool bLoaded; try { bLoaded = pModule->OnLoad(sArgs, sRetMsg); } catch (const CModule::EModException&) { bLoaded = false; sRetMsg = t_s("Caught an exception"); } if (!bLoaded) { UnloadModule(sModule, sModPath); if (!sRetMsg.empty()) sRetMsg = t_f("Module {1} aborted: {2}")(sModule, sRetMsg); else sRetMsg = t_f("Module {1} aborted.")(sModule); return false; } if (!sRetMsg.empty()) { sRetMsg += " "; } sRetMsg += "[" + sModPath + "]"; return true; } bool CModules::UnloadModule(const CString& sModule) { CString s; return UnloadModule(sModule, s); } bool CModules::UnloadModule(const CString& sModule, CString& sRetMsg) { // Make a copy incase the reference passed in is from CModule::GetModName() CString sMod = sModule; CModule* pModule = FindModule(sMod); sRetMsg = ""; if (!pModule) { sRetMsg = t_f("Module [{1}] not loaded.")(sMod); return false; } bool bSuccess; bool bHandled = false; _GLOBALMODULECALL(OnModuleUnloading(pModule, bSuccess, sRetMsg), pModule->GetUser(), pModule->GetNetwork(), nullptr, &bHandled); if (bHandled) return bSuccess; ModHandle p = pModule->GetDLL(); if (p) { delete pModule; for (iterator it = begin(); it != end(); ++it) { if (*it == pModule) { erase(it); break; } } dlclose(p); sRetMsg = t_f("Module {1} unloaded.")(sMod); return true; } sRetMsg = t_f("Unable to unload module {1}.")(sMod); return false; } bool CModules::ReloadModule(const CString& sModule, const CString& sArgs, CUser* pUser, CIRCNetwork* pNetwork, CString& sRetMsg) { // Make a copy incase the reference passed in is from CModule::GetModName() CString sMod = sModule; CModule* pModule = FindModule(sMod); if (!pModule) { sRetMsg = t_f("Module [{1}] not loaded.")(sMod); return false; } CModInfo::EModuleType eType = pModule->GetType(); pModule = nullptr; sRetMsg = ""; if (!UnloadModule(sMod, sRetMsg)) { return false; } if (!LoadModule(sMod, sArgs, eType, pUser, pNetwork, sRetMsg)) { return false; } sRetMsg = t_f("Reloaded module {1}.")(sMod); return true; } bool CModules::GetModInfo(CModInfo& ModInfo, const CString& sModule, CString& sRetMsg) { if (!ValidateModuleName(sModule, sRetMsg)) { return false; } CString sModPath, sTmp; bool bSuccess; bool bHandled = false; GLOBALMODULECALL(OnGetModInfo(ModInfo, sModule, bSuccess, sRetMsg), &bHandled); if (bHandled) return bSuccess; if (!FindModPath(sModule, sModPath, sTmp)) { sRetMsg = t_f("Unable to find module {1}.")(sModule); return false; } return GetModPathInfo(ModInfo, sModule, sModPath, sRetMsg); } bool CModules::GetModPathInfo(CModInfo& ModInfo, const CString& sModule, const CString& sModPath, CString& sRetMsg) { if (!ValidateModuleName(sModule, sRetMsg)) { return false; } ModInfo.SetName(sModule); ModInfo.SetPath(sModPath); ModHandle p = OpenModule(sModule, sModPath, ModInfo, sRetMsg); if (!p) return false; dlclose(p); return true; } void CModules::GetAvailableMods(set& ssMods, CModInfo::EModuleType eType) { ssMods.clear(); unsigned int a = 0; CDir Dir; ModDirList dirs = GetModDirs(); while (!dirs.empty()) { Dir.FillByWildcard(dirs.front().first, "*.so"); dirs.pop(); for (a = 0; a < Dir.size(); a++) { CFile& File = *Dir[a]; CString sName = File.GetShortName(); CString sPath = File.GetLongName(); CModInfo ModInfo; sName.RightChomp(3); CString sIgnoreRetMsg; if (GetModPathInfo(ModInfo, sName, sPath, sIgnoreRetMsg)) { if (ModInfo.SupportsType(eType)) { ssMods.insert(ModInfo); } } } } GLOBALMODULECALL(OnGetAvailableMods(ssMods, eType), NOTHING); } void CModules::GetDefaultMods(set& ssMods, CModInfo::EModuleType eType) { GetAvailableMods(ssMods, eType); const map ns = { {"chansaver", CModInfo::UserModule}, {"controlpanel", CModInfo::UserModule}, {"simple_away", CModInfo::NetworkModule}, {"webadmin", CModInfo::GlobalModule}}; auto it = ssMods.begin(); while (it != ssMods.end()) { auto it2 = ns.find(it->GetName()); if (it2 != ns.end() && it2->second == eType) { ++it; } else { it = ssMods.erase(it); } } } bool CModules::FindModPath(const CString& sModule, CString& sModPath, CString& sDataPath) { CString sMod = sModule; CString sDir = sMod; if (!sModule.Contains(".")) sMod += ".so"; ModDirList dirs = GetModDirs(); while (!dirs.empty()) { sModPath = dirs.front().first + sMod; sDataPath = dirs.front().second; dirs.pop(); if (CFile::Exists(sModPath)) { sDataPath += sDir; return true; } } return false; } CModules::ModDirList CModules::GetModDirs() { ModDirList ret; CString sDir; #ifdef RUN_FROM_SOURCE // ./modules sDir = CZNC::Get().GetCurPath() + "/modules/"; ret.push(std::make_pair(sDir, sDir + "data/")); #endif // ~/.znc/modules sDir = CZNC::Get().GetModPath() + "/"; ret.push(std::make_pair(sDir, sDir)); // and (/lib/znc) ret.push(std::make_pair(_MODDIR_ + CString("/"), _DATADIR_ + CString("/modules/"))); return ret; } ModHandle CModules::OpenModule(const CString& sModule, const CString& sModPath, CModInfo& Info, CString& sRetMsg) { // Some sane defaults in case anything errors out below sRetMsg.clear(); if (!ValidateModuleName(sModule, sRetMsg)) { return nullptr; } // The second argument to dlopen() has a long history. It seems clear // that (despite what the man page says) we must include either of // RTLD_NOW and RTLD_LAZY and either of RTLD_GLOBAL and RTLD_LOCAL. // // RTLD_NOW vs. RTLD_LAZY: We use RTLD_NOW to avoid ZNC dying due to // failed symbol lookups later on. Doesn't really seem to have much of a // performance impact. // // RTLD_GLOBAL vs. RTLD_LOCAL: If perl is loaded with RTLD_LOCAL and later // on loads own modules (which it apparently does with RTLD_LAZY), we will // die in a name lookup since one of perl's symbols isn't found. That's // worse than any theoretical issue with RTLD_GLOBAL. ModHandle p = dlopen((sModPath).c_str(), RTLD_NOW | RTLD_GLOBAL); if (!p) { // dlerror() returns pointer to static buffer, which may be overwritten // very soon with another dl call also it may just return null. const char* cDlError = dlerror(); CString sDlError = cDlError ? cDlError : t_s("Unknown error"); sRetMsg = t_f("Unable to open module {1}: {2}")(sModule, sDlError); return nullptr; } const CModuleEntry* (*fpZNCModuleEntry)() = nullptr; // man dlsym(3) explains this *reinterpret_cast(&fpZNCModuleEntry) = dlsym(p, "ZNCModuleEntry"); if (!fpZNCModuleEntry) { dlclose(p); sRetMsg = t_f("Could not find ZNCModuleEntry in module {1}")(sModule); return nullptr; } const CModuleEntry* pModuleEntry = fpZNCModuleEntry(); if (std::strcmp(pModuleEntry->pcVersion, VERSION_STR) || std::strcmp(pModuleEntry->pcVersionExtra, VERSION_EXTRA)) { sRetMsg = t_f( "Version mismatch for module {1}: core is {2}, module is built for " "{3}. Recompile this module.")( sModule, VERSION_STR VERSION_EXTRA, CString(pModuleEntry->pcVersion) + pModuleEntry->pcVersionExtra); dlclose(p); return nullptr; } if (std::strcmp(pModuleEntry->pcCompileOptions, ZNC_COMPILE_OPTIONS_STRING)) { sRetMsg = t_f( "Module {1} is built incompatibly: core is '{2}', module is '{3}'. " "Recompile this module.")(sModule, ZNC_COMPILE_OPTIONS_STRING, pModuleEntry->pcCompileOptions); dlclose(p); return nullptr; } CTranslationDomainRefHolder translation("znc-" + sModule); pModuleEntry->fpFillModInfo(Info); sRetMsg = ""; return p; } CModCommand::CModCommand() : m_sCmd(), m_pFunc(nullptr), m_Args(""), m_Desc("") {} CModCommand::CModCommand(const CString& sCmd, CModule* pMod, ModCmdFunc func, const CString& sArgs, const CString& sDesc) : m_sCmd(sCmd), m_pFunc([pMod, func](const CString& sLine) { (pMod->*func)(sLine); }), m_Args(sArgs), m_Desc(sDesc) {} CModCommand::CModCommand(const CString& sCmd, CmdFunc func, const COptionalTranslation& Args, const COptionalTranslation& Desc) : m_sCmd(sCmd), m_pFunc(std::move(func)), m_Args(Args), m_Desc(Desc) {} void CModCommand::InitHelp(CTable& Table) { Table.AddColumn(t_s("Command", "modhelpcmd")); Table.AddColumn(t_s("Description", "modhelpcmd")); } void CModCommand::AddHelp(CTable& Table) const { Table.AddRow(); Table.SetCell(t_s("Command", "modhelpcmd"), GetCommand() + " " + GetArgs()); Table.SetCell(t_s("Description", "modhelpcmd"), GetDescription()); } CString CModule::t_s(const CString& sEnglish, const CString& sContext) const { return CTranslation::Get().Singular("znc-" + GetModName(), sContext, sEnglish); } CInlineFormatMessage CModule::t_f(const CString& sEnglish, const CString& sContext) const { return CInlineFormatMessage(t_s(sEnglish, sContext)); } CInlineFormatMessage CModule::t_p(const CString& sEnglish, const CString& sEnglishes, int iNum, const CString& sContext) const { return CInlineFormatMessage(CTranslation::Get().Plural( "znc-" + GetModName(), sContext, sEnglish, sEnglishes, iNum)); } CDelayedTranslation CModule::t_d(const CString& sEnglish, const CString& sContext) const { return CDelayedTranslation("znc-" + GetModName(), sContext, sEnglish); } CString CModInfo::t_s(const CString& sEnglish, const CString& sContext) const { return CTranslation::Get().Singular("znc-" + GetName(), sContext, sEnglish); } znc-1.7.5/src/CMakeLists.txt0000644000175000017500000001102213542151610016063 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if(CMAKE_VERSION VERSION_LESS 3.2) # Since 3.2 it does this automatically from BYPRODUCTS set_source_files_properties("versionc.cpp" PROPERTIES GENERATED true) endif() set(znc_cpp "ZNCString.cpp" "znc.cpp" "IRCNetwork.cpp" "Translation.cpp" "IRCSock.cpp" "Client.cpp" "Chan.cpp" "Nick.cpp" "Server.cpp" "Modules.cpp" "MD5.cpp" "Buffer.cpp" "Utils.cpp" "FileUtils.cpp" "HTTPSock.cpp" "Template.cpp" "ClientCommand.cpp" "Socket.cpp" "SHA256.cpp" "WebModules.cpp" "Listener.cpp" "Config.cpp" "ZNCDebug.cpp" "Threads.cpp" "Query.cpp" "SSLVerifyHost.cpp" "Message.cpp" "User.cpp") znc_add_library(znclib ${lib_type} ${znc_cpp} "Csocket.cpp" "versionc.cpp") znc_add_executable(znc "main.cpp") target_link_libraries(znc PRIVATE znclib) copy_csocket(copy_csocket_cc "${PROJECT_SOURCE_DIR}/third_party/Csocket/Csocket.cc" "${CMAKE_CURRENT_BINARY_DIR}/Csocket.cpp") # make-tarball.sh can create this file, it'll contain -nightly-20151221-71eaf94 if(EXISTS "${PROJECT_SOURCE_DIR}/.nightly") file(READ "${PROJECT_SOURCE_DIR}/.nightly" nightly) string(STRIP "${nightly}" nightly) else() set(nightly "") endif() add_custom_target(version COMMAND "${CMAKE_COMMAND}" -D "nightly=${nightly}" -D "alpha_version=${alpha_version}" -D "append_git_version=${append_git_version}" -D "gitcmd=${GIT_EXECUTABLE}" -D "srcdir=${PROJECT_SOURCE_DIR}" -D "srcfile=${CMAKE_CURRENT_SOURCE_DIR}/version.cpp.in" -D "destfile=${CMAKE_CURRENT_BINARY_DIR}/versionc.cpp" -P "${PROJECT_SOURCE_DIR}/cmake/gen_version.cmake" # This is versionc to avoid possible conflict with version.cpp generated # by make-tarball.sh BYPRODUCTS "versionc.cpp" WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" VERBATIM) add_dependencies(znclib copy_csocket_h copy_csocket_cc version) set(znc_include_dirs "$" "$" "$") target_link_libraries(znclib ${CMAKE_DL_LIBS} Threads::Threads) if(OPENSSL_FOUND) target_link_libraries(znclib ${OPENSSL_LIBRARIES}) list(APPEND znc_include_dirs "${OPENSSL_INCLUDE_DIR}") endif() if(ZLIB_FOUND) target_link_libraries(znclib ${ZLIB_LIBRARIES}) list(APPEND znc_include_dirs ${ZLIB_INCLUDE_DIRS}) endif() if(ICU_FOUND) target_link_libraries(znclib ${ICU_LDFLAGS}) list(APPEND znc_include_dirs ${ICU_INCLUDE_DIRS}) endif() if(Boost_FOUND) target_link_libraries(znclib ${Boost_LIBRARIES}) list(APPEND znc_include_dirs ${Boost_INCLUDE_DIRS}) endif() target_include_directories(znc PUBLIC ${znc_include_dirs}) target_include_directories(znclib PUBLIC ${znc_include_dirs}) set_target_properties(znclib ${znc_link} PROPERTIES COMPILE_OPTIONS "-include;znc/zncconfig.h" INTERFACE_COMPILE_OPTIONS "-include;znc/zncconfig.h" POSITION_INDEPENDENT_CODE true INTERFACE_POSITION_INDEPENDENT_CODE true # This option is relevant only on non-cygwin ENABLE_EXPORTS true) # The following options are relevant only on cygwin set_target_properties(znclib PROPERTIES OUTPUT_NAME "znc" SOVERSION "${ZNC_VERSION}") # CMake started supporting metafeature cxx_std_11 only in 3.8 set(required_cxx11_features cxx_range_for cxx_nullptr cxx_override cxx_lambdas cxx_auto_type) target_compile_features(znc PUBLIC ${required_cxx11_features}) target_compile_features(znclib PUBLIC ${required_cxx11_features}) add_library(ZNC INTERFACE) target_link_libraries(ZNC INTERFACE ${znc_link}) target_compile_definitions(ZNC INTERFACE "znc_export_lib_EXPORTS") if(HAVE_I18N) add_subdirectory(po) endif() install(TARGETS znc ${install_lib} EXPORT znc_internal RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" # this one is libznc.dll.a for cygwin ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") install(TARGETS ZNC EXPORT znc_public) install(EXPORT znc_internal DESTINATION "${CMAKE_INSTALL_DATADIR}/znc/cmake" NAMESPACE ZNC::internal::) install(EXPORT znc_public DESTINATION "${CMAKE_INSTALL_DATADIR}/znc/cmake" NAMESPACE ZNC::) znc-1.7.5/src/Chan.cpp0000644000175000017500000005417113542151610014714 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include using std::set; using std::vector; using std::map; CChan::CChan(const CString& sName, CIRCNetwork* pNetwork, bool bInConfig, CConfig* pConfig) : m_bDetached(false), m_bIsOn(false), m_bAutoClearChanBuffer(pNetwork->GetUser()->AutoClearChanBuffer()), m_bInConfig(bInConfig), m_bDisabled(false), m_bHasBufferCountSet(false), m_bHasAutoClearChanBufferSet(false), m_sName(sName.Token(0)), m_sKey(sName.Token(1)), m_sTopic(""), m_sTopicOwner(""), m_ulTopicDate(0), m_ulCreationDate(0), m_pNetwork(pNetwork), m_Nick(), m_uJoinTries(0), m_sDefaultModes(""), m_msNicks(), m_Buffer(), m_bModeKnown(false), m_mcsModes() { if (!m_pNetwork->IsChan(m_sName)) { m_sName = "#" + m_sName; } m_Nick.SetNetwork(m_pNetwork); m_Buffer.SetLineCount(m_pNetwork->GetUser()->GetChanBufferSize(), true); if (pConfig) { CString sValue; if (pConfig->FindStringEntry("buffer", sValue)) SetBufferCount(sValue.ToUInt(), true); if (pConfig->FindStringEntry("autoclearchanbuffer", sValue)) SetAutoClearChanBuffer(sValue.ToBool()); if (pConfig->FindStringEntry("keepbuffer", sValue)) // XXX Compatibility crap, added in 0.207 SetAutoClearChanBuffer(!sValue.ToBool()); if (pConfig->FindStringEntry("detached", sValue)) SetDetached(sValue.ToBool()); if (pConfig->FindStringEntry("disabled", sValue)) if (sValue.ToBool()) Disable(); if (pConfig->FindStringEntry("autocycle", sValue)) if (sValue.Equals("true")) CUtils::PrintError( "WARNING: AutoCycle has been removed, instead try -> " "LoadModule = autocycle " + sName); if (pConfig->FindStringEntry("key", sValue)) SetKey(sValue); if (pConfig->FindStringEntry("modes", sValue)) SetDefaultModes(sValue); } } CChan::~CChan() { ClearNicks(); } void CChan::Reset() { m_bIsOn = false; m_bModeKnown = false; m_mcsModes.clear(); m_sTopic = ""; m_sTopicOwner = ""; m_ulTopicDate = 0; m_ulCreationDate = 0; m_Nick.Reset(); ClearNicks(); ResetJoinTries(); } CConfig CChan::ToConfig() const { CConfig config; if (m_bHasBufferCountSet) config.AddKeyValuePair("Buffer", CString(GetBufferCount())); if (m_bHasAutoClearChanBufferSet) config.AddKeyValuePair("AutoClearChanBuffer", CString(AutoClearChanBuffer())); if (IsDetached()) config.AddKeyValuePair("Detached", "true"); if (IsDisabled()) config.AddKeyValuePair("Disabled", "true"); if (!GetKey().empty()) config.AddKeyValuePair("Key", GetKey()); if (!GetDefaultModes().empty()) config.AddKeyValuePair("Modes", GetDefaultModes()); return config; } void CChan::Clone(CChan& chan) { // We assume that m_sName and m_pNetwork are equal SetBufferCount(chan.GetBufferCount(), true); SetAutoClearChanBuffer(chan.AutoClearChanBuffer()); SetKey(chan.GetKey()); SetDefaultModes(chan.GetDefaultModes()); if (IsDetached() != chan.IsDetached()) { // Only send something if it makes sense // (= Only detach if client is on the channel // and only attach if we are on the channel) if (IsOn()) { if (IsDetached()) { AttachUser(); } else { DetachUser(); } } SetDetached(chan.IsDetached()); } } void CChan::Cycle() const { m_pNetwork->PutIRC("PART " + GetName() + "\r\nJOIN " + GetName() + " " + GetKey()); } void CChan::JoinUser(const CString& sKey) { if (!IsOn() && !sKey.empty()) { SetKey(sKey); } m_pNetwork->PutIRC("JOIN " + GetName() + " " + GetKey()); } void CChan::AttachUser(CClient* pClient) { m_pNetwork->PutUser( ":" + m_pNetwork->GetIRCNick().GetNickMask() + " JOIN :" + GetName(), pClient); if (!GetTopic().empty()) { m_pNetwork->PutUser(":" + m_pNetwork->GetIRCServer() + " 332 " + m_pNetwork->GetIRCNick().GetNick() + " " + GetName() + " :" + GetTopic(), pClient); m_pNetwork->PutUser(":" + m_pNetwork->GetIRCServer() + " 333 " + m_pNetwork->GetIRCNick().GetNick() + " " + GetName() + " " + GetTopicOwner() + " " + CString(GetTopicDate()), pClient); } CString sPre = ":" + m_pNetwork->GetIRCServer() + " 353 " + m_pNetwork->GetIRCNick().GetNick() + " " + GetModeForNames() + " " + GetName() + " :"; CString sLine = sPre; CString sPerm, sNick; const vector& vpClients = m_pNetwork->GetClients(); for (CClient* pEachClient : vpClients) { CClient* pThisClient; if (!pClient) pThisClient = pEachClient; else pThisClient = pClient; for (map::iterator a = m_msNicks.begin(); a != m_msNicks.end(); ++a) { if (pThisClient->HasNamesx()) { sPerm = a->second.GetPermStr(); } else { char c = a->second.GetPermChar(); sPerm = ""; if (c != '\0') { sPerm += c; } } if (pThisClient->HasUHNames() && !a->second.GetIdent().empty() && !a->second.GetHost().empty()) { sNick = a->first + "!" + a->second.GetIdent() + "@" + a->second.GetHost(); } else { sNick = a->first; } sLine += sPerm + sNick; if (sLine.size() >= 490 || a == (--m_msNicks.end())) { m_pNetwork->PutUser(sLine, pThisClient); sLine = sPre; } else { sLine += " "; } } if (pClient) // We only want to do this for one client break; } m_pNetwork->PutUser(":" + m_pNetwork->GetIRCServer() + " 366 " + m_pNetwork->GetIRCNick().GetNick() + " " + GetName() + " :End of /NAMES list.", pClient); m_bDetached = false; // Send Buffer SendBuffer(pClient); } void CChan::DetachUser() { if (!m_bDetached) { m_pNetwork->PutUser(":" + m_pNetwork->GetIRCNick().GetNickMask() + " PART " + GetName()); m_bDetached = true; } } CString CChan::GetModeString() const { CString sModes, sArgs; for (const auto& it : m_mcsModes) { sModes += it.first; if (it.second.size()) { sArgs += " " + it.second; } } return sModes.empty() ? sModes : CString("+" + sModes + sArgs); } CString CChan::GetModeForNames() const { CString sMode; for (const auto& it : m_mcsModes) { if (it.first == 's') { sMode = "@"; } else if ((it.first == 'p') && sMode.empty()) { sMode = "*"; } } return (sMode.empty() ? "=" : sMode); } void CChan::SetModes(const CString& sModes) { m_mcsModes.clear(); ModeChange(sModes); } void CChan::SetAutoClearChanBuffer(bool b) { m_bHasAutoClearChanBufferSet = true; m_bAutoClearChanBuffer = b; if (m_bAutoClearChanBuffer && !IsDetached() && m_pNetwork->IsUserOnline()) { ClearBuffer(); } } void CChan::InheritAutoClearChanBuffer(bool b) { if (!m_bHasAutoClearChanBufferSet) { m_bAutoClearChanBuffer = b; if (m_bAutoClearChanBuffer && !IsDetached() && m_pNetwork->IsUserOnline()) { ClearBuffer(); } } } void CChan::ResetAutoClearChanBuffer() { SetAutoClearChanBuffer(m_pNetwork->GetUser()->AutoClearChanBuffer()); m_bHasAutoClearChanBufferSet = false; } void CChan::OnWho(const CString& sNick, const CString& sIdent, const CString& sHost) { CNick* pNick = FindNick(sNick); if (pNick) { pNick->SetIdent(sIdent); pNick->SetHost(sHost); } } void CChan::ModeChange(const CString& sModes, const CNick* pOpNick) { CString sModeArg = sModes.Token(0); CString sArgs = sModes.Token(1, true); bool bAdd = true; /* Try to find a CNick* from this channel so that pOpNick->HasPerm() * works as expected. */ if (pOpNick) { CNick* OpNick = FindNick(pOpNick->GetNick()); /* If nothing was found, use the original pOpNick, else use the * CNick* from FindNick() */ if (OpNick) pOpNick = OpNick; } NETWORKMODULECALL(OnRawMode2(pOpNick, *this, sModeArg, sArgs), m_pNetwork->GetUser(), m_pNetwork, nullptr, NOTHING); for (unsigned int a = 0; a < sModeArg.size(); a++) { const char& cMode = sModeArg[a]; if (cMode == '+') { bAdd = true; } else if (cMode == '-') { bAdd = false; } else if (m_pNetwork->GetIRCSock()->IsPermMode(cMode)) { CString sArg = GetModeArg(sArgs); CNick* pNick = FindNick(sArg); if (pNick) { char cPerm = m_pNetwork->GetIRCSock()->GetPermFromMode(cMode); if (cPerm) { bool bNoChange = (pNick->HasPerm(cPerm) == bAdd); if (bAdd) { pNick->AddPerm(cPerm); if (pNick->NickEquals(m_pNetwork->GetCurNick())) { AddPerm(cPerm); } } else { pNick->RemPerm(cPerm); if (pNick->NickEquals(m_pNetwork->GetCurNick())) { RemPerm(cPerm); } } NETWORKMODULECALL(OnChanPermission3(pOpNick, *pNick, *this, cMode, bAdd, bNoChange), m_pNetwork->GetUser(), m_pNetwork, nullptr, NOTHING); if (cMode == CChan::M_Op) { if (bAdd) { NETWORKMODULECALL( OnOp2(pOpNick, *pNick, *this, bNoChange), m_pNetwork->GetUser(), m_pNetwork, nullptr, NOTHING); } else { NETWORKMODULECALL( OnDeop2(pOpNick, *pNick, *this, bNoChange), m_pNetwork->GetUser(), m_pNetwork, nullptr, NOTHING); } } else if (cMode == CChan::M_Voice) { if (bAdd) { NETWORKMODULECALL( OnVoice2(pOpNick, *pNick, *this, bNoChange), m_pNetwork->GetUser(), m_pNetwork, nullptr, NOTHING); } else { NETWORKMODULECALL( OnDevoice2(pOpNick, *pNick, *this, bNoChange), m_pNetwork->GetUser(), m_pNetwork, nullptr, NOTHING); } } } } } else { bool bList = false; CString sArg; switch (m_pNetwork->GetIRCSock()->GetModeType(cMode)) { case CIRCSock::ListArg: bList = true; sArg = GetModeArg(sArgs); break; case CIRCSock::HasArg: sArg = GetModeArg(sArgs); break; case CIRCSock::NoArg: break; case CIRCSock::ArgWhenSet: if (bAdd) { sArg = GetModeArg(sArgs); } break; } bool bNoChange; if (bList) { bNoChange = false; } else if (bAdd) { bNoChange = HasMode(cMode) && GetModeArg(cMode) == sArg; } else { bNoChange = !HasMode(cMode); } NETWORKMODULECALL( OnMode2(pOpNick, *this, cMode, sArg, bAdd, bNoChange), m_pNetwork->GetUser(), m_pNetwork, nullptr, NOTHING); if (!bList) { (bAdd) ? AddMode(cMode, sArg) : RemMode(cMode); } // This is called when we join (ZNC requests the channel modes // on join) *and* when someone changes the channel keys. // We ignore channel key "*" because of some broken nets. if (cMode == M_Key && !bNoChange && bAdd && sArg != "*") { SetKey(sArg); } } } } CString CChan::GetOptions() const { VCString vsRet; if (IsDetached()) { vsRet.push_back("Detached"); } if (AutoClearChanBuffer()) { if (HasAutoClearChanBufferSet()) { vsRet.push_back("AutoClearChanBuffer"); } else { vsRet.push_back("AutoClearChanBuffer (default)"); } } return CString(", ").Join(vsRet.begin(), vsRet.end()); } CString CChan::GetModeArg(char cMode) const { if (cMode) { map::const_iterator it = m_mcsModes.find(cMode); if (it != m_mcsModes.end()) { return it->second; } } return ""; } bool CChan::HasMode(char cMode) const { return (cMode && m_mcsModes.find(cMode) != m_mcsModes.end()); } bool CChan::AddMode(char cMode, const CString& sArg) { m_mcsModes[cMode] = sArg; return true; } bool CChan::RemMode(char cMode) { if (!HasMode(cMode)) { return false; } m_mcsModes.erase(cMode); return true; } CString CChan::GetModeArg(CString& sArgs) const { CString sRet = sArgs.substr(0, sArgs.find(' ')); sArgs = (sRet.size() < sArgs.size()) ? sArgs.substr(sRet.size() + 1) : ""; return sRet; } void CChan::ClearNicks() { m_msNicks.clear(); } int CChan::AddNicks(const CString& sNicks) { int iRet = 0; VCString vsNicks; sNicks.Split(" ", vsNicks, false); for (const CString& sNick : vsNicks) { if (AddNick(sNick)) { iRet++; } } return iRet; } bool CChan::AddNick(const CString& sNick) { const char* p = sNick.c_str(); CString sPrefix, sTmp, sIdent, sHost; while (m_pNetwork->GetIRCSock()->IsPermChar(*p)) { sPrefix += *p; if (!*++p) { return false; } } sTmp = p; // The UHNames extension gets us nick!ident@host instead of just plain nick sIdent = sTmp.Token(1, true, "!"); sHost = sIdent.Token(1, true, "@"); sIdent = sIdent.Token(0, false, "@"); // Get the nick sTmp = sTmp.Token(0, false, "!"); CNick tmpNick(sTmp); CNick* pNick = FindNick(sTmp); if (!pNick) { pNick = &tmpNick; pNick->SetNetwork(m_pNetwork); } if (!sIdent.empty()) pNick->SetIdent(sIdent); if (!sHost.empty()) pNick->SetHost(sHost); for (CString::size_type i = 0; i < sPrefix.length(); i++) { pNick->AddPerm(sPrefix[i]); } if (pNick->NickEquals(m_pNetwork->GetCurNick())) { for (CString::size_type i = 0; i < sPrefix.length(); i++) { AddPerm(sPrefix[i]); } } m_msNicks[pNick->GetNick()] = *pNick; return true; } map CChan::GetPermCounts() const { map mRet; for (const auto& it : m_msNicks) { CString sPerms = it.second.GetPermStr(); for (unsigned int p = 0; p < sPerms.size(); p++) { mRet[sPerms[p]]++; } } return mRet; } bool CChan::RemNick(const CString& sNick) { map::iterator it; it = m_msNicks.find(sNick); if (it == m_msNicks.end()) { return false; } m_msNicks.erase(it); return true; } bool CChan::ChangeNick(const CString& sOldNick, const CString& sNewNick) { map::iterator it = m_msNicks.find(sOldNick); if (it == m_msNicks.end()) { return false; } // Rename this nick it->second.SetNick(sNewNick); // Insert a new element into the map then erase the old one, do this to // change the key to the new nick m_msNicks[sNewNick] = it->second; m_msNicks.erase(it); return true; } const CNick* CChan::FindNick(const CString& sNick) const { map::const_iterator it = m_msNicks.find(sNick); return (it != m_msNicks.end()) ? &it->second : nullptr; } CNick* CChan::FindNick(const CString& sNick) { map::iterator it = m_msNicks.find(sNick); return (it != m_msNicks.end()) ? &it->second : nullptr; } void CChan::SendBuffer(CClient* pClient) { SendBuffer(pClient, m_Buffer); if (AutoClearChanBuffer()) { ClearBuffer(); } } void CChan::SendBuffer(CClient* pClient, const CBuffer& Buffer) { if (m_pNetwork && m_pNetwork->IsUserAttached()) { // in the event that pClient is nullptr, need to send this to all // clients for the user I'm presuming here that pClient is listed // inside vClients thus vClients at this point can't be empty. // // This loop has to be cycled twice to maintain the existing behavior // which is // 1. OnChanBufferStarting // 2. OnChanBufferPlayLine // 3. ClearBuffer() if not keeping the buffer // 4. OnChanBufferEnding // // With the exception of ClearBuffer(), this needs to happen per // client, and if pClient is not nullptr, the loops break after the // first iteration. // // Rework this if you like ... if (!Buffer.IsEmpty()) { const vector& vClients = m_pNetwork->GetClients(); for (CClient* pEachClient : vClients) { CClient* pUseClient = (pClient ? pClient : pEachClient); bool bWasPlaybackActive = pUseClient->IsPlaybackActive(); pUseClient->SetPlaybackActive(true); bool bSkipStatusMsg = pUseClient->HasServerTime(); NETWORKMODULECALL(OnChanBufferStarting(*this, *pUseClient), m_pNetwork->GetUser(), m_pNetwork, nullptr, &bSkipStatusMsg); if (!bSkipStatusMsg) { m_pNetwork->PutUser(":***!znc@znc.in PRIVMSG " + GetName() + " :" + t_s("Buffer Playback..."), pUseClient); } bool bBatch = pUseClient->HasBatch(); CString sBatchName = GetName().MD5(); if (bBatch) { m_pNetwork->PutUser(":znc.in BATCH +" + sBatchName + " znc.in/playback " + GetName(), pUseClient); } size_t uSize = Buffer.Size(); for (size_t uIdx = 0; uIdx < uSize; uIdx++) { const CBufLine& BufLine = Buffer.GetBufLine(uIdx); CMessage Message = BufLine.ToMessage(*pUseClient, MCString::EmptyMap); Message.SetChan(this); Message.SetNetwork(m_pNetwork); Message.SetClient(pUseClient); if (bBatch) { Message.SetTag("batch", sBatchName); } bool bNotShowThisLine = false; NETWORKMODULECALL(OnChanBufferPlayMessage(Message), m_pNetwork->GetUser(), m_pNetwork, nullptr, &bNotShowThisLine); if (bNotShowThisLine) continue; m_pNetwork->PutUser(Message, pUseClient); } bSkipStatusMsg = pUseClient->HasServerTime(); NETWORKMODULECALL(OnChanBufferEnding(*this, *pUseClient), m_pNetwork->GetUser(), m_pNetwork, nullptr, &bSkipStatusMsg); if (!bSkipStatusMsg) { m_pNetwork->PutUser(":***!znc@znc.in PRIVMSG " + GetName() + " :" + t_s("Playback Complete."), pUseClient); } if (bBatch) { m_pNetwork->PutUser(":znc.in BATCH -" + sBatchName, pUseClient); } pUseClient->SetPlaybackActive(bWasPlaybackActive); if (pClient) break; } } } } void CChan::Enable() { ResetJoinTries(); m_bDisabled = false; } void CChan::SetKey(const CString& s) { if (m_sKey != s) { m_sKey = s; if (m_bInConfig) { CZNC::Get().SetConfigState(CZNC::ECONFIG_DELAYED_WRITE); } } } void CChan::SetInConfig(bool b) { if (m_bInConfig != b) { m_bInConfig = b; CZNC::Get().SetConfigState(CZNC::ECONFIG_DELAYED_WRITE); } } void CChan::ResetBufferCount() { SetBufferCount(m_pNetwork->GetUser()->GetBufferCount()); m_bHasBufferCountSet = false; } znc-1.7.5/src/Utils.cpp0000644000175000017500000006661013542151610015144 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef __CYGWIN__ #ifndef _XOPEN_SOURCE // strptime() wants this #define _XOPEN_SOURCE 600 #endif #endif #include #include #include #include #ifdef HAVE_LIBSSL #include #include #include #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER < 0x20700000L) #define X509_getm_notBefore X509_get_notBefore #define X509_getm_notAfter X509_get_notAfter #endif #endif /* HAVE_LIBSSL */ #include #include #include #include #include #include #include #ifdef HAVE_TCSETATTR #include #endif #ifdef HAVE_ICU #include #include #endif // Required with GCC 4.3+ if openssl is disabled #include #include #include using std::map; using std::vector; CUtils::CUtils() {} CUtils::~CUtils() {} #ifdef HAVE_LIBSSL // Generated by "openssl dhparam 2048" constexpr const char* szDefaultDH2048 = "-----BEGIN DH PARAMETERS-----\n" "MIIBCAKCAQEAtS/K3TMY8IHzcCATQSjUF3rDidjDDQmT+mLxyxRORmzMPjFIFkKH\n" "MOmxZvyCBArdaoCCEBBOzrldl/bBLn5TOeZb+MW7mpBLANTuQSOu97DDM7EzbnqC\n" "b6z3QgixZ2+UqxdmQAu4nBPLFwym6W/XPFEHpz6iHISSvjzzo4cfI0xwWTcoAvFQ\n" "r/ZU5BXSXp7XuDxSyyAqaaKUxquElf+x56QWrpNJypjzPpslg5ViAKwWQS0TnCrU\n" "sVuhFtbNlZjqW1tMSBxiWFltS1HoEaaI79MEpf1Ps25OrQl8xqqCGKkZcHlNo4oF\n" "cvUyzAEcCQYHmiYjp2hoZbSa8b690TQaAwIBAg==\n" "-----END DH PARAMETERS-----\n"; void CUtils::GenerateCert(FILE* pOut, const CString& sHost) { const int days = 365; const int years = 10; unsigned int uSeed = (unsigned int)time(nullptr); int serial = (rand_r(&uSeed) % 9999); std::unique_ptr pExponent(BN_new(), ::BN_free); if (!pExponent || !BN_set_word(pExponent.get(), 0x10001)) return; std::unique_ptr pRSA(RSA_new(), ::RSA_free); if (!pRSA || !RSA_generate_key_ex(pRSA.get(), 2048, pExponent.get(), nullptr)) return; std::unique_ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free); if (!pKey || !EVP_PKEY_set1_RSA(pKey.get(), pRSA.get())) return; std::unique_ptr pCert(X509_new(), ::X509_free); if (!pCert) return; X509_set_version(pCert.get(), 2); ASN1_INTEGER_set(X509_get_serialNumber(pCert.get()), serial); X509_gmtime_adj(X509_getm_notBefore(pCert.get()), 0); X509_gmtime_adj(X509_getm_notAfter(pCert.get()), (long)60 * 60 * 24 * days * years); X509_set_pubkey(pCert.get(), pKey.get()); const char* pLogName = getenv("LOGNAME"); const char* pHostName = nullptr; if (!pLogName) pLogName = "Unknown"; if (!sHost.empty()) pHostName = sHost.c_str(); if (!pHostName) pHostName = getenv("HOSTNAME"); if (!pHostName) pHostName = "host.unknown"; CString sEmailAddr = pLogName; sEmailAddr += "@"; sEmailAddr += pHostName; X509_NAME* pName = X509_get_subject_name(pCert.get()); X509_NAME_add_entry_by_txt(pName, "OU", MBSTRING_ASC, (unsigned char*)pLogName, -1, -1, 0); X509_NAME_add_entry_by_txt(pName, "CN", MBSTRING_ASC, (unsigned char*)pHostName, -1, -1, 0); X509_NAME_add_entry_by_txt(pName, "emailAddress", MBSTRING_ASC, (unsigned char*)sEmailAddr.c_str(), -1, -1, 0); X509_set_issuer_name(pCert.get(), pName); if (!X509_sign(pCert.get(), pKey.get(), EVP_sha256())) return; PEM_write_RSAPrivateKey(pOut, pRSA.get(), nullptr, nullptr, 0, nullptr, nullptr); PEM_write_X509(pOut, pCert.get()); fprintf(pOut, "%s", szDefaultDH2048); } #endif /* HAVE_LIBSSL */ CString CUtils::GetIP(unsigned long addr) { char szBuf[16]; memset((char*)szBuf, 0, 16); if (addr >= (1 << 24)) { unsigned long ip[4]; ip[0] = addr >> 24 & 255; ip[1] = addr >> 16 & 255; ip[2] = addr >> 8 & 255; ip[3] = addr & 255; sprintf(szBuf, "%lu.%lu.%lu.%lu", ip[0], ip[1], ip[2], ip[3]); } return szBuf; } unsigned long CUtils::GetLongIP(const CString& sIP) { unsigned long ret; char ip[4][4]; unsigned int i; i = sscanf(sIP.c_str(), "%3[0-9].%3[0-9].%3[0-9].%3[0-9]", ip[0], ip[1], ip[2], ip[3]); if (i != 4) return 0; // Beware that atoi("200") << 24 would overflow and turn negative! ret = atol(ip[0]) << 24; ret += atol(ip[1]) << 16; ret += atol(ip[2]) << 8; ret += atol(ip[3]) << 0; return ret; } // If you change this here and in GetSaltedHashPass(), // don't forget CUser::HASH_DEFAULT! // TODO refactor this const CString CUtils::sDefaultHash = "sha256"; CString CUtils::GetSaltedHashPass(CString& sSalt) { sSalt = GetSalt(); while (true) { CString pass1; do { pass1 = CUtils::GetPass("Enter password"); } while (pass1.empty()); CString pass2 = CUtils::GetPass("Confirm password"); if (!pass1.Equals(pass2, CString::CaseSensitive)) { CUtils::PrintError("The supplied passwords did not match"); } else { // Construct the salted pass return SaltedSHA256Hash(pass1, sSalt); } } } CString CUtils::GetSalt() { return CString::RandomString(20); } CString CUtils::SaltedMD5Hash(const CString& sPass, const CString& sSalt) { return CString(sPass + sSalt).MD5(); } CString CUtils::SaltedSHA256Hash(const CString& sPass, const CString& sSalt) { return CString(sPass + sSalt).SHA256(); } CString CUtils::GetPass(const CString& sPrompt) { #ifdef HAVE_TCSETATTR // Disable echo struct termios t; tcgetattr(1, &t); struct termios t2 = t; t2.c_lflag &= ~ECHO; tcsetattr(1, TCSANOW, &t2); // Read pass CString r; GetInput(sPrompt, r); // Restore echo and go to new line tcsetattr(1, TCSANOW, &t); fprintf(stdout, "\n"); fflush(stdout); return r; #else PrintPrompt(sPrompt); #ifdef HAVE_GETPASSPHRASE return getpassphrase(""); #else return getpass(""); #endif #endif } bool CUtils::GetBoolInput(const CString& sPrompt, bool bDefault) { return CUtils::GetBoolInput(sPrompt, &bDefault); } bool CUtils::GetBoolInput(const CString& sPrompt, bool* pbDefault) { CString sRet, sDefault; if (pbDefault) { sDefault = (*pbDefault) ? "yes" : "no"; } while (true) { GetInput(sPrompt, sRet, sDefault, "yes/no"); if (sRet.Equals("y") || sRet.Equals("yes")) { return true; } else if (sRet.Equals("n") || sRet.Equals("no")) { return false; } } } bool CUtils::GetNumInput(const CString& sPrompt, unsigned int& uRet, unsigned int uMin, unsigned int uMax, unsigned int uDefault) { if (uMin > uMax) { return false; } CString sDefault = (uDefault != (unsigned int)~0) ? CString(uDefault) : ""; CString sNum, sHint; if (uMax != (unsigned int)~0) { sHint = CString(uMin) + " to " + CString(uMax); } else if (uMin > 0) { sHint = CString(uMin) + " and up"; } while (true) { GetInput(sPrompt, sNum, sDefault, sHint); if (sNum.empty()) { return false; } uRet = sNum.ToUInt(); if ((uRet >= uMin && uRet <= uMax)) { break; } CUtils::PrintError("Number must be " + sHint); } return true; } bool CUtils::GetInput(const CString& sPrompt, CString& sRet, const CString& sDefault, const CString& sHint) { CString sExtra; CString sInput; sExtra += (!sHint.empty()) ? (" (" + sHint + ")") : ""; sExtra += (!sDefault.empty()) ? (" [" + sDefault + "]") : ""; PrintPrompt(sPrompt + sExtra); char szBuf[1024]; memset(szBuf, 0, 1024); if (fgets(szBuf, 1024, stdin) == nullptr) { // Reading failed (Error? EOF?) PrintError("Error while reading from stdin. Exiting..."); exit(-1); } sInput = szBuf; sInput.TrimSuffix("\n"); if (sInput.empty()) { sRet = sDefault; } else { sRet = sInput; } return !sRet.empty(); } #define BOLD "\033[1m" #define NORM "\033[22m" #define RED "\033[31m" #define GRN "\033[32m" #define YEL "\033[33m" #define BLU "\033[34m" #define DFL "\033[39m" void CUtils::PrintError(const CString& sMessage) { if (CDebug::StdoutIsTTY()) fprintf(stdout, BOLD BLU "[" RED " ** " BLU "]" DFL NORM " %s\n", sMessage.c_str()); else fprintf(stdout, "%s\n", sMessage.c_str()); fflush(stdout); } void CUtils::PrintPrompt(const CString& sMessage) { if (CDebug::StdoutIsTTY()) fprintf(stdout, BOLD BLU "[" YEL " ?? " BLU "]" DFL NORM " %s: ", sMessage.c_str()); else fprintf(stdout, "[ ?? ] %s: ", sMessage.c_str()); fflush(stdout); } void CUtils::PrintMessage(const CString& sMessage, bool bStrong) { if (CDebug::StdoutIsTTY()) { if (bStrong) fprintf(stdout, BOLD BLU "[" YEL " ** " BLU "]" DFL BOLD " %s" NORM "\n", sMessage.c_str()); else fprintf(stdout, BOLD BLU "[" YEL " ** " BLU "]" DFL NORM " %s\n", sMessage.c_str()); } else fprintf(stdout, "%s\n", sMessage.c_str()); fflush(stdout); } void CUtils::PrintAction(const CString& sMessage) { if (CDebug::StdoutIsTTY()) fprintf(stdout, BOLD BLU "[ .. " BLU "]" DFL NORM " %s...\n", sMessage.c_str()); else fprintf(stdout, "%s... ", sMessage.c_str()); fflush(stdout); } void CUtils::PrintStatus(bool bSuccess, const CString& sMessage) { if (CDebug::StdoutIsTTY()) { if (bSuccess) { if (!sMessage.empty()) fprintf(stdout, BOLD BLU "[" GRN " >> " BLU "]" DFL NORM " %s\n", sMessage.c_str()); } else { fprintf(stdout, BOLD BLU "[" RED " !! " BLU "]" DFL NORM BOLD RED " %s" DFL NORM "\n", sMessage.empty() ? "failed" : sMessage.c_str()); } } else { if (bSuccess) { fprintf(stdout, "%s\n", sMessage.c_str()); } else { if (!sMessage.empty()) { fprintf(stdout, "[ %s ]", sMessage.c_str()); } fprintf(stdout, "\n"); } } fflush(stdout); } namespace { /* Switch GMT-X and GMT+X * * See https://en.wikipedia.org/wiki/Tz_database#Area * * "In order to conform with the POSIX style, those zone names beginning * with "Etc/GMT" have their sign reversed from what most people expect. * In this style, zones west of GMT have a positive sign and those east * have a negative sign in their name (e.g "Etc/GMT-14" is 14 hours * ahead/east of GMT.)" */ inline CString FixGMT(CString sTZ) { if (sTZ.length() >= 4 && sTZ.StartsWith("GMT")) { if (sTZ[3] == '+') { sTZ[3] = '-'; } else if (sTZ[3] == '-') { sTZ[3] = '+'; } } return sTZ; } } // namespace timeval CUtils::GetTime() { #ifdef HAVE_CLOCK_GETTIME timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { return { ts.tv_sec, static_cast(ts.tv_nsec / 1000) }; } #endif struct timeval tv; if (gettimeofday(&tv, nullptr) == 0) { return tv; } // Last resort, no microseconds return { time(nullptr), 0 }; } unsigned long long CUtils::GetMillTime() { struct timeval tv = GetTime(); unsigned long long iTime = 0; iTime = (unsigned long long)tv.tv_sec * 1000; iTime += ((unsigned long long)tv.tv_usec / 1000); return iTime; } CString CUtils::CTime(time_t t, const CString& sTimezone) { char s[30] = {}; // should have at least 26 bytes if (sTimezone.empty()) { ctime_r(&t, s); // ctime() adds a trailing newline return CString(s).Trim_n(); } CString sTZ = FixGMT(sTimezone); // backup old value char* oldTZ = getenv("TZ"); if (oldTZ) oldTZ = strdup(oldTZ); setenv("TZ", sTZ.c_str(), 1); tzset(); ctime_r(&t, s); // restore old value if (oldTZ) { setenv("TZ", oldTZ, 1); free(oldTZ); } else { unsetenv("TZ"); } tzset(); return CString(s).Trim_n(); } CString CUtils::FormatTime(time_t t, const CString& sFormat, const CString& sTimezone) { char s[1024] = {}; tm m; if (sTimezone.empty()) { localtime_r(&t, &m); strftime(s, sizeof(s), sFormat.c_str(), &m); return s; } CString sTZ = FixGMT(sTimezone); // backup old value char* oldTZ = getenv("TZ"); if (oldTZ) oldTZ = strdup(oldTZ); setenv("TZ", sTZ.c_str(), 1); tzset(); localtime_r(&t, &m); strftime(s, sizeof(s), sFormat.c_str(), &m); // restore old value if (oldTZ) { setenv("TZ", oldTZ, 1); free(oldTZ); } else { unsetenv("TZ"); } tzset(); return s; } CString CUtils::FormatTime(const timeval& tv, const CString& sFormat, const CString& sTimezone) { // Parse additional format specifiers before passing them to // strftime, since the way strftime treats unknown format // specifiers is undefined. CString sFormat2; // Make sure %% is parsed correctly, i.e. %%f is passed through to // strftime to become %f, and not 123. bool bInFormat = false; int iDigits; CString::size_type uLastCopied = 0, uFormatStart; for (CString::size_type i = 0; i < sFormat.length(); i++) { if (!bInFormat) { if (sFormat[i] == '%') { uFormatStart = i; bInFormat = true; iDigits = 3; } } else { switch (sFormat[i]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': iDigits = sFormat[i] - '0'; break; case 'f': { int iVal = tv.tv_usec; int iDigitDelta = iDigits - 6; // tv_user is in 10^-6 seconds for (; iDigitDelta > 0; iDigitDelta--) iVal *= 10; for (; iDigitDelta < 0; iDigitDelta++) iVal /= 10; sFormat2 += sFormat.substr(uLastCopied, uFormatStart - uLastCopied); CString sVal = CString(iVal); sFormat2 += CString(iDigits - sVal.length(), '0'); sFormat2 += sVal; uLastCopied = i + 1; bInFormat = false; break; } default: bInFormat = false; } } } if (uLastCopied) { sFormat2 += sFormat.substr(uLastCopied); return FormatTime(tv.tv_sec, sFormat2, sTimezone); } else { // If there are no extended format specifiers, avoid doing any // memory allocations entirely. return FormatTime(tv.tv_sec, sFormat, sTimezone); } } CString CUtils::FormatServerTime(const timeval& tv) { CString s_msec(tv.tv_usec / 1000); while (s_msec.length() < 3) { s_msec = "0" + s_msec; } // TODO support leap seconds properly // TODO support message-tags properly struct tm stm; memset(&stm, 0, sizeof(stm)); // OpenBSD has tv_sec as int, so explicitly convert it to time_t to make // gmtime_r() happy const time_t secs = tv.tv_sec; gmtime_r(&secs, &stm); char sTime[20] = {}; strftime(sTime, sizeof(sTime), "%Y-%m-%dT%H:%M:%S", &stm); return CString(sTime) + "." + s_msec + "Z"; } timeval CUtils::ParseServerTime(const CString& sTime) { struct tm stm; memset(&stm, 0, sizeof(stm)); const char* cp = strptime(sTime.c_str(), "%Y-%m-%dT%H:%M:%S", &stm); struct timeval tv; memset(&tv, 0, sizeof(tv)); if (cp) { tv.tv_sec = mktime(&stm); CString s_usec(cp); if (s_usec.TrimPrefix(".") && s_usec.TrimSuffix("Z")) { tv.tv_usec = s_usec.ToULong() * 1000; } } return tv; } namespace { void FillTimezones(const CString& sPath, SCString& result, const CString& sPrefix) { CDir Dir; Dir.Fill(sPath); for (CFile* pFile : Dir) { CString sName = pFile->GetShortName(); CString sFile = pFile->GetLongName(); if (sName == "posix" || sName == "right") continue; // these 2 dirs contain the same filenames if (sName.EndsWith(".tab") || sName == "posixrules" || sName == "localtime") continue; if (pFile->IsDir()) { if (sName == "Etc") { FillTimezones(sFile, result, sPrefix); } else { FillTimezones(sFile, result, sPrefix + sName + "/"); } } else { result.insert(sPrefix + sName); } } } } // namespace SCString CUtils::GetTimezones() { static SCString result; if (result.empty()) { FillTimezones("/usr/share/zoneinfo", result, ""); } return result; } SCString CUtils::GetEncodings() { static SCString ssResult; #ifdef HAVE_ICU if (ssResult.empty()) { for (int i = 0; i < ucnv_countAvailable(); ++i) { const char* pConvName = ucnv_getAvailableName(i); ssResult.insert(pConvName); icu::ErrorCode e; for (int st = 0; st < ucnv_countStandards(); ++st) { const char* pStdName = ucnv_getStandard(st, e); icu::LocalUEnumerationPointer ue( ucnv_openStandardNames(pConvName, pStdName, e)); while (const char* pStdConvNameEnum = uenum_next(ue.getAlias(), nullptr, e)) { ssResult.insert(pStdConvNameEnum); } } } } #endif return ssResult; } bool CUtils::CheckCIDR(const CString& sIP, const CString& sRange) { if (sIP.WildCmp(sRange)) { return true; } auto deleter = [](addrinfo* ai) { freeaddrinfo(ai); }; // Try to split the string into an IP and routing prefix VCString vsSplitCIDR; if (sRange.Split("/", vsSplitCIDR, false) != 2) return false; const CString sRoutingPrefix = vsSplitCIDR.back(); const int iRoutingPrefix = sRoutingPrefix.ToInt(); if (iRoutingPrefix < 0 || iRoutingPrefix > 128) return false; // If iRoutingPrefix is 0, it could be due to ToInt() failing, so // sRoutingPrefix needs to be all zeroes if (iRoutingPrefix == 0 && sRoutingPrefix != "0") return false; // Convert each IP from a numeric string to an addrinfo addrinfo aiHints; memset(&aiHints, 0, sizeof(addrinfo)); aiHints.ai_flags = AI_NUMERICHOST; addrinfo* aiHostC; int iIsHostValid = getaddrinfo(sIP.c_str(), nullptr, &aiHints, &aiHostC); if (iIsHostValid != 0) return false; std::unique_ptr aiHost(aiHostC, deleter); aiHints.ai_family = aiHost->ai_family; // Host and range must be in // the same address family addrinfo* aiRangeC; int iIsRangeValid = getaddrinfo(vsSplitCIDR.front().c_str(), nullptr, &aiHints, &aiRangeC); if (iIsRangeValid != 0) { return false; } std::unique_ptr aiRange(aiRangeC, deleter); // "/0" allows all IPv[4|6] addresses if (iRoutingPrefix == 0) { return true; } // If both IPs are valid and of the same type, make a bit field mask // from the routing prefix, AND it to the host and range, and see if // they match if (aiHost->ai_family == AF_INET) { if (iRoutingPrefix > 32) { return false; } const sockaddr_in* saHost = reinterpret_cast(aiHost->ai_addr); const sockaddr_in* saRange = reinterpret_cast(aiRange->ai_addr); // Make IPv4 bitmask const in_addr_t inBitmask = htonl((~0u) << (32 - iRoutingPrefix)); // Compare masked IPv4s return ((inBitmask & saHost->sin_addr.s_addr) == (inBitmask & saRange->sin_addr.s_addr)); } else if (aiHost->ai_family == AF_INET6) { // Make IPv6 bitmask in6_addr in6aBitmask; memset(&in6aBitmask, 0, sizeof(in6aBitmask)); for (int i = 0, iBitsLeft = iRoutingPrefix; iBitsLeft > 0; ++i, iBitsLeft -= 8) { if (iBitsLeft >= 8) { in6aBitmask.s6_addr[i] = (uint8_t)(~0u); } else { in6aBitmask.s6_addr[i] = (uint8_t)(~0u) << (8 - iBitsLeft); } } // Compare masked IPv6s const sockaddr_in6* sa6Host = reinterpret_cast(aiHost->ai_addr); const sockaddr_in6* sa6Range = reinterpret_cast(aiRange->ai_addr); for (int i = 0; i < 16; ++i) { if ((in6aBitmask.s6_addr[i] & sa6Host->sin6_addr.s6_addr[i]) != (in6aBitmask.s6_addr[i] & sa6Range->sin6_addr.s6_addr[i])) { return false; } } return true; } else { return false; } } MCString CUtils::GetMessageTags(const CString& sLine) { if (sLine.StartsWith("@")) { return CMessage(sLine).GetTags(); } return MCString::EmptyMap; } void CUtils::SetMessageTags(CString& sLine, const MCString& mssTags) { CMessage Message(sLine); Message.SetTags(mssTags); sLine = Message.ToString(); } bool CTable::AddColumn(const CString& sName) { for (const CString& sHeader : m_vsHeaders) { if (sHeader.Equals(sName)) { return false; } } m_vsHeaders.push_back(sName); m_msuWidths[sName] = sName.size(); return true; } CTable::size_type CTable::AddRow() { // Don't add a row if no headers are defined if (m_vsHeaders.empty()) { return (size_type)-1; } // Add a vector with enough space for each column push_back(vector(m_vsHeaders.size())); return size() - 1; } bool CTable::SetCell(const CString& sColumn, const CString& sValue, size_type uRowIdx) { if (uRowIdx == (size_type)~0) { if (empty()) { return false; } uRowIdx = size() - 1; } unsigned int uColIdx = GetColumnIndex(sColumn); if (uColIdx == (unsigned int)-1) return false; (*this)[uRowIdx][uColIdx] = sValue; if (m_msuWidths[sColumn] < sValue.size()) m_msuWidths[sColumn] = sValue.size(); return true; } bool CTable::GetLine(unsigned int uIdx, CString& sLine) const { std::stringstream ssRet; if (empty()) { return false; } if (uIdx == 1) { ssRet.fill(' '); ssRet << "| "; for (unsigned int a = 0; a < m_vsHeaders.size(); a++) { ssRet.width(GetColumnWidth(a)); ssRet << std::left << m_vsHeaders[a]; ssRet << ((a == m_vsHeaders.size() - 1) ? " |" : " | "); } sLine = ssRet.str(); return true; } else if ((uIdx == 0) || (uIdx == 2) || (uIdx == (size() + 3))) { ssRet.fill('-'); ssRet << "+-"; for (unsigned int a = 0; a < m_vsHeaders.size(); a++) { ssRet.width(GetColumnWidth(a)); ssRet << std::left << "-"; ssRet << ((a == m_vsHeaders.size() - 1) ? "-+" : "-+-"); } sLine = ssRet.str(); return true; } else { uIdx -= 3; if (uIdx < size()) { const std::vector& mRow = (*this)[uIdx]; ssRet.fill(' '); ssRet << "| "; for (unsigned int c = 0; c < m_vsHeaders.size(); c++) { ssRet.width(GetColumnWidth(c)); ssRet << std::left << mRow[c]; ssRet << ((c == m_vsHeaders.size() - 1) ? " |" : " | "); } sLine = ssRet.str(); return true; } } return false; } unsigned int CTable::GetColumnIndex(const CString& sName) const { for (unsigned int i = 0; i < m_vsHeaders.size(); i++) { if (m_vsHeaders[i] == sName) return i; } DEBUG("CTable::GetColumnIndex(" + sName + ") failed"); return (unsigned int)-1; } CString::size_type CTable::GetColumnWidth(unsigned int uIdx) const { if (uIdx >= m_vsHeaders.size()) { return 0; } const CString& sColName = m_vsHeaders[uIdx]; std::map::const_iterator it = m_msuWidths.find(sColName); if (it == m_msuWidths.end()) { // AddColumn() and SetCell() should make sure that we get a value :/ return 0; } return it->second; } void CTable::Clear() { clear(); m_vsHeaders.clear(); m_msuWidths.clear(); } #ifdef HAVE_LIBSSL CBlowfish::CBlowfish(const CString& sPassword, int iEncrypt, const CString& sIvec) : m_ivec((unsigned char*)calloc(sizeof(unsigned char), 8)), m_bkey(), m_iEncrypt(iEncrypt), m_num(0) { if (sIvec.length() >= 8) { memcpy(m_ivec, sIvec.data(), 8); } BF_set_key(&m_bkey, (unsigned int)sPassword.length(), (unsigned char*)sPassword.data()); } CBlowfish::~CBlowfish() { free(m_ivec); } //! output must be freed unsigned char* CBlowfish::MD5(const unsigned char* input, unsigned int ilen) { unsigned char* output = (unsigned char*)malloc(MD5_DIGEST_LENGTH); ::MD5(input, ilen, output); return output; } //! returns an md5 of the CString (not hex encoded) CString CBlowfish::MD5(const CString& sInput, bool bHexEncode) { CString sRet; unsigned char* data = MD5((const unsigned char*)sInput.data(), (unsigned int)sInput.length()); if (!bHexEncode) { sRet.append((const char*)data, MD5_DIGEST_LENGTH); } else { for (int a = 0; a < MD5_DIGEST_LENGTH; a++) { sRet += g_HexDigits[data[a] >> 4]; sRet += g_HexDigits[data[a] & 0xf]; } } free(data); return sRet; } //! output must be the same size as input void CBlowfish::Crypt(unsigned char* input, unsigned char* output, unsigned int uBytes) { BF_cfb64_encrypt(input, output, uBytes, &m_bkey, m_ivec, &m_num, m_iEncrypt); } //! must free result unsigned char* CBlowfish::Crypt(unsigned char* input, unsigned int uBytes) { unsigned char* buff = (unsigned char*)malloc(uBytes); Crypt(input, buff, uBytes); return buff; } CString CBlowfish::Crypt(const CString& sData) { unsigned char* buff = Crypt((unsigned char*)sData.data(), (unsigned int)sData.length()); CString sOutput; sOutput.append((const char*)buff, sData.length()); free(buff); return sOutput; } #endif // HAVE_LIBSSL znc-1.7.5/src/HTTPSock.cpp0000644000175000017500000006050113542151610015434 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #ifdef HAVE_ZLIB #include #endif using std::map; using std::set; #define MAX_POST_SIZE 1024 * 1024 CHTTPSock::CHTTPSock(CModule* pMod, const CString& sURIPrefix) : CHTTPSock(pMod, sURIPrefix, "", 0) { Init(); } CHTTPSock::CHTTPSock(CModule* pMod, const CString& sURIPrefix, const CString& sHostname, unsigned short uPort, int iTimeout) : CSocket(pMod, sHostname, uPort, iTimeout), m_bSentHeader(false), m_bGotHeader(false), m_bLoggedIn(false), m_bPost(false), m_bDone(false), m_bBasicAuth(false), m_uPostLen(0), m_sPostData(""), m_sURI(""), m_sUser(""), m_sPass(""), m_sContentType(""), m_sDocRoot(""), m_sForwardedIP(""), m_msvsPOSTParams(), m_msvsGETParams(), m_msHeaders(), m_bHTTP10Client(false), m_sIfNoneMatch(""), m_bAcceptGzip(false), m_msRequestCookies(), m_msResponseCookies(), m_sURIPrefix(sURIPrefix) { Init(); } void CHTTPSock::Init() { EnableReadLine(); SetMaxBufferThreshold(10240); } CHTTPSock::~CHTTPSock() {} void CHTTPSock::ReadData(const char* data, size_t len) { if (!m_bDone && m_bGotHeader && m_bPost) { m_sPostData.append(data, len); CheckPost(); } } bool CHTTPSock::SendCookie(const CString& sKey, const CString& sValue) { if (!sKey.empty() && !sValue.empty()) { if (m_msRequestCookies.find(sKey) == m_msRequestCookies.end() || m_msRequestCookies[sKey].StrCmp(sValue) != 0) { // only queue a Set-Cookie to be sent if the client didn't send a // Cookie header of the same name+value. m_msResponseCookies[sKey] = sValue; } return true; } return false; } CString CHTTPSock::GetRequestCookie(const CString& sKey) const { MCString::const_iterator it = m_msRequestCookies.find(sKey); return it != m_msRequestCookies.end() ? it->second : ""; } void CHTTPSock::CheckPost() { if (m_sPostData.size() >= m_uPostLen) { ParseParams(m_sPostData.Left(m_uPostLen), m_msvsPOSTParams); GetPage(); m_sPostData.clear(); m_bDone = true; } } void CHTTPSock::ReadLine(const CString& sData) { if (m_bGotHeader) { return; } CString sLine = sData; sLine.TrimRight("\r\n"); CString sName = sLine.Token(0); if (sName.Equals("GET")) { m_bPost = false; m_sURI = sLine.Token(1); m_bHTTP10Client = sLine.Token(2).Equals("HTTP/1.0"); ParseURI(); } else if (sName.Equals("POST")) { m_bPost = true; m_sURI = sLine.Token(1); ParseURI(); } else if (sName.Equals("Cookie:")) { VCString vsNV; sLine.Token(1, true).Split(";", vsNV, false, "", "", true, true); for (const CString& s : vsNV) { m_msRequestCookies[s.Token(0, false, "=") .Escape_n(CString::EURL, CString::EASCII)] = s.Token(1, true, "=").Escape_n(CString::EURL, CString::EASCII); } } else if (sName.Equals("Authorization:")) { CString sUnhashed; sLine.Token(2).Base64Decode(sUnhashed); m_sUser = sUnhashed.Token(0, false, ":"); m_sPass = sUnhashed.Token(1, true, ":"); m_bBasicAuth = true; // Postpone authorization attempt until end of headers, because cookies // should be read before that, otherwise session id will be overwritten // in GetSession() } else if (sName.Equals("Content-Length:")) { m_uPostLen = sLine.Token(1).ToULong(); if (m_uPostLen > MAX_POST_SIZE) PrintErrorPage(413, "Request Entity Too Large", "The request you sent was too large."); } else if (sName.Equals("X-Forwarded-For:")) { // X-Forwarded-For: client, proxy1, proxy2 if (m_sForwardedIP.empty()) { const VCString& vsTrustedProxies = CZNC::Get().GetTrustedProxies(); CString sIP = GetRemoteIP(); VCString vsIPs; sLine.Token(1, true).Split(",", vsIPs, false, "", "", false, true); while (!vsIPs.empty()) { // sIP told us that it got connection from vsIPs.back() // check if sIP is trusted proxy bool bTrusted = false; for (const CString& sTrustedProxy : vsTrustedProxies) { if (CUtils::CheckCIDR(sIP, sTrustedProxy)) { bTrusted = true; break; } } if (bTrusted) { // sIP is trusted proxy, so use vsIPs.back() as new sIP sIP = vsIPs.back(); vsIPs.pop_back(); } else { break; } } // either sIP is not trusted proxy, or it's in the beginning of the // X-Forwarded-For list in both cases use it as the endpoind m_sForwardedIP = sIP; } } else if (sName.Equals("If-None-Match:")) { // this is for proper client cache support (HTTP 304) on static files: m_sIfNoneMatch = sLine.Token(1, true); } else if (sName.Equals("Accept-Encoding:") && !m_bHTTP10Client) { SCString ssEncodings; // trimming whitespace from the tokens is important: sLine.Token(1, true) .Split(",", ssEncodings, false, "", "", false, true); m_bAcceptGzip = (ssEncodings.find("gzip") != ssEncodings.end()); } else if (sLine.empty()) { if (m_bBasicAuth && !m_bLoggedIn) { m_bLoggedIn = OnLogin(m_sUser, m_sPass, true); // After successful login ReadLine("") will be called again to // trigger "else" block Failed login sends error and closes socket, // so no infinite loop here } else { m_bGotHeader = true; if (m_bPost) { m_sPostData = GetInternalReadBuffer(); CheckPost(); } else { GetPage(); } DisableReadLine(); } } } CString CHTTPSock::GetRemoteIP() const { if (!m_sForwardedIP.empty()) { return m_sForwardedIP; } return CSocket::GetRemoteIP(); } CString CHTTPSock::GetDate(time_t stamp) { struct tm tm; std::stringstream stream; const char* wkday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; const char* month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; if (stamp == 0) time(&stamp); gmtime_r(&stamp, &tm); stream << wkday[tm.tm_wday] << ", "; stream << std::setfill('0') << std::setw(2) << tm.tm_mday << " "; stream << month[tm.tm_mon] << " "; stream << std::setfill('0') << std::setw(4) << tm.tm_year + 1900 << " "; stream << std::setfill('0') << std::setw(2) << tm.tm_hour << ":"; stream << std::setfill('0') << std::setw(2) << tm.tm_min << ":"; stream << std::setfill('0') << std::setw(2) << tm.tm_sec << " GMT"; return stream.str(); } void CHTTPSock::GetPage() { DEBUG("Page Request [" << m_sURI << "] "); // Check that the requested path starts with the prefix. Strip it if so. if (!m_sURI.TrimPrefix(m_sURIPrefix)) { DEBUG("INVALID path => Does not start with prefix [" + m_sURIPrefix + "]"); DEBUG("Expected prefix: " << m_sURIPrefix); DEBUG("Requested path: " << m_sURI); Redirect("/"); } else if (m_sURI.empty()) { // This can happen if prefix was /foo, and the requested page is /foo Redirect("/"); } else { OnPageRequest(m_sURI); } } #ifdef HAVE_ZLIB static bool InitZlibStream(z_stream* zStrm, const char* buf) { memset(zStrm, 0, sizeof(z_stream)); zStrm->next_in = (Bytef*)buf; // "15" is the default value for good compression, // the weird "+ 16" means "please generate a gzip header and trailer". const int WINDOW_BITS = 15 + 16; const int MEMLEVEL = 8; return (deflateInit2(zStrm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, WINDOW_BITS, MEMLEVEL, Z_DEFAULT_STRATEGY) == Z_OK); } #endif void CHTTPSock::PrintPage(const CString& sPage) { #ifdef HAVE_ZLIB if (m_bAcceptGzip && !SentHeader()) { char szBuf[4096]; z_stream zStrm; int zStatus, zFlush = Z_NO_FLUSH; if (InitZlibStream(&zStrm, sPage.c_str())) { DEBUG("- Sending gzip-compressed."); AddHeader("Content-Encoding", "gzip"); PrintHeader(0); // we do not know the compressed data's length zStrm.avail_in = sPage.size(); do { if (zStrm.avail_in == 0) { zFlush = Z_FINISH; } zStrm.next_out = (Bytef*)szBuf; zStrm.avail_out = sizeof(szBuf); zStatus = deflate(&zStrm, zFlush); if ((zStatus == Z_OK || zStatus == Z_STREAM_END) && zStrm.avail_out < sizeof(szBuf)) { Write(szBuf, sizeof(szBuf) - zStrm.avail_out); } } while (zStatus == Z_OK); Close(Csock::CLT_AFTERWRITE); deflateEnd(&zStrm); return; } } // else: fall through #endif if (!SentHeader()) { PrintHeader(sPage.length()); } else { DEBUG("PrintPage(): Header was already sent"); } Write(sPage); Close(Csock::CLT_AFTERWRITE); } bool CHTTPSock::PrintFile(const CString& sFileName, CString sContentType) { CString sFilePath = sFileName; if (!m_sDocRoot.empty()) { sFilePath.TrimLeft("/"); sFilePath = CDir::CheckPathPrefix(m_sDocRoot, sFilePath, m_sDocRoot); if (sFilePath.empty()) { PrintErrorPage(403, "Forbidden", "You don't have permission to access that file on " "this server."); DEBUG("THIS FILE: [" << sFilePath << "] does not live in ..."); DEBUG("DOCUMENT ROOT: [" << m_sDocRoot << "]"); return false; } } CFile File(sFilePath); if (!File.Open()) { PrintNotFound(); return false; } if (sContentType.empty()) { if (sFileName.EndsWith(".html") || sFileName.EndsWith(".htm")) { sContentType = "text/html; charset=utf-8"; } else if (sFileName.EndsWith(".css")) { sContentType = "text/css; charset=utf-8"; } else if (sFileName.EndsWith(".js")) { sContentType = "application/x-javascript; charset=utf-8"; } else if (sFileName.EndsWith(".jpg")) { sContentType = "image/jpeg"; } else if (sFileName.EndsWith(".gif")) { sContentType = "image/gif"; } else if (sFileName.EndsWith(".ico")) { sContentType = "image/x-icon"; } else if (sFileName.EndsWith(".png")) { sContentType = "image/png"; } else if (sFileName.EndsWith(".bmp")) { sContentType = "image/bmp"; } else { sContentType = "text/plain; charset=utf-8"; } } const time_t iMTime = File.GetMTime(); bool bNotModified = false; CString sETag; if (iMTime > 0 && !m_bHTTP10Client) { sETag = "-" + CString(iMTime); // lighttpd style ETag AddHeader("Last-Modified", GetDate(iMTime)); AddHeader("ETag", "\"" + sETag + "\""); AddHeader("Cache-Control", "public"); if (!m_sIfNoneMatch.empty()) { m_sIfNoneMatch.Trim("\\\"'"); bNotModified = (m_sIfNoneMatch.Equals(sETag, CString::CaseSensitive)); } } if (bNotModified) { PrintHeader(0, sContentType, 304, "Not Modified"); } else { off_t iSize = File.GetSize(); // Don't try to send files over 16 MiB, because it might block // the whole process and use huge amounts of memory. if (iSize > 16 * 1024 * 1024) { DEBUG("- Abort: File is over 16 MiB big: " << iSize); PrintErrorPage(500, "Internal Server Error", "File too big"); return true; } #ifdef HAVE_ZLIB bool bGzip = m_bAcceptGzip && (sContentType.StartsWith("text/") || sFileName.EndsWith(".js")); if (bGzip) { DEBUG("- Sending gzip-compressed."); AddHeader("Content-Encoding", "gzip"); PrintHeader( 0, sContentType); // we do not know the compressed data's length WriteFileGzipped(File); } else #endif { PrintHeader(iSize, sContentType); WriteFileUncompressed(File); } } DEBUG("- ETag: [" << sETag << "] / If-None-Match [" << m_sIfNoneMatch << "]"); Close(Csock::CLT_AFTERWRITE); return true; } void CHTTPSock::WriteFileUncompressed(CFile& File) { char szBuf[4096]; off_t iLen = 0; ssize_t i = 0; off_t iSize = File.GetSize(); // while we haven't reached iSize and read() succeeds... while (iLen < iSize && (i = File.Read(szBuf, sizeof(szBuf))) > 0) { Write(szBuf, i); iLen += i; } if (i < 0) { DEBUG("- Error while reading file: " << strerror(errno)); } } #ifdef HAVE_ZLIB void CHTTPSock::WriteFileGzipped(CFile& File) { char szBufIn[8192]; char szBufOut[8192]; off_t iFileSize = File.GetSize(), iFileReadTotal = 0; z_stream zStrm; int zFlush = Z_NO_FLUSH; int zStatus; if (!InitZlibStream(&zStrm, szBufIn)) { DEBUG("- Error initializing zlib!"); return; } do { ssize_t iFileRead = 0; if (zStrm.avail_in == 0) { // input buffer is empty, try to read more data from file. // if there is no more data, finish the stream. if (iFileReadTotal < iFileSize) { iFileRead = File.Read(szBufIn, sizeof(szBufIn)); if (iFileRead < 1) { // wtf happened? better quit compressing. iFileReadTotal = iFileSize; zFlush = Z_FINISH; } else { iFileReadTotal += iFileRead; zStrm.next_in = (Bytef*)szBufIn; zStrm.avail_in = iFileRead; } } else { zFlush = Z_FINISH; } } zStrm.next_out = (Bytef*)szBufOut; zStrm.avail_out = sizeof(szBufOut); zStatus = deflate(&zStrm, zFlush); if ((zStatus == Z_OK || zStatus == Z_STREAM_END) && zStrm.avail_out < sizeof(szBufOut)) { // there's data in the buffer: Write(szBufOut, sizeof(szBufOut) - zStrm.avail_out); } } while (zStatus == Z_OK); deflateEnd(&zStrm); } #endif void CHTTPSock::ParseURI() { ParseParams(m_sURI.Token(1, true, "?"), m_msvsGETParams); m_sURI = m_sURI.Token(0, false, "?"); } CString CHTTPSock::GetPath() const { return m_sURI.Token(0, false, "?"); } void CHTTPSock::ParseParams(const CString& sParams, map& msvsParams) { msvsParams.clear(); VCString vsPairs; sParams.Split("&", vsPairs, true); for (const CString& sPair : vsPairs) { CString sName = sPair.Token(0, false, "=").Escape_n(CString::EURL, CString::EASCII); CString sValue = sPair.Token(1, true, "=").Escape_n(CString::EURL, CString::EASCII); msvsParams[sName].push_back(sValue); } } void CHTTPSock::SetDocRoot(const CString& s) { m_sDocRoot = s + "/"; m_sDocRoot.Replace("//", "/"); } const CString& CHTTPSock::GetDocRoot() const { return m_sDocRoot; } const CString& CHTTPSock::GetUser() const { return m_sUser; } const CString& CHTTPSock::GetPass() const { return m_sPass; } const CString& CHTTPSock::GetContentType() const { return m_sContentType; } const CString& CHTTPSock::GetParamString() const { return m_sPostData; } const CString& CHTTPSock::GetURI() const { return m_sURI; } const CString& CHTTPSock::GetURIPrefix() const { return m_sURIPrefix; } bool CHTTPSock::HasParam(const CString& sName, bool bPost) const { if (bPost) return (m_msvsPOSTParams.find(sName) != m_msvsPOSTParams.end()); return (m_msvsGETParams.find(sName) != m_msvsGETParams.end()); } CString CHTTPSock::GetRawParam(const CString& sName, bool bPost) const { if (bPost) return GetRawParam(sName, m_msvsPOSTParams); return GetRawParam(sName, m_msvsGETParams); } CString CHTTPSock::GetRawParam(const CString& sName, const map& msvsParams) { CString sRet; map::const_iterator it = msvsParams.find(sName); if (it != msvsParams.end() && it->second.size() > 0) { sRet = it->second[0]; } return sRet; } CString CHTTPSock::GetParam(const CString& sName, bool bPost, const CString& sFilter) const { if (bPost) return GetParam(sName, m_msvsPOSTParams, sFilter); return GetParam(sName, m_msvsGETParams, sFilter); } CString CHTTPSock::GetParam(const CString& sName, const map& msvsParams, const CString& sFilter) { CString sRet = GetRawParam(sName, msvsParams); sRet.Trim(); for (size_t i = 0; i < sFilter.length(); i++) { sRet.Replace(CString(sFilter.at(i)), ""); } return sRet; } size_t CHTTPSock::GetParamValues(const CString& sName, set& ssRet, bool bPost, const CString& sFilter) const { if (bPost) return GetParamValues(sName, ssRet, m_msvsPOSTParams, sFilter); return GetParamValues(sName, ssRet, m_msvsGETParams, sFilter); } size_t CHTTPSock::GetParamValues(const CString& sName, set& ssRet, const map& msvsParams, const CString& sFilter) { ssRet.clear(); map::const_iterator it = msvsParams.find(sName); if (it != msvsParams.end()) { for (CString sParam : it->second) { sParam.Trim(); for (size_t i = 0; i < sFilter.length(); i++) { sParam.Replace(CString(sFilter.at(i)), ""); } ssRet.insert(sParam); } } return ssRet.size(); } size_t CHTTPSock::GetParamValues(const CString& sName, VCString& vsRet, bool bPost, const CString& sFilter) const { if (bPost) return GetParamValues(sName, vsRet, m_msvsPOSTParams, sFilter); return GetParamValues(sName, vsRet, m_msvsGETParams, sFilter); } size_t CHTTPSock::GetParamValues(const CString& sName, VCString& vsRet, const map& msvsParams, const CString& sFilter) { vsRet.clear(); map::const_iterator it = msvsParams.find(sName); if (it != msvsParams.end()) { for (CString sParam : it->second) { sParam.Trim(); for (size_t i = 0; i < sFilter.length(); i++) { sParam.Replace(CString(sFilter.at(i)), ""); } vsRet.push_back(sParam); } } return vsRet.size(); } const map& CHTTPSock::GetParams(bool bPost) const { if (bPost) return m_msvsPOSTParams; return m_msvsGETParams; } bool CHTTPSock::IsPost() const { return m_bPost; } bool CHTTPSock::PrintNotFound() { return PrintErrorPage(404, "Not Found", "The requested URL was not found on this server."); } bool CHTTPSock::PrintErrorPage(unsigned int uStatusId, const CString& sStatusMsg, const CString& sMessage) { if (SentHeader()) { DEBUG("PrintErrorPage(): Header was already sent"); return false; } CString sPage = "\r\n" "\r\n" "\r\n" "\r\n" "\r\n" "" + CString(uStatusId) + " " + sStatusMsg.Escape_n(CString::EHTML) + "\r\n" "\r\n" "\r\n" "

" + sStatusMsg.Escape_n(CString::EHTML) + "

\r\n" "

" + sMessage.Escape_n(CString::EHTML) + "

\r\n" "
\r\n" "

" + CZNC::GetTag(false, /* bHTML = */ true) + "

\r\n" "\r\n" "\r\n"; PrintHeader(sPage.length(), "text/html; charset=utf-8", uStatusId, sStatusMsg); Write(sPage); Close(Csock::CLT_AFTERWRITE); return true; } bool CHTTPSock::ForceLogin() { if (m_bLoggedIn) { return true; } if (SentHeader()) { DEBUG("ForceLogin(): Header was already sent!"); return false; } AddHeader("WWW-Authenticate", "Basic realm=\"" + CZNC::GetTag(false) + "\""); PrintErrorPage(401, "Unauthorized", "You need to login to view this page."); return false; } bool CHTTPSock::OnLogin(const CString& sUser, const CString& sPass, bool bBasic) { return false; } bool CHTTPSock::SentHeader() const { return m_bSentHeader; } bool CHTTPSock::PrintHeader(off_t uContentLength, const CString& sContentType, unsigned int uStatusId, const CString& sStatusMsg) { if (SentHeader()) { DEBUG("PrintHeader(): Header was already sent!"); return false; } if (!sContentType.empty()) { m_sContentType = sContentType; } if (m_sContentType.empty()) { m_sContentType = "text/html; charset=utf-8"; } DEBUG("- " << uStatusId << " (" << sStatusMsg << ") [" << m_sContentType << "]"); Write("HTTP/" + CString(m_bHTTP10Client ? "1.0 " : "1.1 ") + CString(uStatusId) + " " + sStatusMsg + "\r\n"); Write("Date: " + GetDate() + "\r\n"); Write("Server: " + CZNC::GetTag(false) + "\r\n"); if (uContentLength > 0) { Write("Content-Length: " + CString(uContentLength) + "\r\n"); } Write("Content-Type: " + m_sContentType + "\r\n"); for (const auto& it : m_msResponseCookies) { Write("Set-Cookie: " + it.first.Escape_n(CString::EURL) + "=" + it.second.Escape_n(CString::EURL) + "; HttpOnly; path=/;" + (GetSSL() ? "Secure;" : "") + " SameSite=Strict;\r\n"); } for (const auto& it : m_msHeaders) { Write(it.first + ": " + it.second + "\r\n"); } Write("Connection: Close\r\n"); Write("\r\n"); m_bSentHeader = true; return true; } void CHTTPSock::SetContentType(const CString& sContentType) { m_sContentType = sContentType; } void CHTTPSock::AddHeader(const CString& sName, const CString& sValue) { m_msHeaders[sName] = sValue; } bool CHTTPSock::Redirect(const CString& sURL) { if (SentHeader()) { DEBUG("Redirect() - Header was already sent"); return false; } else if (!sURL.StartsWith("/")) { // HTTP/1.1 only admits absolute URIs for the Location header. DEBUG("Redirect to relative URI [" + sURL + "] is not allowed."); return false; } else { CString location = m_sURIPrefix + sURL; DEBUG("- Redirect to [" << location << "] with prefix [" + m_sURIPrefix + "]"); AddHeader("Location", location); PrintErrorPage(302, "Found", "The document has moved here."); return true; } } void CHTTPSock::Connected() { SetTimeout(120); } znc-1.7.5/src/ZNCString.cpp0000644000175000017500000012120113542151610015651 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include using std::stringstream; CString::CString(char c) : string() { stringstream s; s << c; *this = s.str(); } CString::CString(unsigned char c) : string() { stringstream s; s << c; *this = s.str(); } CString::CString(short i) : string() { stringstream s; s << i; *this = s.str(); } CString::CString(unsigned short i) : string() { stringstream s; s << i; *this = s.str(); } CString::CString(int i) : string() { stringstream s; s << i; *this = s.str(); } CString::CString(unsigned int i) : string() { stringstream s; s << i; *this = s.str(); } CString::CString(long i) : string() { stringstream s; s << i; *this = s.str(); } CString::CString(unsigned long i) : string() { stringstream s; s << i; *this = s.str(); } CString::CString(long long i) : string() { stringstream s; s << i; *this = s.str(); } CString::CString(unsigned long long i) : string() { stringstream s; s << i; *this = s.str(); } CString::CString(double i, int precision) : string() { stringstream s; s.precision(precision); s << std::fixed << i; *this = s.str(); } CString::CString(float i, int precision) : string() { stringstream s; s.precision(precision); s << std::fixed << i; *this = s.str(); } unsigned char* CString::strnchr(const unsigned char* src, unsigned char c, unsigned int iMaxBytes, unsigned char* pFill, unsigned int* piCount) const { for (unsigned int a = 0; a < iMaxBytes && *src; a++, src++) { if (pFill) { pFill[a] = *src; } if (*src == c) { if (pFill) { pFill[a + 1] = 0; } if (piCount) { *piCount = a; } return (unsigned char*)src; } } if (pFill) { *pFill = 0; } if (piCount) { *piCount = 0; } return nullptr; } int CString::CaseCmp(const CString& s, CString::size_type uLen) const { if (uLen != CString::npos) { return strncasecmp(c_str(), s.c_str(), uLen); } return strcasecmp(c_str(), s.c_str()); } int CString::StrCmp(const CString& s, CString::size_type uLen) const { if (uLen != CString::npos) { return strncmp(c_str(), s.c_str(), uLen); } return strcmp(c_str(), s.c_str()); } bool CString::Equals(const CString& s, CaseSensitivity cs) const { if (cs == CaseSensitive) { return (StrCmp(s) == 0); } else { return (CaseCmp(s) == 0); } } bool CString::Equals(const CString& s, bool bCaseSensitive, CString::size_type uLen) const { if (bCaseSensitive) { return (StrCmp(s, uLen) == 0); } else { return (CaseCmp(s, uLen) == 0); } } bool CString::WildCmp(const CString& sWild, const CString& sString, CaseSensitivity cs) { // avoid a copy when cs == CaseSensitive (C++ deliberately specifies that // binding a temporary object to a reference to const on the stack // lengthens the lifetime of the temporary to the lifetime of the reference // itself) const CString& sWld = (cs == CaseSensitive ? sWild : sWild.AsLower()); const CString& sStr = (cs == CaseSensitive ? sString : sString.AsLower()); // Written by Jack Handy - jakkhandy@hotmail.com const char* wild = sWld.c_str(), *CString = sStr.c_str(); const char* cp = nullptr, *mp = nullptr; while ((*CString) && (*wild != '*')) { if ((*wild != *CString) && (*wild != '?')) { return false; } wild++; CString++; } while (*CString) { if (*wild == '*') { if (!*++wild) { return true; } mp = wild; cp = CString + 1; } else if ((*wild == *CString) || (*wild == '?')) { wild++; CString++; } else { wild = mp; CString = cp++; } } while (*wild == '*') { wild++; } return (*wild == 0); } bool CString::WildCmp(const CString& sWild, CaseSensitivity cs) const { return CString::WildCmp(sWild, *this, cs); } CString& CString::MakeUpper() { for (char& c : *this) { // TODO use unicode c = (char)toupper(c); } return *this; } CString& CString::MakeLower() { for (char& c : *this) { // TODO use unicode c = (char)tolower(c); } return *this; } CString CString::AsUpper() const { CString sRet = *this; sRet.MakeUpper(); return sRet; } CString CString::AsLower() const { CString sRet = *this; sRet.MakeLower(); return sRet; } CString::EEscape CString::ToEscape(const CString& sEsc) { if (sEsc.Equals("ASCII")) { return EASCII; } else if (sEsc.Equals("HTML")) { return EHTML; } else if (sEsc.Equals("URL")) { return EURL; } else if (sEsc.Equals("SQL")) { return ESQL; } else if (sEsc.Equals("NAMEDFMT")) { return ENAMEDFMT; } else if (sEsc.Equals("DEBUG")) { return EDEBUG; } else if (sEsc.Equals("MSGTAG")) { return EMSGTAG; } else if (sEsc.Equals("HEXCOLON")) { return EHEXCOLON; } return EASCII; } CString CString::Escape_n(EEscape eFrom, EEscape eTo) const { CString sRet; const char szHex[] = "0123456789ABCDEF"; const unsigned char* pStart = (const unsigned char*)data(); const unsigned char* p = (const unsigned char*)data(); size_type iLength = length(); sRet.reserve(iLength * 3); unsigned char pTmp[21]; unsigned int iCounted = 0; for (unsigned int a = 0; a < iLength; a++, p = pStart + a) { unsigned char ch = 0; switch (eFrom) { case EHTML: if ((*p == '&') && (strnchr((unsigned char*)p, ';', sizeof(pTmp) - 1, pTmp, &iCounted))) { // please note that we do not have any Unicode or UTF-8 // support here at all. if ((iCounted >= 3) && (pTmp[1] == '#')) { // do XML and HTML a < int base = 10; if ((pTmp[2] & 0xDF) == 'X') { base = 16; } char* endptr = nullptr; unsigned long int b = strtol((const char*)(pTmp + 2 + (base == 16)), &endptr, base); if ((*endptr == ';') && (b <= 255)) { // incase they do something like � ch = (unsigned char)b; a += iCounted; break; } } if (ch == 0) { if (!strncasecmp((const char*)&pTmp, "<", 2)) ch = '<'; else if (!strncasecmp((const char*)&pTmp, ">", 2)) ch = '>'; else if (!strncasecmp((const char*)&pTmp, """, 4)) ch = '"'; else if (!strncasecmp((const char*)&pTmp, "&", 3)) ch = '&'; } if (ch > 0) { a += iCounted; } else { ch = *p; // Not a valid escape, just record the & } } else { ch = *p; } break; case EASCII: ch = *p; break; case EURL: if (*p == '%' && (a + 2) < iLength && isxdigit(*(p + 1)) && isxdigit(*(p + 2))) { p++; if (isdigit(*p)) { ch = (unsigned char)((*p - '0') << 4); } else { ch = (unsigned char)((tolower(*p) - 'a' + 10) << 4); } p++; if (isdigit(*p)) { ch |= (unsigned char)(*p - '0'); } else { ch |= (unsigned char)(tolower(*p) - 'a' + 10); } a += 2; } else if (pStart[a] == '+') { ch = ' '; } else { ch = *p; } break; case ESQL: if (*p != '\\' || iLength < (a + 1)) { ch = *p; } else { a++; p++; if (*p == 'n') { ch = '\n'; } else if (*p == 'r') { ch = '\r'; } else if (*p == '0') { ch = '\0'; } else if (*p == 't') { ch = '\t'; } else if (*p == 'b') { ch = '\b'; } else { ch = *p; } } break; case ENAMEDFMT: if (*p != '\\' || iLength < (a + 1)) { ch = *p; } else { a++; p++; ch = *p; } break; case EDEBUG: if (*p == '\\' && (a + 3) < iLength && *(p + 1) == 'x' && isxdigit(*(p + 2)) && isxdigit(*(p + 3))) { p += 2; if (isdigit(*p)) { ch = (unsigned char)((*p - '0') << 4); } else { ch = (unsigned char)((tolower(*p) - 'a' + 10) << 4); } p++; if (isdigit(*p)) { ch |= (unsigned char)(*p - '0'); } else { ch |= (unsigned char)(tolower(*p) - 'a' + 10); } a += 3; } else if (*p == '\\' && a + 1 < iLength && *(p + 1) == '.') { a++; p++; ch = '\\'; } else { ch = *p; } break; case EMSGTAG: if (*p != '\\' || iLength < (a + 1)) { ch = *p; } else { a++; p++; if (*p == ':') { ch = ';'; } else if (*p == 's') { ch = ' '; } else if (*p == '0') { ch = '\0'; } else if (*p == '\\') { ch = '\\'; } else if (*p == 'r') { ch = '\r'; } else if (*p == 'n') { ch = '\n'; } else { ch = *p; } } break; case EHEXCOLON: { while (!isxdigit(*p) && a < iLength) { a++; p++; } if (a == iLength) { continue; } if (isdigit(*p)) { ch = (unsigned char)((*p - '0') << 4); } else { ch = (unsigned char)((tolower(*p) - 'a' + 10) << 4); } a++; p++; while (!isxdigit(*p) && a < iLength) { a++; p++; } if (a == iLength) { continue; } if (isdigit(*p)) { ch |= (unsigned char)(*p - '0'); } else { ch |= (unsigned char)(tolower(*p) - 'a' + 10); } } break; } switch (eTo) { case EHTML: if (ch == '<') sRet += "<"; else if (ch == '>') sRet += ">"; else if (ch == '"') sRet += """; else if (ch == '&') sRet += "&"; else { sRet += ch; } break; case EASCII: sRet += ch; break; case EURL: if (isalnum(ch) || ch == '_' || ch == '.' || ch == '-') { sRet += ch; } else if (ch == ' ') { sRet += '+'; } else { sRet += '%'; sRet += szHex[ch >> 4]; sRet += szHex[ch & 0xf]; } break; case ESQL: if (ch == '\0') { sRet += '\\'; sRet += '0'; } else if (ch == '\n') { sRet += '\\'; sRet += 'n'; } else if (ch == '\t') { sRet += '\\'; sRet += 't'; } else if (ch == '\r') { sRet += '\\'; sRet += 'r'; } else if (ch == '\b') { sRet += '\\'; sRet += 'b'; } else if (ch == '\"') { sRet += '\\'; sRet += '\"'; } else if (ch == '\'') { sRet += '\\'; sRet += '\''; } else if (ch == '\\') { sRet += '\\'; sRet += '\\'; } else { sRet += ch; } break; case ENAMEDFMT: if (ch == '\\') { sRet += '\\'; sRet += '\\'; } else if (ch == '{') { sRet += '\\'; sRet += '{'; } else if (ch == '}') { sRet += '\\'; sRet += '}'; } else { sRet += ch; } break; case EDEBUG: if (ch < 0x20 || ch == 0x7F) { sRet += "\\x"; sRet += szHex[ch >> 4]; sRet += szHex[ch & 0xf]; } else if (ch == '\\') { sRet += "\\."; } else { sRet += ch; } break; case EMSGTAG: if (ch == ';') { sRet += '\\'; sRet += ':'; } else if (ch == ' ') { sRet += '\\'; sRet += 's'; } else if (ch == '\0') { sRet += '\\'; sRet += '0'; } else if (ch == '\\') { sRet += '\\'; sRet += '\\'; } else if (ch == '\r') { sRet += '\\'; sRet += 'r'; } else if (ch == '\n') { sRet += '\\'; sRet += 'n'; } else { sRet += ch; } break; case EHEXCOLON: { sRet += tolower(szHex[ch >> 4]); sRet += tolower(szHex[ch & 0xf]); sRet += ":"; } break; } } if (eTo == EHEXCOLON) { sRet.TrimRight(":"); } return sRet; } CString CString::Escape_n(EEscape eTo) const { return Escape_n(EASCII, eTo); } CString& CString::Escape(EEscape eFrom, EEscape eTo) { return (*this = Escape_n(eFrom, eTo)); } CString& CString::Escape(EEscape eTo) { return (*this = Escape_n(eTo)); } CString CString::Replace_n(const CString& sReplace, const CString& sWith, const CString& sLeft, const CString& sRight, bool bRemoveDelims) const { CString sRet = *this; CString::Replace(sRet, sReplace, sWith, sLeft, sRight, bRemoveDelims); return sRet; } unsigned int CString::Replace(const CString& sReplace, const CString& sWith, const CString& sLeft, const CString& sRight, bool bRemoveDelims) { return CString::Replace(*this, sReplace, sWith, sLeft, sRight, bRemoveDelims); } unsigned int CString::Replace(CString& sStr, const CString& sReplace, const CString& sWith, const CString& sLeft, const CString& sRight, bool bRemoveDelims) { unsigned int uRet = 0; CString sCopy = sStr; sStr.clear(); size_type uReplaceWidth = sReplace.length(); size_type uLeftWidth = sLeft.length(); size_type uRightWidth = sRight.length(); const char* p = sCopy.c_str(); bool bInside = false; while (*p) { if (!bInside && uLeftWidth && strncmp(p, sLeft.c_str(), uLeftWidth) == 0) { if (!bRemoveDelims) { sStr += sLeft; } p += uLeftWidth - 1; bInside = true; } else if (bInside && uRightWidth && strncmp(p, sRight.c_str(), uRightWidth) == 0) { if (!bRemoveDelims) { sStr += sRight; } p += uRightWidth - 1; bInside = false; } else if (!bInside && strncmp(p, sReplace.c_str(), uReplaceWidth) == 0) { sStr += sWith; p += uReplaceWidth - 1; uRet++; } else { sStr.append(p, 1); } p++; } return uRet; } CString CString::Token(size_t uPos, bool bRest, const CString& sSep, bool bAllowEmpty, const CString& sLeft, const CString& sRight, bool bTrimQuotes) const { VCString vsTokens; if (Split(sSep, vsTokens, bAllowEmpty, sLeft, sRight, bTrimQuotes) > uPos) { CString sRet; for (size_t a = uPos; a < vsTokens.size(); a++) { if (a > uPos) { sRet += sSep; } sRet += vsTokens[a]; if (!bRest) { break; } } return sRet; } return Token(uPos, bRest, sSep, bAllowEmpty); } CString CString::Token(size_t uPos, bool bRest, const CString& sSep, bool bAllowEmpty) const { const char* sep_str = sSep.c_str(); size_t sep_len = sSep.length(); const char* str = c_str(); size_t str_len = length(); size_t start_pos = 0; size_t end_pos; if (!bAllowEmpty) { while (strncmp(&str[start_pos], sep_str, sep_len) == 0) { start_pos += sep_len; } } // First, find the start of our token while (uPos != 0 && start_pos < str_len) { bool bFoundSep = false; while (strncmp(&str[start_pos], sep_str, sep_len) == 0 && (!bFoundSep || !bAllowEmpty)) { start_pos += sep_len; bFoundSep = true; } if (bFoundSep) { uPos--; } else { start_pos++; } } // String is over? if (start_pos >= str_len) return ""; // If they want everything from here on, give it to them if (bRest) { return substr(start_pos); } // Now look for the end of the token they want end_pos = start_pos; while (end_pos < str_len) { if (strncmp(&str[end_pos], sep_str, sep_len) == 0) return substr(start_pos, end_pos - start_pos); end_pos++; } // They want the last token in the string, not something in between return substr(start_pos); } CString CString::Ellipsize(unsigned int uLen) const { if (uLen >= size()) { return *this; } string sRet; // @todo this looks suspect if (uLen < 4) { for (unsigned int a = 0; a < uLen; a++) { sRet += "."; } return sRet; } sRet = substr(0, uLen - 3) + "..."; return sRet; } CString CString::Left(size_type uCount) const { uCount = (uCount > length()) ? length() : uCount; return substr(0, uCount); } CString CString::Right(size_type uCount) const { uCount = (uCount > length()) ? length() : uCount; return substr(length() - uCount, uCount); } CString::size_type CString::URLSplit(MCString& msRet) const { msRet.clear(); VCString vsPairs; Split("&", vsPairs); for (const CString& sPair : vsPairs) { msRet[sPair.Token(0, false, "=") .Escape(CString::EURL, CString::EASCII)] = sPair.Token(1, true, "=").Escape(CString::EURL, CString::EASCII); } return msRet.size(); } CString::size_type CString::OptionSplit(MCString& msRet, bool bUpperKeys) const { CString sName; CString sCopy(*this); msRet.clear(); while (!sCopy.empty()) { sName = sCopy.Token(0, false, "=", false, "\"", "\"", false).Trim_n(); sCopy = sCopy.Token(1, true, "=", false, "\"", "\"", false).TrimLeft_n(); if (sName.empty()) { continue; } VCString vsNames; sName.Split(" ", vsNames, false, "\"", "\""); for (unsigned int a = 0; a < vsNames.size(); a++) { CString sKeyName = vsNames[a]; if (bUpperKeys) { sKeyName.MakeUpper(); } if ((a + 1) == vsNames.size()) { msRet[sKeyName] = sCopy.Token(0, false, " ", false, "\"", "\""); sCopy = sCopy.Token(1, true, " ", false, "\"", "\"", false); } else { msRet[sKeyName] = ""; } } } return msRet.size(); } CString::size_type CString::QuoteSplit(VCString& vsRet) const { vsRet.clear(); return Split(" ", vsRet, false, "\"", "\"", true); } CString::size_type CString::Split(const CString& sDelim, VCString& vsRet, bool bAllowEmpty, const CString& sLeft, const CString& sRight, bool bTrimQuotes, bool bTrimWhiteSpace) const { vsRet.clear(); if (empty()) { return 0; } CString sTmp; bool bInside = false; size_type uDelimLen = sDelim.length(); size_type uLeftLen = sLeft.length(); size_type uRightLen = sRight.length(); const char* p = c_str(); if (!bAllowEmpty) { while (strncasecmp(p, sDelim.c_str(), uDelimLen) == 0) { p += uDelimLen; } } while (*p) { if (uLeftLen && uRightLen && !bInside && strncasecmp(p, sLeft.c_str(), uLeftLen) == 0) { if (!bTrimQuotes) { sTmp += sLeft; } p += uLeftLen; bInside = true; continue; } if (uLeftLen && uRightLen && bInside && strncasecmp(p, sRight.c_str(), uRightLen) == 0) { if (!bTrimQuotes) { sTmp += sRight; } p += uRightLen; bInside = false; continue; } if (uDelimLen && !bInside && strncasecmp(p, sDelim.c_str(), uDelimLen) == 0) { if (bTrimWhiteSpace) { sTmp.Trim(); } vsRet.push_back(sTmp); sTmp.clear(); p += uDelimLen; if (!bAllowEmpty) { while (strncasecmp(p, sDelim.c_str(), uDelimLen) == 0) { p += uDelimLen; } } bInside = false; continue; } else { sTmp += *p; } p++; } if (!sTmp.empty()) { if (bTrimWhiteSpace) { sTmp.Trim(); } vsRet.push_back(sTmp); } return vsRet.size(); } CString::size_type CString::Split(const CString& sDelim, SCString& ssRet, bool bAllowEmpty, const CString& sLeft, const CString& sRight, bool bTrimQuotes, bool bTrimWhiteSpace) const { VCString vsTokens; Split(sDelim, vsTokens, bAllowEmpty, sLeft, sRight, bTrimQuotes, bTrimWhiteSpace); ssRet.clear(); for (const CString& sToken : vsTokens) { ssRet.insert(sToken); } return ssRet.size(); } CString CString::NamedFormat(const CString& sFormat, const MCString& msValues) { CString sRet; CString sKey; bool bEscape = false; bool bParam = false; const char* p = sFormat.c_str(); while (*p) { if (!bParam) { if (bEscape) { sRet += *p; bEscape = false; } else if (*p == '\\') { bEscape = true; } else if (*p == '{') { bParam = true; sKey.clear(); } else { sRet += *p; } } else { if (bEscape) { sKey += *p; bEscape = false; } else if (*p == '\\') { bEscape = true; } else if (*p == '}') { bParam = false; MCString::const_iterator it = msValues.find(sKey); if (it != msValues.end()) { sRet += (*it).second; } } else { sKey += *p; } } p++; } return sRet; } CString CString::RandomString(unsigned int uLength) { const char chars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789!?.,:;/*-+_()"; // -1 because sizeof() includes the trailing '\0' byte const size_t len = sizeof(chars) / sizeof(chars[0]) - 1; size_t p; CString sRet; for (unsigned int a = 0; a < uLength; a++) { p = (size_t)(len * (rand() / (RAND_MAX + 1.0))); sRet += chars[p]; } return sRet; } bool CString::Base64Encode(unsigned int uWrap) { CString sCopy(*this); return sCopy.Base64Encode(*this, uWrap); } unsigned long CString::Base64Decode() { CString sCopy(*this); return sCopy.Base64Decode(*this); } CString CString::Base64Encode_n(unsigned int uWrap) const { CString sRet; Base64Encode(sRet, uWrap); return sRet; } CString CString::Base64Decode_n() const { CString sRet; Base64Decode(sRet); return sRet; } bool CString::Base64Encode(CString& sRet, unsigned int uWrap) const { const char b64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; sRet.clear(); size_t len = size(); const unsigned char* input = (const unsigned char*)c_str(); unsigned char* output, *p; size_t i = 0, mod = len % 3, toalloc; toalloc = (len / 3) * 4 + (3 - mod) % 3 + 1 + 8; if (uWrap) { toalloc += len / 57; if (len % 57) { toalloc++; } } if (toalloc < len) { return 0; } p = output = new unsigned char[toalloc]; while (i < len - mod) { *p++ = b64table[input[i++] >> 2]; *p++ = b64table[((input[i - 1] << 4) | (input[i] >> 4)) & 0x3f]; *p++ = b64table[((input[i] << 2) | (input[i + 1] >> 6)) & 0x3f]; *p++ = b64table[input[i + 1] & 0x3f]; i += 2; if (uWrap && !(i % 57)) { *p++ = '\n'; } } if (!mod) { if (uWrap && i % 57) { *p++ = '\n'; } } else { *p++ = b64table[input[i++] >> 2]; *p++ = b64table[((input[i - 1] << 4) | (input[i] >> 4)) & 0x3f]; if (mod == 1) { *p++ = '='; } else { *p++ = b64table[(input[i] << 2) & 0x3f]; } *p++ = '='; if (uWrap) { *p++ = '\n'; } } *p = 0; sRet = (char*)output; delete[] output; return true; } unsigned long CString::Base64Decode(CString& sRet) const { CString sTmp(*this); // remove new lines sTmp.Replace("\r", ""); sTmp.Replace("\n", ""); const char* in = sTmp.c_str(); char c, c1, *p; unsigned long i; unsigned long uLen = sTmp.size(); char* out = new char[uLen + 1]; for (i = 0, p = out; i < uLen; i++) { c = (char)base64_table[(unsigned char)in[i++]]; c1 = (char)base64_table[(unsigned char)in[i++]]; *p++ = char((c << 2) | ((c1 >> 4) & 0x3)); if (i < uLen) { if (in[i] == '=') { break; } c = (char)base64_table[(unsigned char)in[i]]; *p++ = char(((c1 << 4) & 0xf0) | ((c >> 2) & 0xf)); } if (++i < uLen) { if (in[i] == '=') { break; } *p++ = char(((c << 6) & 0xc0) | (char)base64_table[(unsigned char)in[i]]); } } *p = '\0'; unsigned long uRet = p - out; sRet.clear(); sRet.append(out, uRet); delete[] out; return uRet; } CString CString::MD5() const { return (const char*)CMD5(*this); } CString CString::SHA256() const { unsigned char digest[SHA256_DIGEST_SIZE]; char digest_hex[SHA256_DIGEST_SIZE * 2 + 1]; const unsigned char* message = (const unsigned char*)c_str(); sha256(message, length(), digest); snprintf(digest_hex, sizeof(digest_hex), "%02x%02x%02x%02x%02x%02x%02x%02x" "%02x%02x%02x%02x%02x%02x%02x%02x" "%02x%02x%02x%02x%02x%02x%02x%02x" "%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15], digest[16], digest[17], digest[18], digest[19], digest[20], digest[21], digest[22], digest[23], digest[24], digest[25], digest[26], digest[27], digest[28], digest[29], digest[30], digest[31]); return digest_hex; } #ifdef HAVE_LIBSSL CString CString::Encrypt_n(const CString& sPass, const CString& sIvec) const { CString sRet; sRet.Encrypt(sPass, sIvec); return sRet; } CString CString::Decrypt_n(const CString& sPass, const CString& sIvec) const { CString sRet; sRet.Decrypt(sPass, sIvec); return sRet; } void CString::Encrypt(const CString& sPass, const CString& sIvec) { Crypt(sPass, true, sIvec); } void CString::Decrypt(const CString& sPass, const CString& sIvec) { Crypt(sPass, false, sIvec); } void CString::Crypt(const CString& sPass, bool bEncrypt, const CString& sIvec) { unsigned char szIvec[8] = {0, 0, 0, 0, 0, 0, 0, 0}; BF_KEY bKey; if (sIvec.length() >= 8) { memcpy(szIvec, sIvec.data(), 8); } BF_set_key(&bKey, (unsigned int)sPass.length(), (unsigned char*)sPass.data()); unsigned int uPad = (length() % 8); if (uPad) { uPad = 8 - uPad; append(uPad, '\0'); } size_t uLen = length(); unsigned char* szBuff = (unsigned char*)malloc(uLen); BF_cbc_encrypt((const unsigned char*)data(), szBuff, uLen, &bKey, szIvec, ((bEncrypt) ? BF_ENCRYPT : BF_DECRYPT)); clear(); append((const char*)szBuff, uLen); free(szBuff); } #endif // HAVE_LIBSSL CString CString::ToPercent(double d) { char szRet[32]; snprintf(szRet, 32, "%.02f%%", d); return szRet; } CString CString::ToByteStr(unsigned long long d) { const unsigned long long KiB = 1024; const unsigned long long MiB = KiB * 1024; const unsigned long long GiB = MiB * 1024; const unsigned long long TiB = GiB * 1024; if (d > TiB) { return CString(d / TiB) + " TiB"; } else if (d > GiB) { return CString(d / GiB) + " GiB"; } else if (d > MiB) { return CString(d / MiB) + " MiB"; } else if (d > KiB) { return CString(d / KiB) + " KiB"; } return CString(d) + " B"; } CString CString::ToTimeStr(unsigned long s) { const unsigned long m = 60; const unsigned long h = m * 60; const unsigned long d = h * 24; const unsigned long w = d * 7; const unsigned long y = d * 365; CString sRet; #define TIMESPAN(time, str) \ if (s >= time) { \ sRet += CString(s / time) + str " "; \ s = s % time; \ } TIMESPAN(y, "y"); TIMESPAN(w, "w"); TIMESPAN(d, "d"); TIMESPAN(h, "h"); TIMESPAN(m, "m"); TIMESPAN(1, "s"); if (sRet.empty()) return "0s"; return sRet.RightChomp_n(); } bool CString::ToBool() const { CString sTrimmed = Trim_n(); return (!sTrimmed.Trim_n("0").empty() && !sTrimmed.Equals("false") && !sTrimmed.Equals("off") && !sTrimmed.Equals("no") && !sTrimmed.Equals("n")); } short CString::ToShort() const { return (short int)strtol(this->c_str(), (char**)nullptr, 10); } unsigned short CString::ToUShort() const { return (unsigned short int)strtoul(this->c_str(), (char**)nullptr, 10); } unsigned int CString::ToUInt() const { return (unsigned int)strtoul(this->c_str(), (char**)nullptr, 10); } int CString::ToInt() const { return (int)strtol(this->c_str(), (char**)nullptr, 10); } long CString::ToLong() const { return strtol(this->c_str(), (char**)nullptr, 10); } unsigned long CString::ToULong() const { return strtoul(c_str(), nullptr, 10); } unsigned long long CString::ToULongLong() const { return strtoull(c_str(), nullptr, 10); } long long CString::ToLongLong() const { return strtoll(c_str(), nullptr, 10); } double CString::ToDouble() const { return strtod(c_str(), nullptr); } bool CString::Trim(const CString& s) { bool bLeft = TrimLeft(s); return (TrimRight(s) || bLeft); } bool CString::TrimLeft(const CString& s) { size_type i = find_first_not_of(s); if (i == 0) return false; if (i != npos) this->erase(0, i); else this->clear(); return true; } bool CString::TrimRight(const CString& s) { size_type i = find_last_not_of(s); if (i + 1 == length()) return false; if (i != npos) this->erase(i + 1, npos); else this->clear(); return true; } CString CString::Trim_n(const CString& s) const { CString sRet = *this; sRet.Trim(s); return sRet; } CString CString::TrimLeft_n(const CString& s) const { CString sRet = *this; sRet.TrimLeft(s); return sRet; } CString CString::TrimRight_n(const CString& s) const { CString sRet = *this; sRet.TrimRight(s); return sRet; } bool CString::TrimPrefix(const CString& sPrefix) { if (StartsWith(sPrefix)) { LeftChomp(sPrefix.length()); return true; } else { return false; } } bool CString::TrimSuffix(const CString& sSuffix) { if (Right(sSuffix.length()).Equals(sSuffix)) { RightChomp(sSuffix.length()); return true; } else { return false; } } size_t CString::Find(const CString& s, CaseSensitivity cs) const { if (cs == CaseSensitive) { return find(s); } else { return AsLower().find(s.AsLower()); } } bool CString::StartsWith(const CString& sPrefix, CaseSensitivity cs) const { return Left(sPrefix.length()).Equals(sPrefix, cs); } bool CString::EndsWith(const CString& sSuffix, CaseSensitivity cs) const { return Right(sSuffix.length()).Equals(sSuffix, cs); } bool CString::Contains(const CString& s, CaseSensitivity cs) const { return Find(s, cs) != npos; } CString CString::TrimPrefix_n(const CString& sPrefix) const { CString sRet = *this; sRet.TrimPrefix(sPrefix); return sRet; } CString CString::TrimSuffix_n(const CString& sSuffix) const { CString sRet = *this; sRet.TrimSuffix(sSuffix); return sRet; } CString CString::LeftChomp_n(size_type uLen) const { CString sRet = *this; sRet.LeftChomp(uLen); return sRet; } CString CString::RightChomp_n(size_type uLen) const { CString sRet = *this; sRet.RightChomp(uLen); return sRet; } bool CString::LeftChomp(size_type uLen) { bool bRet = false; while ((uLen--) && (length())) { erase(0, 1); bRet = true; } return bRet; } bool CString::RightChomp(size_type uLen) { bool bRet = false; while ((uLen--) && (length())) { erase(length() - 1); bRet = true; } return bRet; } CString CString::StripControls_n() const { CString sRet; const unsigned char* pStart = (const unsigned char*)data(); unsigned char ch = *pStart; size_type iLength = length(); sRet.reserve(iLength); bool colorCode = false; unsigned int digits = 0; bool comma = false; for (unsigned int a = 0; a < iLength; a++, ch = pStart[a]) { // Color code. Format: \x03([0-9]{1,2}(,[0-9]{1,2})?)? if (ch == 0x03) { colorCode = true; digits = 0; comma = false; continue; } if (colorCode) { if (isdigit(ch) && digits < 2) { digits++; continue; } if (ch == ',' && !comma) { comma = true; digits = 0; continue; } colorCode = false; if (digits == 0 && comma) { // There was a ',' which wasn't followed by digits, we should // print it. sRet += ','; } } // CO controls codes if (ch < 0x20 || ch == 0x7F) continue; sRet += ch; } if (colorCode && digits == 0 && comma) { sRet += ','; } sRet.reserve(0); return sRet; } CString& CString::StripControls() { return (*this = StripControls_n()); } //////////////// MCString //////////////// const MCString MCString::EmptyMap; MCString::status_t MCString::WriteToDisk(const CString& sPath, mode_t iMode) const { CFile cFile(sPath); if (this->empty()) { if (!cFile.Exists()) return MCS_SUCCESS; if (cFile.Delete()) return MCS_SUCCESS; } if (!cFile.Open(O_WRONLY | O_CREAT | O_TRUNC, iMode)) { return MCS_EOPEN; } for (const auto& it : *this) { CString sKey = it.first; CString sValue = it.second; if (!WriteFilter(sKey, sValue)) { return MCS_EWRITEFIL; } if (sKey.empty()) { continue; } if (cFile.Write(Encode(sKey) + " " + Encode(sValue) + "\n") <= 0) { return MCS_EWRITE; } } cFile.Close(); return MCS_SUCCESS; } MCString::status_t MCString::ReadFromDisk(const CString& sPath) { clear(); CFile cFile(sPath); if (!cFile.Open(O_RDONLY)) { return MCS_EOPEN; } CString sBuffer; while (cFile.ReadLine(sBuffer)) { sBuffer.Trim(); CString sKey = sBuffer.Token(0); CString sValue = sBuffer.Token(1); Decode(sKey); Decode(sValue); if (!ReadFilter(sKey, sValue)) return MCS_EREADFIL; (*this)[sKey] = sValue; } cFile.Close(); return MCS_SUCCESS; } static const char hexdigits[] = "0123456789abcdef"; CString& MCString::Encode(CString& sValue) const { CString sTmp; for (unsigned char c : sValue) { // isalnum() needs unsigned char as argument and this code // assumes unsigned, too. if (isalnum(c)) { sTmp += c; } else { sTmp += "%"; sTmp += hexdigits[c >> 4]; sTmp += hexdigits[c & 0xf]; sTmp += ";"; } } sValue = sTmp; return sValue; } CString& MCString::Decode(CString& sValue) const { const char* pTmp = sValue.c_str(); char* endptr; CString sTmp; while (*pTmp) { if (*pTmp != '%') { sTmp += *pTmp++; } else { char ch = (char)strtol(pTmp + 1, &endptr, 16); if (*endptr == ';') { sTmp += ch; pTmp = ++endptr; } else { sTmp += *pTmp++; } } } sValue = sTmp; return sValue; } znc-1.7.5/src/main.cpp0000644000175000017500000004506213542151610014766 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #if defined(HAVE_LIBSSL) && defined(HAVE_PTHREAD) && \ (!defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100004) /* Starting with version 1.1.0-pre4, OpenSSL has a new threading implementation that doesn't need locking callbacks. "OpenSSL now uses a new threading API. It is no longer necessary to set locking callbacks to use OpenSSL in a multi-threaded environment. There are two supported threading models: pthreads and windows threads. It is also possible to configure OpenSSL at compile time for "no-threads". The old threading API should no longer be used. The functions have been replaced with "no-op" compatibility macros." See openssl/openssl@2e52e7df518d80188c865ea3f7bb3526d14b0c08. */ #include #include #include static std::vector> lock_cs; static void locking_callback(int mode, int type, const char* file, int line) { if (mode & CRYPTO_LOCK) { lock_cs[type]->lock(); } else { lock_cs[type]->unlock(); } } #if OPENSSL_VERSION_NUMBER >= 0x10000000 static void thread_id_callback(CRYPTO_THREADID *id) { CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self()); } #else static unsigned long thread_id_callback() { return (unsigned long)pthread_self(); } #endif static CRYPTO_dynlock_value* dyn_create_callback(const char* file, int line) { return (CRYPTO_dynlock_value*)new CMutex; } static void dyn_lock_callback(int mode, CRYPTO_dynlock_value* dlock, const char* file, int line) { CMutex* mtx = (CMutex*)dlock; if (mode & CRYPTO_LOCK) { mtx->lock(); } else { mtx->unlock(); } } static void dyn_destroy_callback(CRYPTO_dynlock_value* dlock, const char* file, int line) { CMutex* mtx = (CMutex*)dlock; delete mtx; } static void thread_setup() { lock_cs.resize(CRYPTO_num_locks()); for (std::unique_ptr& mtx : lock_cs) mtx = std::unique_ptr(new CMutex()); #if OPENSSL_VERSION_NUMBER >= 0x10000000 CRYPTO_THREADID_set_callback(&thread_id_callback); #else CRYPTO_set_id_callback(&thread_id_callback); #endif CRYPTO_set_locking_callback(&locking_callback); CRYPTO_set_dynlock_create_callback(&dyn_create_callback); CRYPTO_set_dynlock_lock_callback(&dyn_lock_callback); CRYPTO_set_dynlock_destroy_callback(&dyn_destroy_callback); } #else #define thread_setup() #endif using std::cout; using std::endl; using std::set; #ifdef HAVE_GETOPT_LONG #include #else #define no_argument 0 #define required_argument 1 #define optional_argument 2 struct option { const char* a; int opt; int* flag; int val; }; static inline int getopt_long(int argc, char* const argv[], const char* optstring, const struct option*, int*) { return getopt(argc, argv, optstring); } #endif static const struct option g_LongOpts[] = { {"help", no_argument, nullptr, 'h'}, {"version", no_argument, nullptr, 'v'}, {"debug", no_argument, nullptr, 'D'}, {"foreground", no_argument, nullptr, 'f'}, {"no-color", no_argument, nullptr, 'n'}, {"allow-root", no_argument, nullptr, 'r'}, {"makeconf", no_argument, nullptr, 'c'}, {"makepass", no_argument, nullptr, 's'}, {"makepem", no_argument, nullptr, 'p'}, {"datadir", required_argument, nullptr, 'd'}, {nullptr, 0, nullptr, 0}}; static void GenerateHelp(const char* appname) { CUtils::PrintMessage("USAGE: " + CString(appname) + " [options]"); CUtils::PrintMessage("Options are:"); CUtils::PrintMessage( "\t-h, --help List available command line options (this page)"); CUtils::PrintMessage( "\t-v, --version Output version information and exit"); CUtils::PrintMessage( "\t-c, --makeconf Interactively create a new config"); CUtils::PrintMessage( "\t-d, --datadir Set a different ZNC repository (default is " "~/.znc)"); CUtils::PrintMessage( "\t-D, --debug Output debugging information (Implies -f)"); CUtils::PrintMessage("\t-f, --foreground Don't fork into the background"); CUtils::PrintMessage( "\t-n, --no-color Don't use escape sequences in the output"); #ifdef HAVE_LIBSSL CUtils::PrintMessage( "\t-p, --makepem Generates a pemfile for use with SSL"); #endif /* HAVE_LIBSSL */ CUtils::PrintMessage( "\t-r, --allow-root Don't complain if ZNC is run as root"); CUtils::PrintMessage( "\t-s, --makepass Generates a password for use in config"); } class CSignalHandler { public: CSignalHandler(CZNC* pZNC) { if (pipe(m_iPipe)) { DEBUG("Ouch, can't open pipe for signal handler: " << strerror(errno)); exit(1); } pZNC->GetManager().MonitorFD(new CSignalHandlerMonitorFD(m_iPipe[0])); sigset_t signals; sigfillset(&signals); pthread_sigmask(SIG_SETMASK, &signals, nullptr); m_thread = std::thread([=]() { HandleSignals(pZNC); }); } ~CSignalHandler() { pthread_cancel(m_thread.native_handle()); m_thread.join(); } private: class CSignalHandlerMonitorFD : public CSMonitorFD { // This class just prevents the pipe buffer from filling by clearing it public: CSignalHandlerMonitorFD(int fd) { Add(fd, CSockManager::ECT_Read); } bool FDsThatTriggered( const std::map& miiReadyFds) override { for (const auto& it : miiReadyFds) { if (it.second) { int sig; read(it.first, &sig, sizeof(sig)); } } return true; } }; void HandleSignals(CZNC* pZNC) { sigset_t signals; sigemptyset(&signals); sigaddset(&signals, SIGHUP); sigaddset(&signals, SIGUSR1); sigaddset(&signals, SIGINT); sigaddset(&signals, SIGQUIT); sigaddset(&signals, SIGTERM); sigaddset(&signals, SIGPIPE); // Handle only these signals specially; the rest will have their default // action, but in this thread pthread_sigmask(SIG_SETMASK, &signals, nullptr); while (true) { int sig; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr); // This thread can be cancelled, but only during this function. // Such cancel will be the only way to finish this thread. if (sigwait(&signals, &sig) == -1) continue; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr); // TODO probably move switch() to CSignalHandlerMonitorFD? switch (sig) { case SIGHUP: pZNC->SetConfigState(CZNC::ECONFIG_NEED_REHASH); break; case SIGUSR1: pZNC->SetConfigState(CZNC::ECONFIG_NEED_VERBOSE_WRITE); break; case SIGINT: case SIGQUIT: case SIGTERM: pZNC->SetConfigState(CZNC::ECONFIG_NEED_QUIT); // Reset handler to default by: // * not blocking it // * not waiting for it // So, if ^C is pressed, but for some reason it didn't work, // second ^C will kill the process for sure. sigdelset(&signals, sig); pthread_sigmask(SIG_SETMASK, &signals, nullptr); break; case SIGPIPE: default: break; } // This write() must succeed because POSIX guarantees that writes of // less than PIPE_BUF are atomic (and PIPE_BUF is at least 512). size_t w = write(m_iPipe[1], &sig, sizeof(sig)); if (w != sizeof(sig)) { DEBUG( "Something bad happened during write() to a pipe for " "signal handler, wrote " << w << " bytes: " << strerror(errno)); exit(1); } } } std::thread m_thread; // pipe for waking up the main thread int m_iPipe[2]; }; static bool isRoot() { // User root? If one of these were root, we could switch the others to root, // too return (geteuid() == 0 || getuid() == 0); } static void seedPRNG() { struct timeval tv; unsigned int seed; // Try to find a seed which can't be as easily guessed as only time() if (gettimeofday(&tv, nullptr) == 0) { seed = (unsigned int)tv.tv_sec; // This is in [0:1e6], which means that roughly 20 bits are // actually used, let's try to shuffle the high bits. seed ^= uint32_t((tv.tv_usec << 10) | tv.tv_usec); } else seed = (unsigned int)time(nullptr); seed ^= rand(); seed ^= getpid(); srand(seed); } int main(int argc, char** argv) { CString sConfig; CString sDataDir = ""; thread_setup(); seedPRNG(); CDebug::SetStdoutIsTTY(isatty(1)); int iArg, iOptIndex = -1; bool bMakeConf = false; bool bMakePass = false; bool bAllowRoot = false; bool bForeground = false; #ifdef ALWAYS_RUN_IN_FOREGROUND bForeground = true; #endif #ifdef HAVE_LIBSSL bool bMakePem = false; #endif CZNC::CreateInstance(); while ((iArg = getopt_long(argc, argv, "hvnrcspd:Df", g_LongOpts, &iOptIndex)) != -1) { switch (iArg) { case 'h': GenerateHelp(argv[0]); return 0; case 'v': cout << CZNC::GetTag() << endl; cout << CZNC::GetCompileOptionsString() << endl; return 0; case 'n': CDebug::SetStdoutIsTTY(false); break; case 'r': bAllowRoot = true; break; case 'c': bMakeConf = true; break; case 's': bMakePass = true; break; case 'p': #ifdef HAVE_LIBSSL bMakePem = true; break; #else CUtils::PrintError("ZNC is compiled without SSL support."); return 1; #endif /* HAVE_LIBSSL */ case 'd': sDataDir = CString(optarg); break; case 'f': bForeground = true; break; case 'D': bForeground = true; CDebug::SetDebug(true); break; case '?': default: GenerateHelp(argv[0]); return 1; } } if (optind < argc) { CUtils::PrintError("Unrecognized command line arguments."); CUtils::PrintError("Did you mean to run `/znc " + CString(argv[optind]) + "' in IRC client instead?"); CUtils::PrintError("Hint: `/znc " + CString(argv[optind]) + "' is an alias for `/msg *status " + CString(argv[optind]) + "'"); return 1; } CZNC* pZNC = &CZNC::Get(); pZNC->InitDirs(((argc) ? argv[0] : ""), sDataDir); #ifdef HAVE_LIBSSL if (bMakePem) { pZNC->WritePemFile(); CZNC::DestroyInstance(); return 0; } #endif /* HAVE_LIBSSL */ if (bMakePass) { CString sSalt; CUtils::PrintMessage("Type your new password."); CString sHash = CUtils::GetSaltedHashPass(sSalt); CUtils::PrintMessage("Kill ZNC process, if it's running."); CUtils::PrintMessage( "Then replace password in the section of your config with " "this:"); // Not PrintMessage(), to remove [**] from the beginning, to ease // copypasting std::cout << "" << std::endl; std::cout << "\tMethod = " << CUtils::sDefaultHash << std::endl; std::cout << "\tHash = " << sHash << std::endl; std::cout << "\tSalt = " << sSalt << std::endl; std::cout << "" << std::endl; CUtils::PrintMessage( "After that start ZNC again, and you should be able to login with " "the new password."); CZNC::DestroyInstance(); return 0; } { set ssGlobalMods; set ssUserMods; set ssNetworkMods; CUtils::PrintAction("Checking for list of available modules"); pZNC->GetModules().GetAvailableMods(ssGlobalMods, CModInfo::GlobalModule); pZNC->GetModules().GetAvailableMods(ssUserMods, CModInfo::UserModule); pZNC->GetModules().GetAvailableMods(ssNetworkMods, CModInfo::NetworkModule); if (ssGlobalMods.empty() && ssUserMods.empty() && ssNetworkMods.empty()) { CUtils::PrintStatus(false, ""); CUtils::PrintError( "No modules found. Perhaps you didn't install ZNC properly?"); CUtils::PrintError( "Read https://wiki.znc.in/Installation for instructions."); if (!CUtils::GetBoolInput( "Do you really want to run ZNC without any modules?", false)) { CZNC::DestroyInstance(); return 1; } } CUtils::PrintStatus(true, ""); } if (isRoot()) { CUtils::PrintError( "You are running ZNC as root! Don't do that! There are not many " "valid"); CUtils::PrintError( "reasons for this and it can, in theory, cause great damage!"); if (!bAllowRoot) { CZNC::DestroyInstance(); return 1; } CUtils::PrintError("You have been warned."); CUtils::PrintError( "Hit CTRL+C now if you don't want to run ZNC as root."); CUtils::PrintError("ZNC will start in 30 seconds."); sleep(30); } if (bMakeConf) { if (!pZNC->WriteNewConfig(sConfig)) { CZNC::DestroyInstance(); return 0; } /* Fall through to normal bootup */ } CString sConfigError; if (!pZNC->ParseConfig(sConfig, sConfigError)) { CUtils::PrintError("Unrecoverable config error."); CZNC::DestroyInstance(); return 1; } if (!pZNC->OnBoot()) { CUtils::PrintError("Exiting due to module boot errors."); CZNC::DestroyInstance(); return 1; } if (bForeground) { int iPid = getpid(); CUtils::PrintMessage("Staying open for debugging [pid: " + CString(iPid) + "]"); pZNC->WritePidFile(iPid); CUtils::PrintMessage(CZNC::GetTag()); } else { CUtils::PrintAction("Forking into the background"); int iPid = fork(); if (iPid == -1) { CUtils::PrintStatus(false, strerror(errno)); CZNC::DestroyInstance(); return 1; } if (iPid > 0) { // We are the parent. We are done and will go to bed. CUtils::PrintStatus(true, "[pid: " + CString(iPid) + "]"); pZNC->WritePidFile(iPid); CUtils::PrintMessage(CZNC::GetTag()); /* Don't destroy pZNC here or it will delete the pid file. */ return 0; } /* fcntl() locks don't necessarily propagate to forked() * children. Reacquire the lock here. Use the blocking * call to avoid race condition with parent exiting. */ if (!pZNC->WaitForChildLock()) { CUtils::PrintError( "Child was unable to obtain lock on config file."); CZNC::DestroyInstance(); return 1; } // Redirect std in/out/err to /dev/null close(0); open("/dev/null", O_RDONLY); close(1); open("/dev/null", O_WRONLY); close(2); open("/dev/null", O_WRONLY); CDebug::SetStdoutIsTTY(false); // We are the child. There is no way we can be a process group // leader, thus setsid() must succeed. setsid(); // Now we are in our own process group and session (no // controlling terminal). We are independent! } // Handle all signals in separate thread std::unique_ptr SignalHandler(new CSignalHandler(pZNC)); int iRet = 0; try { pZNC->Loop(); } catch (const CException& e) { switch (e.GetType()) { case CException::EX_Shutdown: iRet = 0; break; case CException::EX_Restart: { // strdup() because GCC is stupid char* args[] = { strdup(argv[0]), strdup("--datadir"), strdup(pZNC->GetZNCPath().c_str()), nullptr, nullptr, nullptr, nullptr}; int pos = 3; if (CDebug::Debug()) args[pos++] = strdup("--debug"); else if (bForeground) args[pos++] = strdup("--foreground"); if (!CDebug::StdoutIsTTY()) args[pos++] = strdup("--no-color"); if (bAllowRoot) args[pos++] = strdup("--allow-root"); // The above code adds 3 entries to args tops // which means the array should be big enough SignalHandler.reset(); CZNC::DestroyInstance(); execvp(args[0], args); CUtils::PrintError("Unable to restart ZNC [" + CString(strerror(errno)) + "]"); } /* Fall through */ default: iRet = 1; } } SignalHandler.reset(); CZNC::DestroyInstance(); CUtils::PrintMessage("Exiting"); return iRet; } znc-1.7.5/src/Client.cpp0000644000175000017500000013117313542151610015257 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include using std::set; using std::map; using std::vector; #define CALLMOD(MOD, CLIENT, USER, NETWORK, FUNC) \ { \ CModule* pModule = nullptr; \ if (NETWORK && (pModule = (NETWORK)->GetModules().FindModule(MOD))) { \ try { \ CClient* pOldClient = pModule->GetClient(); \ pModule->SetClient(CLIENT); \ pModule->FUNC; \ pModule->SetClient(pOldClient); \ } catch (const CModule::EModException& e) { \ if (e == CModule::UNLOAD) { \ (NETWORK)->GetModules().UnloadModule(MOD); \ } \ } \ } else if ((pModule = (USER)->GetModules().FindModule(MOD))) { \ try { \ CClient* pOldClient = pModule->GetClient(); \ CIRCNetwork* pOldNetwork = pModule->GetNetwork(); \ pModule->SetClient(CLIENT); \ pModule->SetNetwork(NETWORK); \ pModule->FUNC; \ pModule->SetClient(pOldClient); \ pModule->SetNetwork(pOldNetwork); \ } catch (const CModule::EModException& e) { \ if (e == CModule::UNLOAD) { \ (USER)->GetModules().UnloadModule(MOD); \ } \ } \ } else if ((pModule = CZNC::Get().GetModules().FindModule(MOD))) { \ try { \ CClient* pOldClient = pModule->GetClient(); \ CIRCNetwork* pOldNetwork = pModule->GetNetwork(); \ CUser* pOldUser = pModule->GetUser(); \ pModule->SetClient(CLIENT); \ pModule->SetNetwork(NETWORK); \ pModule->SetUser(USER); \ pModule->FUNC; \ pModule->SetClient(pOldClient); \ pModule->SetNetwork(pOldNetwork); \ pModule->SetUser(pOldUser); \ } catch (const CModule::EModException& e) { \ if (e == CModule::UNLOAD) { \ CZNC::Get().GetModules().UnloadModule(MOD); \ } \ } \ } else { \ PutStatus(t_f("No such module {1}")(MOD)); \ } \ } CClient::~CClient() { if (m_spAuth) { CClientAuth* pAuth = (CClientAuth*)&(*m_spAuth); pAuth->Invalidate(); } if (m_pUser != nullptr) { m_pUser->AddBytesRead(GetBytesRead()); m_pUser->AddBytesWritten(GetBytesWritten()); } } void CClient::SendRequiredPasswordNotice() { PutClient(":irc.znc.in 464 " + GetNick() + " :Password required"); PutClient( ":irc.znc.in NOTICE " + GetNick() + " :*** " "You need to send your password. " "Configure your client to send a server password."); PutClient( ":irc.znc.in NOTICE " + GetNick() + " :*** " "To connect now, you can use /quote PASS :, " "or /quote PASS /: to connect to a " "specific network."); } void CClient::ReadLine(const CString& sData) { CLanguageScope user_lang(GetUser() ? GetUser()->GetLanguage() : ""); CString sLine = sData; sLine.Replace("\n", ""); sLine.Replace("\r", ""); DEBUG("(" << GetFullName() << ") CLI -> ZNC [" << CDebug::Filter(sLine) << "]"); bool bReturn = false; if (IsAttached()) { NETWORKMODULECALL(OnUserRaw(sLine), m_pUser, m_pNetwork, this, &bReturn); } else { GLOBALMODULECALL(OnUnknownUserRaw(this, sLine), &bReturn); } if (bReturn) return; CMessage Message(sLine); Message.SetClient(this); if (IsAttached()) { NETWORKMODULECALL(OnUserRawMessage(Message), m_pUser, m_pNetwork, this, &bReturn); } else { GLOBALMODULECALL(OnUnknownUserRawMessage(Message), &bReturn); } if (bReturn) return; CString sCommand = Message.GetCommand(); if (!IsAttached()) { // The following commands happen before authentication with ZNC if (sCommand.Equals("PASS")) { m_bGotPass = true; CString sAuthLine = Message.GetParam(0); ParsePass(sAuthLine); AuthUser(); // Don't forward this msg. ZNC has already registered us. return; } else if (sCommand.Equals("NICK")) { CString sNick = Message.GetParam(0); m_sNick = sNick; m_bGotNick = true; AuthUser(); // Don't forward this msg. ZNC will handle nick changes until auth // is complete return; } else if (sCommand.Equals("USER")) { CString sAuthLine = Message.GetParam(0); if (m_sUser.empty() && !sAuthLine.empty()) { ParseUser(sAuthLine); } m_bGotUser = true; if (m_bGotPass) { AuthUser(); } else if (!m_bInCap) { SendRequiredPasswordNotice(); } // Don't forward this msg. ZNC has already registered us. return; } } if (Message.GetType() == CMessage::Type::Capability) { HandleCap(Message); // Don't let the client talk to the server directly about CAP, // we don't want anything enabled that ZNC does not support. return; } if (!m_pUser) { // Only CAP, NICK, USER and PASS are allowed before login return; } switch (Message.GetType()) { case CMessage::Type::Action: bReturn = OnActionMessage(Message); break; case CMessage::Type::CTCP: bReturn = OnCTCPMessage(Message); break; case CMessage::Type::Join: bReturn = OnJoinMessage(Message); break; case CMessage::Type::Mode: bReturn = OnModeMessage(Message); break; case CMessage::Type::Notice: bReturn = OnNoticeMessage(Message); break; case CMessage::Type::Part: bReturn = OnPartMessage(Message); break; case CMessage::Type::Ping: bReturn = OnPingMessage(Message); break; case CMessage::Type::Pong: bReturn = OnPongMessage(Message); break; case CMessage::Type::Quit: bReturn = OnQuitMessage(Message); break; case CMessage::Type::Text: bReturn = OnTextMessage(Message); break; case CMessage::Type::Topic: bReturn = OnTopicMessage(Message); break; default: bReturn = OnOtherMessage(Message); break; } if (bReturn) return; PutIRC(Message.ToString(CMessage::ExcludePrefix | CMessage::ExcludeTags)); } void CClient::SetNick(const CString& s) { m_sNick = s; } void CClient::SetNetwork(CIRCNetwork* pNetwork, bool bDisconnect, bool bReconnect) { if (m_pNetwork) { m_pNetwork->ClientDisconnected(this); if (bDisconnect) { ClearServerDependentCaps(); // Tell the client they are no longer in these channels. const vector& vChans = m_pNetwork->GetChans(); for (const CChan* pChan : vChans) { if (!(pChan->IsDetached())) { PutClient(":" + m_pNetwork->GetIRCNick().GetNickMask() + " PART " + pChan->GetName()); } } } } else if (m_pUser) { m_pUser->UserDisconnected(this); } m_pNetwork = pNetwork; if (bReconnect) { if (m_pNetwork) { m_pNetwork->ClientConnected(this); } else if (m_pUser) { m_pUser->UserConnected(this); } } } const vector& CClient::GetClients() const { if (m_pNetwork) { return m_pNetwork->GetClients(); } return m_pUser->GetUserClients(); } const CIRCSock* CClient::GetIRCSock() const { if (m_pNetwork) { return m_pNetwork->GetIRCSock(); } return nullptr; } CIRCSock* CClient::GetIRCSock() { if (m_pNetwork) { return m_pNetwork->GetIRCSock(); } return nullptr; } void CClient::StatusCTCP(const CString& sLine) { CString sCommand = sLine.Token(0); if (sCommand.Equals("PING")) { PutStatusNotice("\001PING " + sLine.Token(1, true) + "\001"); } else if (sCommand.Equals("VERSION")) { PutStatusNotice("\001VERSION " + CZNC::GetTag() + "\001"); } } bool CClient::SendMotd() { const VCString& vsMotd = CZNC::Get().GetMotd(); if (!vsMotd.size()) { return false; } for (const CString& sLine : vsMotd) { if (m_pNetwork) { PutStatusNotice(m_pNetwork->ExpandString(sLine)); } else { PutStatusNotice(m_pUser->ExpandString(sLine)); } } return true; } void CClient::AuthUser() { if (!m_bGotNick || !m_bGotUser || !m_bGotPass || m_bInCap || IsAttached()) return; m_spAuth = std::make_shared(this, m_sUser, m_sPass); CZNC::Get().AuthUser(m_spAuth); } CClientAuth::CClientAuth(CClient* pClient, const CString& sUsername, const CString& sPassword) : CAuthBase(sUsername, sPassword, pClient), m_pClient(pClient) {} void CClientAuth::RefusedLogin(const CString& sReason) { if (m_pClient) { m_pClient->RefuseLogin(sReason); } } CString CAuthBase::GetRemoteIP() const { if (m_pSock) return m_pSock->GetRemoteIP(); return ""; } void CAuthBase::Invalidate() { m_pSock = nullptr; } void CAuthBase::AcceptLogin(CUser& User) { if (m_pSock) { AcceptedLogin(User); Invalidate(); } } void CAuthBase::RefuseLogin(const CString& sReason) { if (!m_pSock) return; CUser* pUser = CZNC::Get().FindUser(GetUsername()); // If the username is valid, notify that user that someone tried to // login. Use sReason because there are other reasons than "wrong // password" for a login to be rejected (e.g. fail2ban). if (pUser) { pUser->PutStatusNotice(t_f( "A client from {1} attempted to login as you, but was rejected: " "{2}")(GetRemoteIP(), sReason)); } GLOBALMODULECALL(OnFailedLogin(GetUsername(), GetRemoteIP()), NOTHING); RefusedLogin(sReason); Invalidate(); } void CClient::RefuseLogin(const CString& sReason) { PutStatus("Bad username and/or password."); PutClient(":irc.znc.in 464 " + GetNick() + " :" + sReason); Close(Csock::CLT_AFTERWRITE); } void CClientAuth::AcceptedLogin(CUser& User) { if (m_pClient) { m_pClient->AcceptLogin(User); } } void CClient::AcceptLogin(CUser& User) { m_sPass = ""; m_pUser = &User; // Set our proper timeout and set back our proper timeout mode // (constructor set a different timeout and mode) SetTimeout(User.GetNoTrafficTimeout(), TMO_READ); SetSockName("USR::" + m_pUser->GetUserName()); SetEncoding(m_pUser->GetClientEncoding()); if (!m_sNetwork.empty()) { m_pNetwork = m_pUser->FindNetwork(m_sNetwork); if (!m_pNetwork) { PutStatus(t_f("Network {1} doesn't exist.")(m_sNetwork)); } } else if (!m_pUser->GetNetworks().empty()) { // If a user didn't supply a network, and they have a network called // "default" then automatically use this network. m_pNetwork = m_pUser->FindNetwork("default"); // If no "default" network, try "user" network. It's for compatibility // with early network stuff in ZNC, which converted old configs to // "user" network. if (!m_pNetwork) m_pNetwork = m_pUser->FindNetwork("user"); // Otherwise, just try any network of the user. if (!m_pNetwork) m_pNetwork = *m_pUser->GetNetworks().begin(); if (m_pNetwork && m_pUser->GetNetworks().size() > 1) { PutStatusNotice( t_s("You have several networks configured, but no network was " "specified for the connection.")); PutStatusNotice( t_f("Selecting network {1}. To see list of all configured " "networks, use /znc ListNetworks")(m_pNetwork->GetName())); PutStatusNotice(t_f( "If you want to choose another network, use /znc JumpNetwork " ", or connect to ZNC with username {1}/ " "(instead of just {1})")(m_pUser->GetUserName())); } } else { PutStatusNotice( t_s("You have no networks configured. Use /znc AddNetwork " " to add one.")); } SetNetwork(m_pNetwork, false); SendMotd(); NETWORKMODULECALL(OnClientLogin(), m_pUser, m_pNetwork, this, NOTHING); } void CClient::Timeout() { PutClient("ERROR :" + t_s("Closing link: Timeout")); } void CClient::Connected() { DEBUG(GetSockName() << " == Connected();"); } void CClient::ConnectionRefused() { DEBUG(GetSockName() << " == ConnectionRefused()"); } void CClient::Disconnected() { DEBUG(GetSockName() << " == Disconnected()"); CIRCNetwork* pNetwork = m_pNetwork; SetNetwork(nullptr, false, false); if (m_pUser) { NETWORKMODULECALL(OnClientDisconnect(), m_pUser, pNetwork, this, NOTHING); } } void CClient::ReachedMaxBuffer() { DEBUG(GetSockName() << " == ReachedMaxBuffer()"); if (IsAttached()) { PutClient("ERROR :" + t_s("Closing link: Too long raw line")); } Close(); } void CClient::BouncedOff() { PutStatusNotice( t_s("You are being disconnected because another user just " "authenticated as you.")); Close(Csock::CLT_AFTERWRITE); } void CClient::PutIRC(const CString& sLine) { if (m_pNetwork) { m_pNetwork->PutIRC(sLine); } } CString CClient::GetFullName() const { if (!m_pUser) return GetRemoteIP(); CString sFullName = m_pUser->GetUserName(); if (!m_sIdentifier.empty()) sFullName += "@" + m_sIdentifier; if (m_pNetwork) sFullName += "/" + m_pNetwork->GetName(); return sFullName; } void CClient::PutClient(const CString& sLine) { PutClient(CMessage(sLine)); } bool CClient::PutClient(const CMessage& Message) { if (!m_bAwayNotify && Message.GetType() == CMessage::Type::Away) { return false; } else if (!m_bAccountNotify && Message.GetType() == CMessage::Type::Account) { return false; } CMessage Msg(Message); const CIRCSock* pIRCSock = GetIRCSock(); if (pIRCSock) { if (Msg.GetType() == CMessage::Type::Numeric) { unsigned int uCode = Msg.As().GetCode(); if (uCode == 352) { // RPL_WHOREPLY if (!m_bNamesx && pIRCSock->HasNamesx()) { // The server has NAMESX, but the client doesn't, so we need // to remove extra prefixes CString sNick = Msg.GetParam(6); if (sNick.size() > 1 && pIRCSock->IsPermChar(sNick[1])) { CString sNewNick = sNick; size_t pos = sNick.find_first_not_of(pIRCSock->GetPerms()); if (pos >= 2 && pos != CString::npos) { sNewNick = sNick[0] + sNick.substr(pos); } Msg.SetParam(6, sNewNick); } } } else if (uCode == 353) { // RPL_NAMES if ((!m_bNamesx && pIRCSock->HasNamesx()) || (!m_bUHNames && pIRCSock->HasUHNames())) { // The server has either UHNAMES or NAMESX, but the client // is missing either or both CString sNicks = Msg.GetParam(3); VCString vsNicks; sNicks.Split(" ", vsNicks, false); for (CString& sNick : vsNicks) { if (sNick.empty()) break; if (!m_bNamesx && pIRCSock->HasNamesx() && pIRCSock->IsPermChar(sNick[0])) { // The server has NAMESX, but the client doesn't, so // we just use the first perm char size_t pos = sNick.find_first_not_of(pIRCSock->GetPerms()); if (pos >= 2 && pos != CString::npos) { sNick = sNick[0] + sNick.substr(pos); } } if (!m_bUHNames && pIRCSock->HasUHNames()) { // The server has UHNAMES, but the client doesn't, // so we strip away ident and host sNick = sNick.Token(0, false, "!"); } } Msg.SetParam( 3, CString(" ").Join(vsNicks.begin(), vsNicks.end())); } } } else if (Msg.GetType() == CMessage::Type::Join) { if (!m_bExtendedJoin && pIRCSock->HasExtendedJoin()) { Msg.SetParams({Msg.As().GetTarget()}); } } } MCString mssTags; for (const auto& it : Msg.GetTags()) { if (IsTagEnabled(it.first)) { mssTags[it.first] = it.second; } } if (HasServerTime()) { // If the server didn't set the time tag, manually set it mssTags.emplace("time", CUtils::FormatServerTime(Msg.GetTime())); } Msg.SetTags(mssTags); Msg.SetClient(this); Msg.SetNetwork(m_pNetwork); bool bReturn = false; NETWORKMODULECALL(OnSendToClientMessage(Msg), m_pUser, m_pNetwork, this, &bReturn); if (bReturn) return false; return PutClientRaw(Msg.ToString()); } bool CClient::PutClientRaw(const CString& sLine) { CString sCopy = sLine; bool bReturn = false; NETWORKMODULECALL(OnSendToClient(sCopy, *this), m_pUser, m_pNetwork, this, &bReturn); if (bReturn) return false; DEBUG("(" << GetFullName() << ") ZNC -> CLI [" << CDebug::Filter(sCopy) << "]"); Write(sCopy + "\r\n"); return true; } void CClient::PutStatusNotice(const CString& sLine) { PutModNotice("status", sLine); } unsigned int CClient::PutStatus(const CTable& table) { unsigned int idx = 0; CString sLine; while (table.GetLine(idx++, sLine)) PutStatus(sLine); return idx - 1; } void CClient::PutStatus(const CString& sLine) { PutModule("status", sLine); } void CClient::PutModNotice(const CString& sModule, const CString& sLine) { if (!m_pUser) { return; } DEBUG("(" << GetFullName() << ") ZNC -> CLI [:" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.in NOTICE " << GetNick() << " :" << sLine << "]"); Write(":" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.in NOTICE " + GetNick() + " :" + sLine + "\r\n"); } void CClient::PutModule(const CString& sModule, const CString& sLine) { if (!m_pUser) { return; } DEBUG("(" << GetFullName() << ") ZNC -> CLI [:" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.in PRIVMSG " << GetNick() << " :" << sLine << "]"); VCString vsLines; sLine.Split("\n", vsLines); for (const CString& s : vsLines) { Write(":" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.in PRIVMSG " + GetNick() + " :" + s + "\r\n"); } } CString CClient::GetNick(bool bAllowIRCNick) const { CString sRet; const CIRCSock* pSock = GetIRCSock(); if (bAllowIRCNick && pSock && pSock->IsAuthed()) { sRet = pSock->GetNick(); } return (sRet.empty()) ? m_sNick : sRet; } CString CClient::GetNickMask() const { if (GetIRCSock() && GetIRCSock()->IsAuthed()) { return GetIRCSock()->GetNickMask(); } CString sHost = m_pNetwork ? m_pNetwork->GetBindHost() : m_pUser->GetBindHost(); if (sHost.empty()) { sHost = "irc.znc.in"; } return GetNick() + "!" + (m_pNetwork ? m_pNetwork->GetIdent() : m_pUser->GetIdent()) + "@" + sHost; } bool CClient::IsValidIdentifier(const CString& sIdentifier) { // ^[-\w]+$ if (sIdentifier.empty()) { return false; } const char* p = sIdentifier.c_str(); while (*p) { if (*p != '_' && *p != '-' && !isalnum(*p)) { return false; } p++; } return true; } void CClient::RespondCap(const CString& sResponse) { PutClient(":irc.znc.in CAP " + GetNick() + " " + sResponse); } void CClient::HandleCap(const CMessage& Message) { CString sSubCmd = Message.GetParam(0); if (sSubCmd.Equals("LS")) { SCString ssOfferCaps; for (const auto& it : m_mCoreCaps) { bool bServerDependent = std::get<0>(it.second); if (!bServerDependent || m_ssServerDependentCaps.count(it.first) > 0) ssOfferCaps.insert(it.first); } GLOBALMODULECALL(OnClientCapLs(this, ssOfferCaps), NOTHING); CString sRes = CString(" ").Join(ssOfferCaps.begin(), ssOfferCaps.end()); RespondCap("LS :" + sRes); m_bInCap = true; if (Message.GetParam(1).ToInt() >= 302) { m_bCapNotify = true; } } else if (sSubCmd.Equals("END")) { m_bInCap = false; if (!IsAttached()) { if (!m_pUser && m_bGotUser && !m_bGotPass) { SendRequiredPasswordNotice(); } else { AuthUser(); } } } else if (sSubCmd.Equals("REQ")) { VCString vsTokens; Message.GetParam(1).Split(" ", vsTokens, false); for (const CString& sToken : vsTokens) { bool bVal = true; CString sCap = sToken; if (sCap.TrimPrefix("-")) bVal = false; bool bAccepted = false; const auto& it = m_mCoreCaps.find(sCap); if (m_mCoreCaps.end() != it) { bool bServerDependent = std::get<0>(it->second); bAccepted = !bServerDependent || m_ssServerDependentCaps.count(sCap) > 0; } GLOBALMODULECALL(IsClientCapSupported(this, sCap, bVal), &bAccepted); if (!bAccepted) { // Some unsupported capability is requested RespondCap("NAK :" + Message.GetParam(1)); return; } } // All is fine, we support what was requested for (const CString& sToken : vsTokens) { bool bVal = true; CString sCap = sToken; if (sCap.TrimPrefix("-")) bVal = false; auto handler_it = m_mCoreCaps.find(sCap); if (m_mCoreCaps.end() != handler_it) { const auto& handler = std::get<1>(handler_it->second); handler(bVal); } GLOBALMODULECALL(OnClientCapRequest(this, sCap, bVal), NOTHING); if (bVal) { m_ssAcceptedCaps.insert(sCap); } else { m_ssAcceptedCaps.erase(sCap); } } RespondCap("ACK :" + Message.GetParam(1)); } else if (sSubCmd.Equals("LIST")) { CString sList = CString(" ").Join(m_ssAcceptedCaps.begin(), m_ssAcceptedCaps.end()); RespondCap("LIST :" + sList); } else { PutClient(":irc.znc.in 410 " + GetNick() + " " + sSubCmd + " :Invalid CAP subcommand"); } } void CClient::ParsePass(const CString& sAuthLine) { // [user[@identifier][/network]:]password const size_t uColon = sAuthLine.find(":"); if (uColon != CString::npos) { m_sPass = sAuthLine.substr(uColon + 1); ParseUser(sAuthLine.substr(0, uColon)); } else { m_sPass = sAuthLine; } } void CClient::ParseUser(const CString& sAuthLine) { // user[@identifier][/network] const size_t uSlash = sAuthLine.rfind("/"); if (uSlash != CString::npos) { m_sNetwork = sAuthLine.substr(uSlash + 1); ParseIdentifier(sAuthLine.substr(0, uSlash)); } else { ParseIdentifier(sAuthLine); } } void CClient::ParseIdentifier(const CString& sAuthLine) { // user[@identifier] const size_t uAt = sAuthLine.rfind("@"); if (uAt != CString::npos) { const CString sId = sAuthLine.substr(uAt + 1); if (IsValidIdentifier(sId)) { m_sIdentifier = sId; m_sUser = sAuthLine.substr(0, uAt); } else { m_sUser = sAuthLine; } } else { m_sUser = sAuthLine; } } void CClient::SetTagSupport(const CString& sTag, bool bState) { if (bState) { m_ssSupportedTags.insert(sTag); } else { m_ssSupportedTags.erase(sTag); } } void CClient::NotifyServerDependentCaps(const SCString& ssCaps) { for (const CString& sCap : ssCaps) { const auto& it = m_mCoreCaps.find(sCap); if (m_mCoreCaps.end() != it) { bool bServerDependent = std::get<0>(it->second); if (bServerDependent) { m_ssServerDependentCaps.insert(sCap); } } } if (HasCapNotify() && !m_ssServerDependentCaps.empty()) { CString sCaps = CString(" ").Join(m_ssServerDependentCaps.begin(), m_ssServerDependentCaps.end()); PutClient(":irc.znc.in CAP " + GetNick() + " NEW :" + sCaps); } } void CClient::ClearServerDependentCaps() { if (HasCapNotify() && !m_ssServerDependentCaps.empty()) { CString sCaps = CString(" ").Join(m_ssServerDependentCaps.begin(), m_ssServerDependentCaps.end()); PutClient(":irc.znc.in CAP " + GetNick() + " DEL :" + sCaps); for (const CString& sCap : m_ssServerDependentCaps) { const auto& it = m_mCoreCaps.find(sCap); if (m_mCoreCaps.end() != it) { const auto& handler = std::get<1>(it->second); handler(false); } } } m_ssServerDependentCaps.clear(); } template void CClient::AddBuffer(const T& Message) { const CString sTarget = Message.GetTarget(); T Format; Format.Clone(Message); Format.SetNick(CNick(_NAMEDFMT(GetNickMask()))); Format.SetTarget(_NAMEDFMT(sTarget)); Format.SetText("{text}"); CChan* pChan = m_pNetwork->FindChan(sTarget); if (pChan) { if (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline()) { pChan->AddBuffer(Format, Message.GetText()); } } else if (Message.GetType() != CMessage::Type::Notice) { if (!m_pUser->AutoClearQueryBuffer() || !m_pNetwork->IsUserOnline()) { CQuery* pQuery = m_pNetwork->AddQuery(sTarget); if (pQuery) { pQuery->AddBuffer(Format, Message.GetText()); } } } } void CClient::EchoMessage(const CMessage& Message) { CMessage EchoedMessage = Message; for (CClient* pClient : GetClients()) { if (pClient->HasEchoMessage() || (pClient != this && (m_pNetwork->IsChan(Message.GetParam(0)) || pClient->HasSelfMessage()))) { EchoedMessage.SetNick(GetNickMask()); pClient->PutClient(EchoedMessage); } } } set CClient::MatchChans(const CString& sPatterns) const { VCString vsPatterns; sPatterns.Replace_n(",", " ") .Split(" ", vsPatterns, false, "", "", true, true); set sChans; for (const CString& sPattern : vsPatterns) { vector vChans = m_pNetwork->FindChans(sPattern); sChans.insert(vChans.begin(), vChans.end()); } return sChans; } unsigned int CClient::AttachChans(const std::set& sChans) { unsigned int uAttached = 0; for (CChan* pChan : sChans) { if (!pChan->IsDetached()) continue; uAttached++; pChan->AttachUser(); } return uAttached; } unsigned int CClient::DetachChans(const std::set& sChans) { unsigned int uDetached = 0; for (CChan* pChan : sChans) { if (pChan->IsDetached()) continue; uDetached++; pChan->DetachUser(); } return uDetached; } bool CClient::OnActionMessage(CActionMessage& Message) { CString sTargets = Message.GetTarget(); VCString vTargets; sTargets.Split(",", vTargets, false); for (CString& sTarget : vTargets) { Message.SetTarget(sTarget); if (m_pNetwork) { // May be nullptr. Message.SetChan(m_pNetwork->FindChan(sTarget)); } bool bContinue = false; NETWORKMODULECALL(OnUserActionMessage(Message), m_pUser, m_pNetwork, this, &bContinue); if (bContinue) continue; if (m_pNetwork) { AddBuffer(Message); EchoMessage(Message); PutIRC(Message.ToString(CMessage::ExcludePrefix | CMessage::ExcludeTags)); } } return true; } bool CClient::OnCTCPMessage(CCTCPMessage& Message) { CString sTargets = Message.GetTarget(); VCString vTargets; sTargets.Split(",", vTargets, false); if (Message.IsReply()) { CString sCTCP = Message.GetText(); if (sCTCP.Token(0) == "VERSION") { // There are 2 different scenarios: // // a) CTCP reply for VERSION is not set. // 1. ZNC receives CTCP VERSION from someone // 2. ZNC forwards CTCP VERSION to client // 3. Client replies with something // 4. ZNC adds itself to the reply // 5. ZNC sends the modified reply to whoever asked // // b) CTCP reply for VERSION is set. // 1. ZNC receives CTCP VERSION from someone // 2. ZNC replies with the configured reply (or just drops it if // empty), without forwarding anything to client // 3. Client does not see any CTCP request, and does not reply // // So, if user doesn't want "via ZNC" in CTCP VERSION reply, they // can set custom reply. // // See more bikeshedding at github issues #820 and #1012 Message.SetText(sCTCP + " via " + CZNC::GetTag(false)); } } for (CString& sTarget : vTargets) { Message.SetTarget(sTarget); if (m_pNetwork) { // May be nullptr. Message.SetChan(m_pNetwork->FindChan(sTarget)); } bool bContinue = false; if (Message.IsReply()) { NETWORKMODULECALL(OnUserCTCPReplyMessage(Message), m_pUser, m_pNetwork, this, &bContinue); } else { NETWORKMODULECALL(OnUserCTCPMessage(Message), m_pUser, m_pNetwork, this, &bContinue); } if (bContinue) continue; if (!GetIRCSock()) { // Some lagmeters do a NOTICE to their own nick, ignore those. if (!sTarget.Equals(m_sNick)) PutStatus(t_f( "Your CTCP to {1} got lost, you are not connected to IRC!")( Message.GetTarget())); continue; } if (m_pNetwork) { PutIRC(Message.ToString(CMessage::ExcludePrefix | CMessage::ExcludeTags)); } } return true; } bool CClient::OnJoinMessage(CJoinMessage& Message) { CString sChans = Message.GetTarget(); CString sKeys = Message.GetKey(); VCString vsChans; sChans.Split(",", vsChans, false); sChans.clear(); VCString vsKeys; sKeys.Split(",", vsKeys, true); sKeys.clear(); for (unsigned int a = 0; a < vsChans.size(); a++) { Message.SetTarget(vsChans[a]); Message.SetKey((a < vsKeys.size()) ? vsKeys[a] : ""); if (m_pNetwork) { // May be nullptr. Message.SetChan(m_pNetwork->FindChan(vsChans[a])); } bool bContinue = false; NETWORKMODULECALL(OnUserJoinMessage(Message), m_pUser, m_pNetwork, this, &bContinue); if (bContinue) continue; CString sChannel = Message.GetTarget(); CString sKey = Message.GetKey(); if (m_pNetwork) { CChan* pChan = m_pNetwork->FindChan(sChannel); if (pChan) { if (pChan->IsDetached()) pChan->AttachUser(this); else pChan->JoinUser(sKey); continue; } else if (!sChannel.empty()) { pChan = new CChan(sChannel, m_pNetwork, false); if (m_pNetwork->AddChan(pChan)) { pChan->SetKey(sKey); } } } if (!sChannel.empty()) { sChans += (sChans.empty()) ? sChannel : CString("," + sChannel); if (!vsKeys.empty()) { sKeys += (sKeys.empty()) ? sKey : CString("," + sKey); } } } Message.SetTarget(sChans); Message.SetKey(sKeys); return sChans.empty(); } bool CClient::OnModeMessage(CModeMessage& Message) { CString sTarget = Message.GetTarget(); CString sModes = Message.GetModes(); if (m_pNetwork && m_pNetwork->IsChan(sTarget) && sModes.empty()) { // If we are on that channel and already received a // /mode reply from the server, we can answer this // request ourself. CChan* pChan = m_pNetwork->FindChan(sTarget); if (pChan && pChan->IsOn() && !pChan->GetModeString().empty()) { PutClient(":" + m_pNetwork->GetIRCServer() + " 324 " + GetNick() + " " + sTarget + " " + pChan->GetModeString()); if (pChan->GetCreationDate() > 0) { PutClient(":" + m_pNetwork->GetIRCServer() + " 329 " + GetNick() + " " + sTarget + " " + CString(pChan->GetCreationDate())); } return true; } } return false; } bool CClient::OnNoticeMessage(CNoticeMessage& Message) { CString sTargets = Message.GetTarget(); VCString vTargets; sTargets.Split(",", vTargets, false); for (CString& sTarget : vTargets) { Message.SetTarget(sTarget); if (m_pNetwork) { // May be nullptr. Message.SetChan(m_pNetwork->FindChan(sTarget)); } if (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) { if (!sTarget.Equals("status")) { CALLMOD(sTarget, this, m_pUser, m_pNetwork, OnModNotice(Message.GetText())); } continue; } bool bContinue = false; NETWORKMODULECALL(OnUserNoticeMessage(Message), m_pUser, m_pNetwork, this, &bContinue); if (bContinue) continue; if (!GetIRCSock()) { // Some lagmeters do a NOTICE to their own nick, ignore those. if (!sTarget.Equals(m_sNick)) PutStatus( t_f("Your notice to {1} got lost, you are not connected to " "IRC!")(Message.GetTarget())); continue; } if (m_pNetwork) { AddBuffer(Message); EchoMessage(Message); PutIRC(Message.ToString(CMessage::ExcludePrefix | CMessage::ExcludeTags)); } } return true; } bool CClient::OnPartMessage(CPartMessage& Message) { CString sChans = Message.GetTarget(); VCString vsChans; sChans.Split(",", vsChans, false); sChans.clear(); for (CString& sChan : vsChans) { bool bContinue = false; Message.SetTarget(sChan); if (m_pNetwork) { // May be nullptr. Message.SetChan(m_pNetwork->FindChan(sChan)); } NETWORKMODULECALL(OnUserPartMessage(Message), m_pUser, m_pNetwork, this, &bContinue); if (bContinue) continue; sChan = Message.GetTarget(); CChan* pChan = m_pNetwork ? m_pNetwork->FindChan(sChan) : nullptr; if (pChan && !pChan->IsOn()) { PutStatusNotice(t_f("Removing channel {1}")(sChan)); m_pNetwork->DelChan(sChan); } else { sChans += (sChans.empty()) ? sChan : CString("," + sChan); } } if (sChans.empty()) { return true; } Message.SetTarget(sChans); return false; } bool CClient::OnPingMessage(CMessage& Message) { // All PONGs are generated by ZNC. We will still forward this to // the ircd, but all PONGs from irc will be blocked. if (!Message.GetParams().empty()) PutClient(":irc.znc.in PONG irc.znc.in " + Message.GetParamsColon(0)); else PutClient(":irc.znc.in PONG irc.znc.in"); return false; } bool CClient::OnPongMessage(CMessage& Message) { // Block PONGs, we already responded to the pings return true; } bool CClient::OnQuitMessage(CQuitMessage& Message) { bool bReturn = false; NETWORKMODULECALL(OnUserQuitMessage(Message), m_pUser, m_pNetwork, this, &bReturn); if (!bReturn) { Close(Csock::CLT_AFTERWRITE); // Treat a client quit as a detach } // Don't forward this msg. We don't want the client getting us // disconnected. return true; } bool CClient::OnTextMessage(CTextMessage& Message) { CString sTargets = Message.GetTarget(); VCString vTargets; sTargets.Split(",", vTargets, false); for (CString& sTarget : vTargets) { Message.SetTarget(sTarget); if (m_pNetwork) { // May be nullptr. Message.SetChan(m_pNetwork->FindChan(sTarget)); } if (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) { if (sTarget.Equals("status")) { CString sMsg = Message.GetText(); UserCommand(sMsg); } else { CALLMOD(sTarget, this, m_pUser, m_pNetwork, OnModCommand(Message.GetText())); } continue; } bool bContinue = false; NETWORKMODULECALL(OnUserTextMessage(Message), m_pUser, m_pNetwork, this, &bContinue); if (bContinue) continue; if (!GetIRCSock()) { // Some lagmeters do a PRIVMSG to their own nick, ignore those. if (!sTarget.Equals(m_sNick)) PutStatus( t_f("Your message to {1} got lost, you are not connected " "to IRC!")(Message.GetTarget())); continue; } if (m_pNetwork) { AddBuffer(Message); EchoMessage(Message); PutIRC(Message.ToString(CMessage::ExcludePrefix | CMessage::ExcludeTags)); } } return true; } bool CClient::OnTopicMessage(CTopicMessage& Message) { bool bReturn = false; CString sChan = Message.GetTarget(); CString sTopic = Message.GetTopic(); if (m_pNetwork) { // May be nullptr. Message.SetChan(m_pNetwork->FindChan(sChan)); } if (!sTopic.empty()) { NETWORKMODULECALL(OnUserTopicMessage(Message), m_pUser, m_pNetwork, this, &bReturn); } else { NETWORKMODULECALL(OnUserTopicRequest(sChan), m_pUser, m_pNetwork, this, &bReturn); Message.SetTarget(sChan); } return bReturn; } bool CClient::OnOtherMessage(CMessage& Message) { const CString& sCommand = Message.GetCommand(); if (sCommand.Equals("ZNC")) { CString sTarget = Message.GetParam(0); CString sModCommand; if (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) { sModCommand = Message.GetParamsColon(1); } else { sTarget = "status"; sModCommand = Message.GetParamsColon(0); } if (sTarget.Equals("status")) { if (sModCommand.empty()) PutStatus(t_s("Hello. How may I help you?")); else UserCommand(sModCommand); } else { if (sModCommand.empty()) CALLMOD(sTarget, this, m_pUser, m_pNetwork, PutModule(t_s("Hello. How may I help you?"))) else CALLMOD(sTarget, this, m_pUser, m_pNetwork, OnModCommand(sModCommand)) } return true; } else if (sCommand.Equals("ATTACH")) { if (!m_pNetwork) { return true; } CString sPatterns = Message.GetParamsColon(0); if (sPatterns.empty()) { PutStatusNotice(t_s("Usage: /attach <#chans>")); return true; } set sChans = MatchChans(sPatterns); unsigned int uAttachedChans = AttachChans(sChans); PutStatusNotice(t_p("There was {1} channel matching [{2}]", "There were {1} channels matching [{2}]", sChans.size())(sChans.size(), sPatterns)); PutStatusNotice(t_p("Attached {1} channel", "Attached {1} channels", uAttachedChans)(uAttachedChans)); return true; } else if (sCommand.Equals("DETACH")) { if (!m_pNetwork) { return true; } CString sPatterns = Message.GetParamsColon(0); if (sPatterns.empty()) { PutStatusNotice(t_s("Usage: /detach <#chans>")); return true; } set sChans = MatchChans(sPatterns); unsigned int uDetached = DetachChans(sChans); PutStatusNotice(t_p("There was {1} channel matching [{2}]", "There were {1} channels matching [{2}]", sChans.size())(sChans.size(), sPatterns)); PutStatusNotice(t_p("Detached {1} channel", "Detached {1} channels", uDetached)(uDetached)); return true; } else if (sCommand.Equals("PROTOCTL")) { for (const CString& sParam : Message.GetParams()) { if (sParam == "NAMESX") { m_bNamesx = true; } else if (sParam == "UHNAMES") { m_bUHNames = true; } } return true; // If the server understands it, we already enabled namesx // / uhnames } return false; } znc-1.7.5/src/Threads.cpp0000644000175000017500000001731713542151610015436 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #ifdef HAVE_PTHREAD #include #include #include /* Just an arbitrary limit for the number of idle threads */ static const size_t MAX_IDLE_THREADS = 3; /* Just an arbitrary limit for the number of running threads */ static const size_t MAX_TOTAL_THREADS = 20; CThreadPool& CThreadPool::Get() { static CThreadPool pool; return pool; } CThreadPool::CThreadPool() : m_mutex(), m_cond(), m_cancellationCond(), m_exit_cond(), m_done(false), m_num_threads(0), m_num_idle(0), m_iJobPipe{0, 0}, m_jobs() { if (pipe(m_iJobPipe)) { DEBUG("Ouch, can't open pipe for thread pool: " << strerror(errno)); exit(1); } } void CThreadPool::jobDone(CJob* job) { // This must be called with the mutex locked! enum CJob::EJobState oldState = job->m_eState; job->m_eState = CJob::DONE; if (oldState == CJob::CANCELLED) { // Signal the main thread that cancellation is done m_cancellationCond.notify_one(); return; } // This write() must succeed because POSIX guarantees that writes of // less than PIPE_BUF are atomic (and PIPE_BUF is at least 512). // (Yes, this really wants to write a pointer(!) to the pipe. size_t w = write(m_iJobPipe[1], &job, sizeof(job)); if (w != sizeof(job)) { DEBUG( "Something bad happened during write() to a pipe for thread pool, " "wrote " << w << " bytes: " << strerror(errno)); exit(1); } } void CThreadPool::handlePipeReadable() const { finishJob(getJobFromPipe()); } CJob* CThreadPool::getJobFromPipe() const { CJob* a = nullptr; ssize_t need = sizeof(a); ssize_t r = read(m_iJobPipe[0], &a, need); if (r != need) { DEBUG( "Something bad happened during read() from a pipe for thread pool: " << strerror(errno)); exit(1); } return a; } void CThreadPool::finishJob(CJob* job) const { job->runMain(); delete job; } CThreadPool::~CThreadPool() { CMutexLocker guard(m_mutex); m_done = true; while (m_num_threads > 0) { m_cond.notify_all(); m_exit_cond.wait(m_mutex); } } bool CThreadPool::threadNeeded() const { if (m_num_idle > MAX_IDLE_THREADS) return false; return !m_done; } void CThreadPool::threadFunc() { CMutexLocker guard(m_mutex); // m_num_threads was already increased m_num_idle++; while (true) { while (m_jobs.empty()) { if (!threadNeeded()) break; m_cond.wait(m_mutex); } if (!threadNeeded()) break; // Figure out a job to do CJob* job = m_jobs.front(); m_jobs.pop_front(); // Now do the actual job m_num_idle--; job->m_eState = CJob::RUNNING; guard.unlock(); job->runThread(); guard.lock(); jobDone(job); m_num_idle++; } assert(m_num_threads > 0 && m_num_idle > 0); m_num_threads--; m_num_idle--; if (m_num_threads == 0 && m_done) m_exit_cond.notify_one(); } void CThreadPool::addJob(CJob* job) { CMutexLocker guard(m_mutex); m_jobs.push_back(job); // Do we already have a thread which can handle this job? if (m_num_idle > 0) { m_cond.notify_one(); return; } if (m_num_threads >= MAX_TOTAL_THREADS) // We can't start a new thread. The job will be handled once // some thread finishes its current job. return; // Start a new thread for our pool m_num_threads++; std::thread([this]() { threadFunc(); }).detach(); } void CThreadPool::cancelJob(CJob* job) { std::set jobs; jobs.insert(job); cancelJobs(jobs); } void CThreadPool::cancelJobs(const std::set& jobs) { // Thanks to the mutex, jobs cannot change state anymore. There are // three different states which can occur: // // READY: The job is still in our list of pending jobs and no threads // got it yet. Just clean up. // // DONE: The job finished running and was already written to the pipe // that is used for waking up finished jobs. We can just read from the // pipe until we see this job. // // RUNNING: This is the complicated case. The job is currently being // executed. We change its state to CANCELLED so that wasCancelled() // returns true. Afterwards we wait on a CV for the job to have finished // running. This CV is signaled by jobDone() which checks the job's // status and sees that the job was cancelled. It signals to us that // cancellation is done by changing the job's status to DONE. CMutexLocker guard(m_mutex); std::set wait, finished, deleteLater; std::set::const_iterator it; // Start cancelling all jobs for (it = jobs.begin(); it != jobs.end(); ++it) { switch ((*it)->m_eState) { case CJob::READY: { (*it)->m_eState = CJob::CANCELLED; // Job wasn't started yet, must be in the queue std::list::iterator it2 = std::find(m_jobs.begin(), m_jobs.end(), *it); assert(it2 != m_jobs.end()); m_jobs.erase(it2); deleteLater.insert(*it); continue; } case CJob::RUNNING: (*it)->m_eState = CJob::CANCELLED; wait.insert(*it); continue; case CJob::DONE: (*it)->m_eState = CJob::CANCELLED; finished.insert(*it); continue; case CJob::CANCELLED: default: assert(0); } } // Now wait for cancellation to be done // Collect jobs that really were cancelled. Finished cancellation is // signaled by changing their state to DONE. while (!wait.empty()) { it = wait.begin(); while (it != wait.end()) { if ((*it)->m_eState != CJob::CANCELLED) { assert((*it)->m_eState == CJob::DONE); // Re-set state for the destructor (*it)->m_eState = CJob::CANCELLED; deleteLater.insert(*it); wait.erase(it++); } else it++; } if (wait.empty()) break; // Then wait for more to be done m_cancellationCond.wait(m_mutex); } // We must call destructors with m_mutex unlocked so that they can call // wasCancelled() guard.unlock(); // Handle finished jobs. They must already be in the pipe. while (!finished.empty()) { CJob* job = getJobFromPipe(); if (finished.erase(job) > 0) { assert(job->m_eState == CJob::CANCELLED); delete job; } else finishJob(job); } // Delete things that still need to be deleted while (!deleteLater.empty()) { delete *deleteLater.begin(); deleteLater.erase(deleteLater.begin()); } } bool CJob::wasCancelled() const { CMutexLocker guard(CThreadPool::Get().m_mutex); return m_eState == CANCELLED; } #endif // HAVE_PTHREAD znc-1.7.5/src/Message.cpp0000644000175000017500000001731013542151610015421 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include CMessage::CMessage(const CString& sMessage) { Parse(sMessage); InitTime(); } CMessage::CMessage(const CNick& Nick, const CString& sCommand, const VCString& vsParams, const MCString& mssTags) : m_Nick(Nick), m_sCommand(sCommand), m_vsParams(vsParams), m_mssTags(mssTags) { InitTime(); } bool CMessage::Equals(const CMessage& Other) const { return m_Nick.NickEquals(Other.GetNick().GetNick()) && m_sCommand.Equals(Other.GetCommand()) && m_vsParams == Other.GetParams(); } void CMessage::Clone(const CMessage& Message) { if (&Message != this) { *this = Message; } } void CMessage::SetCommand(const CString& sCommand) { m_sCommand = sCommand; InitType(); } CString CMessage::GetParamsColon(unsigned int uIdx, unsigned int uLen) const { if (m_vsParams.empty() || uLen == 0) { return ""; } if (uLen > m_vsParams.size() - uIdx - 1) { uLen = m_vsParams.size() - uIdx; } VCString vsParams; unsigned uParams = m_vsParams.size(); for (unsigned int i = uIdx; i < uIdx + uLen; ++i) { CString sParam = m_vsParams[i]; if (i == uParams - 1 && (m_bColon || sParam.empty() || sParam.StartsWith(":") || sParam.Contains(" "))) { sParam = ":" + sParam; } vsParams.push_back(sParam); } return CString(" ").Join(vsParams.begin(), vsParams.end()); } void CMessage::SetParams(const VCString& vsParams) { m_vsParams = vsParams; m_bColon = false; if (m_eType == Type::Text || m_eType == Type::Notice || m_eType == Type::Action || m_eType == Type::CTCP) { InitType(); } } CString CMessage::GetParam(unsigned int uIdx) const { if (uIdx >= m_vsParams.size()) { return ""; } return m_vsParams[uIdx]; } void CMessage::SetParam(unsigned int uIdx, const CString& sParam) { if (uIdx >= m_vsParams.size()) { m_vsParams.resize(uIdx + 1); } m_vsParams[uIdx] = sParam; if (uIdx == 1 && (m_eType == Type::Text || m_eType == Type::Notice || m_eType == Type::Action || m_eType == Type::CTCP)) { InitType(); } } CString CMessage::GetTag(const CString& sKey) const { MCString::const_iterator it = m_mssTags.find(sKey); if (it != m_mssTags.end()) { return it->second; } return ""; } void CMessage::SetTag(const CString& sKey, const CString& sValue) { m_mssTags[sKey] = sValue; } CString CMessage::ToString(unsigned int uFlags) const { CString sMessage; // if (!(uFlags & ExcludeTags) && !m_mssTags.empty()) { CString sTags; for (const auto& it : m_mssTags) { if (!sTags.empty()) { sTags += ";"; } sTags += it.first; if (!it.second.empty()) sTags += "=" + it.second.Escape_n(CString::EMSGTAG); } sMessage = "@" + sTags; } // if (!(uFlags & ExcludePrefix)) { CString sPrefix = m_Nick.GetHostMask(); if (!sPrefix.empty()) { if (!sMessage.empty()) { sMessage += " "; } sMessage += ":" + sPrefix; } } // if (!m_sCommand.empty()) { if (!sMessage.empty()) { sMessage += " "; } sMessage += m_sCommand; } // if (!m_vsParams.empty()) { if (!sMessage.empty()) { sMessage += " "; } sMessage += GetParamsColon(0); } return sMessage; } void CMessage::Parse(CString sMessage) { // m_mssTags.clear(); if (sMessage.StartsWith("@")) { VCString vsTags; sMessage.Token(0).TrimPrefix_n("@").Split(";", vsTags, false); for (const CString& sTag : vsTags) { CString sKey = sTag.Token(0, false, "=", true); CString sValue = sTag.Token(1, true, "=", true); m_mssTags[sKey] = sValue.Escape(CString::EMSGTAG, CString::CString::EASCII); } sMessage = sMessage.Token(1, true); } // ::= [':' ] // ::= | [ '!' ] [ '@' ] // ::= { } | // ::= ' ' { ' ' } // ::= [ ':' | ] // ::= // ::= // if (sMessage.TrimPrefix(":")) { m_Nick.Parse(sMessage.Token(0)); sMessage = sMessage.Token(1, true); } // m_sCommand = sMessage.Token(0); sMessage = sMessage.Token(1, true); // m_bColon = false; m_vsParams.clear(); while (!sMessage.empty()) { m_bColon = sMessage.TrimPrefix(":"); if (m_bColon) { m_vsParams.push_back(sMessage); sMessage.clear(); } else { m_vsParams.push_back(sMessage.Token(0)); sMessage = sMessage.Token(1, true); } } InitType(); } void CMessage::InitTime() { auto it = m_mssTags.find("time"); if (it != m_mssTags.end()) { m_time = CUtils::ParseServerTime(it->second); return; } m_time = CUtils::GetTime(); } void CMessage::InitType() { if (m_sCommand.length() == 3 && isdigit(m_sCommand[0]) && isdigit(m_sCommand[1]) && isdigit(m_sCommand[2])) { m_eType = Type::Numeric; } else if (m_sCommand.Equals("PRIVMSG")) { CString sParam = GetParam(1); if (sParam.TrimPrefix("\001") && sParam.EndsWith("\001")) { if (sParam.StartsWith("ACTION ")) { m_eType = Type::Action; } else { m_eType = Type::CTCP; } } else { m_eType = Type::Text; } } else if (m_sCommand.Equals("NOTICE")) { CString sParam = GetParam(1); if (sParam.StartsWith("\001") && sParam.EndsWith("\001")) { m_eType = Type::CTCP; } else { m_eType = Type::Notice; } } else { std::map mTypes = { {"ACCOUNT", Type::Account}, {"AWAY", Type::Away}, {"CAP", Type::Capability}, {"ERROR", Type::Error}, {"INVITE", Type::Invite}, {"JOIN", Type::Join}, {"KICK", Type::Kick}, {"MODE", Type::Mode}, {"NICK", Type::Nick}, {"PART", Type::Part}, {"PING", Type::Ping}, {"PONG", Type::Pong}, {"QUIT", Type::Quit}, {"TOPIC", Type::Topic}, {"WALLOPS", Type::Wallops}, }; auto it = mTypes.find(m_sCommand.AsUpper()); if (it != mTypes.end()) { m_eType = it->second; } else { m_eType = Type::Unknown; } } } znc-1.7.5/src/Listener.cpp0000644000175000017500000001365113542151610015626 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include CListener::~CListener() { if (m_pListener) CZNC::Get().GetManager().DelSockByAddr(m_pListener); } bool CListener::Listen() { if (!m_uPort || m_pListener) { errno = EINVAL; return false; } m_pListener = new CRealListener(*this); bool bSSL = false; #ifdef HAVE_LIBSSL if (IsSSL()) { bSSL = true; m_pListener->SetPemLocation(CZNC::Get().GetPemLocation()); m_pListener->SetKeyLocation(CZNC::Get().GetKeyLocation()); m_pListener->SetDHParamLocation(CZNC::Get().GetDHParamLocation()); } #endif // If e.g. getaddrinfo() fails, the following might not set errno. // Make sure there is a consistent error message, not something random // which might even be "Error: Success". errno = EINVAL; return CZNC::Get().GetManager().ListenHost(m_uPort, "_LISTENER", m_sBindHost, bSSL, SOMAXCONN, m_pListener, 0, m_eAddr); } void CListener::ResetRealListener() { m_pListener = nullptr; } CRealListener::~CRealListener() { m_Listener.ResetRealListener(); } bool CRealListener::ConnectionFrom(const CString& sHost, unsigned short uPort) { bool bHostAllowed = CZNC::Get().IsHostAllowed(sHost); DEBUG(GetSockName() << " == ConnectionFrom(" << sHost << ", " << uPort << ") [" << (bHostAllowed ? "Allowed" : "Not allowed") << "]"); return bHostAllowed; } Csock* CRealListener::GetSockObj(const CString& sHost, unsigned short uPort) { CIncomingConnection* pClient = new CIncomingConnection( sHost, uPort, m_Listener.GetAcceptType(), m_Listener.GetURIPrefix()); if (CZNC::Get().AllowConnectionFrom(sHost)) { GLOBALMODULECALL(OnClientConnect(pClient, sHost, uPort), NOTHING); } else { pClient->Write( ":irc.znc.in 464 unknown-nick :Too many anonymous connections from " "your IP\r\n"); pClient->Close(Csock::CLT_AFTERWRITE); GLOBALMODULECALL(OnFailedLogin("", sHost), NOTHING); } return pClient; } void CRealListener::SockError(int iErrno, const CString& sDescription) { DEBUG(GetSockName() << " == SockError(" << sDescription << ", " << strerror(iErrno) << ")"); if (iErrno == EMFILE) { // We have too many open fds, let's close this listening port to be able // to continue // to work, next rehash will (try to) reopen it. CZNC::Get().Broadcast( "We hit the FD limit, closing listening socket on [" + GetLocalIP() + " : " + CString(GetLocalPort()) + "]"); CZNC::Get().Broadcast( "An admin has to rehash to reopen the listening port"); Close(); } } CIncomingConnection::CIncomingConnection(const CString& sHostname, unsigned short uPort, CListener::EAcceptType eAcceptType, const CString& sURIPrefix) : CZNCSock(sHostname, uPort), m_eAcceptType(eAcceptType), m_sURIPrefix(sURIPrefix) { // The socket will time out in 120 secs, no matter what. // This has to be fixed up later, if desired. SetTimeout(120, 0); SetEncoding("UTF-8"); EnableReadLine(); } void CIncomingConnection::ReachedMaxBuffer() { if (GetCloseType() != CLT_DONT) return; // Already closing // We don't actually SetMaxBufferThreshold() because that would be // inherited by sockets after SwapSockByAddr(). if (GetInternalReadBuffer().length() <= 4096) return; // We should never get here with legitimate requests :/ Close(); } void CIncomingConnection::ReadLine(const CString& sLine) { bool bIsHTTP = (sLine.WildCmp("GET * HTTP/1.?\r\n") || sLine.WildCmp("POST * HTTP/1.?\r\n")); bool bAcceptHTTP = (m_eAcceptType == CListener::ACCEPT_ALL) || (m_eAcceptType == CListener::ACCEPT_HTTP); bool bAcceptIRC = (m_eAcceptType == CListener::ACCEPT_ALL) || (m_eAcceptType == CListener::ACCEPT_IRC); Csock* pSock = nullptr; if (!bIsHTTP) { // Let's assume it's an IRC connection if (!bAcceptIRC) { Write("ERROR :We don't take kindly to your types around here!\r\n"); Close(CLT_AFTERWRITE); DEBUG("Refused IRC connection to non IRC port"); return; } pSock = new CClient(); CZNC::Get().GetManager().SwapSockByAddr(pSock, this); // And don't forget to give it some sane name / timeout pSock->SetSockName("USR::???"); } else { // This is a HTTP request, let the webmods handle it if (!bAcceptHTTP) { Write( "HTTP/1.0 403 Access Denied\r\n\r\nWeb Access is not " "enabled.\r\n"); Close(CLT_AFTERWRITE); DEBUG("Refused HTTP connection to non HTTP port"); return; } pSock = new CWebSock(m_sURIPrefix); CZNC::Get().GetManager().SwapSockByAddr(pSock, this); // And don't forget to give it some sane name / timeout pSock->SetSockName("WebMod::Client"); } // TODO can we somehow get rid of this? pSock->ReadLine(sLine); pSock->PushBuff("", 0, true); } znc-1.7.5/src/IRCSock.cpp0000644000175000017500000014014013542151610015270 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include using std::set; using std::vector; using std::map; #define IRCSOCKMODULECALL(macFUNC, macEXITER) \ NETWORKMODULECALL(macFUNC, m_pNetwork->GetUser(), m_pNetwork, nullptr, \ macEXITER) // These are used in OnGeneralCTCP() const time_t CIRCSock::m_uCTCPFloodTime = 5; const unsigned int CIRCSock::m_uCTCPFloodCount = 5; // It will be bad if user sets it to 0.00000000000001 // If you want no flood protection, set network's flood rate to -1 // TODO move this constant to CIRCNetwork? static const double FLOOD_MINIMAL_RATE = 0.3; class CIRCFloodTimer : public CCron { CIRCSock* m_pSock; public: CIRCFloodTimer(CIRCSock* pSock) : m_pSock(pSock) { StartMaxCycles(m_pSock->m_fFloodRate, 0); } CIRCFloodTimer(const CIRCFloodTimer&) = delete; CIRCFloodTimer& operator=(const CIRCFloodTimer&) = delete; void RunJob() override { if (m_pSock->m_iSendsAllowed < m_pSock->m_uFloodBurst) { m_pSock->m_iSendsAllowed++; } m_pSock->TrySend(); } }; bool CIRCSock::IsFloodProtected(double fRate) { return fRate > FLOOD_MINIMAL_RATE; } CIRCSock::CIRCSock(CIRCNetwork* pNetwork) : CIRCSocket(), m_bAuthed(false), m_bNamesx(false), m_bUHNames(false), m_bAwayNotify(false), m_bAccountNotify(false), m_bExtendedJoin(false), m_bServerTime(false), m_sPerms("*!@%+"), m_sPermModes("qaohv"), m_scUserModes(), m_mceChanModes(), m_pNetwork(pNetwork), m_Nick(), m_sPass(""), m_msChans(), m_uMaxNickLen(9), m_uCapPaused(0), m_ssAcceptedCaps(), m_ssPendingCaps(), m_lastCTCP(0), m_uNumCTCP(0), m_mISupport(), m_vSendQueue(), m_iSendsAllowed(pNetwork->GetFloodBurst()), m_uFloodBurst(pNetwork->GetFloodBurst()), m_fFloodRate(pNetwork->GetFloodRate()), m_bFloodProtection(IsFloodProtected(pNetwork->GetFloodRate())) { EnableReadLine(); m_Nick.SetIdent(m_pNetwork->GetIdent()); m_Nick.SetHost(m_pNetwork->GetBindHost()); SetEncoding(m_pNetwork->GetEncoding()); m_mceChanModes['b'] = ListArg; m_mceChanModes['e'] = ListArg; m_mceChanModes['I'] = ListArg; m_mceChanModes['k'] = HasArg; m_mceChanModes['l'] = ArgWhenSet; m_mceChanModes['p'] = NoArg; m_mceChanModes['s'] = NoArg; m_mceChanModes['t'] = NoArg; m_mceChanModes['i'] = NoArg; m_mceChanModes['n'] = NoArg; pNetwork->SetIRCSocket(this); // RFC says a line can have 512 chars max + 512 chars for message tags, but // we don't care ;) SetMaxBufferThreshold(2048); if (m_bFloodProtection) { AddCron(new CIRCFloodTimer(this)); } } CIRCSock::~CIRCSock() { if (!m_bAuthed) { IRCSOCKMODULECALL(OnIRCConnectionError(this), NOTHING); } const vector& vChans = m_pNetwork->GetChans(); for (CChan* pChan : vChans) { pChan->Reset(); } m_pNetwork->IRCDisconnected(); for (const auto& it : m_msChans) { delete it.second; } Quit(); m_msChans.clear(); m_pNetwork->AddBytesRead(GetBytesRead()); m_pNetwork->AddBytesWritten(GetBytesWritten()); } void CIRCSock::Quit(const CString& sQuitMsg) { if (IsClosed()) { return; } if (!m_bAuthed) { Close(CLT_NOW); return; } if (!sQuitMsg.empty()) { PutIRC("QUIT :" + sQuitMsg); } else { PutIRC("QUIT :" + m_pNetwork->ExpandString(m_pNetwork->GetQuitMsg())); } Close(CLT_AFTERWRITE); } void CIRCSock::ReadLine(const CString& sData) { CString sLine = sData; sLine.Replace("\n", ""); sLine.Replace("\r", ""); DEBUG("(" << m_pNetwork->GetUser()->GetUserName() << "/" << m_pNetwork->GetName() << ") IRC -> ZNC [" << sLine << "]"); bool bReturn = false; IRCSOCKMODULECALL(OnRaw(sLine), &bReturn); if (bReturn) return; CMessage Message(sLine); Message.SetNetwork(m_pNetwork); IRCSOCKMODULECALL(OnRawMessage(Message), &bReturn); if (bReturn) return; switch (Message.GetType()) { case CMessage::Type::Account: bReturn = OnAccountMessage(Message); break; case CMessage::Type::Action: bReturn = OnActionMessage(Message); break; case CMessage::Type::Away: bReturn = OnAwayMessage(Message); break; case CMessage::Type::Capability: bReturn = OnCapabilityMessage(Message); break; case CMessage::Type::CTCP: bReturn = OnCTCPMessage(Message); break; case CMessage::Type::Error: bReturn = OnErrorMessage(Message); break; case CMessage::Type::Invite: bReturn = OnInviteMessage(Message); break; case CMessage::Type::Join: bReturn = OnJoinMessage(Message); break; case CMessage::Type::Kick: bReturn = OnKickMessage(Message); break; case CMessage::Type::Mode: bReturn = OnModeMessage(Message); break; case CMessage::Type::Nick: bReturn = OnNickMessage(Message); break; case CMessage::Type::Notice: bReturn = OnNoticeMessage(Message); break; case CMessage::Type::Numeric: bReturn = OnNumericMessage(Message); break; case CMessage::Type::Part: bReturn = OnPartMessage(Message); break; case CMessage::Type::Ping: bReturn = OnPingMessage(Message); break; case CMessage::Type::Pong: bReturn = OnPongMessage(Message); break; case CMessage::Type::Quit: bReturn = OnQuitMessage(Message); break; case CMessage::Type::Text: bReturn = OnTextMessage(Message); break; case CMessage::Type::Topic: bReturn = OnTopicMessage(Message); break; case CMessage::Type::Wallops: bReturn = OnWallopsMessage(Message); break; default: break; } if (bReturn) return; m_pNetwork->PutUser(Message); } void CIRCSock::SendNextCap() { if (!m_uCapPaused) { if (m_ssPendingCaps.empty()) { // We already got all needed ACK/NAK replies. PutIRC("CAP END"); } else { CString sCap = *m_ssPendingCaps.begin(); m_ssPendingCaps.erase(m_ssPendingCaps.begin()); PutIRC("CAP REQ :" + sCap); } } } void CIRCSock::PauseCap() { ++m_uCapPaused; } void CIRCSock::ResumeCap() { --m_uCapPaused; SendNextCap(); } bool CIRCSock::OnServerCapAvailable(const CString& sCap) { bool bResult = false; IRCSOCKMODULECALL(OnServerCapAvailable(sCap), &bResult); return bResult; } // #124: OnChanMsg(): nick doesn't have perms static void FixupChanNick(CNick& Nick, CChan* pChan) { // A channel nick has up-to-date channel perms, but might be // lacking (usernames-in-host) the associated ident & host. // An incoming message, on the other hand, has normally a full // nick!ident@host prefix. Sync the two so that channel nicks // get the potentially missing piece of info and module hooks // get the perms. CNick* pChanNick = pChan->FindNick(Nick.GetNick()); if (pChanNick) { if (!Nick.GetIdent().empty()) { pChanNick->SetIdent(Nick.GetIdent()); } if (!Nick.GetHost().empty()) { pChanNick->SetHost(Nick.GetHost()); } Nick.Clone(*pChanNick); } } bool CIRCSock::OnAccountMessage(CMessage& Message) { // TODO: IRCSOCKMODULECALL(OnAccountMessage(Message)) ? return false; } bool CIRCSock::OnActionMessage(CActionMessage& Message) { bool bResult = false; CChan* pChan = nullptr; CString sTarget = Message.GetTarget(); if (sTarget.Equals(GetNick())) { IRCSOCKMODULECALL(OnPrivCTCPMessage(Message), &bResult); if (bResult) return true; IRCSOCKMODULECALL(OnPrivActionMessage(Message), &bResult); if (bResult) return true; if (!m_pNetwork->IsUserOnline() || !m_pNetwork->GetUser()->AutoClearQueryBuffer()) { const CNick& Nick = Message.GetNick(); CQuery* pQuery = m_pNetwork->AddQuery(Nick.GetNick()); if (pQuery) { CActionMessage Format; Format.Clone(Message); Format.SetNick(_NAMEDFMT(Nick.GetNickMask())); Format.SetTarget("{target}"); Format.SetText("{text}"); pQuery->AddBuffer(Format, Message.GetText()); } } } else { pChan = m_pNetwork->FindChan(sTarget); if (pChan) { Message.SetChan(pChan); FixupChanNick(Message.GetNick(), pChan); IRCSOCKMODULECALL(OnChanCTCPMessage(Message), &bResult); if (bResult) return true; IRCSOCKMODULECALL(OnChanActionMessage(Message), &bResult); if (bResult) return true; if (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline() || pChan->IsDetached()) { CActionMessage Format; Format.Clone(Message); Format.SetNick(_NAMEDFMT(Message.GetNick().GetNickMask())); Format.SetTarget(_NAMEDFMT(Message.GetTarget())); Format.SetText("{text}"); pChan->AddBuffer(Format, Message.GetText()); } } } return (pChan && pChan->IsDetached()); } bool CIRCSock::OnAwayMessage(CMessage& Message) { // TODO: IRCSOCKMODULECALL(OnAwayMessage(Message)) ? return false; } bool CIRCSock::OnCapabilityMessage(CMessage& Message) { // CAPs are supported only before authorization. if (!m_bAuthed) { // The first parameter is most likely "*". No idea why, the // CAP spec don't mention this, but all implementations // I've seen add this extra asterisk CString sSubCmd = Message.GetParam(1); // If the caplist of a reply is too long, it's split // into multiple replies. A "*" is prepended to show // that the list was split into multiple replies. // This is useful mainly for LS. For ACK and NAK // replies, there's no real need for this, because // we request only 1 capability per line. // If we will need to support broken servers or will // send several requests per line, need to delay ACK // actions until all ACK lines are received and // to recognize past request of NAK by 100 chars // of this reply. CString sArgs; if (Message.GetParam(2) == "*") { sArgs = Message.GetParam(3); } else { sArgs = Message.GetParam(2); } std::map> mSupportedCaps = { {"multi-prefix", [this](bool bVal) { m_bNamesx = bVal; }}, {"userhost-in-names", [this](bool bVal) { m_bUHNames = bVal; }}, {"away-notify", [this](bool bVal) { m_bAwayNotify = bVal; }}, {"account-notify", [this](bool bVal) { m_bAccountNotify = bVal; }}, {"extended-join", [this](bool bVal) { m_bExtendedJoin = bVal; }}, {"server-time", [this](bool bVal) { m_bServerTime = bVal; }}, {"znc.in/server-time-iso", [this](bool bVal) { m_bServerTime = bVal; }}, }; if (sSubCmd == "LS") { VCString vsTokens; sArgs.Split(" ", vsTokens, false); for (const CString& sCap : vsTokens) { if (OnServerCapAvailable(sCap) || mSupportedCaps.count(sCap)) { m_ssPendingCaps.insert(sCap); } } } else if (sSubCmd == "ACK") { sArgs.Trim(); IRCSOCKMODULECALL(OnServerCapResult(sArgs, true), NOTHING); const auto& it = mSupportedCaps.find(sArgs); if (it != mSupportedCaps.end()) { it->second(true); } m_ssAcceptedCaps.insert(sArgs); } else if (sSubCmd == "NAK") { // This should work because there's no [known] // capability with length of name more than 100 characters. sArgs.Trim(); IRCSOCKMODULECALL(OnServerCapResult(sArgs, false), NOTHING); } SendNextCap(); } // Don't forward any CAP stuff to the client return true; } bool CIRCSock::OnCTCPMessage(CCTCPMessage& Message) { bool bResult = false; CChan* pChan = nullptr; CString sTarget = Message.GetTarget(); if (sTarget.Equals(GetNick())) { if (Message.IsReply()) { IRCSOCKMODULECALL(OnCTCPReplyMessage(Message), &bResult); return bResult; } else { IRCSOCKMODULECALL(OnPrivCTCPMessage(Message), &bResult); if (bResult) return true; } } else { pChan = m_pNetwork->FindChan(sTarget); if (pChan) { Message.SetChan(pChan); FixupChanNick(Message.GetNick(), pChan); if (Message.IsReply()) { IRCSOCKMODULECALL(OnCTCPReplyMessage(Message), &bResult); return bResult; } else { IRCSOCKMODULECALL(OnChanCTCPMessage(Message), &bResult); } if (bResult) return true; } } const CNick& Nick = Message.GetNick(); const CString& sMessage = Message.GetText(); const MCString& mssCTCPReplies = m_pNetwork->GetUser()->GetCTCPReplies(); CString sQuery = sMessage.Token(0).AsUpper(); MCString::const_iterator it = mssCTCPReplies.find(sQuery); bool bHaveReply = false; CString sReply; if (it != mssCTCPReplies.end()) { sReply = m_pNetwork->ExpandString(it->second); bHaveReply = true; if (sReply.empty()) { return true; } } if (!bHaveReply && !m_pNetwork->IsUserAttached()) { if (sQuery == "VERSION") { sReply = CZNC::GetTag(false); } else if (sQuery == "PING") { sReply = sMessage.Token(1, true); } } if (!sReply.empty()) { time_t now = time(nullptr); // If the last CTCP is older than m_uCTCPFloodTime, reset the counter if (m_lastCTCP + m_uCTCPFloodTime < now) m_uNumCTCP = 0; m_lastCTCP = now; // If we are over the limit, don't reply to this CTCP if (m_uNumCTCP >= m_uCTCPFloodCount) { DEBUG("CTCP flood detected - not replying to query"); return true; } m_uNumCTCP++; PutIRC("NOTICE " + Nick.GetNick() + " :\001" + sQuery + " " + sReply + "\001"); return true; } return (pChan && pChan->IsDetached()); } bool CIRCSock::OnErrorMessage(CMessage& Message) { // ERROR :Closing Link: nick[24.24.24.24] (Excess Flood) CString sError = Message.GetParam(0); m_pNetwork->PutStatus(t_f("Error from server: {1}")(sError)); return true; } bool CIRCSock::OnInviteMessage(CMessage& Message) { bool bResult = false; IRCSOCKMODULECALL(OnInvite(Message.GetNick(), Message.GetParam(1)), &bResult); return bResult; } bool CIRCSock::OnJoinMessage(CJoinMessage& Message) { const CNick& Nick = Message.GetNick(); CString sChan = Message.GetParam(0); CChan* pChan = nullptr; if (Nick.NickEquals(GetNick())) { m_pNetwork->AddChan(sChan, false); pChan = m_pNetwork->FindChan(sChan); if (pChan) { pChan->Enable(); pChan->SetIsOn(true); PutIRC("MODE " + sChan); } } else { pChan = m_pNetwork->FindChan(sChan); } if (pChan) { pChan->AddNick(Nick.GetNickMask()); Message.SetChan(pChan); IRCSOCKMODULECALL(OnJoinMessage(Message), NOTHING); if (pChan->IsDetached()) { return true; } } return false; } bool CIRCSock::OnKickMessage(CKickMessage& Message) { CString sChan = Message.GetParam(0); CString sKickedNick = Message.GetKickedNick(); CChan* pChan = m_pNetwork->FindChan(sChan); if (pChan) { Message.SetChan(pChan); IRCSOCKMODULECALL(OnKickMessage(Message), NOTHING); // do not remove the nick till after the OnKick call, so modules // can do Chan.FindNick or something to get more info. pChan->RemNick(sKickedNick); } if (GetNick().Equals(sKickedNick) && pChan) { pChan->SetIsOn(false); // Don't try to rejoin! pChan->Disable(); } return (pChan && pChan->IsDetached()); } bool CIRCSock::OnModeMessage(CModeMessage& Message) { const CNick& Nick = Message.GetNick(); CString sTarget = Message.GetTarget(); CString sModes = Message.GetModes(); CChan* pChan = m_pNetwork->FindChan(sTarget); if (pChan) { pChan->ModeChange(sModes, &Nick); if (pChan->IsDetached()) { return true; } } else if (sTarget == m_Nick.GetNick()) { CString sModeArg = sModes.Token(0); bool bAdd = true; /* no module call defined (yet?) MODULECALL(OnRawUserMode(*pOpNick, *this, sModeArg, sArgs), m_pNetwork->GetUser(), nullptr, ); */ for (unsigned int a = 0; a < sModeArg.size(); a++) { const char& cMode = sModeArg[a]; if (cMode == '+') { bAdd = true; } else if (cMode == '-') { bAdd = false; } else { if (bAdd) { m_scUserModes.insert(cMode); } else { m_scUserModes.erase(cMode); } } } } return false; } bool CIRCSock::OnNickMessage(CNickMessage& Message) { const CNick& Nick = Message.GetNick(); CString sNewNick = Message.GetNewNick(); bool bIsVisible = false; vector vFoundChans; const vector& vChans = m_pNetwork->GetChans(); for (CChan* pChan : vChans) { if (pChan->ChangeNick(Nick.GetNick(), sNewNick)) { vFoundChans.push_back(pChan); if (!pChan->IsDetached()) { bIsVisible = true; } } } if (Nick.NickEquals(GetNick())) { // We are changing our own nick, the clients always must see this! bIsVisible = false; SetNick(sNewNick); m_pNetwork->PutUser(Message); } IRCSOCKMODULECALL(OnNickMessage(Message, vFoundChans), NOTHING); return !bIsVisible; } bool CIRCSock::OnNoticeMessage(CNoticeMessage& Message) { CString sTarget = Message.GetTarget(); bool bResult = false; if (sTarget.Equals(GetNick())) { IRCSOCKMODULECALL(OnPrivNoticeMessage(Message), &bResult); if (bResult) return true; if (!m_pNetwork->IsUserOnline()) { // If the user is detached, add to the buffer CNoticeMessage Format; Format.Clone(Message); Format.SetNick(CNick(_NAMEDFMT(Message.GetNick().GetNickMask()))); Format.SetTarget("{target}"); Format.SetText("{text}"); m_pNetwork->AddNoticeBuffer(Format, Message.GetText()); } return false; } else { CChan* pChan = m_pNetwork->FindChan(sTarget); if (pChan) { Message.SetChan(pChan); FixupChanNick(Message.GetNick(), pChan); IRCSOCKMODULECALL(OnChanNoticeMessage(Message), &bResult); if (bResult) return true; if (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline() || pChan->IsDetached()) { CNoticeMessage Format; Format.Clone(Message); Format.SetNick(_NAMEDFMT(Message.GetNick().GetNickMask())); Format.SetTarget(_NAMEDFMT(Message.GetTarget())); Format.SetText("{text}"); pChan->AddBuffer(Format, Message.GetText()); } } return (pChan && pChan->IsDetached()); } } static CMessage BufferMessage(const CNumericMessage& Message) { CMessage Format(Message); Format.SetNick(CNick(_NAMEDFMT(Message.GetNick().GetHostMask()))); Format.SetParam(0, "{target}"); unsigned uParams = Format.GetParams().size(); for (unsigned int i = 1; i < uParams; ++i) { Format.SetParam(i, _NAMEDFMT(Format.GetParam(i))); } return Format; } bool CIRCSock::OnNumericMessage(CNumericMessage& Message) { const CString& sCmd = Message.GetCommand(); CString sServer = Message.GetNick().GetHostMask(); unsigned int uRaw = Message.GetCode(); CString sNick = Message.GetParam(0); bool bResult = false; IRCSOCKMODULECALL(OnNumericMessage(Message), &bResult); if (bResult) return true; switch (uRaw) { case 1: { // :irc.server.com 001 nick :Welcome to the Internet Relay if (m_bAuthed && sServer == "irc.znc.in") { // m_bAuthed == true => we already received another 001 => we // might be in a traffic loop m_pNetwork->PutStatus(t_s( "ZNC seems to be connected to itself, disconnecting...")); Quit(); return true; } m_pNetwork->SetIRCServer(sServer); // Now that we are connected, let nature take its course SetTimeout(m_pNetwork->GetUser()->GetNoTrafficTimeout(), TMO_READ); PutIRC("WHO " + sNick); m_bAuthed = true; const vector& vClients = m_pNetwork->GetClients(); for (CClient* pClient : vClients) { CString sClientNick = pClient->GetNick(false); if (!sClientNick.Equals(sNick)) { // If they connected with a nick that doesn't match the one // we got on irc, then we need to update them pClient->PutClient(":" + sClientNick + "!" + m_Nick.GetIdent() + "@" + m_Nick.GetHost() + " NICK :" + sNick); } } SetNick(sNick); m_pNetwork->PutStatus("Connected!"); IRCSOCKMODULECALL(OnIRCConnected(), NOTHING); m_pNetwork->ClearRawBuffer(); m_pNetwork->AddRawBuffer(BufferMessage(Message)); m_pNetwork->IRCConnected(); break; } case 5: ParseISupport(Message); m_pNetwork->UpdateExactRawBuffer(BufferMessage(Message)); break; case 10: { // :irc.server.com 010 nick : CString sHost = Message.GetParam(1); CString sPort = Message.GetParam(2); CString sInfo = Message.GetParam(3); m_pNetwork->PutStatus( t_f("Server {1} redirects us to {2}:{3} with reason: {4}")( m_pNetwork->GetCurrentServer()->GetString(false), sHost, sPort, sInfo)); m_pNetwork->PutStatus( t_s("Perhaps you want to add it as a new server.")); // Don't send server redirects to the client return true; } case 2: case 3: case 4: case 250: // highest connection count case 251: // user count case 252: // oper count case 254: // channel count case 255: // client count case 265: // local users case 266: // global users m_pNetwork->UpdateRawBuffer(sCmd, BufferMessage(Message)); break; case 305: m_pNetwork->SetIRCAway(false); break; case 306: m_pNetwork->SetIRCAway(true); break; case 324: { // MODE // :irc.server.com 324 nick #chan +nstk key CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { pChan->SetModes(Message.GetParamsColon(2)); // We don't SetModeKnown(true) here, // because a 329 will follow if (!pChan->IsModeKnown()) { // When we JOIN, we send a MODE // request. This makes sure the // reply isn't forwarded. return true; } if (pChan->IsDetached()) { return true; } } } break; case 329: { // :irc.server.com 329 nick #chan 1234567890 CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { unsigned long ulDate = Message.GetParam(2).ToULong(); pChan->SetCreationDate(ulDate); if (!pChan->IsModeKnown()) { pChan->SetModeKnown(true); // When we JOIN, we send a MODE // request. This makes sure the // reply isn't forwarded. return true; } if (pChan->IsDetached()) { return true; } } } break; case 331: { // :irc.server.com 331 yournick #chan :No topic is set. CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { pChan->SetTopic(""); if (pChan->IsDetached()) { return true; } } break; } case 332: { // :irc.server.com 332 yournick #chan :This is a topic CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { CString sTopic = Message.GetParam(2); pChan->SetTopic(sTopic); if (pChan->IsDetached()) { return true; } } break; } case 333: { // :irc.server.com 333 yournick #chan setternick 1112320796 CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { sNick = Message.GetParam(2); unsigned long ulDate = Message.GetParam(3).ToULong(); pChan->SetTopicOwner(sNick); pChan->SetTopicDate(ulDate); if (pChan->IsDetached()) { return true; } } break; } case 352: { // WHO // :irc.yourserver.com 352 yournick #chan ident theirhost.com irc.theirserver.com theirnick H :0 Real Name sNick = Message.GetParam(5); CString sChan = Message.GetParam(1); CString sIdent = Message.GetParam(2); CString sHost = Message.GetParam(3); if (sNick.Equals(GetNick())) { m_Nick.SetIdent(sIdent); m_Nick.SetHost(sHost); } m_pNetwork->SetIRCNick(m_Nick); m_pNetwork->SetIRCServer(sServer); // A nick can only have one ident and hostname. Yes, you can query // this information per-channel, but it is still global. For // example, if the client supports UHNAMES, but the IRC server does // not, then AFAIR "passive snooping of WHO replies" is the only way // that ZNC can figure out the ident and host for the UHNAMES // replies. const vector& vChans = m_pNetwork->GetChans(); for (CChan* pChan : vChans) { pChan->OnWho(sNick, sIdent, sHost); } CChan* pChan = m_pNetwork->FindChan(sChan); if (pChan && pChan->IsDetached()) { return true; } break; } case 353: { // NAMES // :irc.server.com 353 nick @ #chan :nick1 nick2 // Todo: allow for non @+= server msgs CChan* pChan = m_pNetwork->FindChan(Message.GetParam(2)); // If we don't know that channel, some client might have // requested a /names for it and we really should forward this. if (pChan) { CString sNicks = Message.GetParam(3); pChan->AddNicks(sNicks); if (pChan->IsDetached()) { return true; } } break; } case 366: { // end of names list // :irc.server.com 366 nick #chan :End of /NAMES list. CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { if (pChan->IsOn()) { // If we are the only one in the chan, set our default modes if (pChan->GetNickCount() == 1) { CString sModes = pChan->GetDefaultModes(); if (sModes.empty()) { sModes = m_pNetwork->GetUser()->GetDefaultChanModes(); } if (!sModes.empty()) { PutIRC("MODE " + pChan->GetName() + " " + sModes); } } } if (pChan->IsDetached()) { // don't put it to clients return true; } } break; } case 375: // begin motd case 422: // MOTD File is missing if (m_pNetwork->GetIRCServer().Equals(sServer)) { m_pNetwork->ClearMotdBuffer(); } case 372: // motd case 376: // end motd if (m_pNetwork->GetIRCServer().Equals(sServer)) { m_pNetwork->AddMotdBuffer(BufferMessage(Message)); } break; case 437: // :irc.server.net 437 * badnick :Nick/channel is temporarily unavailable // :irc.server.net 437 mynick badnick :Nick/channel is temporarily unavailable // :irc.server.net 437 mynick badnick :Cannot change nickname while banned on channel if (m_pNetwork->IsChan(Message.GetParam(1)) || sNick != "*") break; case 432: // :irc.server.com 432 * nick :Erroneous Nickname: Illegal chars case 433: { CString sBadNick = Message.GetParam(1); if (!m_bAuthed) { SendAltNick(sBadNick); return true; } break; } case 451: // :irc.server.com 451 CAP :You have not registered // Servers that don't support CAP will give us this error, don't send // it to the client if (sNick.Equals("CAP")) return true; case 470: { // :irc.unreal.net 470 mynick [Link] #chan1 has become full, so you are automatically being transferred to the linked channel #chan2 // :mccaffrey.freenode.net 470 mynick #electronics ##electronics :Forwarding to another channel // freenode style numeric CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (!pChan) { // unreal style numeric pChan = m_pNetwork->FindChan(Message.GetParam(2)); } if (pChan) { pChan->Disable(); m_pNetwork->PutStatus( t_f("Channel {1} is linked to another channel and was thus " "disabled.")(pChan->GetName())); } break; } case 670: // :hydra.sector5d.org 670 kylef :STARTTLS successful, go ahead with TLS handshake // // 670 is a response to `STARTTLS` telling the client to switch to // TLS if (!GetSSL()) { StartTLS(); m_pNetwork->PutStatus(t_s("Switched to SSL (STARTTLS)")); } return true; } return false; } bool CIRCSock::OnPartMessage(CPartMessage& Message) { const CNick& Nick = Message.GetNick(); CString sChan = Message.GetTarget(); CChan* pChan = m_pNetwork->FindChan(sChan); bool bDetached = false; if (pChan) { pChan->RemNick(Nick.GetNick()); Message.SetChan(pChan); IRCSOCKMODULECALL(OnPartMessage(Message), NOTHING); if (pChan->IsDetached()) bDetached = true; } if (Nick.NickEquals(GetNick())) { m_pNetwork->DelChan(sChan); } /* * We use this boolean because * m_pNetwork->DelChan() will delete this channel * and thus we would dereference an * already-freed pointer! */ return bDetached; } bool CIRCSock::OnPingMessage(CMessage& Message) { // Generate a reply and don't forward this to any user, // we don't want any PING forwarded PutIRCQuick("PONG " + Message.GetParam(0)); return true; } bool CIRCSock::OnPongMessage(CMessage& Message) { // Block PONGs, we already responded to the pings return true; } bool CIRCSock::OnQuitMessage(CQuitMessage& Message) { const CNick& Nick = Message.GetNick(); bool bIsVisible = false; if (Nick.NickEquals(GetNick())) { m_pNetwork->PutStatus(t_f("You quit: {1}")(Message.GetReason())); // We don't call module hooks and we don't // forward this quit to clients (Some clients // disconnect if they receive such a QUIT) return true; } vector vFoundChans; const vector& vChans = m_pNetwork->GetChans(); for (CChan* pChan : vChans) { if (pChan->RemNick(Nick.GetNick())) { vFoundChans.push_back(pChan); if (!pChan->IsDetached()) { bIsVisible = true; } } } IRCSOCKMODULECALL(OnQuitMessage(Message, vFoundChans), NOTHING); return !bIsVisible; } bool CIRCSock::OnTextMessage(CTextMessage& Message) { bool bResult = false; CChan* pChan = nullptr; CString sTarget = Message.GetTarget(); if (sTarget.Equals(GetNick())) { IRCSOCKMODULECALL(OnPrivTextMessage(Message), &bResult); if (bResult) return true; if (!m_pNetwork->IsUserOnline() || !m_pNetwork->GetUser()->AutoClearQueryBuffer()) { const CNick& Nick = Message.GetNick(); CQuery* pQuery = m_pNetwork->AddQuery(Nick.GetNick()); if (pQuery) { CTextMessage Format; Format.Clone(Message); Format.SetNick(_NAMEDFMT(Nick.GetNickMask())); Format.SetTarget("{target}"); Format.SetText("{text}"); pQuery->AddBuffer(Format, Message.GetText()); } } } else { pChan = m_pNetwork->FindChan(sTarget); if (pChan) { Message.SetChan(pChan); FixupChanNick(Message.GetNick(), pChan); IRCSOCKMODULECALL(OnChanTextMessage(Message), &bResult); if (bResult) return true; if (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline() || pChan->IsDetached()) { CTextMessage Format; Format.Clone(Message); Format.SetNick(_NAMEDFMT(Message.GetNick().GetNickMask())); Format.SetTarget(_NAMEDFMT(Message.GetTarget())); Format.SetText("{text}"); pChan->AddBuffer(Format, Message.GetText()); } } } return (pChan && pChan->IsDetached()); } bool CIRCSock::OnTopicMessage(CTopicMessage& Message) { const CNick& Nick = Message.GetNick(); CChan* pChan = m_pNetwork->FindChan(Message.GetParam(0)); if (pChan) { Message.SetChan(pChan); bool bReturn = false; IRCSOCKMODULECALL(OnTopicMessage(Message), &bReturn); if (bReturn) return true; pChan->SetTopicOwner(Nick.GetNick()); pChan->SetTopicDate((unsigned long)time(nullptr)); pChan->SetTopic(Message.GetTopic()); } return (pChan && pChan->IsDetached()); } bool CIRCSock::OnWallopsMessage(CMessage& Message) { // :blub!dummy@rox-8DBEFE92 WALLOPS :this is a test CString sMsg = Message.GetParam(0); if (!m_pNetwork->IsUserOnline()) { CMessage Format(Message); Format.SetNick(CNick(_NAMEDFMT(Message.GetNick().GetHostMask()))); Format.SetParam(0, "{text}"); m_pNetwork->AddNoticeBuffer(Format, sMsg); } return false; } void CIRCSock::PutIRC(const CString& sLine) { PutIRC(CMessage(sLine)); } void CIRCSock::PutIRC(const CMessage& Message) { // Only print if the line won't get sent immediately (same condition as in // TrySend()!) if (m_bFloodProtection && m_iSendsAllowed <= 0) { DEBUG("(" << m_pNetwork->GetUser()->GetUserName() << "/" << m_pNetwork->GetName() << ") ZNC -> IRC [" << CDebug::Filter(Message.ToString()) << "] (queued)"); } m_vSendQueue.push_back(Message); TrySend(); } void CIRCSock::PutIRCQuick(const CString& sLine) { // Only print if the line won't get sent immediately (same condition as in // TrySend()!) if (m_bFloodProtection && m_iSendsAllowed <= 0) { DEBUG("(" << m_pNetwork->GetUser()->GetUserName() << "/" << m_pNetwork->GetName() << ") ZNC -> IRC [" << CDebug::Filter(sLine) << "] (queued to front)"); } m_vSendQueue.emplace_front(sLine); TrySend(); } void CIRCSock::TrySend() { // This condition must be the same as in PutIRC() and PutIRCQuick()! while (!m_vSendQueue.empty() && (!m_bFloodProtection || m_iSendsAllowed > 0)) { m_iSendsAllowed--; CMessage& Message = m_vSendQueue.front(); MCString mssTags; for (const auto& it : Message.GetTags()) { if (IsTagEnabled(it.first)) { mssTags[it.first] = it.second; } } Message.SetTags(mssTags); Message.SetNetwork(m_pNetwork); bool bSkip = false; IRCSOCKMODULECALL(OnSendToIRCMessage(Message), &bSkip); if (!bSkip) { PutIRCRaw(Message.ToString()); } m_vSendQueue.pop_front(); } } void CIRCSock::PutIRCRaw(const CString& sLine) { CString sCopy = sLine; bool bSkip = false; IRCSOCKMODULECALL(OnSendToIRC(sCopy), &bSkip); if (!bSkip) { DEBUG("(" << m_pNetwork->GetUser()->GetUserName() << "/" << m_pNetwork->GetName() << ") ZNC -> IRC [" << CDebug::Filter(sCopy) << "]"); Write(sCopy + "\r\n"); } } void CIRCSock::SetNick(const CString& sNick) { m_Nick.SetNick(sNick); m_pNetwork->SetIRCNick(m_Nick); } void CIRCSock::Connected() { DEBUG(GetSockName() << " == Connected()"); CString sPass = m_sPass; CString sNick = m_pNetwork->GetNick(); CString sIdent = m_pNetwork->GetIdent(); CString sRealName = m_pNetwork->GetRealName(); bool bReturn = false; IRCSOCKMODULECALL(OnIRCRegistration(sPass, sNick, sIdent, sRealName), &bReturn); if (bReturn) return; PutIRC("CAP LS"); if (!sPass.empty()) { PutIRC("PASS " + sPass); } PutIRC("NICK " + sNick); PutIRC("USER " + sIdent + " \"" + sIdent + "\" \"" + sIdent + "\" :" + sRealName); // SendAltNick() needs this m_Nick.SetNick(sNick); } void CIRCSock::Disconnected() { IRCSOCKMODULECALL(OnIRCDisconnected(), NOTHING); DEBUG(GetSockName() << " == Disconnected()"); if (!m_pNetwork->GetUser()->IsBeingDeleted() && m_pNetwork->GetIRCConnectEnabled() && m_pNetwork->GetServers().size() != 0) { m_pNetwork->PutStatus(t_s("Disconnected from IRC. Reconnecting...")); } m_pNetwork->ClearRawBuffer(); m_pNetwork->ClearMotdBuffer(); ResetChans(); // send a "reset user modes" cmd to the client. // otherwise, on reconnect, it might think it still // had user modes that it actually doesn't have. CString sUserMode; for (char cMode : m_scUserModes) { sUserMode += cMode; } if (!sUserMode.empty()) { m_pNetwork->PutUser(":" + m_pNetwork->GetIRCNick().GetNickMask() + " MODE " + m_pNetwork->GetIRCNick().GetNick() + " :-" + sUserMode); } // also clear the user modes in our space: m_scUserModes.clear(); } void CIRCSock::SockError(int iErrno, const CString& sDescription) { CString sError = sDescription; DEBUG(GetSockName() << " == SockError(" << iErrno << " " << sError << ")"); if (!m_pNetwork->GetUser()->IsBeingDeleted()) { if (GetConState() != CST_OK) { m_pNetwork->PutStatus( t_f("Cannot connect to IRC ({1}). Retrying...")(sError)); } else { m_pNetwork->PutStatus( t_f("Disconnected from IRC ({1}). Reconnecting...")(sError)); } #ifdef HAVE_LIBSSL if (iErrno == errnoBadSSLCert) { // Stringify bad cert X509* pCert = GetX509(); if (pCert) { BIO* mem = BIO_new(BIO_s_mem()); X509_print(mem, pCert); X509_free(pCert); char* pCertStr = nullptr; long iLen = BIO_get_mem_data(mem, &pCertStr); CString sCert(pCertStr, iLen); BIO_free(mem); VCString vsCert; sCert.Split("\n", vsCert); for (const CString& s : vsCert) { // It shouldn't contain any bad characters, but let's be // safe... m_pNetwork->PutStatus("|" + s.Escape_n(CString::EDEBUG)); } CString sSHA1; if (GetPeerFingerprint(sSHA1)) m_pNetwork->PutStatus( "SHA1: " + sSHA1.Escape_n(CString::EHEXCOLON, CString::EHEXCOLON)); CString sSHA256 = GetSSLPeerFingerprint(); m_pNetwork->PutStatus("SHA-256: " + sSHA256); m_pNetwork->PutStatus( t_f("If you trust this certificate, do /znc " "AddTrustedServerFingerprint {1}")(sSHA256)); } } #endif } m_pNetwork->ClearRawBuffer(); m_pNetwork->ClearMotdBuffer(); ResetChans(); m_scUserModes.clear(); } void CIRCSock::Timeout() { DEBUG(GetSockName() << " == Timeout()"); if (!m_pNetwork->GetUser()->IsBeingDeleted()) { m_pNetwork->PutStatus( t_s("IRC connection timed out. Reconnecting...")); } m_pNetwork->ClearRawBuffer(); m_pNetwork->ClearMotdBuffer(); ResetChans(); m_scUserModes.clear(); } void CIRCSock::ConnectionRefused() { DEBUG(GetSockName() << " == ConnectionRefused()"); if (!m_pNetwork->GetUser()->IsBeingDeleted()) { m_pNetwork->PutStatus(t_s("Connection Refused. Reconnecting...")); } m_pNetwork->ClearRawBuffer(); m_pNetwork->ClearMotdBuffer(); } void CIRCSock::ReachedMaxBuffer() { DEBUG(GetSockName() << " == ReachedMaxBuffer()"); m_pNetwork->PutStatus(t_s("Received a too long line from the IRC server!")); Quit(); } void CIRCSock::ParseISupport(const CMessage& Message) { const VCString vsParams = Message.GetParams(); for (size_t i = 1; i + 1 < vsParams.size(); ++i) { const CString& sParam = vsParams[i]; CString sName = sParam.Token(0, false, "="); CString sValue = sParam.Token(1, true, "="); if (0 < sName.length() && ':' == sName[0]) { break; } m_mISupport[sName] = sValue; if (sName.Equals("PREFIX")) { CString sPrefixes = sValue.Token(1, false, ")"); CString sPermModes = sValue.Token(0, false, ")"); sPermModes.TrimLeft("("); if (!sPrefixes.empty() && sPermModes.size() == sPrefixes.size()) { m_sPerms = sPrefixes; m_sPermModes = sPermModes; } } else if (sName.Equals("CHANTYPES")) { m_pNetwork->SetChanPrefixes(sValue); } else if (sName.Equals("NICKLEN")) { unsigned int uMax = sValue.ToUInt(); if (uMax) { m_uMaxNickLen = uMax; } } else if (sName.Equals("CHANMODES")) { if (!sValue.empty()) { m_mceChanModes.clear(); for (unsigned int a = 0; a < 4; a++) { CString sModes = sValue.Token(a, false, ","); for (unsigned int b = 0; b < sModes.size(); b++) { m_mceChanModes[sModes[b]] = (EChanModeArgs)a; } } } } else if (sName.Equals("NAMESX")) { if (m_bNamesx) continue; m_bNamesx = true; PutIRC("PROTOCTL NAMESX"); } else if (sName.Equals("UHNAMES")) { if (m_bUHNames) continue; m_bUHNames = true; PutIRC("PROTOCTL UHNAMES"); } } } CString CIRCSock::GetISupport(const CString& sKey, const CString& sDefault) const { MCString::const_iterator i = m_mISupport.find(sKey.AsUpper()); if (i == m_mISupport.end()) { return sDefault; } else { return i->second; } } void CIRCSock::SendAltNick(const CString& sBadNick) { const CString& sLastNick = m_Nick.GetNick(); // We don't know the maximum allowed nick length yet, but we know which // nick we sent last. If sBadNick is shorter than that, we assume the // server truncated our nick. if (sBadNick.length() < sLastNick.length()) m_uMaxNickLen = (unsigned int)sBadNick.length(); unsigned int uMax = m_uMaxNickLen; const CString& sConfNick = m_pNetwork->GetNick(); const CString& sAltNick = m_pNetwork->GetAltNick(); CString sNewNick = sConfNick.Left(uMax - 1); if (sLastNick.Equals(sConfNick)) { if ((!sAltNick.empty()) && (!sConfNick.Equals(sAltNick))) { sNewNick = sAltNick; } else { sNewNick += "-"; } } else if (sLastNick.Equals(sAltNick) && !sAltNick.Equals(sNewNick + "-")) { sNewNick += "-"; } else if (sLastNick.Equals(sNewNick + "-") && !sAltNick.Equals(sNewNick + "|")) { sNewNick += "|"; } else if (sLastNick.Equals(sNewNick + "|") && !sAltNick.Equals(sNewNick + "^")) { sNewNick += "^"; } else if (sLastNick.Equals(sNewNick + "^") && !sAltNick.Equals(sNewNick + "a")) { sNewNick += "a"; } else { char cLetter = 0; if (sBadNick.empty()) { m_pNetwork->PutUser(t_s("No free nick available")); Quit(); return; } cLetter = sBadNick.back(); if (cLetter == 'z') { m_pNetwork->PutUser(t_s("No free nick found")); Quit(); return; } sNewNick = sConfNick.Left(uMax - 1) + ++cLetter; if (sNewNick.Equals(sAltNick)) sNewNick = sConfNick.Left(uMax - 1) + ++cLetter; } PutIRC("NICK " + sNewNick); m_Nick.SetNick(sNewNick); } char CIRCSock::GetPermFromMode(char cMode) const { if (m_sPermModes.size() == m_sPerms.size()) { for (unsigned int a = 0; a < m_sPermModes.size(); a++) { if (m_sPermModes[a] == cMode) { return m_sPerms[a]; } } } return 0; } CIRCSock::EChanModeArgs CIRCSock::GetModeType(char cMode) const { map::const_iterator it = m_mceChanModes.find(cMode); if (it == m_mceChanModes.end()) { return NoArg; } return it->second; } void CIRCSock::ResetChans() { for (const auto& it : m_msChans) { it.second->Reset(); } } void CIRCSock::SetTagSupport(const CString& sTag, bool bState) { if (bState) { m_ssSupportedTags.insert(sTag); } else { m_ssSupportedTags.erase(sTag); } } znc-1.7.5/src/Nick.cpp0000644000175000017500000001106113542151610014716 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include using std::vector; using std::map; CNick::CNick() : m_sChanPerms(""), m_pNetwork(nullptr), m_sNick(""), m_sIdent(""), m_sHost("") {} CNick::CNick(const CString& sNick) : CNick() { Parse(sNick); } CNick::~CNick() {} void CNick::Reset() { m_sChanPerms.clear(); m_pNetwork = nullptr; } void CNick::Parse(const CString& sNickMask) { if (sNickMask.empty()) { return; } CString::size_type uPos = sNickMask.find('!'); if (uPos == CString::npos) { m_sNick = sNickMask.substr((sNickMask[0] == ':')); return; } m_sNick = sNickMask.substr((sNickMask[0] == ':'), uPos - (sNickMask[0] == ':')); m_sHost = sNickMask.substr(uPos + 1); if ((uPos = m_sHost.find('@')) != CString::npos) { m_sIdent = m_sHost.substr(0, uPos); m_sHost = m_sHost.substr(uPos + 1); } } size_t CNick::GetCommonChans(vector& vRetChans, CIRCNetwork* pNetwork) const { vRetChans.clear(); const vector& vChans = pNetwork->GetChans(); for (CChan* pChan : vChans) { const map& msNicks = pChan->GetNicks(); for (const auto& it : msNicks) { if (it.first.Equals(m_sNick)) { vRetChans.push_back(pChan); continue; } } } return vRetChans.size(); } bool CNick::NickEquals(const CString& nickname) const { // TODO add proper IRC case mapping here // https://tools.ietf.org/html/draft-brocklesby-irc-isupport-03#section-3.1 return m_sNick.Equals(nickname); } void CNick::SetNetwork(CIRCNetwork* pNetwork) { m_pNetwork = pNetwork; } void CNick::SetNick(const CString& s) { m_sNick = s; } void CNick::SetIdent(const CString& s) { m_sIdent = s; } void CNick::SetHost(const CString& s) { m_sHost = s; } bool CNick::HasPerm(char cPerm) const { return (cPerm && m_sChanPerms.find(cPerm) != CString::npos); } bool CNick::AddPerm(char cPerm) { if (!cPerm || HasPerm(cPerm)) { return false; } m_sChanPerms.append(1, cPerm); return true; } bool CNick::RemPerm(char cPerm) { CString::size_type uPos = m_sChanPerms.find(cPerm); if (uPos == CString::npos) { return false; } m_sChanPerms.erase(uPos, 1); return true; } char CNick::GetPermChar() const { CIRCSock* pIRCSock = (!m_pNetwork) ? nullptr : m_pNetwork->GetIRCSock(); const CString& sChanPerms = (!pIRCSock) ? "@+" : pIRCSock->GetPerms(); for (unsigned int a = 0; a < sChanPerms.size(); a++) { const char& c = sChanPerms[a]; if (HasPerm(c)) { return c; } } return '\0'; } CString CNick::GetPermStr() const { CIRCSock* pIRCSock = (!m_pNetwork) ? nullptr : m_pNetwork->GetIRCSock(); const CString& sChanPerms = (!pIRCSock) ? "@+" : pIRCSock->GetPerms(); CString sRet; for (unsigned int a = 0; a < sChanPerms.size(); a++) { const char& c = sChanPerms[a]; if (HasPerm(c)) { sRet += c; } } return sRet; } const CString& CNick::GetNick() const { return m_sNick; } const CString& CNick::GetIdent() const { return m_sIdent; } const CString& CNick::GetHost() const { return m_sHost; } CString CNick::GetNickMask() const { CString sRet = m_sNick; if (!m_sHost.empty()) { if (!m_sIdent.empty()) sRet += "!" + m_sIdent; sRet += "@" + m_sHost; } return sRet; } CString CNick::GetHostMask() const { CString sRet = m_sNick; if (!m_sIdent.empty()) { sRet += "!" + m_sIdent; } if (!m_sHost.empty()) { sRet += "@" + m_sHost; } return (sRet); } void CNick::Clone(const CNick& SourceNick) { SetNick(SourceNick.GetNick()); SetIdent(SourceNick.GetIdent()); SetHost(SourceNick.GetHost()); m_sChanPerms = SourceNick.m_sChanPerms; m_pNetwork = SourceNick.m_pNetwork; } znc-1.7.5/src/version.cpp.in0000644000175000017500000000133613542151610016130 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include const char* ZNC_VERSION_EXTRA = VERSION_EXTRA "@alpha_version@" "@git_info@"; znc-1.7.5/src/ClientCommand.cpp0000644000175000017500000021156513542151610016562 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include using std::vector; using std::set; using std::map; void CClient::UserCommand(CString& sLine) { if (!m_pUser) { return; } if (sLine.empty()) { return; } bool bReturn = false; NETWORKMODULECALL(OnStatusCommand(sLine), m_pUser, m_pNetwork, this, &bReturn); if (bReturn) return; const CString sCommand = sLine.Token(0); if (sCommand.Equals("HELP")) { HelpUser(sLine.Token(1)); } else if (sCommand.Equals("LISTNICKS")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } CString sChan = sLine.Token(1); if (sChan.empty()) { PutStatus(t_s("Usage: ListNicks <#chan>")); return; } CChan* pChan = m_pNetwork->FindChan(sChan); if (!pChan) { PutStatus(t_f("You are not on [{1}]")(sChan)); return; } if (!pChan->IsOn()) { PutStatus(t_f("You are not on [{1}] (trying)")(sChan)); return; } const map& msNicks = pChan->GetNicks(); CIRCSock* pIRCSock = m_pNetwork->GetIRCSock(); const CString& sPerms = (pIRCSock) ? pIRCSock->GetPerms() : ""; if (msNicks.empty()) { PutStatus(t_f("No nicks on [{1}]")(sChan)); return; } CTable Table; for (unsigned int p = 0; p < sPerms.size(); p++) { CString sPerm; sPerm += sPerms[p]; Table.AddColumn(sPerm); } Table.AddColumn(t_s("Nick")); Table.AddColumn(t_s("Ident")); Table.AddColumn(t_s("Host")); for (const auto& it : msNicks) { Table.AddRow(); for (unsigned int b = 0; b < sPerms.size(); b++) { if (it.second.HasPerm(sPerms[b])) { CString sPerm; sPerm += sPerms[b]; Table.SetCell(sPerm, sPerm); } } Table.SetCell(t_s("Nick"), it.second.GetNick()); Table.SetCell(t_s("Ident"), it.second.GetIdent()); Table.SetCell(t_s("Host"), it.second.GetHost()); } PutStatus(Table); } else if (sCommand.Equals("ATTACH")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } CString sPatterns = sLine.Token(1, true); if (sPatterns.empty()) { PutStatus(t_s("Usage: Attach <#chans>")); return; } set sChans = MatchChans(sPatterns); unsigned int uAttachedChans = AttachChans(sChans); PutStatus(t_p("There was {1} channel matching [{2}]", "There were {1} channels matching [{2}]", sChans.size())(sChans.size(), sPatterns)); PutStatus(t_p("Attached {1} channel", "Attached {1} channels", uAttachedChans)(uAttachedChans)); } else if (sCommand.Equals("DETACH")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } CString sPatterns = sLine.Token(1, true); if (sPatterns.empty()) { PutStatus(t_s("Usage: Detach <#chans>")); return; } set sChans = MatchChans(sPatterns); unsigned int uDetached = DetachChans(sChans); PutStatus(t_p("There was {1} channel matching [{2}]", "There were {1} channels matching [{2}]", sChans.size())(sChans.size(), sPatterns)); PutStatus(t_p("Detached {1} channel", "Detached {1} channels", uDetached)(uDetached)); } else if (sCommand.Equals("VERSION")) { PutStatus(CZNC::GetTag()); PutStatus(CZNC::GetCompileOptionsString()); } else if (sCommand.Equals("MOTD") || sCommand.Equals("ShowMOTD")) { if (!SendMotd()) { PutStatus(t_s("There is no MOTD set.")); } } else if (m_pUser->IsAdmin() && sCommand.Equals("Rehash")) { CString sRet; if (CZNC::Get().RehashConfig(sRet)) { PutStatus(t_s("Rehashing succeeded!")); } else { PutStatus(t_f("Rehashing failed: {1}")(sRet)); } } else if (m_pUser->IsAdmin() && sCommand.Equals("SaveConfig")) { if (CZNC::Get().WriteConfig()) { PutStatus(t_f("Wrote config to {1}")(CZNC::Get().GetConfigFile())); } else { PutStatus(t_s("Error while trying to write config.")); } } else if (sCommand.Equals("LISTCLIENTS")) { CUser* pUser = m_pUser; CString sNick = sLine.Token(1); if (!sNick.empty()) { if (!m_pUser->IsAdmin()) { PutStatus("Usage: ListClients"); return; } pUser = CZNC::Get().FindUser(sNick); if (!pUser) { PutStatus("No such user [" + sNick + "]"); return; } } vector vClients = pUser->GetAllClients(); if (vClients.empty()) { PutStatus("No clients are connected"); return; } CTable Table; Table.AddColumn("Host"); Table.AddColumn("Network"); Table.AddColumn("Identifier"); for (const CClient* pClient : vClients) { Table.AddRow(); Table.SetCell("Host", pClient->GetRemoteIP()); if (pClient->GetNetwork()) { Table.SetCell("Network", pClient->GetNetwork()->GetName()); } Table.SetCell("Identifier", pClient->GetIdentifier()); } PutStatus(Table); } else if (m_pUser->IsAdmin() && sCommand.Equals("LISTUSERS")) { const map& msUsers = CZNC::Get().GetUserMap(); CTable Table; Table.AddColumn("Username"); Table.AddColumn("Networks"); Table.AddColumn("Clients"); for (const auto& it : msUsers) { Table.AddRow(); Table.SetCell("Username", it.first); Table.SetCell("Networks", CString(it.second->GetNetworks().size())); Table.SetCell("Clients", CString(it.second->GetAllClients().size())); } PutStatus(Table); } else if (m_pUser->IsAdmin() && sCommand.Equals("LISTALLUSERNETWORKS")) { const map& msUsers = CZNC::Get().GetUserMap(); CTable Table; Table.AddColumn("Username"); Table.AddColumn("Network"); Table.AddColumn("Clients"); Table.AddColumn("OnIRC"); Table.AddColumn("IRC Server"); Table.AddColumn("IRC User"); Table.AddColumn("Channels"); for (const auto& it : msUsers) { Table.AddRow(); Table.SetCell("Username", it.first); Table.SetCell("Network", "N/A"); Table.SetCell("Clients", CString(it.second->GetUserClients().size())); const vector& vNetworks = it.second->GetNetworks(); for (const CIRCNetwork* pNetwork : vNetworks) { Table.AddRow(); if (pNetwork == vNetworks.back()) { Table.SetCell("Username", "`-"); } else { Table.SetCell("Username", "|-"); } Table.SetCell("Network", pNetwork->GetName()); Table.SetCell("Clients", CString(pNetwork->GetClients().size())); if (pNetwork->IsIRCConnected()) { Table.SetCell("OnIRC", "Yes"); Table.SetCell("IRC Server", pNetwork->GetIRCServer()); Table.SetCell("IRC User", pNetwork->GetIRCNick().GetNickMask()); Table.SetCell("Channels", CString(pNetwork->GetChans().size())); } else { Table.SetCell("OnIRC", "No"); } } } PutStatus(Table); } else if (m_pUser->IsAdmin() && sCommand.Equals("SetMOTD")) { CString sMessage = sLine.Token(1, true); if (sMessage.empty()) { PutStatus("Usage: SetMOTD "); } else { CZNC::Get().SetMotd(sMessage); PutStatus("MOTD set to [" + sMessage + "]"); } } else if (m_pUser->IsAdmin() && sCommand.Equals("AddMOTD")) { CString sMessage = sLine.Token(1, true); if (sMessage.empty()) { PutStatus("Usage: AddMOTD "); } else { CZNC::Get().AddMotd(sMessage); PutStatus("Added [" + sMessage + "] to MOTD"); } } else if (m_pUser->IsAdmin() && sCommand.Equals("ClearMOTD")) { CZNC::Get().ClearMotd(); PutStatus("Cleared MOTD"); } else if (m_pUser->IsAdmin() && sCommand.Equals("BROADCAST")) { CZNC::Get().Broadcast(sLine.Token(1, true)); } else if (m_pUser->IsAdmin() && (sCommand.Equals("SHUTDOWN") || sCommand.Equals("RESTART"))) { bool bRestart = sCommand.Equals("RESTART"); CString sMessage = sLine.Token(1, true); bool bForce = false; if (sMessage.Token(0).Equals("FORCE")) { bForce = true; sMessage = sMessage.Token(1, true); } if (sMessage.empty()) { sMessage = (bRestart ? "ZNC is being restarted NOW!" : "ZNC is being shut down NOW!"); } if (!CZNC::Get().WriteConfig() && !bForce) { PutStatus( "ERROR: Writing config file to disk failed! Aborting. Use " + sCommand.AsUpper() + " FORCE to ignore."); } else { CZNC::Get().Broadcast(sMessage); throw CException(bRestart ? CException::EX_Restart : CException::EX_Shutdown); } } else if (sCommand.Equals("JUMP") || sCommand.Equals("CONNECT")) { if (!m_pNetwork) { PutStatus( "You must be connected with a network to use this command"); return; } if (!m_pNetwork->HasServers()) { PutStatus("You don't have any servers added."); return; } CString sArgs = sLine.Token(1, true); sArgs.Trim(); CServer* pServer = nullptr; if (!sArgs.empty()) { pServer = m_pNetwork->FindServer(sArgs); if (!pServer) { PutStatus("Server [" + sArgs + "] not found"); return; } m_pNetwork->SetNextServer(pServer); // If we are already connecting to some server, // we have to abort that attempt Csock* pIRCSock = GetIRCSock(); if (pIRCSock && !pIRCSock->IsConnected()) { pIRCSock->Close(); } } if (!pServer) { pServer = m_pNetwork->GetNextServer(false); } if (GetIRCSock()) { GetIRCSock()->Quit(); if (pServer) PutStatus("Connecting to [" + pServer->GetName() + "]..."); else PutStatus("Jumping to the next server in the list..."); } else { if (pServer) PutStatus("Connecting to [" + pServer->GetName() + "]..."); else PutStatus("Connecting..."); } m_pNetwork->SetIRCConnectEnabled(true); return; } else if (sCommand.Equals("DISCONNECT")) { if (!m_pNetwork) { PutStatus( "You must be connected with a network to use this command"); return; } if (GetIRCSock()) { CString sQuitMsg = sLine.Token(1, true); GetIRCSock()->Quit(sQuitMsg); } m_pNetwork->SetIRCConnectEnabled(false); PutStatus("Disconnected from IRC. Use 'connect' to reconnect."); return; } else if (sCommand.Equals("ENABLECHAN")) { if (!m_pNetwork) { PutStatus( "You must be connected with a network to use this command"); return; } CString sPatterns = sLine.Token(1, true); if (sPatterns.empty()) { PutStatus("Usage: EnableChan <#chans>"); } else { set sChans = MatchChans(sPatterns); unsigned int uEnabled = 0; for (CChan* pChan : sChans) { if (!pChan->IsDisabled()) continue; uEnabled++; pChan->Enable(); } PutStatus("There were [" + CString(sChans.size()) + "] channels matching [" + sPatterns + "]"); PutStatus("Enabled [" + CString(uEnabled) + "] channels"); } } else if (sCommand.Equals("DISABLECHAN")) { if (!m_pNetwork) { PutStatus( "You must be connected with a network to use this command"); return; } CString sPatterns = sLine.Token(1, true); if (sPatterns.empty()) { PutStatus("Usage: DisableChan <#chans>"); } else { set sChans = MatchChans(sPatterns); unsigned int uDisabled = 0; for (CChan* pChan : sChans) { if (pChan->IsDisabled()) continue; uDisabled++; pChan->Disable(); } PutStatus("There were [" + CString(sChans.size()) + "] channels matching [" + sPatterns + "]"); PutStatus("Disabled [" + CString(uDisabled) + "] channels"); } } else if (sCommand.Equals("LISTCHANS")) { if (!m_pNetwork) { PutStatus( "You must be connected with a network to use this command"); return; } CIRCNetwork* pNetwork = m_pNetwork; const CString sUser = sLine.Token(1); const CString sNetwork = sLine.Token(2); if (!sUser.empty()) { if (!m_pUser->IsAdmin()) { PutStatus(t_s("Usage: ListChans")); return; } CUser* pUser = CZNC::Get().FindUser(sUser); if (!pUser) { PutStatus(t_f("No such user [{1}]")(sUser)); return; } pNetwork = pUser->FindNetwork(sNetwork); if (!pNetwork) { PutStatus(t_f("User [{1}] doesn't have network [{2}]")( sUser, sNetwork)); return; } } const vector& vChans = pNetwork->GetChans(); CIRCSock* pIRCSock = pNetwork->GetIRCSock(); CString sPerms = pIRCSock ? pIRCSock->GetPerms() : ""; if (vChans.empty()) { PutStatus(t_s("There are no channels defined.")); return; } CTable Table; Table.AddColumn(t_s("Name", "listchans")); Table.AddColumn(t_s("Status", "listchans")); Table.AddColumn(t_s("In config", "listchans")); Table.AddColumn(t_s("Buffer", "listchans")); Table.AddColumn(t_s("Clear", "listchans")); Table.AddColumn(t_s("Modes", "listchans")); Table.AddColumn(t_s("Users", "listchans")); for (char cPerm : sPerms) { Table.AddColumn(CString(cPerm)); } unsigned int uNumDetached = 0, uNumDisabled = 0, uNumJoined = 0; for (const CChan* pChan : vChans) { Table.AddRow(); Table.SetCell(t_s("Name", "listchans"), pChan->GetPermStr() + pChan->GetName()); Table.SetCell( t_s("Status", "listchans"), pChan->IsOn() ? (pChan->IsDetached() ? t_s("Detached", "listchans") : t_s("Joined", "listchans")) : (pChan->IsDisabled() ? t_s("Disabled", "listchans") : t_s("Trying", "listchans"))); Table.SetCell( t_s("In config", "listchans"), CString(pChan->InConfig() ? t_s("yes", "listchans") : "")); Table.SetCell(t_s("Buffer", "listchans"), CString(pChan->HasBufferCountSet() ? "*" : "") + CString(pChan->GetBufferCount())); Table.SetCell( t_s("Clear", "listchans"), CString(pChan->HasAutoClearChanBufferSet() ? "*" : "") + CString(pChan->AutoClearChanBuffer() ? t_s("yes", "listchans") : "")); Table.SetCell(t_s("Modes", "listchans"), pChan->GetModeString()); Table.SetCell(t_s("Users", "listchans"), CString(pChan->GetNickCount())); std::map mPerms = pChan->GetPermCounts(); for (char cPerm : sPerms) { Table.SetCell(CString(cPerm), CString(mPerms[cPerm])); } if (pChan->IsDetached()) uNumDetached++; if (pChan->IsOn()) uNumJoined++; if (pChan->IsDisabled()) uNumDisabled++; } PutStatus(Table); PutStatus(t_f("Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}")( vChans.size(), uNumJoined, uNumDetached, uNumDisabled)); } else if (sCommand.Equals("ADDNETWORK")) { if (!m_pUser->IsAdmin() && !m_pUser->HasSpaceForNewNetwork()) { PutStatus(t_s( "Network number limit reached. Ask an admin to increase the " "limit for you, or delete unneeded networks using /znc " "DelNetwork ")); return; } CString sNetwork = sLine.Token(1); if (sNetwork.empty()) { PutStatus(t_s("Usage: AddNetwork ")); return; } if (!CIRCNetwork::IsValidNetwork(sNetwork)) { PutStatus(t_s("Network name should be alphanumeric")); return; } CString sNetworkAddError; if (m_pUser->AddNetwork(sNetwork, sNetworkAddError)) { PutStatus( t_f("Network added. Use /znc JumpNetwork {1}, or connect to " "ZNC with username {2} (instead of just {3}) to connect to " "it.")(sNetwork, m_pUser->GetUserName() + "/" + sNetwork, m_pUser->GetUserName())); } else { PutStatus(t_s("Unable to add that network")); PutStatus(sNetworkAddError); } } else if (sCommand.Equals("DELNETWORK")) { CString sNetwork = sLine.Token(1); if (sNetwork.empty()) { PutStatus(t_s("Usage: DelNetwork ")); return; } if (m_pNetwork && m_pNetwork->GetName().Equals(sNetwork)) { SetNetwork(nullptr); } if (m_pUser->DeleteNetwork(sNetwork)) { PutStatus(t_s("Network deleted")); } else { PutStatus( t_s("Failed to delete network, perhaps this network doesn't " "exist")); } } else if (sCommand.Equals("LISTNETWORKS")) { CUser* pUser = m_pUser; if (m_pUser->IsAdmin() && !sLine.Token(1).empty()) { pUser = CZNC::Get().FindUser(sLine.Token(1)); if (!pUser) { PutStatus(t_f("User {1} not found")(sLine.Token(1))); return; } } const vector& vNetworks = pUser->GetNetworks(); CTable Table; Table.AddColumn(t_s("Network", "listnetworks")); Table.AddColumn(t_s("On IRC", "listnetworks")); Table.AddColumn(t_s("IRC Server", "listnetworks")); Table.AddColumn(t_s("IRC User", "listnetworks")); Table.AddColumn(t_s("Channels", "listnetworks")); for (const CIRCNetwork* pNetwork : vNetworks) { Table.AddRow(); Table.SetCell(t_s("Network", "listnetworks"), pNetwork->GetName()); if (pNetwork->IsIRCConnected()) { Table.SetCell(t_s("On IRC", "listnetworks"), t_s("Yes", "listnetworks")); Table.SetCell(t_s("IRC Server", "listnetworks"), pNetwork->GetIRCServer()); Table.SetCell(t_s("IRC User", "listnetworks"), pNetwork->GetIRCNick().GetNickMask()); Table.SetCell(t_s("Channels", "listnetworks"), CString(pNetwork->GetChans().size())); } else { Table.SetCell(t_s("On IRC", "listnetworks"), t_s("No", "listnetworks")); } } if (PutStatus(Table) == 0) { PutStatus(t_s("No networks", "listnetworks")); } } else if (sCommand.Equals("MOVENETWORK")) { if (!m_pUser->IsAdmin()) { PutStatus(t_s("Access denied.")); return; } CString sOldUser = sLine.Token(1); CString sOldNetwork = sLine.Token(2); CString sNewUser = sLine.Token(3); CString sNewNetwork = sLine.Token(4); if (sOldUser.empty() || sOldNetwork.empty() || sNewUser.empty()) { PutStatus(t_s( "Usage: MoveNetwork [new " "network]")); return; } if (sNewNetwork.empty()) { sNewNetwork = sOldNetwork; } CUser* pOldUser = CZNC::Get().FindUser(sOldUser); if (!pOldUser) { PutStatus(t_f("Old user {1} not found.")(sOldUser)); return; } CIRCNetwork* pOldNetwork = pOldUser->FindNetwork(sOldNetwork); if (!pOldNetwork) { PutStatus(t_f("Old network {1} not found.")(sOldNetwork)); return; } CUser* pNewUser = CZNC::Get().FindUser(sNewUser); if (!pNewUser) { PutStatus(t_f("New user {1} not found.")(sNewUser)); return; } if (pNewUser->FindNetwork(sNewNetwork)) { PutStatus(t_f("User {1} already has network {2}.")(sNewUser, sNewNetwork)); return; } if (!CIRCNetwork::IsValidNetwork(sNewNetwork)) { PutStatus(t_f("Invalid network name [{1}]")(sNewNetwork)); return; } const CModules& vMods = pOldNetwork->GetModules(); for (CModule* pMod : vMods) { CString sOldModPath = pOldNetwork->GetNetworkPath() + "/moddata/" + pMod->GetModName(); CString sNewModPath = pNewUser->GetUserPath() + "/networks/" + sNewNetwork + "/moddata/" + pMod->GetModName(); CDir oldDir(sOldModPath); for (CFile* pFile : oldDir) { if (pFile->GetShortName() != ".registry") { PutStatus( t_f("Some files seem to be in {1}. You might want to " "move them to {2}")(sOldModPath, sNewModPath)); break; } } pMod->MoveRegistry(sNewModPath); } CString sNetworkAddError; CIRCNetwork* pNewNetwork = pNewUser->AddNetwork(sNewNetwork, sNetworkAddError); if (!pNewNetwork) { PutStatus(t_f("Error adding network: {1}")(sNetworkAddError)); return; } pNewNetwork->Clone(*pOldNetwork, false); if (m_pNetwork && m_pNetwork->GetName().Equals(sOldNetwork) && m_pUser == pOldUser) { SetNetwork(nullptr); } if (pOldUser->DeleteNetwork(sOldNetwork)) { PutStatus(t_s("Success.")); } else { PutStatus( t_s("Copied the network to new user, but failed to delete old " "network")); } } else if (sCommand.Equals("JUMPNETWORK")) { CString sNetwork = sLine.Token(1); if (sNetwork.empty()) { PutStatus(t_s("No network supplied.")); return; } if (m_pNetwork && (m_pNetwork->GetName() == sNetwork)) { PutStatus(t_s("You are already connected with this network.")); return; } CIRCNetwork* pNetwork = m_pUser->FindNetwork(sNetwork); if (pNetwork) { PutStatus(t_f("Switched to {1}")(sNetwork)); SetNetwork(pNetwork); } else { PutStatus(t_f("You don't have a network named {1}")(sNetwork)); } } else if (sCommand.Equals("ADDSERVER")) { CString sServer = sLine.Token(1); if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } if (sServer.empty()) { PutStatus(t_s("Usage: AddServer [[+]port] [pass]")); return; } if (m_pNetwork->AddServer(sLine.Token(1, true))) { PutStatus(t_s("Server added")); } else { PutStatus( t_s("Unable to add that server. Perhaps the server is already " "added or openssl is disabled?")); } } else if (sCommand.Equals("REMSERVER") || sCommand.Equals("DELSERVER")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } CString sServer = sLine.Token(1); unsigned short uPort = sLine.Token(2).ToUShort(); CString sPass = sLine.Token(3); if (sServer.empty()) { PutStatus(t_s("Usage: DelServer [port] [pass]")); return; } if (!m_pNetwork->HasServers()) { PutStatus(t_s("You don't have any servers added.")); return; } if (m_pNetwork->DelServer(sServer, uPort, sPass)) { PutStatus(t_s("Server removed")); } else { PutStatus(t_s("No such server")); } } else if (sCommand.Equals("LISTSERVERS")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } if (m_pNetwork->HasServers()) { const vector& vServers = m_pNetwork->GetServers(); CServer* pCurServ = m_pNetwork->GetCurrentServer(); CTable Table; Table.AddColumn(t_s("Host", "listservers")); Table.AddColumn(t_s("Port", "listservers")); Table.AddColumn(t_s("SSL", "listservers")); Table.AddColumn(t_s("Password", "listservers")); for (const CServer* pServer : vServers) { Table.AddRow(); Table.SetCell(t_s("Host", "listservers"), pServer->GetName() + (pServer == pCurServ ? "*" : "")); Table.SetCell(t_s("Port", "listservers"), CString(pServer->GetPort())); Table.SetCell( t_s("SSL", "listservers"), (pServer->IsSSL()) ? t_s("SSL", "listservers|cell") : ""); Table.SetCell(t_s("Password", "listservers"), pServer->GetPass().empty() ? "" : "******"); } PutStatus(Table); } else { PutStatus(t_s("You don't have any servers added.")); } } else if (sCommand.Equals("AddTrustedServerFingerprint")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } CString sFP = sLine.Token(1); if (sFP.empty()) { PutStatus(t_s("Usage: AddTrustedServerFingerprint ")); return; } m_pNetwork->AddTrustedFingerprint(sFP); PutStatus(t_s("Done.")); } else if (sCommand.Equals("DelTrustedServerFingerprint")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } CString sFP = sLine.Token(1); if (sFP.empty()) { PutStatus(t_s("Usage: DelTrustedServerFingerprint ")); return; } m_pNetwork->DelTrustedFingerprint(sFP); PutStatus(t_s("Done.")); } else if (sCommand.Equals("ListTrustedServerFingerprints")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } const SCString& ssFPs = m_pNetwork->GetTrustedFingerprints(); if (ssFPs.empty()) { PutStatus(t_s("No fingerprints added.")); } else { int k = 0; for (const CString& sFP : ssFPs) { PutStatus(CString(++k) + ". " + sFP); } } } else if (sCommand.Equals("TOPICS")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } const vector& vChans = m_pNetwork->GetChans(); CTable Table; Table.AddColumn(t_s("Channel", "topicscmd")); Table.AddColumn(t_s("Set By", "topicscmd")); Table.AddColumn(t_s("Topic", "topicscmd")); for (const CChan* pChan : vChans) { Table.AddRow(); Table.SetCell(t_s("Channel", "topicscmd"), pChan->GetName()); Table.SetCell(t_s("Set By", "topicscmd"), pChan->GetTopicOwner()); Table.SetCell(t_s("Topic", "topicscmd"), pChan->GetTopic()); } PutStatus(Table); } else if (sCommand.Equals("LISTMODS") || sCommand.Equals("LISTMODULES")) { const auto PrintModules = [this](const CModules& Modules) { CTable Table; Table.AddColumn(t_s("Name", "listmods")); Table.AddColumn(t_s("Arguments", "listmods")); for (const CModule* pMod : Modules) { Table.AddRow(); Table.SetCell(t_s("Name", "listmods"), pMod->GetModName()); Table.SetCell(t_s("Arguments", "listmods"), pMod->GetArgs()); } PutStatus(Table); }; if (m_pUser->IsAdmin()) { const CModules& GModules = CZNC::Get().GetModules(); if (!GModules.size()) { PutStatus(t_s("No global modules loaded.")); } else { PutStatus(t_s("Global modules:")); PrintModules(GModules); } } const CModules& UModules = m_pUser->GetModules(); if (!UModules.size()) { PutStatus(t_s("Your user has no modules loaded.")); } else { PutStatus(t_s("User modules:")); PrintModules(UModules); } if (m_pNetwork) { const CModules& NetworkModules = m_pNetwork->GetModules(); if (NetworkModules.empty()) { PutStatus(t_s("This network has no modules loaded.")); } else { PutStatus(t_s("Network modules:")); PrintModules(NetworkModules); } } return; } else if (sCommand.Equals("LISTAVAILMODS") || sCommand.Equals("LISTAVAILABLEMODULES")) { if (m_pUser->DenyLoadMod()) { PutStatus(t_s("Access denied.")); return; } const auto PrintModules = [this](const set& ssModules) { CTable Table; Table.AddColumn(t_s("Name", "listavailmods")); Table.AddColumn(t_s("Description", "listavailmods")); for (const CModInfo& Info : ssModules) { Table.AddRow(); Table.SetCell( t_s("Name", "listavailmods"), (CZNC::Get().GetModules().FindModule(Info.GetName()) ? "*" : " ") + Info.GetName()); Table.SetCell(t_s("Description", "listavailmods"), Info.GetDescription().Ellipsize(128)); } PutStatus(Table); }; if (m_pUser->IsAdmin()) { set ssGlobalMods; CZNC::Get().GetModules().GetAvailableMods(ssGlobalMods, CModInfo::GlobalModule); if (ssGlobalMods.empty()) { PutStatus(t_s("No global modules available.")); } else { PutStatus(t_s("Global modules:")); PrintModules(ssGlobalMods); } } set ssUserMods; CZNC::Get().GetModules().GetAvailableMods(ssUserMods); if (ssUserMods.empty()) { PutStatus(t_s("No user modules available.")); } else { PutStatus(t_s("User modules:")); PrintModules(ssUserMods); } set ssNetworkMods; CZNC::Get().GetModules().GetAvailableMods(ssNetworkMods, CModInfo::NetworkModule); if (ssNetworkMods.empty()) { PutStatus(t_s("No network modules available.")); } else { PutStatus(t_s("Network modules:")); PrintModules(ssNetworkMods); } return; } else if (sCommand.Equals("LOADMOD") || sCommand.Equals("LOADMODULE")) { CModInfo::EModuleType eType; CString sType = sLine.Token(1); CString sMod = sLine.Token(2); CString sArgs = sLine.Token(3, true); // TODO use proper library for parsing arguments if (sType.Equals("--type=global")) { eType = CModInfo::GlobalModule; } else if (sType.Equals("--type=user")) { eType = CModInfo::UserModule; } else if (sType.Equals("--type=network")) { eType = CModInfo::NetworkModule; } else { sMod = sType; sArgs = sLine.Token(2, true); sType = "default"; // Will be set correctly later eType = CModInfo::UserModule; } if (m_pUser->DenyLoadMod()) { PutStatus(t_f("Unable to load {1}: Access denied.")(sMod)); return; } if (sMod.empty()) { PutStatus(t_s( "Usage: LoadMod [--type=global|user|network] [args]")); return; } CModInfo ModInfo; CString sRetMsg; if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sMod, sRetMsg)) { PutStatus(t_f("Unable to load {1}: {2}")(sMod, sRetMsg)); return; } if (sType.Equals("default")) { eType = ModInfo.GetDefaultType(); } if (eType == CModInfo::GlobalModule && !m_pUser->IsAdmin()) { PutStatus( t_f("Unable to load global module {1}: Access denied.")(sMod)); return; } if (eType == CModInfo::NetworkModule && !m_pNetwork) { PutStatus( t_f("Unable to load network module {1}: Not connected with a " "network.")(sMod)); return; } CString sModRet; bool bLoaded = false; switch (eType) { case CModInfo::GlobalModule: bLoaded = CZNC::Get().GetModules().LoadModule( sMod, sArgs, eType, nullptr, nullptr, sModRet); break; case CModInfo::UserModule: bLoaded = m_pUser->GetModules().LoadModule(sMod, sArgs, eType, m_pUser, nullptr, sModRet); break; case CModInfo::NetworkModule: bLoaded = m_pNetwork->GetModules().LoadModule( sMod, sArgs, eType, m_pUser, m_pNetwork, sModRet); break; default: sModRet = t_s("Unknown module type"); } if (bLoaded) { if (sModRet.empty()) { PutStatus(t_f("Loaded module {1}")(sMod)); } else { PutStatus(t_f("Loaded module {1}: {2}")(sMod, sModRet)); } } else { PutStatus(t_f("Unable to load module {1}: {2}")(sMod, sModRet)); } return; } else if (sCommand.Equals("UNLOADMOD") || sCommand.Equals("UNLOADMODULE")) { CModInfo::EModuleType eType = CModInfo::UserModule; CString sType = sLine.Token(1); CString sMod = sLine.Token(2); // TODO use proper library for parsing arguments if (sType.Equals("--type=global")) { eType = CModInfo::GlobalModule; } else if (sType.Equals("--type=user")) { eType = CModInfo::UserModule; } else if (sType.Equals("--type=network")) { eType = CModInfo::NetworkModule; } else { sMod = sType; sType = "default"; } if (m_pUser->DenyLoadMod()) { PutStatus(t_f("Unable to unload {1}: Access denied.")(sMod)); return; } if (sMod.empty()) { PutStatus( t_s("Usage: UnloadMod [--type=global|user|network] ")); return; } if (sType.Equals("default")) { CModInfo ModInfo; CString sRetMsg; if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sMod, sRetMsg)) { PutStatus( t_f("Unable to determine type of {1}: {2}")(sMod, sRetMsg)); return; } eType = ModInfo.GetDefaultType(); } if (eType == CModInfo::GlobalModule && !m_pUser->IsAdmin()) { PutStatus(t_f("Unable to unload global module {1}: Access denied.")( sMod)); return; } if (eType == CModInfo::NetworkModule && !m_pNetwork) { PutStatus( t_f("Unable to unload network module {1}: Not connected with a " "network.")(sMod)); return; } CString sModRet; switch (eType) { case CModInfo::GlobalModule: CZNC::Get().GetModules().UnloadModule(sMod, sModRet); break; case CModInfo::UserModule: m_pUser->GetModules().UnloadModule(sMod, sModRet); break; case CModInfo::NetworkModule: m_pNetwork->GetModules().UnloadModule(sMod, sModRet); break; default: sModRet = t_f( "Unable to unload module {1}: Unknown module type")(sMod); } PutStatus(sModRet); return; } else if (sCommand.Equals("RELOADMOD") || sCommand.Equals("RELOADMODULE")) { CModInfo::EModuleType eType; CString sType = sLine.Token(1); CString sMod = sLine.Token(2); CString sArgs = sLine.Token(3, true); if (m_pUser->DenyLoadMod()) { PutStatus(t_s("Unable to reload modules. Access denied.")); return; } // TODO use proper library for parsing arguments if (sType.Equals("--type=global")) { eType = CModInfo::GlobalModule; } else if (sType.Equals("--type=user")) { eType = CModInfo::UserModule; } else if (sType.Equals("--type=network")) { eType = CModInfo::NetworkModule; } else { sMod = sType; sArgs = sLine.Token(2, true); sType = "default"; // Will be set correctly later eType = CModInfo::UserModule; } if (sMod.empty()) { PutStatus( t_s("Usage: ReloadMod [--type=global|user|network] " "[args]")); return; } if (sType.Equals("default")) { CModInfo ModInfo; CString sRetMsg; if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sMod, sRetMsg)) { PutStatus(t_f("Unable to reload {1}: {2}")(sMod, sRetMsg)); return; } eType = ModInfo.GetDefaultType(); } if (eType == CModInfo::GlobalModule && !m_pUser->IsAdmin()) { PutStatus(t_f("Unable to reload global module {1}: Access denied.")( sMod)); return; } if (eType == CModInfo::NetworkModule && !m_pNetwork) { PutStatus( t_f("Unable to reload network module {1}: Not connected with a " "network.")(sMod)); return; } CString sModRet; switch (eType) { case CModInfo::GlobalModule: CZNC::Get().GetModules().ReloadModule(sMod, sArgs, nullptr, nullptr, sModRet); break; case CModInfo::UserModule: m_pUser->GetModules().ReloadModule(sMod, sArgs, m_pUser, nullptr, sModRet); break; case CModInfo::NetworkModule: m_pNetwork->GetModules().ReloadModule(sMod, sArgs, m_pUser, m_pNetwork, sModRet); break; default: sModRet = t_f( "Unable to reload module {1}: Unknown module type")(sMod); } PutStatus(sModRet); return; } else if ((sCommand.Equals("UPDATEMOD") || sCommand.Equals("UPDATEMODULE")) && m_pUser->IsAdmin()) { CString sMod = sLine.Token(1); if (sMod.empty()) { PutStatus(t_s("Usage: UpdateMod ")); return; } PutStatus(t_f("Reloading {1} everywhere")(sMod)); if (CZNC::Get().UpdateModule(sMod)) { PutStatus(t_s("Done")); } else { PutStatus( t_f("Done, but there were errors, module {1} could not be " "reloaded everywhere.")(sMod)); } } else if ((sCommand.Equals("SETBINDHOST") || sCommand.Equals("SETVHOST")) && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command. Try " "SetUserBindHost instead")); return; } CString sArg = sLine.Token(1); if (sArg.empty()) { PutStatus(t_s("Usage: SetBindHost ")); return; } if (sArg.Equals(m_pNetwork->GetBindHost())) { PutStatus(t_s("You already have this bind host!")); return; } m_pNetwork->SetBindHost(sArg); PutStatus(t_f("Set bind host for network {1} to {2}")( m_pNetwork->GetName(), m_pNetwork->GetBindHost())); } else if (sCommand.Equals("SETUSERBINDHOST") && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { CString sArg = sLine.Token(1); if (sArg.empty()) { PutStatus(t_s("Usage: SetUserBindHost ")); return; } if (sArg.Equals(m_pUser->GetBindHost())) { PutStatus(t_s("You already have this bind host!")); return; } m_pUser->SetBindHost(sArg); PutStatus(t_f("Set default bind host to {1}")(m_pUser->GetBindHost())); } else if ((sCommand.Equals("CLEARBINDHOST") || sCommand.Equals("CLEARVHOST")) && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command. Try " "ClearUserBindHost instead")); return; } m_pNetwork->SetBindHost(""); PutStatus(t_s("Bind host cleared for this network.")); } else if (sCommand.Equals("CLEARUSERBINDHOST") && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { m_pUser->SetBindHost(""); PutStatus(t_s("Default bind host cleared for your user.")); } else if (sCommand.Equals("SHOWBINDHOST")) { if (m_pUser->GetBindHost().empty()) { PutStatus(t_s("This user's default bind host not set")); } else { PutStatus(t_f("This user's default bind host is {1}")( m_pUser->GetBindHost())); } if (m_pNetwork) { if (m_pNetwork->GetBindHost().empty()) { PutStatus(t_s("This network's bind host not set")); } else { PutStatus(t_f("This network's default bind host is {1}")( m_pNetwork->GetBindHost())); } } } else if (sCommand.Equals("PLAYBUFFER")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } CString sBuffer = sLine.Token(1); if (sBuffer.empty()) { PutStatus(t_s("Usage: PlayBuffer <#chan|query>")); return; } if (m_pNetwork->IsChan(sBuffer)) { CChan* pChan = m_pNetwork->FindChan(sBuffer); if (!pChan) { PutStatus(t_f("You are not on {1}")(sBuffer)); return; } if (!pChan->IsOn()) { PutStatus(t_f("You are not on {1} (trying to join)")(sBuffer)); return; } if (pChan->GetBuffer().IsEmpty()) { PutStatus(t_f("The buffer for channel {1} is empty")(sBuffer)); return; } pChan->SendBuffer(this); } else { CQuery* pQuery = m_pNetwork->FindQuery(sBuffer); if (!pQuery) { PutStatus(t_f("No active query with {1}")(sBuffer)); return; } if (pQuery->GetBuffer().IsEmpty()) { PutStatus(t_f("The buffer for {1} is empty")(sBuffer)); return; } pQuery->SendBuffer(this); } } else if (sCommand.Equals("CLEARBUFFER")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } CString sBuffer = sLine.Token(1); if (sBuffer.empty()) { PutStatus(t_s("Usage: ClearBuffer <#chan|query>")); return; } unsigned int uMatches = 0; vector vChans = m_pNetwork->FindChans(sBuffer); for (CChan* pChan : vChans) { uMatches++; pChan->ClearBuffer(); } vector vQueries = m_pNetwork->FindQueries(sBuffer); for (CQuery* pQuery : vQueries) { uMatches++; m_pNetwork->DelQuery(pQuery->GetName()); } PutStatus(t_p("{1} buffer matching {2} has been cleared", "{1} buffers matching {2} have been cleared", uMatches)(uMatches, sBuffer)); } else if (sCommand.Equals("CLEARALLCHANNELBUFFERS")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } for (CChan* pChan : m_pNetwork->GetChans()) { pChan->ClearBuffer(); } PutStatus(t_s("All channel buffers have been cleared")); } else if (sCommand.Equals("CLEARALLQUERYBUFFERS")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } m_pNetwork->ClearQueryBuffer(); PutStatus(t_s("All query buffers have been cleared")); } else if (sCommand.Equals("CLEARALLBUFFERS")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } for (CChan* pChan : m_pNetwork->GetChans()) { pChan->ClearBuffer(); } m_pNetwork->ClearQueryBuffer(); PutStatus(t_s("All buffers have been cleared")); } else if (sCommand.Equals("SETBUFFER")) { if (!m_pNetwork) { PutStatus(t_s( "You must be connected with a network to use this command")); return; } CString sBuffer = sLine.Token(1); if (sBuffer.empty()) { PutStatus(t_s("Usage: SetBuffer <#chan|query> [linecount]")); return; } unsigned int uLineCount = sLine.Token(2).ToUInt(); unsigned int uMatches = 0, uFail = 0; vector vChans = m_pNetwork->FindChans(sBuffer); for (CChan* pChan : vChans) { uMatches++; if (!pChan->SetBufferCount(uLineCount)) uFail++; } vector vQueries = m_pNetwork->FindQueries(sBuffer); for (CQuery* pQuery : vQueries) { uMatches++; if (!pQuery->SetBufferCount(uLineCount)) uFail++; } if (uFail > 0) { PutStatus(t_p("Setting buffer size failed for {1} buffer", "Setting buffer size failed for {1} buffers", uFail)(uFail)); PutStatus(t_p("Maximum buffer size is {1} line", "Maximum buffer size is {1} lines", CZNC::Get().GetMaxBufferSize())( CZNC::Get().GetMaxBufferSize())); } else { PutStatus(t_p("Size of every buffer was set to {1} line", "Size of every buffer was set to {1} lines", uLineCount)(uLineCount)); } } else if (m_pUser->IsAdmin() && sCommand.Equals("TRAFFIC")) { CZNC::TrafficStatsPair Users, ZNC, Total; CZNC::TrafficStatsMap traffic = CZNC::Get().GetTrafficStats(Users, ZNC, Total); CTable Table; Table.AddColumn(t_s("Username", "trafficcmd")); Table.AddColumn(t_s("In", "trafficcmd")); Table.AddColumn(t_s("Out", "trafficcmd")); Table.AddColumn(t_s("Total", "trafficcmd")); for (const auto& it : traffic) { Table.AddRow(); Table.SetCell(t_s("Username", "trafficcmd"), it.first); Table.SetCell(t_s("In", "trafficcmd"), CString::ToByteStr(it.second.first)); Table.SetCell(t_s("Out", "trafficcmd"), CString::ToByteStr(it.second.second)); Table.SetCell( t_s("Total", "trafficcmd"), CString::ToByteStr(it.second.first + it.second.second)); } Table.AddRow(); Table.SetCell(t_s("Username", "trafficcmd"), t_s("", "trafficcmd")); Table.SetCell(t_s("In", "trafficcmd"), CString::ToByteStr(Users.first)); Table.SetCell(t_s("Out", "trafficcmd"), CString::ToByteStr(Users.second)); Table.SetCell(t_s("Total", "trafficcmd"), CString::ToByteStr(Users.first + Users.second)); Table.AddRow(); Table.SetCell(t_s("Username", "trafficcmd"), t_s("", "trafficcmd")); Table.SetCell(t_s("In", "trafficcmd"), CString::ToByteStr(ZNC.first)); Table.SetCell(t_s("Out", "trafficcmd"), CString::ToByteStr(ZNC.second)); Table.SetCell(t_s("Total", "trafficcmd"), CString::ToByteStr(ZNC.first + ZNC.second)); Table.AddRow(); Table.SetCell(t_s("Username", "trafficcmd"), t_s("", "trafficcmd")); Table.SetCell(t_s("In", "trafficcmd"), CString::ToByteStr(Total.first)); Table.SetCell(t_s("Out", "trafficcmd"), CString::ToByteStr(Total.second)); Table.SetCell(t_s("Total", "trafficcmd"), CString::ToByteStr(Total.first + Total.second)); PutStatus(Table); } else if (sCommand.Equals("UPTIME")) { PutStatus(t_f("Running for {1}")(CZNC::Get().GetUptime())); } else if (m_pUser->IsAdmin() && (sCommand.Equals("LISTPORTS") || sCommand.Equals("ADDPORT") || sCommand.Equals("DELPORT"))) { UserPortCommand(sLine); } else { PutStatus(t_s("Unknown command, try 'Help'")); } } void CClient::UserPortCommand(CString& sLine) { const CString sCommand = sLine.Token(0); if (sCommand.Equals("LISTPORTS")) { CTable Table; Table.AddColumn(t_s("Port", "listports")); Table.AddColumn(t_s("BindHost", "listports")); Table.AddColumn(t_s("SSL", "listports")); Table.AddColumn(t_s("Protocol", "listports")); Table.AddColumn(t_s("IRC", "listports")); Table.AddColumn(t_s("Web", "listports")); const vector& vpListeners = CZNC::Get().GetListeners(); for (const CListener* pListener : vpListeners) { Table.AddRow(); Table.SetCell(t_s("Port", "listports"), CString(pListener->GetPort())); Table.SetCell(t_s("BindHost", "listports"), (pListener->GetBindHost().empty() ? CString("*") : pListener->GetBindHost())); Table.SetCell(t_s("SSL", "listports"), pListener->IsSSL() ? t_s("yes", "listports|ssl") : t_s("no", "listports|ssl")); EAddrType eAddr = pListener->GetAddrType(); Table.SetCell(t_s("Protocol", "listports"), eAddr == ADDR_ALL ? t_s("IPv4 and IPv6", "listports") : (eAddr == ADDR_IPV4ONLY ? t_s("IPv4", "listports") : t_s("IPv6", "listports"))); CListener::EAcceptType eAccept = pListener->GetAcceptType(); Table.SetCell(t_s("IRC", "listports"), eAccept == CListener::ACCEPT_ALL || eAccept == CListener::ACCEPT_IRC ? t_s("yes", "listports|irc") : t_s("no", "listports|irc")); Table.SetCell(t_s("Web", "listports"), eAccept == CListener::ACCEPT_ALL || eAccept == CListener::ACCEPT_HTTP ? t_f("yes, on {1}", "listports|irc")( pListener->GetURIPrefix() + "/") : t_s("no", "listports|web")); } PutStatus(Table); return; } CString sPort = sLine.Token(1); CString sAddr = sLine.Token(2); EAddrType eAddr = ADDR_ALL; if (sAddr.Equals("IPV4")) { eAddr = ADDR_IPV4ONLY; } else if (sAddr.Equals("IPV6")) { eAddr = ADDR_IPV6ONLY; } else if (sAddr.Equals("ALL")) { eAddr = ADDR_ALL; } else { sAddr.clear(); } unsigned short uPort = sPort.ToUShort(); if (sCommand.Equals("ADDPORT")) { CListener::EAcceptType eAccept = CListener::ACCEPT_ALL; CString sAccept = sLine.Token(3); if (sAccept.Equals("WEB")) { eAccept = CListener::ACCEPT_HTTP; } else if (sAccept.Equals("IRC")) { eAccept = CListener::ACCEPT_IRC; } else if (sAccept.Equals("ALL")) { eAccept = CListener::ACCEPT_ALL; } else { sAccept.clear(); } if (sPort.empty() || sAddr.empty() || sAccept.empty()) { PutStatus( t_s("Usage: AddPort <[+]port> " "[bindhost [uriprefix]]")); } else { bool bSSL = (sPort.StartsWith("+")); const CString sBindHost = sLine.Token(4); const CString sURIPrefix = sLine.Token(5); CListener* pListener = new CListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept); if (!pListener->Listen()) { auto e = errno; delete pListener; PutStatus(t_f("Unable to bind: {1}")(CString(strerror(e)))); } else { if (CZNC::Get().AddListener(pListener)) { PutStatus(t_s("Port added")); } else { PutStatus(t_s("Couldn't add port")); } } } } else if (sCommand.Equals("DELPORT")) { if (sPort.empty() || sAddr.empty()) { PutStatus(t_s("Usage: DelPort [bindhost]")); } else { const CString sBindHost = sLine.Token(3); CListener* pListener = CZNC::Get().FindListener(uPort, sBindHost, eAddr); if (pListener) { CZNC::Get().DelListener(pListener); PutStatus(t_s("Deleted Port")); } else { PutStatus(t_s("Unable to find a matching port")); } } } } void CClient::HelpUser(const CString& sFilter) { CTable Table; Table.AddColumn(t_s("Command", "helpcmd")); Table.AddColumn(t_s("Description", "helpcmd")); if (sFilter.empty()) { PutStatus( t_s("In the following list all occurrences of <#chan> support " "wildcards (* and ?) except ListNicks")); } const auto AddCommandHelp = [&](const CString& sCmd, const CString& sArgs, const CString& sDesc) { if (sFilter.empty() || sCmd.StartsWith(sFilter) || sCmd.AsLower().WildCmp(sFilter.AsLower())) { Table.AddRow(); Table.SetCell(t_s("Command", "helpcmd"), sCmd + " " + sArgs); Table.SetCell(t_s("Description", "helpcmd"), sDesc); } }; AddCommandHelp( "Version", "", t_s("Print which version of ZNC this is", "helpcmd|Version|desc")); AddCommandHelp("ListMods", "", t_s("List all loaded modules", "helpcmd|ListMods|desc")); AddCommandHelp( "ListAvailMods", "", t_s("List all available modules", "helpcmd|ListAvailMods|desc")); if (!m_pUser->IsAdmin()) { // If they are an admin we will add this command below with an argument AddCommandHelp("ListChans", "", t_s("List all channels", "helpcmd|ListChans|desc")); } AddCommandHelp( "ListNicks", t_s("<#chan>", "helpcmd|ListNicks|args"), t_s("List all nicks on a channel", "helpcmd|ListNicks|desc")); if (!m_pUser->IsAdmin()) { AddCommandHelp("ListClients", "", t_s("List all clients connected to your ZNC user", "helpcmd|ListClients|desc")); } AddCommandHelp("ListServers", "", t_s("List all servers of current IRC network", "helpcmd|ListServers|desc")); AddCommandHelp( "AddNetwork", t_s("", "helpcmd|AddNetwork|args"), t_s("Add a network to your user", "helpcmd|AddNetwork|desc")); AddCommandHelp( "DelNetwork", t_s("", "helpcmd|DelNetwork|args"), t_s("Delete a network from your user", "helpcmd|DelNetwork|desc")); AddCommandHelp("ListNetworks", "", t_s("List all networks", "helpcmd|ListNetworks|desc")); if (m_pUser->IsAdmin()) { AddCommandHelp("MoveNetwork", t_s(" [new network]", "helpcmd|MoveNetwork|args"), t_s("Move an IRC network from one user to another", "helpcmd|MoveNetwork|desc")); } AddCommandHelp( "JumpNetwork", t_s("", "helpcmd|JumpNetwork|args"), t_s("Jump to another network (Alternatively, you can connect to ZNC " "several times, using `user/network` as username)", "helpcmd|JumpNetwork|desc")); AddCommandHelp("AddServer", t_s(" [[+]port] [pass]", "helpcmd|AddServer|args"), t_s("Add a server to the list of alternate/backup servers " "of current IRC network.", "helpcmd|AddServer|desc")); AddCommandHelp("DelServer", t_s(" [port] [pass]", "helpcmd|DelServer|args"), t_s("Remove a server from the list of alternate/backup " "servers of current IRC network", "helpcmd|DelServer|desc")); AddCommandHelp( "AddTrustedServerFingerprint", t_s("", "helpcmd|AddTrustedServerFingerprint|args"), t_s("Add a trusted server SSL certificate fingerprint (SHA-256) to " "current IRC network.", "helpcmd|AddTrustedServerFingerprint|desc")); AddCommandHelp( "DelTrustedServerFingerprint", t_s("", "helpcmd|DelTrustedServerFingerprint|args"), t_s("Delete a trusted server SSL certificate from current IRC network.", "helpcmd|DelTrustedServerFingerprint|desc")); AddCommandHelp( "ListTrustedServerFingerprints", "", t_s("List all trusted server SSL certificates of current IRC network.", "helpcmd|ListTrustedServerFingerprints|desc")); AddCommandHelp("EnableChan", t_s("<#chans>", "helpcmd|EnableChan|args"), t_s("Enable channels", "helpcmd|EnableChan|desc")); AddCommandHelp("DisableChan", t_s("<#chans>", "helpcmd|DisableChan|args"), t_s("Disable channels", "helpcmd|DisableChan|desc")); AddCommandHelp("Attach", t_s("<#chans>", "helpcmd|Attach|args"), t_s("Attach to channels", "helpcmd|Attach|desc")); AddCommandHelp("Detach", t_s("<#chans>", "helpcmd|Detach|args"), t_s("Detach from channels", "helpcmd|Detach|desc")); AddCommandHelp( "Topics", "", t_s("Show topics in all your channels", "helpcmd|Topics|desc")); AddCommandHelp( "PlayBuffer", t_s("<#chan|query>", "helpcmd|PlayBuffer|args"), t_s("Play back the specified buffer", "helpcmd|PlayBuffer|desc")); AddCommandHelp( "ClearBuffer", t_s("<#chan|query>", "helpcmd|ClearBuffer|args"), t_s("Clear the specified buffer", "helpcmd|ClearBuffer|desc")); AddCommandHelp("ClearAllBuffers", "", t_s("Clear all channel and query buffers", "helpcmd|ClearAllBuffers|desc")); AddCommandHelp("ClearAllChannelBuffers", "", t_s("Clear the channel buffers", "helpcmd|ClearAllChannelBuffers|desc")); AddCommandHelp( "ClearAllQueryBuffers", "", t_s("Clear the query buffers", "helpcmd|ClearAllQueryBuffers|desc")); AddCommandHelp("SetBuffer", t_s("<#chan|query> [linecount]", "helpcmd|SetBuffer|args"), t_s("Set the buffer count", "helpcmd|SetBuffer|desc")); if (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost()) { AddCommandHelp("SetBindHost", t_s("", "helpcmd|SetBindHost|args"), t_s("Set the bind host for this network", "helpcmd|SetBindHost|desc")); AddCommandHelp( "SetUserBindHost", t_s("", "helpcmd|SetUserBindHost|args"), t_s("Set the default bind host for this user", "helpcmd|SetUserBindHost|desc")); AddCommandHelp("ClearBindHost", "", t_s("Clear the bind host for this network", "helpcmd|ClearBindHost|desc")); AddCommandHelp("ClearUserBindHost", "", t_s("Clear the default bind host for this user", "helpcmd|ClearUserBindHost|desc")); } AddCommandHelp( "ShowBindHost", "", t_s("Show currently selected bind host", "helpcmd|ShowBindHost|desc")); AddCommandHelp( "Jump", t_s("[server]", "helpcmd|Jump|args"), t_s("Jump to the next or the specified server", "helpcmd|Jump|desc")); AddCommandHelp("Disconnect", t_s("[message]", "helpcmd|Disconnect|args"), t_s("Disconnect from IRC", "helpcmd|Disconnect|desc")); AddCommandHelp("Connect", "", t_s("Reconnect to IRC", "helpcmd|Connect|desc")); AddCommandHelp( "Uptime", "", t_s("Show for how long ZNC has been running", "helpcmd|Uptime|desc")); if (!m_pUser->DenyLoadMod()) { AddCommandHelp("LoadMod", t_s("[--type=global|user|network] [args]", "helpcmd|LoadMod|args"), t_s("Load a module", "helpcmd|LoadMod|desc")); AddCommandHelp("UnloadMod", t_s("[--type=global|user|network] ", "helpcmd|UnloadMod|args"), t_s("Unload a module", "helpcmd|UnloadMod|desc")); AddCommandHelp("ReloadMod", t_s("[--type=global|user|network] [args]", "helpcmd|ReloadMod|args"), t_s("Reload a module", "helpcmd|ReloadMod|desc")); if (m_pUser->IsAdmin()) { AddCommandHelp( "UpdateMod", t_s("", "helpcmd|UpdateMod|args"), t_s("Reload a module everywhere", "helpcmd|UpdateMod|desc")); } } AddCommandHelp( "ShowMOTD", "", t_s("Show ZNC's message of the day", "helpcmd|ShowMOTD|desc")); if (m_pUser->IsAdmin()) { AddCommandHelp( "SetMOTD", t_s("", "helpcmd|SetMOTD|args"), t_s("Set ZNC's message of the day", "helpcmd|SetMOTD|desc")); AddCommandHelp( "AddMOTD", t_s("", "helpcmd|AddMOTD|args"), t_s("Append to ZNC's MOTD", "helpcmd|AddMOTD|desc")); AddCommandHelp("ClearMOTD", "", t_s("Clear ZNC's MOTD", "helpcmd|ClearMOTD|desc")); AddCommandHelp( "ListPorts", "", t_s("Show all active listeners", "helpcmd|ListPorts|desc")); AddCommandHelp("AddPort", t_s("<[+]port> [bindhost " "[uriprefix]]", "helpcmd|AddPort|args"), t_s("Add another port for ZNC to listen on", "helpcmd|AddPort|desc")); AddCommandHelp( "DelPort", t_s(" [bindhost]", "helpcmd|DelPort|args"), t_s("Remove a port from ZNC", "helpcmd|DelPort|desc")); AddCommandHelp( "Rehash", "", t_s("Reload global settings, modules, and listeners from znc.conf", "helpcmd|Rehash|desc")); AddCommandHelp("SaveConfig", "", t_s("Save the current settings to disk", "helpcmd|SaveConfig|desc")); AddCommandHelp("ListUsers", "", t_s("List all ZNC users and their connection status", "helpcmd|ListUsers|desc")); AddCommandHelp("ListAllUserNetworks", "", t_s("List all ZNC users and their networks", "helpcmd|ListAllUserNetworks|desc")); AddCommandHelp("ListChans", t_s("[user ]", "helpcmd|ListChans|args"), t_s("List all channels", "helpcmd|ListChans|desc")); AddCommandHelp( "ListClients", t_s("[user]", "helpcmd|ListClients|args"), t_s("List all connected clients", "helpcmd|ListClients|desc")); AddCommandHelp("Traffic", "", t_s("Show basic traffic stats for all ZNC users", "helpcmd|Traffic|desc")); AddCommandHelp("Broadcast", t_s("[message]", "helpcmd|Broadcast|args"), t_s("Broadcast a message to all ZNC users", "helpcmd|Broadcast|desc")); AddCommandHelp( "Shutdown", t_s("[message]", "helpcmd|Shutdown|args"), t_s("Shut down ZNC completely", "helpcmd|Shutdown|desc")); AddCommandHelp("Restart", t_s("[message]", "helpcmd|Restart|args"), t_s("Restart ZNC", "helpcmd|Restart|desc")); } if (Table.empty()) { PutStatus(t_f("No matches for '{1}'")(sFilter)); } else { PutStatus(Table); } } znc-1.7.5/src/Socket.cpp0000644000175000017500000005341213542151610015270 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #ifdef HAVE_ICU #include #endif #ifdef HAVE_LIBSSL // Copypasted from // https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 // at 2018-04-01 static CString ZNC_DefaultCipher() { return "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-" "ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-" "AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-" "SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-" "RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:" "ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-" "SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:" "DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:" "ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:" "AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-" "SHA:DES-CBC3-SHA:!DSS"; } #endif CZNCSock::CZNCSock(int timeout) : Csock(timeout), m_sHostToVerifySSL(""), m_ssTrustedFingerprints(), m_ssCertVerificationErrors() { #ifdef HAVE_LIBSSL DisableSSLCompression(); FollowSSLCipherServerPreference(); DisableSSLProtocols(CZNC::Get().GetDisabledSSLProtocols()); CString sCipher = CZNC::Get().GetSSLCiphers(); if (sCipher.empty()) { sCipher = ZNC_DefaultCipher(); } SetCipher(sCipher); #endif } CZNCSock::CZNCSock(const CString& sHost, u_short port, int timeout) : Csock(sHost, port, timeout), m_sHostToVerifySSL(""), m_ssTrustedFingerprints(), m_ssCertVerificationErrors() { #ifdef HAVE_LIBSSL DisableSSLCompression(); FollowSSLCipherServerPreference(); DisableSSLProtocols(CZNC::Get().GetDisabledSSLProtocols()); #endif } unsigned int CSockManager::GetAnonConnectionCount(const CString& sIP) const { const_iterator it; unsigned int ret = 0; for (it = begin(); it != end(); ++it) { Csock* pSock = *it; // Logged in CClients have "USR::" as their sockname if (pSock->GetType() == Csock::INBOUND && pSock->GetRemoteIP() == sIP && !pSock->GetSockName().StartsWith("USR::")) { ret++; } } DEBUG("There are [" << ret << "] clients from [" << sIP << "]"); return ret; } int CZNCSock::ConvertAddress(const struct sockaddr_storage* pAddr, socklen_t iAddrLen, CString& sIP, u_short* piPort) const { int ret = Csock::ConvertAddress(pAddr, iAddrLen, sIP, piPort); if (ret == 0) sIP.TrimPrefix("::ffff:"); return ret; } #ifdef HAVE_LIBSSL int CZNCSock::VerifyPeerCertificate(int iPreVerify, X509_STORE_CTX* pStoreCTX) { if (iPreVerify == 0) { m_ssCertVerificationErrors.insert( X509_verify_cert_error_string(X509_STORE_CTX_get_error(pStoreCTX))); } return 1; } void CZNCSock::SSLHandShakeFinished() { if (GetType() != ETConn::OUTBOUND) { return; } X509* pCert = GetX509(); if (!pCert) { DEBUG(GetSockName() + ": No cert"); CallSockError(errnoBadSSLCert, "Anonymous SSL cert is not allowed"); Close(); return; } if (GetTrustAllCerts()) { DEBUG(GetSockName() + ": Verification disabled, trusting all."); return; } CString sHostVerifyError; if (!ZNC_SSLVerifyHost(m_sHostToVerifySSL, pCert, sHostVerifyError)) { m_ssCertVerificationErrors.insert(sHostVerifyError); } X509_free(pCert); if (GetTrustPKI() && m_ssCertVerificationErrors.empty()) { DEBUG(GetSockName() + ": Good cert (PKI valid)"); return; } CString sFP = GetSSLPeerFingerprint(); if (m_ssTrustedFingerprints.count(sFP) != 0) { DEBUG(GetSockName() + ": Cert explicitly trusted by user: " << sFP); return; } DEBUG(GetSockName() + ": Bad cert"); CString sErrorMsg = "Invalid SSL certificate: "; sErrorMsg += CString(", ").Join(begin(m_ssCertVerificationErrors), end(m_ssCertVerificationErrors)); CallSockError(errnoBadSSLCert, sErrorMsg); Close(); } bool CZNCSock::SNIConfigureClient(CString& sHostname) { sHostname = m_sHostToVerifySSL; return true; } #endif CString CZNCSock::GetSSLPeerFingerprint() const { #ifdef HAVE_LIBSSL // Csocket's version returns insecure SHA-1 // This one is SHA-256 const EVP_MD* evp = EVP_sha256(); X509* pCert = GetX509(); if (!pCert) { DEBUG(GetSockName() + ": GetSSLPeerFingerprint: Anonymous cert"); return ""; } unsigned char buf[256 / 8]; unsigned int _32 = 256 / 8; int iSuccess = X509_digest(pCert, evp, buf, &_32); X509_free(pCert); if (!iSuccess) { DEBUG(GetSockName() + ": GetSSLPeerFingerprint: Couldn't find digest"); return ""; } return CString(reinterpret_cast(buf), sizeof buf) .Escape_n(CString::EASCII, CString::EHEXCOLON); #else return ""; #endif } void CZNCSock::SetEncoding(const CString& sEncoding) { #ifdef HAVE_ICU Csock::SetEncoding(CZNC::Get().FixupEncoding(sEncoding)); #endif } #ifdef HAVE_PTHREAD class CSockManager::CThreadMonitorFD : public CSMonitorFD { public: CThreadMonitorFD() { Add(CThreadPool::Get().getReadFD(), ECT_Read); } bool FDsThatTriggered(const std::map& miiReadyFds) override { if (miiReadyFds.find(CThreadPool::Get().getReadFD())->second) { CThreadPool::Get().handlePipeReadable(); } return true; } }; #endif #ifdef HAVE_THREADED_DNS void CSockManager::CDNSJob::runThread() { int iCount = 0; while (true) { addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_ADDRCONFIG; iRes = getaddrinfo(sHostname.c_str(), nullptr, &hints, &aiResult); if (EAGAIN != iRes) { break; } iCount++; if (iCount > 5) { iRes = ETIMEDOUT; break; } sleep(5); // wait 5 seconds before next try } } void CSockManager::CDNSJob::runMain() { if (0 != this->iRes) { DEBUG("Error in threaded DNS: " << gai_strerror(this->iRes) << " while trying to resolve " << this->sHostname); if (this->aiResult) { DEBUG("And aiResult is not nullptr..."); } // just for case. Maybe to call freeaddrinfo()? this->aiResult = nullptr; } pManager->SetTDNSThreadFinished(this->task, this->bBind, this->aiResult); } void CSockManager::StartTDNSThread(TDNSTask* task, bool bBind) { CString sHostname = bBind ? task->sBindhost : task->sHostname; CDNSJob* arg = new CDNSJob; arg->sHostname = sHostname; arg->task = task; arg->bBind = bBind; arg->pManager = this; CThreadPool::Get().addJob(arg); } static CString RandomFromSet(const SCString& sSet, std::default_random_engine& gen) { std::uniform_int_distribution<> distr(0, sSet.size() - 1); auto it = sSet.cbegin(); std::advance(it, distr(gen)); return *it; } static std::tuple RandomFrom2SetsWithBias( const SCString& ss4, const SCString& ss6, std::default_random_engine& gen) { // It's not quite what RFC says how to choose between IPv4 and IPv6, but // proper way is harder to implement. // It would require to maintain some state between Csock objects. bool bUseIPv6; if (ss4.empty()) { bUseIPv6 = true; } else if (ss6.empty()) { bUseIPv6 = false; } else { // Let's prefer IPv6 :) std::discrete_distribution<> d({2, 3}); bUseIPv6 = d(gen); } const SCString& sSet = bUseIPv6 ? ss6 : ss4; return std::make_tuple(RandomFromSet(sSet, gen), bUseIPv6); } void CSockManager::SetTDNSThreadFinished(TDNSTask* task, bool bBind, addrinfo* aiResult) { if (bBind) { task->aiBind = aiResult; task->bDoneBind = true; } else { task->aiTarget = aiResult; task->bDoneTarget = true; } // Now that something is done, check if everything we needed is done if (!task->bDoneBind || !task->bDoneTarget) { return; } // All needed DNS is done, now collect the results SCString ssTargets4; SCString ssTargets6; for (addrinfo* ai = task->aiTarget; ai; ai = ai->ai_next) { char s[INET6_ADDRSTRLEN] = {}; getnameinfo(ai->ai_addr, ai->ai_addrlen, s, sizeof(s), nullptr, 0, NI_NUMERICHOST); switch (ai->ai_family) { case AF_INET: ssTargets4.insert(s); break; #ifdef HAVE_IPV6 case AF_INET6: ssTargets6.insert(s); break; #endif } } SCString ssBinds4; SCString ssBinds6; for (addrinfo* ai = task->aiBind; ai; ai = ai->ai_next) { char s[INET6_ADDRSTRLEN] = {}; getnameinfo(ai->ai_addr, ai->ai_addrlen, s, sizeof(s), nullptr, 0, NI_NUMERICHOST); switch (ai->ai_family) { case AF_INET: ssBinds4.insert(s); break; #ifdef HAVE_IPV6 case AF_INET6: ssBinds6.insert(s); break; #endif } } if (task->aiTarget) freeaddrinfo(task->aiTarget); if (task->aiBind) freeaddrinfo(task->aiBind); CString sBindhost; CString sTargetHost; std::random_device rd; std::default_random_engine gen(rd()); try { if (ssTargets4.empty() && ssTargets6.empty()) { throw t_s("Can't resolve server hostname"); } else if (task->sBindhost.empty()) { // Choose random target std::tie(sTargetHost, std::ignore) = RandomFrom2SetsWithBias(ssTargets4, ssTargets6, gen); } else if (ssBinds4.empty() && ssBinds6.empty()) { throw t_s( "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost"); } else if (ssBinds4.empty()) { if (ssTargets6.empty()) { throw t_s( "Server address is IPv4-only, but bindhost is IPv6-only"); } else { // Choose random target and bindhost from IPv6-only sets sTargetHost = RandomFromSet(ssTargets6, gen); sBindhost = RandomFromSet(ssBinds6, gen); } } else if (ssBinds6.empty()) { if (ssTargets4.empty()) { throw t_s( "Server address is IPv6-only, but bindhost is IPv4-only"); } else { // Choose random target and bindhost from IPv4-only sets sTargetHost = RandomFromSet(ssTargets4, gen); sBindhost = RandomFromSet(ssBinds4, gen); } } else { // Choose random target bool bUseIPv6; std::tie(sTargetHost, bUseIPv6) = RandomFrom2SetsWithBias(ssTargets4, ssTargets6, gen); // Choose random bindhost matching chosen target const SCString& ssBinds = bUseIPv6 ? ssBinds6 : ssBinds4; sBindhost = RandomFromSet(ssBinds, gen); } DEBUG("TDNS: " << task->sSockName << ", connecting to [" << sTargetHost << "] using bindhost [" << sBindhost << "]"); FinishConnect(sTargetHost, task->iPort, task->sSockName, task->iTimeout, task->bSSL, sBindhost, task->pcSock); } catch (const CString& s) { DEBUG(task->sSockName << ", dns resolving error: " << s); task->pcSock->SetSockName(task->sSockName); task->pcSock->SockError(-1, s); delete task->pcSock; } delete task; } #endif /* HAVE_THREADED_DNS */ CSockManager::CSockManager() { #ifdef HAVE_PTHREAD MonitorFD(new CThreadMonitorFD()); #endif } CSockManager::~CSockManager() {} void CSockManager::Connect(const CString& sHostname, u_short iPort, const CString& sSockName, int iTimeout, bool bSSL, const CString& sBindHost, CZNCSock* pcSock) { m_InFlightDnsSockets[pcSock] = false; if (pcSock) { pcSock->SetHostToVerifySSL(sHostname); } #ifdef HAVE_THREADED_DNS DEBUG("TDNS: initiating resolving of [" << sHostname << "] and bindhost [" << sBindHost << "]"); TDNSTask* task = new TDNSTask; task->sHostname = sHostname; task->iPort = iPort; task->sSockName = sSockName; task->iTimeout = iTimeout; task->bSSL = bSSL; task->sBindhost = sBindHost; task->pcSock = pcSock; if (sBindHost.empty()) { task->bDoneBind = true; } else { StartTDNSThread(task, true); } StartTDNSThread(task, false); #else /* HAVE_THREADED_DNS */ // Just let Csocket handle DNS itself FinishConnect(sHostname, iPort, sSockName, iTimeout, bSSL, sBindHost, pcSock); #endif } void CSockManager::FinishConnect(const CString& sHostname, u_short iPort, const CString& sSockName, int iTimeout, bool bSSL, const CString& sBindHost, CZNCSock* pcSock) { auto it = m_InFlightDnsSockets.find(pcSock); if (it != m_InFlightDnsSockets.end()) { bool bSocketDeletedAlready = it->second; m_InFlightDnsSockets.erase(it); if (bSocketDeletedAlready) { DEBUG("TDNS: Socket [" << sSockName << "] is deleted already, not proceeding with connection"); return; } } else { // impossible } CSConnection C(sHostname, iPort, iTimeout); C.SetSockName(sSockName); C.SetIsSSL(bSSL); C.SetBindHost(sBindHost); #ifdef HAVE_LIBSSL CString sCipher = CZNC::Get().GetSSLCiphers(); if (sCipher.empty()) { sCipher = ZNC_DefaultCipher(); } C.SetCipher(sCipher); #endif TSocketManager::Connect(C, pcSock); } void CSockManager::DelSockByAddr(Csock* pcSock) { auto it = m_InFlightDnsSockets.find(pcSock); if (it != m_InFlightDnsSockets.end()) { // The socket is resolving its DNS. When that finishes, let it silently // die without crash. it->second = true; } TSocketManager::DelSockByAddr(pcSock); } /////////////////// CSocket /////////////////// CSocket::CSocket(CModule* pModule) : CZNCSock(), m_pModule(pModule) { if (m_pModule) m_pModule->AddSocket(this); EnableReadLine(); SetMaxBufferThreshold(10240); } CSocket::CSocket(CModule* pModule, const CString& sHostname, unsigned short uPort, int iTimeout) : CZNCSock(sHostname, uPort, iTimeout), m_pModule(pModule) { if (m_pModule) m_pModule->AddSocket(this); EnableReadLine(); SetMaxBufferThreshold(10240); } CSocket::~CSocket() { CUser* pUser = nullptr; CIRCNetwork* pNetwork = nullptr; // CWebSock could cause us to have a nullptr pointer here if (m_pModule) { pUser = m_pModule->GetUser(); pNetwork = m_pModule->GetNetwork(); m_pModule->UnlinkSocket(this); } if (pNetwork && m_pModule && (m_pModule->GetType() == CModInfo::NetworkModule)) { pNetwork->AddBytesWritten(GetBytesWritten()); pNetwork->AddBytesRead(GetBytesRead()); } else if (pUser && m_pModule && (m_pModule->GetType() == CModInfo::UserModule)) { pUser->AddBytesWritten(GetBytesWritten()); pUser->AddBytesRead(GetBytesRead()); } else { CZNC::Get().AddBytesWritten(GetBytesWritten()); CZNC::Get().AddBytesRead(GetBytesRead()); } } void CSocket::ReachedMaxBuffer() { DEBUG(GetSockName() << " == ReachedMaxBuffer()"); if (m_pModule) m_pModule->PutModule( t_s("Some socket reached its max buffer limit and was closed!")); Close(); } void CSocket::SockError(int iErrno, const CString& sDescription) { DEBUG(GetSockName() << " == SockError(" << sDescription << ", " << strerror(iErrno) << ")"); if (iErrno == EMFILE) { // We have too many open fds, this can cause a busy loop. Close(); } } bool CSocket::ConnectionFrom(const CString& sHost, unsigned short uPort) { return CZNC::Get().AllowConnectionFrom(sHost); } bool CSocket::Connect(const CString& sHostname, unsigned short uPort, bool bSSL, unsigned int uTimeout) { if (!m_pModule) { DEBUG( "ERROR: CSocket::Connect called on instance without m_pModule " "handle!"); return false; } CUser* pUser = m_pModule->GetUser(); CString sSockName = "MOD::C::" + m_pModule->GetModName(); CString sBindHost; if (pUser) { sSockName += "::" + pUser->GetUserName(); sBindHost = pUser->GetBindHost(); CIRCNetwork* pNetwork = m_pModule->GetNetwork(); if (pNetwork) { sSockName += "::" + pNetwork->GetName(); sBindHost = pNetwork->GetBindHost(); } } // Don't overwrite the socket name if one is already set if (!GetSockName().empty()) { sSockName = GetSockName(); } m_pModule->GetManager()->Connect(sHostname, uPort, sSockName, uTimeout, bSSL, sBindHost, this); return true; } bool CSocket::Listen(unsigned short uPort, bool bSSL, unsigned int uTimeout) { if (!m_pModule) { DEBUG( "ERROR: CSocket::Listen called on instance without m_pModule " "handle!"); return false; } CUser* pUser = m_pModule->GetUser(); CString sSockName = "MOD::L::" + m_pModule->GetModName(); if (pUser) { sSockName += "::" + pUser->GetUserName(); } // Don't overwrite the socket name if one is already set if (!GetSockName().empty()) { sSockName = GetSockName(); } return m_pModule->GetManager()->ListenAll(uPort, sSockName, bSSL, SOMAXCONN, this); } CModule* CSocket::GetModule() const { return m_pModule; } /////////////////// !CSocket /////////////////// #ifdef HAVE_ICU void CIRCSocket::IcuExtToUCallback(UConverterToUnicodeArgs* toArgs, const char* codeUnits, int32_t length, UConverterCallbackReason reason, UErrorCode* err) { // From http://www.mirc.com/colors.html // The Control+O key combination in mIRC inserts ascii character 15, // which turns off all previous attributes, including color, bold, // underline, and italics. // // \x02 bold // \x03 mIRC-compatible color // \x04 RRGGBB color // \x0F normal/reset (turn off bold, colors, etc.) // \x12 reverse (weechat) // \x16 reverse (mirc, kvirc) // \x1D italic // \x1F underline // Also see http://www.visualirc.net/tech-attrs.php // // Keep in sync with CUser::AddTimestamp and CIRCSocket::IcuExtFromUCallback static const std::set scAllowedChars = { '\x02', '\x03', '\x04', '\x0F', '\x12', '\x16', '\x1D', '\x1F'}; if (reason == UCNV_ILLEGAL && length == 1 && scAllowedChars.count(*codeUnits)) { *err = U_ZERO_ERROR; UChar c = *codeUnits; ucnv_cbToUWriteUChars(toArgs, &c, 1, 0, err); return; } Csock::IcuExtToUCallback(toArgs, codeUnits, length, reason, err); } void CIRCSocket::IcuExtFromUCallback(UConverterFromUnicodeArgs* fromArgs, const UChar* codeUnits, int32_t length, UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err) { // See comment in CIRCSocket::IcuExtToUCallback static const std::set scAllowedChars = {0x02, 0x03, 0x04, 0x0F, 0x12, 0x16, 0x1D, 0x1F}; if (reason == UCNV_ILLEGAL && scAllowedChars.count(codePoint)) { *err = U_ZERO_ERROR; char c = codePoint; ucnv_cbFromUWriteBytes(fromArgs, &c, 1, 0, err); return; } Csock::IcuExtFromUCallback(fromArgs, codeUnits, length, codePoint, reason, err); } #endif CString CSocket::t_s(const CString& sEnglish, const CString& sContext) const { return GetModule()->t_s(sEnglish, sContext); } CInlineFormatMessage CSocket::t_f(const CString& sEnglish, const CString& sContext) const { return GetModule()->t_f(sEnglish, sContext); } CInlineFormatMessage CSocket::t_p(const CString& sEnglish, const CString& sEnglishes, int iNum, const CString& sContext) const { return GetModule()->t_p(sEnglish, sEnglishes, iNum, sContext); } CDelayedTranslation CSocket::t_d(const CString& sEnglish, const CString& sContext) const { return GetModule()->t_d(sEnglish, sContext); } znc-1.7.5/src/Query.cpp0000644000175000017500000000746413542151610015153 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include using std::vector; CQuery::CQuery(const CString& sName, CIRCNetwork* pNetwork) : m_sName(sName), m_pNetwork(pNetwork), m_Buffer() { SetBufferCount(m_pNetwork->GetUser()->GetQueryBufferSize(), true); } CQuery::~CQuery() {} void CQuery::SendBuffer(CClient* pClient) { SendBuffer(pClient, m_Buffer); } void CQuery::SendBuffer(CClient* pClient, const CBuffer& Buffer) { if (m_pNetwork && m_pNetwork->IsUserAttached()) { // Based on CChan::SendBuffer() if (!Buffer.IsEmpty()) { const vector& vClients = m_pNetwork->GetClients(); for (CClient* pEachClient : vClients) { CClient* pUseClient = (pClient ? pClient : pEachClient); MCString msParams; msParams["target"] = pUseClient->GetNick(); bool bWasPlaybackActive = pUseClient->IsPlaybackActive(); pUseClient->SetPlaybackActive(true); NETWORKMODULECALL(OnPrivBufferStarting(*this, *pUseClient), m_pNetwork->GetUser(), m_pNetwork, nullptr, NOTHING); bool bBatch = pUseClient->HasBatch(); CString sBatchName = m_sName.MD5(); if (bBatch) { m_pNetwork->PutUser(":znc.in BATCH +" + sBatchName + " znc.in/playback " + m_sName, pUseClient); } size_t uSize = Buffer.Size(); for (size_t uIdx = 0; uIdx < uSize; uIdx++) { const CBufLine& BufLine = Buffer.GetBufLine(uIdx); CMessage Message = BufLine.ToMessage(*pUseClient, msParams); if (!pUseClient->HasEchoMessage() && !pUseClient->HasSelfMessage()) { if (Message.GetNick().NickEquals( pUseClient->GetNick())) { continue; } } Message.SetNetwork(m_pNetwork); Message.SetClient(pUseClient); if (bBatch) { Message.SetTag("batch", sBatchName); } bool bContinue = false; NETWORKMODULECALL(OnPrivBufferPlayMessage(Message), m_pNetwork->GetUser(), m_pNetwork, nullptr, &bContinue); if (bContinue) continue; m_pNetwork->PutUser(Message, pUseClient); } if (bBatch) { m_pNetwork->PutUser(":znc.in BATCH -" + sBatchName, pUseClient); } NETWORKMODULECALL(OnPrivBufferEnding(*this, *pUseClient), m_pNetwork->GetUser(), m_pNetwork, nullptr, NOTHING); pUseClient->SetPlaybackActive(bWasPlaybackActive); if (pClient) break; } } } } znc-1.7.5/src/ZNCDebug.cpp0000644000175000017500000000355513542151610015444 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include bool CDebug::stdoutIsTTY = true; bool CDebug::debug = false; CString CDebug::Filter(const CString& sUnfilteredLine) { CString sFilteredLine = sUnfilteredLine; // If the line is a PASS command to authenticate to a server / znc if (sUnfilteredLine.StartsWith("PASS ")) { VCString vsSafeCopy; sUnfilteredLine.Split(":", vsSafeCopy); if (vsSafeCopy.size() > 1) { sFilteredLine = vsSafeCopy[0] + ":"; } } return sFilteredLine; } CDebugStream::~CDebugStream() { timeval tTime = CUtils::GetTime(); time_t tSec = (time_t)tTime.tv_sec; // some systems (e.g. openbsd) define // tv_sec as long int instead of time_t tm tM; tzset(); // localtime_r requires this localtime_r(&tSec, &tM); char sTime[20] = {}; strftime(sTime, sizeof(sTime), "%Y-%m-%d %H:%M:%S", &tM); char sUsec[7] = {}; snprintf(sUsec, sizeof(sUsec), "%06lu", (unsigned long int)tTime.tv_usec); std::cout << "[" << sTime << "." << sUsec << "] " << CString(this->str()).Escape_n(CString::EDEBUG) << std::endl; } znc-1.7.5/src/po/0000755000175000017500000000000013542151610013745 5ustar somebodysomebodyznc-1.7.5/src/po/znc.es_ES.po0000644000175000017500000013600713542151610016103 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/src/po/znc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "Conectado como: {1}" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "No conectado" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "Salir" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "Inicio" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "Módulos globales" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "Módulos de usuario" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "Módulos de red ({1})" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "¡Bienvenido a la interfaz web de ZNC!" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" "No se han cargado módulos web. Carga algunos módulos desde IRC (\"/msg " "*status help\" y \"/msg *status loadmod <módulo>" "\"). Una vez lo hayas hecho, el menú se expandirá." #: znc.cpp:1563 msgid "User already exists" msgstr "El usuario ya existe" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "IPv6 no está disponible" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "SSL no está habilitado" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "No se ha localizado el fichero pem: {1}" #: znc.cpp:1706 msgid "Invalid port" msgstr "Puerto no válido" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "Imposible enlazar: {1}" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "Cambiando de servidor porque este servidor ya no está en la lista" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "Bienvenido a ZNC" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "Estás desconectado del IRC. Usa 'connect' para reconectar." #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "Esta red está siendo eliminada o movida a otro usuario." #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "El canal {1} no es accesible, deshabilitado." #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "Tu servidor actual ha sido eliminado. Cambiando de servidor..." #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "" "No se puede conectar a {1} porque ZNC no se ha compilado con soporte SSL." #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "Algún módulo ha abortado el intento de conexión" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "Error del servidor: {1}" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "ZNC parece que se ha conectado a si mismo, desconectando..." #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "Servidor {1} nos redirige a {2}:{3} por: {4}" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "Puede que quieras añadirlo como nuevo servidor." #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "El canal {1} está enlazado a otro canal y por eso está deshabilitado." #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "Cambiado a SSL (STARTTLS)" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "Has salido: {1}" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "Desconectado del IRC. Volviendo a conectar..." #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "No se puede conectar al IRC ({1}). Reintentándolo..." #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "Desconectado del IRC ({1}). Volviendo a conectar..." #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" "Si confías en este certificado, ejecuta /znc AddTrustedServerFingerprint {1}" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "Tiempo de espera agotado en la conexión al IRC. Reconectando..." #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "Conexión rechazada. Reconectando..." #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "¡Recibida línea demasiado larga desde el servidor de IRC!" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "No hay ningún nick disponible" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "No se ha encontrado ningún nick disponible" #: Client.cpp:74 msgid "No such module {1}" msgstr "No existe el módulo {1}" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "" "Un cliente desde {1} ha intentado conectarse por ti, pero ha sido rechazado " "{2}" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "La red {1} no existe." #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" "Tienes varias redes configuradas, pero ninguna ha sido especificada para la " "conexión." #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" "Seleccionando la red {1}. Para ver una lista de todas las redes " "configuradas, ejecuta /znc ListNetworks" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" "Si quieres escoger otra red, utiliza /znc JumpNetwork , o conecta a " "ZNC mediante usuario {1}/ (en vez de solo {1})" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" "No tienes redes configuradas. Ejecuta /znc AddNetwork para añadir " "una." #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "Cerrando conexión: tiempo de espera agotado" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "Cerrando conexión: linea raw demasiado larga" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "" "Estás siendo desconectado porque otro usuario se ha autenticado por ti." #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "Tu CTCP a {1} se ha perdido, ¡no estás conectado al IRC!" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "Tu notice a {1} se ha perdido, ¡no estás conectado al IRC!" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "Eliminando canal {1}" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "Tu mensaje a {1} se ha perdido, ¡no estás conectado al IRC!" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "Hola. ¿En qué te puedo ayudar?" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "Uso: /attach <#canales>" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "Hay {1} canal que coincide con [{2}]" msgstr[1] "Hay {1} canales que coinciden con [{2}]" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "Vinculado a {1} canal" msgstr[1] "Unido a {1} canales" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "Uso: /detach <#canales>" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "Desvinculado {1} canal" msgstr[1] "Separados {1} canales" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "Reproducción de buffer..." #: Chan.cpp:676 msgid "Playback Complete." msgstr "Reproducción completa." #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "Generar esta salida" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "No hay coincidencias para '{1}'" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "Este módulo no dispone de comandos." #: Modules.cpp:693 msgid "Unknown command!" msgstr "¡Comando desconocido!" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" "Los nombres de módulos solo pueden contener letras, números y guiones bajos, " "[{1}] no es válido" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "Módulo {1} ya cargado." #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "No se ha encontrado el módulo {1}" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "El módulo {1} no soporta el tipo de módulo {2}." #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "El módulo {1} requiere un usuario." #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "El módulo {1} requiere una red." #: Modules.cpp:1707 msgid "Caught an exception" msgstr "Capturada una excepción" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "Módulo {1} abortado: {2}" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "Módulo {1} abortado." #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "Módulo [{1}] no cargado." #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "Módulo {1} descargado." #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "Imposible descargar el módulo {1}." #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "Recargado el módulo {1}." #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "No se ha encontrado el módulo {1}." #: Modules.cpp:1963 msgid "Unknown error" msgstr "Error desconocido" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "No se puede abrir el módulo {1}: {2}" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "No se ha encontrado ZNCModuleEntry en el módulo {1}" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" "Versiones no coincidentes para el módulo {1}: el núcleo es {2}, pero el " "módulo está hecho para {3}. Recompila este módulo." #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" "El módulo {1} es incompatible: el núcleo es '{2}', el módulo es '{3}'. " "Recompila este módulo." #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "Comando" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "Descripción" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "Debes estar conectado a una red para usar este comando" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "Uso: ListNicks <#canal>" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "No estás en [{1}]" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "No estás en [{1}] (intentándolo)" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "No hay nicks en [{1}]" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "Apodo" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "Ident" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "Servidor" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "Uso: Attach <#canales>" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "Uso: Detach <#canales>" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "No hay un MOTD configurado." #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "¡Recarga completada!" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "Recarga fallada: {1}" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "Guardada la configuración en {1}" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "Error al escribir la configuración." #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "Uso: ListChans" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "Usuario no encontrado [{1}]" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "El usuario [{1}] no tiene red [{2}]" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "No hay canales definidos." #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "Nombre" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "Estado" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "En configuración" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "Búfer" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "Borrar" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "Modos" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "Usuarios" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "Desvinculado" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "Unido" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "Deshabilitado" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "Probando" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "sí" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "Total: {1}, Unidos: {2}, Separados: {3}, Deshabilitados: {4}" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "Limite de redes alcanzado. Píde a un administrador que te incremente el " "límite, o elimina redes innecesarias usando /znc DelNetwork " #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "Uso: AddNetwork " #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "El nombre de la red debe ser alfanumérico" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" "Red añadida. Utiliza /znc JumpNetwork {1}, o conecta a ZNC con el usuario " "{2} (en vez de solo {3}) para conectar a la red." #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "No se ha podido añadir esta red" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "Uso: DelNetwork " #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "Red eliminada" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "Fallo al eliminar la red, puede que esta red no exista" #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "Usuario {1} no encontrado" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "Red" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "En IRC" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "Servidor IRC" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "Usuario IRC" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "Canales" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "Sí" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "No" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "No hay redes" #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "Acceso denegado." #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" "Uso: MoveNetwork [nueva " "red]" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "Anterior usuario {1} no encontrado." #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "Anterior red {1} no encontrada." #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "Nuevo usuario {1} no encontrado." #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "El usuario {1} ya tiene una red {2}." #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "Nombre de red no válido [{1}]" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "" "Algunos archivos parece que están en {1}. Puede que quieras moverlos a {2}" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "Error al añadir la red: {1}" #: ClientCommand.cpp:718 msgid "Success." msgstr "Completado." #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "" "Copiada la red al nuevo usuario, pero se ha fallado al borrar la anterior red" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "No se ha proporcionado una red." #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "Ya estás conectado con esta red." #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "Cambiado a {1}" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "No tienes una red llamada {1}" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "Uso: AddServer [[+]puerto] [contraseña]" #: ClientCommand.cpp:759 msgid "Server added" msgstr "Servidor añadido" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" "No se ha podido añadir el servidor. ¿Quizá el servidor ya está añadido o el " "openssl está deshabilitado?" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "Uso: DelServer [puerto] [contraseña]" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "No tienes ningún servidor añadido." #: ClientCommand.cpp:787 msgid "Server removed" msgstr "Servidor eliminado" #: ClientCommand.cpp:789 msgid "No such server" msgstr "No existe el servidor" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "Servidor" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "Puerto" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "Contraseña" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "Uso: AddTrustedServerFingerprint " #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "Hecho." #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "Uso: DelTrustedServerFingerprint " #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "No se han añadido huellas." #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "Canal" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "Puesto por" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "Tema" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "Nombre" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "Parámetros" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "No se han cargado módulos globales." #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "Módulos globales:" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "Tu usuario no tiene módulos cargados." #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "Módulos de usuario:" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "Esta red no tiene módulos cargados." #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "Módulos de red:" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "Nombre" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "Descripción" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "No hay disponibles módulos globales." #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "No hay disponibles módulos de usuario." #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "No hay módulos de red disponibles." #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "No se ha podido cargar {1}: acceso denegado." #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "Uso: LoadMod [--type=global|user|network] [parámetros]" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "No se ha podido cargar {1}: {2}" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "No se ha podido cargar el módulo global {1}: acceso denegado." #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "" "No se ha podido cargar el módulo de red {1}: no estás conectado con una red." #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "Tipo de módulo desconocido" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "Cargado módulo {1}" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "Cargado módulo {1}: {2}" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "No se ha podido cargar el módulo {1}: {2}" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "No se ha podido descargar {1}: acceso denegado." #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "Uso: UnLoadMod [--type=global|user|network] " #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "No se ha podido determinar el tipo de {1}: {2}" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "No se ha podido descargar el módulo global {1}: acceso denegado." #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "" "No se ha podido descargar el módulo de red {1}: no estás conectado con una " "red." #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "No se ha podido descargar el módulo {1}: tipo de módulo desconocido" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "No se han podido recargar los módulos: acceso denegado." #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "Uso: ReoadMod [--type=global|user|network] [parámetros]" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "No se ha podido recargar {1}: {2}" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "No se ha podido recargar el módulo global {1}: acceso denegado." #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "" "No se ha podido recargar el módulo de red {1}: no estás conectado con una " "red." #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "No se ha podido recargar el módulo {1}: tipo de módulo desconocido" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "Uso: UpdateMod " #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "Recargando {1} en todas partes" #: ClientCommand.cpp:1242 msgid "Done" msgstr "Hecho" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "" "Hecho, pero hay errores, el módulo {1} no se ha podido recargar en todas " "partes." #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" "Debes estar conectado a una red para usar este comando. Prueba " "SetUserBindHost" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "Uso: SetBindHost " #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "¡Ya tienes este host vinculado!" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "Modificado bind host para la red {1} a {2}" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "Uso: SetUserBindHost " #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "Configurado bind host predeterminado a {1}" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" "Debes estar conectado a una red para usar este comando. Prueba " "ClearUserBindHost" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "Borrado bindhost para esta red." #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "Borrado bindhost predeterminado para tu usuario." #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "Este usuario no tiene un bindhost predeterminado" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "El bindhost predeterminado de este usuario es {1}" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "Esta red no tiene un bindhost" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "El bindhost predeterminado de esta red es {1}" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "Uso: PlayBuffer <#canal|privado>" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "No estás en {1}" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "No estás en {1} (intentando entrar)" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "El búfer del canal {1} está vacio" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "No hay un privado activo con {1}" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "El búfer de {1} está vacio" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "Uso: ClearBuffer <#canal|privado>" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "{1} búfer coincidente con {2} ha sido borrado" msgstr[1] "{1} búfers coincidentes con {2} han sido borrados" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "Todos los búfers de canales han sido borrados" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "Todos los búfers de privados han sido borrados" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "Todos los búfers han sido borrados" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "Uso: SetBuffer <#canal|privado> [lineas]" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "Fallo al definir el tamaño para el búfer {1}" msgstr[1] "Fallo al definir el tamaño para los búfers {1}" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "El tamaño máximo de búfer es {1} línea" msgstr[1] "El tamaño máximo de búfer es {1} líneas" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "El tamaño de cada búfer se ha cambiado a {1} línea" msgstr[1] "El tamaño de cada búfer se ha cambiado a {1} líneas" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "Usuario" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "Entrada" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "Salida" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "Total" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "Ejecutado desde {1}" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "Comando desconocido, prueba 'Help'" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "Puerto" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "BindHost" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "Protocolo" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "IRC" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "Web" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "sí" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "no" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "IPv4 y IPv6" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "IPv4" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "IPv6" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "sí" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "no" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "sí, en {1}" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "no" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" "Uso: AddPort <[+]puerto> [bindhost " "[prefijourl]]" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "Puerto añadido" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "No se puede añadir el puerto" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "Uso: DelPort [bindhost]" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "Puerto eliminado" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "No se ha encontrado un puerto que coincida" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "Comando" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "Descripción" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" "En la siguiente lista todas las coincidencias de <#canal> soportan comodines " "(* y ?) excepto ListNicks" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "Imprime la versión de ZNC" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "Lista todos los módulos cargados" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "Lista todos los módulos disponibles" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "Lista todos los canales" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "<#canal>" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "Lista todos los nicks de un canal" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "Lista todos los clientes conectados en tu usuario de ZNC" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "Lista todos los servidores de la red IRC actual" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "Añade una red a tu usario" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "Elimina una red de tu usuario" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "Lista todas las redes" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr " [nueva red]" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "Mueve una red de IRC de un usuario a otro" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" "Saltar a otra red (alternativamente, puedes conectar a ZNC varias veces, " "usando `usuario/red` como nombre de usuario)" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr " [[+]puerto] [contraseña]" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" "Añade un servidor a la lista de servidores alternativos de la red IRC actual." #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr " [puerto] [contraseña]" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" "Elimina un servidor de la lista de servidores alternativos de la red IRC " "actual" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" "Añade un certificado digital (SHA-256) de confianza del servidor SSL a la " "red IRC actual." #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "Elimina un certificado digital de confianza de la red IRC actual." #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "Lista todos los certificados SSL de confianza de la red IRC actual." #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "<#canales>" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "Habilita canales" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "<#canales>" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "Deshabilita canales" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "<#canales>" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "Unirse a canales" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "<#canales>" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "Separarse de canales" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "Mostrar topics de tus canales" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "<#canal|privado>" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "Reproduce el búfer especificado" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "<#canal|privado>" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "Borra el búfer especificado" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "Borra todos los búfers de canales y privados" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "Borrar todos los búfers de canales" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "Borrar todos los búfers de privados" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "<#canal|privado> [lineas]" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "Ajusta las líneas de búfer" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "Define el bind host para esta red" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "Define el bind host predeterminado para este usuario" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "Borrar el bind host para esta red" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "Borrar el bind host predeterminado para este usuario" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "Mostrar el bind host seleccionado" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "[servidor]" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "Saltar al siguiente servidor" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "[mensaje]" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "Desconectar del IRC" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "Reconectar al IRC" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "Mostrar cuanto tiempo lleva ZNC ejecutándose" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "Cargar un módulo" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "[--type=global|user|network] " #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "Descargar un módulo" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "Recargar un módulo" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "Recargar un módulo en todas partes" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "Mostrar el mensaje del día de ZNC" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "Definir el mensaje del día de ZNC" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "Añadir un al MOTD de ZNC" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "Borrar el MOTD de ZNC" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "Mostrar todos los puertos en escucha" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "<[+]puerto> [bindhost [prefijouri]]" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "Añadir otro puerto de escucha a ZNC" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr " [bindhost]" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "Eliminar un puerto de ZNC" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "" "Recargar ajustes globales, módulos, y puertos de escucha desde znc.conf" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "Guardar la configuración actual en disco" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "Mostrar todos los usuarios de ZNC y su estado de conexión" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "Mostrar todos los usuarios de ZNC y sus redes" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "[usuario ]" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "[usuario]" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "Mostrar todos los clientes conectados" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "Mostrar estadísticas de tráfico de todos los usuarios de ZNC" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "[mensaje]" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "Difundir un mensaje a todos los usuarios de ZNC" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "[mensaje]" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "Cerrar ZNC completamente" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "[mensaje]" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "Reiniciar ZNC" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "No se puede resolver el hostname del servidor" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" "No se puede resolver el bindhost. Prueba /znc ClearBindHost y /znc " "ClearUserBindHost" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "La dirección del servidor es solo-IPv4, pero el bindhost es solo-IPv6" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "La dirección del servidor es solo-IPv6, pero el bindhost es solo-IPv4" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "" "¡Algún socket ha alcanzado el límite de su búfer máximo y se ha cerrado!" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "el hostname no coincide" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "hostname incorrecto en el certificado" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "error de verificación de hostname" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" "Nombre de red no válido. Debe ser alfanumérico. No confundir con el nombre " "del servidor" #: User.cpp:511 msgid "Network {1} already exists" msgstr "La red {1} ya existe" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" "Has sido desconectado porque a tu IP ya no se le permite conectar a este " "usuario" #: User.cpp:907 msgid "Password is empty" msgstr "La contraseña está vacía" #: User.cpp:912 msgid "Username is empty" msgstr "El nombre de usuario está vacío" #: User.cpp:917 msgid "Username is invalid" msgstr "El nombre de usuario no es válido" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "No se ha podido encontrar modinfo {1}: {2}" znc-1.7.5/src/po/CMakeLists.txt0000644000175000017500000000153113542151610016505 0ustar somebodysomebody# # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(translation) set(tmpl_dirs) file(GLOB skins "${PROJECT_SOURCE_DIR}/webskins/*") foreach(skin ${skins}) list(APPEND tmpl_dirs "${skin}/tmpl") endforeach() translation(SHORT "znc" FULL "znc" SOURCES ${znc_cpp} TMPLDIRS ${tmpl_dirs}) znc-1.7.5/src/po/znc.pot0000644000175000017500000010366113542151610015272 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" #: znc.cpp:1563 msgid "User already exists" msgstr "" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "" #: znc.cpp:1706 msgid "Invalid port" msgstr "" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "" #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "" #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "" #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "" #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "" #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "" #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "" #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "" #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "" #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "" #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "" #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "" #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "" #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "" #: Client.cpp:74 msgid "No such module {1}" msgstr "" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "" #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "" #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "" msgstr[1] "" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "" msgstr[1] "" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "" msgstr[1] "" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "" #: Chan.cpp:676 msgid "Playback Complete." msgstr "" #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "" #: Modules.cpp:693 msgid "Unknown command!" msgstr "" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "" #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "" #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "" #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "" #: Modules.cpp:1707 msgid "Caught an exception" msgstr "" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "" #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "" #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "" #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "" #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "" #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "" #: Modules.cpp:1963 msgid "Unknown error" msgstr "" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "" #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "" #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "" #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "" #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "" #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "" #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "" #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "" #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "" #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "" #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "" #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "" #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "" #: ClientCommand.cpp:718 msgid "Success." msgstr "" #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "" #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "" #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "" #: ClientCommand.cpp:759 msgid "Server added" msgstr "" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "" #: ClientCommand.cpp:787 msgid "Server removed" msgstr "" #: ClientCommand.cpp:789 msgid "No such server" msgstr "" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "" #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "" #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "" #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "" #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "" #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "" #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "" #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "" #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "" #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "" #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "" #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "" #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "" #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "" #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "" #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "" #: ClientCommand.cpp:1242 msgid "Done" msgstr "" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "" #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "" #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "" #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "" #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "" #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "" msgstr[1] "" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "" msgstr[1] "" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "" msgstr[1] "" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "" msgstr[1] "" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr "" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr "" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr "" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "" #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "" #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "" #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr "" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" #: User.cpp:511 msgid "Network {1} already exists" msgstr "" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" #: User.cpp:907 msgid "Password is empty" msgstr "" #: User.cpp:912 msgid "Username is empty" msgstr "" #: User.cpp:917 msgid "Username is invalid" msgstr "" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "" znc-1.7.5/src/po/znc.id_ID.po0000644000175000017500000011126113542151610016050 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/src/po/znc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "Masuk sebagai: {1}" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "Belum masuk" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "Keluar" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "Beranda" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "Modul Umum" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "Modul Pengguna" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "Modul Jaringan ({1})" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "Selamat datang di antarmuka web ZNC's!" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" "Tidak ada modul Web-enabled dimuat. Muat modul dari IRC (\"/msg * " "status help \" dan \"/msg * status loadmod <module>" "\"). Setelah anda memuat beberapa modul Web-enabled, menu ini akan diperluas." #: znc.cpp:1563 msgid "User already exists" msgstr "Pengguna sudah ada" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "IPv6 tidak diaktifkan" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "SSL tidak diaktifkan" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "Tidak dapat menemukan berkas pem: {1}" #: znc.cpp:1706 msgid "Invalid port" msgstr "Port tidak valid" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "Tidak dapat mengikat: {1}" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "Melompati server karena server ini tidak lagi dalam daftar" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "Selamat datang di ZNC" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "" "Anda saat ini terputus dari IRC. Gunakan 'connect' untuk terhubung kembali." #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "Jaringan ini sedang dihapus atau dipindahkan ke pengguna lain." #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "Tidak dapat join ke channel {1}. menonaktifkan." #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "Server anda saat ini dihapus, melompati..." #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "" "Tidak dapat terhubung ke {1}, karena ZNC tidak dikompilasi dengan dukungan " "SSL." #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "Beberapa modul membatalkan upaya koneksi" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "Kesalahan dari server: {1}" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "ZNC tampaknya terhubung dengan sendiri, memutuskan..." #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "Server {1} mengalihkan ke {2}: {3} dengan alasan: {4}" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "Mungkin anda ingin menambahkannya sebagai server baru." #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "Channel {1} terhubung ke channel lain dan karenanya dinonaktifkan." #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "Beralih ke SSL (STARTTLS)" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "Anda keluar: {1}" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "Terputus dari IRC. Menghubungkan..." #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "Tidak dapat terhubung ke IRC ({1}). Mencoba lagi..." #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "Terputus dari IRC ({1}). Menghubungkan..." #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" "Jika anda mempercayai sertifikat ini, lakukan /znc " "AddTrustedServerFingerprint {1}" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "Koneksi IRC kehabisan waktu. Menghubungkan..." #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "Koneksi tertolak. Menguhungkan..." #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "Menerima baris terlalu panjang dari server IRC!" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "Tidak ada nick tersedia" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "Tidak ada nick ditemukan" #: Client.cpp:74 msgid "No such module {1}" msgstr "Modul tidak ada {1}" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "Klien dari {1} berusaha masuk seperti anda, namun ditolak: {2}" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "Jaringan {1} tidak ada." #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" "Anda memiliki beberapa jaringan terkonfigurasi, tetapi tidak ada jaringan " "ditentukan untuk sambungan." #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" "Memilih jaringan {1}. Untuk melihat daftar semua jaringan terkonfigurasi, " "gunakan /znc ListNetworks" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" "Jika anda ingin memilih jaringan lain, gunakan /znc JumpNetwork , " "atau hubungkan ke ZNC dengan nama pengguna {1}/ (bukan hanya {1})" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" "Anda tidak memiliki jaringan terkonfigurasi. Gunakan /znc AddNetwork " " untuk menambahkannya." #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "Menutup link: Waktu habis" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "Menutup link: Baris raw terlalu panjang" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "Anda terputus karena pengguna lain hanya diautentikasi sebagai anda." #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "CTCP anda untuk {1} tersesat, anda tidak terhubung ke IRC!" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "Notice anda untuk {1} tersesat, anda tidak terhubung ke IRC!" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "Menghapus channel {1}" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "Pesan anda untuk {1} tersesat, anda tidak terhubung ke IRC!" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "Halo. Bagaimana saya bisa membantu anda?" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "Gunakan: /attach <#chan>" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "Ada {1} pencocokan saluran [{2}]" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "" #: Chan.cpp:676 msgid "Playback Complete." msgstr "" #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "" #: Modules.cpp:693 msgid "Unknown command!" msgstr "" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "" #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "" #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "" #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "" #: Modules.cpp:1707 msgid "Caught an exception" msgstr "" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "" #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "" #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "" #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "" #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "" #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "" #: Modules.cpp:1963 msgid "Unknown error" msgstr "" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "" #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "" #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "" #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "" #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "" #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "" #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "" #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "" #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "" #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "" #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "" #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "" #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "" #: ClientCommand.cpp:718 msgid "Success." msgstr "" #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "" #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "" #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "" #: ClientCommand.cpp:759 msgid "Server added" msgstr "" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "" #: ClientCommand.cpp:787 msgid "Server removed" msgstr "" #: ClientCommand.cpp:789 msgid "No such server" msgstr "" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "" #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "" #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "" #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "" #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "" #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "" #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "" #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "" #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "" #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "" #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "" #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "" #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "" #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "" #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "" #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "" #: ClientCommand.cpp:1242 msgid "Done" msgstr "" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "" #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "" #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "" #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "" #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "" #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr "" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr "" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr "" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "" #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "" #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "" #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr "" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" #: User.cpp:511 msgid "Network {1} already exists" msgstr "" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" #: User.cpp:907 msgid "Password is empty" msgstr "" #: User.cpp:912 msgid "Username is empty" msgstr "" #: User.cpp:917 msgid "Username is invalid" msgstr "" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "" znc-1.7.5/src/po/znc.bg_BG.po0000644000175000017500000010445713542151610016051 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/src/po/znc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" #: znc.cpp:1563 msgid "User already exists" msgstr "" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "" #: znc.cpp:1706 msgid "Invalid port" msgstr "" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "" #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "" #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "" #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "" #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "" #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "" #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "Сървъра{1} ни пренаÑочва към {2}:{3} Ñ Ð¿Ñ€Ð¸Ñ‡Ð¸Ð½Ð°: {4}" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "" #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "" #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "" #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "" #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "" #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "" #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "" #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "" #: Client.cpp:74 msgid "No such module {1}" msgstr "" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "" #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "" #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "" msgstr[1] "" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "" msgstr[1] "" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "" msgstr[1] "" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "" #: Chan.cpp:676 msgid "Playback Complete." msgstr "" #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "" #: Modules.cpp:693 msgid "Unknown command!" msgstr "" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "" #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "" #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "" #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "" #: Modules.cpp:1707 msgid "Caught an exception" msgstr "" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "" #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "" #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "" #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "" #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "" #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "" #: Modules.cpp:1963 msgid "Unknown error" msgstr "" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "" #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "" #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "" #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "" #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "" #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "" #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "" #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "" #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "" #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "" #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "" #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "" #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "" #: ClientCommand.cpp:718 msgid "Success." msgstr "" #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "" #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "" #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "" #: ClientCommand.cpp:759 msgid "Server added" msgstr "" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "" #: ClientCommand.cpp:787 msgid "Server removed" msgstr "" #: ClientCommand.cpp:789 msgid "No such server" msgstr "" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "" #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "" #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "" #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "" #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "" #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "" #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "" #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "" #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "" #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "" #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "" #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "" #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "" #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "" #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "" #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "" #: ClientCommand.cpp:1242 msgid "Done" msgstr "" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "" #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "" #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "" #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "" #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "" #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "" msgstr[1] "" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "" msgstr[1] "" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "" msgstr[1] "" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "" msgstr[1] "" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr "" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr "" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr "" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "" #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "" #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "" #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr "" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" #: User.cpp:511 msgid "Network {1} already exists" msgstr "" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" #: User.cpp:907 msgid "Password is empty" msgstr "" #: User.cpp:912 msgid "Username is empty" msgstr "" #: User.cpp:917 msgid "Username is invalid" msgstr "" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "" znc-1.7.5/src/po/znc.pt_BR.po0000644000175000017500000012735213542151610016116 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/src/po/znc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "Sessão iniciada como: {1}" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "Sessão não iniciada" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "Finalizar sessão" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "Página inicial" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "Módulos globais" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "Módulos do usuário" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "Módulos da rede ({1})" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "Seja bem-vindo(a) à interface web do ZNC!" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" "Nenhum módulo habilitado para a Web foi carregado. Carregue módulos pelo IRC " "(“/msg *status help†e “/msg *status loadmod <" "module>â€). Depois de carregar alguns módulos habilitados para a " "Web, o menu será expandido." #: znc.cpp:1563 msgid "User already exists" msgstr "O usuário já existe" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "O IPv6 não está habilitado" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "O SSL não está habilitado" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "Falha ao localizar o arquivo PEM: {1}" #: znc.cpp:1706 msgid "Invalid port" msgstr "Porta inválida" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "Não foi possível vincular: {1}" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "Trocando de servidor, pois este servidor não está mais na lista" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "Bem-vindo(a) ao ZNC" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "" "Você está desconectado do IRC no momento. Digite 'connect' para reconectar." #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "Esta rede está sendo excluída ou movida para outro usuário." #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "Não foi possível entrar no canal {1}. Desabilitando-o." #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "O seu servidor atual foi removido, trocando de servidor..." #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "" "Não foi possível conectar-se a {1}. O ZNC não foi compilado com suporte a " "SSL." #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "Algum módulo cancelou a tentativa de conexão" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "Erro do servidor: {1}" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "Parece que o ZNC está conectado a si mesmo. Desconectando..." #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "Talvez você queira adicioná-lo como um novo servidor." #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "O canal {1} foi desabilitado por estar vinculado a outro canal." #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "Alternado para SSL (STARTTLS)" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "Você saiu: {1}" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "Desconectado. Reconectando..." #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "Não foi possível conectar-se ao IRC ({1}). Tentando novamente..." #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "Desconectado do IRC ({1}). Reconectando..." #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" "Caso confie neste certificado, digite /znc AddTrustedServerFingerprint {1}" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "A conexão ao servidor expirou. Reconectando..." #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "Conexão rejeitada. Reconectando..." #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "Uma linha muito longa foi recebida do servidor de IRC!" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "Não há apelidos livres disponíveis" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "Nenhum apelido livre foi encontrado" #: Client.cpp:74 msgid "No such module {1}" msgstr "O módulo {1} não existe" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "" "Um cliente com o IP {1} tentou iniciar sessão na sua conta, mas foi " "rejeitado: {2}" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "A rede {1} não existe." #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" "Você possui várias redes configuradas mas nenhuma delas foi especificada " "para conectar." #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" "Selecionando a rede {1}. Para ver a lista das redes configuradas, digite /" "znc ListNetworks" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" "Caso queira escolher outra rede, digite /znc JumpNetwork , ou então " "conecte ao ZNC com o nome de usuário {1}/ (em vez de somente {1})" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" "Você não possui redes configuradas. Digite /znc AddNetwork para " "adicionar uma rede." #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "Fechando link: Tempo limite excedido" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "Fechando link: Linha raw muito longa" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "" "Você está sendo desconectado porque outro usuário acabou de autenticar-se " "como você." #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "O seu CTCP para {1} foi perdido, você não está conectado ao IRC!" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "O seu aviso para {1} foi perdido, você não está conectado ao IRC!" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "Removendo canal {1}" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "Sua mensagem para {1} foi perdida, você não está conectado ao IRC!" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "Olá. Como posso ajudá-lo(a)?" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "Uso: /attach <#canais>" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "Foi encontrado {1} canal correspondente a [{2}]" msgstr[1] "Foi encontrado {1} canal correspondentes a [{2}]" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "{1} canal foi anexado" msgstr[1] "{1} canais foram anexados" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "Uso: /detach <#canais>" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "{1} canal foi desanexado" msgstr[1] "{1} canais foram desanexados" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "Reprodução de buffer..." #: Chan.cpp:676 msgid "Playback Complete." msgstr "Reprodução completa." #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "Gera essa saída" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "Nenhuma correspondência para '{1}'" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "Este módulo não implementa comando algum." #: Modules.cpp:693 msgid "Unknown command!" msgstr "Comando desconhecido!" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" "Os nomes de módulos podem conter apenas letras, números e underlines. [{1}] " "é inválido" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "O módulo {1} já está carregado." #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "Não foi possível encontrar o módulo {1}" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "O módulo {1} não suporta o tipo de módulo {2}." #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "O módulo {1} requer um usuário." #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "O módulo {1} requer uma rede." #: Modules.cpp:1707 msgid "Caught an exception" msgstr "Houve uma exceção" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "Módulo {1} finalizado: {2}" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "Módulo {1} finalizado." #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "O módulo [{1}] não foi carregado." #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "Módulo {1} desligado." #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "Não foi possível desativar o módulo {1}." #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "O módulo {1} foi reiniciado." #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "Não foi possível encontrar o módulo {1}." #: Modules.cpp:1963 msgid "Unknown error" msgstr "Erro desconhecido" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "Não foi possível abrir o módulo {1}: {2}" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "Não foi possível encontrar ZNCModuleEntry no módulo {1}" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" "Incompatibilidade de versão para o módulo {1}: core é {2}, mas o módulo foi " "compilado para {3}. Recompile esse módulo." #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" "Módulo {1} foi compilado de forma incompatível: core é '{2}', o módulo é " "'{3}'. Recompile este módulo." #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "Comando" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "Descrição" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "Você precisa estar conectado a uma rede para usar este comando" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "Uso: ListNicks <#canal>" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "Você não está em [{1}]" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "Você não está em [{1}] (tentando)" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "Nenhum nick em [{1}]" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "Apelido" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "Ident" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "Host" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "Uso: Attach <#canais>" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "Uso: Detach <#canais>" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "Não há MOTD definido." #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "Rehash efetuado com êxito!" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "Rehash falhou: {1}" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "Configuração salva em {1}" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "Erro ao tentar gravar as configurações." #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "Uso: ListChans" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "Usuário não encontrado [{1}]" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "Usuário [{1}] não tem uma rede [{2}]" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "Não há canais definidos." #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "Nome" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "Estado" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "Na configuração" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "Buffer" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "Limpar" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "Modos" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "Usuários" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "Desanexado" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "Entrou" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "Desabilitado" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "Tentando" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "sim" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "Total: {1}, Ingressados: {2}, Desanexados: {3}, Desativados: {4}" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "O limite de redes foi atingido. Peça a um administrador para aumentar o seu " "limite de redes, ou então exclua redes desnecessárias usando o comando /znc " "DelNetwork " #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "Uso: AddNetwork " #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "O nome da rede deve ser alfanumérico" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" "Rede adicionada. Use /znc JumpNetwork {1}, ou conecte-se ao ZNC com nome de " "usuário {2} (em vez de apenas {3}) para conectar-se a rede." #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "Não foi possível adicionar esta rede" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "Uso: DelNetwork " #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "A rede foi excluída" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "Falha ao excluir rede. Talvez esta rede não existe." #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "Usuário {1} não encontrado" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "Rede" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "No IRC" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "Servidor IRC" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "Usuário IRC" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "Canais" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "Sim" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "Não" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "Não há redes disponíveis." #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "Acesso negado." #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" "Uso: MoveNetwork [nova rede]" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "Usuário antigo [{1}] não foi encontrado." #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "Rede antiga [{1}] não foi encontrada." #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "Novo usuário [{1}] não foi encontrado." #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "O usuário {1} já possui a rede {2}." #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "Nome de rede inválido [{1}]" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "" "Alguns arquivos parecem estar em {1}. É recomendável que você mova-os para " "{2}" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "Falha ao adicionar rede: {1}" #: ClientCommand.cpp:718 msgid "Success." msgstr "Sucesso." #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "" "Rede copiada para o novo usuário, mas não foi possível deletar a rede antiga" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "Nenhuma rede fornecida." #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "Você já está conectado com esta rede." #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "Trocado para {1}" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "Você não tem uma rede chamada {1}" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "Uso: AddServer [[+]porta] [pass]" #: ClientCommand.cpp:759 msgid "Server added" msgstr "Servidor adicionado" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" "Não é possível adicionar esse servidor. Talvez o servidor já tenha sido " "adicionado ou o openssl esteja desativado?" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "Uso: DelServer [port] [pass]" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "Você não tem servidores adicionados." #: ClientCommand.cpp:787 msgid "Server removed" msgstr "" #: ClientCommand.cpp:789 msgid "No such server" msgstr "" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "Host" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "Porta" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "Senha" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "" #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "" #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "" #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "" #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "Canal" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "" #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "" #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "" #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "Nome" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "Descrição" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "Não há módulos globais disponíveis." #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "Não há módulos de usuário disponíveis." #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "Não há módulos de rede disponíveis." #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "Falha ao carregar {1}: acesso negado." #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "Uso: LoadMod [--type=global|user|network] [parâmetros]" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "Módulo {1} carregado" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "Módulo {1} carregado: {2}" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "" #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "" #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "" #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "" #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "" #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "Uso: UpdateMod " #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "" #: ClientCommand.cpp:1242 msgid "Done" msgstr "" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "" #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "" #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "" #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "" #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "" #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "Você não está em {1}" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "Você não está em {1} (tentando entrar)" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "O buffer para o canal {1} está vazio" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "Nenhum query ativo com {1}" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "O buffer para {1} está vazio" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "Uso: ClearBuffer <#canal|query>" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "{1} buffer correspondente a {2} foi limpo" msgstr[1] "{1} buffers correspondentes a {2} foram limpos" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "Todos os buffers de canais foram limpos" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "Todos os buffers de queries foram limpos" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "Todos os buffers foram limpos" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "Uso: SetBuffer <#canal|query> [linecount]" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "A configuração do tamanho de buffer para {1} buffer falhou" msgstr[1] "A configuração do tamanho de buffer para {1} buffers falharam" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "Tamanho mínimo de buffer é de {1} linha" msgstr[1] "Tamanho mínimo de buffer é de {1} linhas" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "O tamanho de cada buffer foi configurado para {1} linha" msgstr[1] "O tamanho de cada buffer foi configurado para {1} linhas" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "Nome de usuário" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "Entrada" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "Saída" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "Total" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "Rodando por {1}" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "Comando desconhecido, tente 'Help'" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "Porta" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "BindHost" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "Protocolo" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "IRC" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "Web" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "sim" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "não" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "IPv4 e IPv6" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "IPv4" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "IPv6" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "sim" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "não" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "sim, em {1}" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "não" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" "Uso: AddPort <[+]porta> [bindhost [uriprefix]]" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "Porta adicionada" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "Não foi possível adicionar esta porta" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "Uso: DelPort [bindhost]" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "Porta deletada" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "Não foi possível encontrar uma porta correspondente" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "Comando" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "Descrição" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" "Na lista a seguir, todas as ocorrências de <#chan> suportam wildcards (* " "e ?), exceto ListNicks" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "Imprime qual é esta versão do ZNC" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "Lista todos os módulos carregados" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "Lista todos os módulos disponíveis" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr "" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr "" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr "" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "" #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "" #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "[mensagem]" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "Desconecta do IRC" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "Reconecta ao IRC" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "Mostra por quanto tempo o ZNC está rodando" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "Carrega um módulo" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "[--type=global|user|network] " #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "Descarrega um módulo" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "Recarrega um módulo" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "Recarrega um módulo em todos os lugares" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "Mostra a mensagem do dia do ZNC" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "Configura a mensagem do dia do ZNC" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "Anexa ao MOTD do ZNC" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "Limpa o MOTD do ZNC" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "Mostra todos os listeners ativos" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "<[+]porta> [bindhost [uriprefix]]" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "Adiciona outra porta ao ZNC" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr " [bindhost]" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "Remove uma porta do ZNC" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "Recarrega configurações globais, módulos e listeners do znc.conf" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "Grava as configurações atuais no disco" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "Lista todos os usuários do ZNC e seus estados de conexão" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "Lista todos os usuários ZNC e suas redes" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "[usuário ]" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "[user]" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "Lista todos os clientes conectados" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "Mostra estatísticas básicas de trafego de todos os usuários do ZNC" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "[message]" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "Transmite uma mensagem para todos os usuários do ZNC" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "[message]" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "Desliga o ZNC completamente" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "[message]" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "Reinicia o ZNC" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "Não é possível resolver o nome do host do servidor" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" "Não é possível resolver o nome do host de ligação (BindHost). Tente /znc " "ClearBindHost e /znc ClearUserBindHost" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "" "O endereço do servidor permite apenas IPv4, mas o bindhost é apenas IPv6" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "" "O endereço do servidor permite apenas IPv6, mas o bindhost é apenas IPv4" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "Algum socket atingiu seu limite máximo de buffer e foi fechado!" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "nome de host não corresponde" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "nome de host malformado no certificado" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "erro de verificação do nome de host" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" "Nome de rede inválido. O nome deve ser alfanumérico. Não confundir com o " "nome do servidor" #: User.cpp:511 msgid "Network {1} already exists" msgstr "Rede {1} já existe" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" "Você está sendo desconectado porque seu IP não tem mais permissão para " "conectar-se a esse usuário" #: User.cpp:907 msgid "Password is empty" msgstr "A senha está vazia" #: User.cpp:912 msgid "Username is empty" msgstr "Nome de usuário está vazio" #: User.cpp:917 msgid "Username is invalid" msgstr "Nome de usuário inválido" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "Não foi possível encontrar o modinfo {1}: {2}" znc-1.7.5/src/po/znc.ru_RU.po0000644000175000017500000014543013542151610016141 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/src/po/znc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "Ð’Ñ‹ вошли как: {1}" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "Ð’Ñ‹ не вошли в ÑиÑтему" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "Выйти" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "Домой" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "Глобальные модули" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "ПользовательÑкие модули" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "Модули Ñети {1}" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "Добро пожаловать в веб-Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ZNC!" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" "Ðет загруженных модулей Ñ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ¾Ð¹ веб-интерфейÑа. Ð’Ñ‹ можете загрузить их " "из IRC («/msg *status help» и «/msg *status loadmod <" "модуль>»). Когда такие модули будут загружены, они будут доÑтупны " "в меню Ñбоку." #: znc.cpp:1563 msgid "User already exists" msgstr "Такой пользователь уже еÑть" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "IPv6 не включён" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "SSL не включён" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "Ðе могу найти файл pem: {1}" #: znc.cpp:1706 msgid "Invalid port" msgstr "Ðекорректный порт" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "Ðе получилоÑÑŒ Ñлушать: {1}" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "Текущий Ñервер больше не в ÑпиÑке, переподключаюÑÑŒ" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "Добро пожаловать в ZNC" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "Ð’Ñ‹ отключены от IRC. Введите «connect» Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ." #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "Эта Ñеть будет удалена или перемещена к другому пользователю." #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "Ðе могу зайти на канал {1}, выключаю его." #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "Текущий Ñервер был удалён, переподключаюÑÑŒ..." #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "Ðе могу подключитьÑÑ Ðº {1}, Ñ‚. к. ZNC Ñобран без поддержки SSL." #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "Какой-то модуль оборвал попытку ÑоединениÑ" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "Ошибка от Ñервера: {1}" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "Похоже, ZNC подключён к Ñамому Ñебе, отключаюÑÑŒ..." #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "Возможно, вам Ñтоит добавить его в качеÑтве нового Ñервера." #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "Канал {1} отÑылает к другому каналу и потому будет выключен." #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "Перешёл на SSL (STARTTLS)" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "Ð’Ñ‹ вышли: {1}" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "Отключён от IRC. ПереподключаюÑÑŒ..." #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "Ðе могу подключитьÑÑ Ðº IRC ({1}). ПытаюÑÑŒ ещё раз..." #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "Отключён от IRC ({1}). ПереподключаюÑÑŒ..." #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" "ЕÑли вы доверÑете Ñтому Ñертификату, введите /znc " "AddTrustedServerFingerprint {1}" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "Подключение IRC завершилоÑÑŒ по тайм-ауту. ПереподключаюÑÑŒ..." #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "Ð’ Ñоединении отказано. ПереподключаюÑÑŒ..." #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "От IRC-Ñервера получена Ñлишком Ð´Ð»Ð¸Ð½Ð½Ð°Ñ Ñтрока!" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "Ðе могу найти Ñвободный ник" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "Ðе могу найти Ñвободный ник" #: Client.cpp:74 msgid "No such module {1}" msgstr "Ðет Ð¼Ð¾Ð´ÑƒÐ»Ñ {1}" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "Клиент Ñ {1} попыталÑÑ Ð·Ð°Ð¹Ñ‚Ð¸ под вашим именем, но был отвергнут: {2}" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "Сеть {1} не ÑущеÑтвует." #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" "У Ð²Ð°Ñ Ð½Ð°Ñтроены неÑколько Ñетей, но Ð´Ð»Ñ Ñтого ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð½Ð¸ одна не указана." #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" "Выбираю Ñеть {1}. Чтобы увидеть веÑÑŒ ÑпиÑок, введите команду /znc " "ListNetworks" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" "Чтобы выбрать другую Ñеть, введите /znc JumpNetwork <Ñеть> либо " "подключайтеÑÑŒ к ZNC Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ {1}/<Ñеть> вмеÑто {1}" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" "Ð’Ñ‹ не наÑтроили ни одну Ñеть. Введите команду /znc AddNetwork <Ñеть> чтобы " "добавить Ñеть." #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "Завершаю ÑвÑзь по тайм-ауту" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "Завершаю ÑвÑзь: получена Ñлишком Ð´Ð»Ð¸Ð½Ð½Ð°Ñ Ñтрока" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "Другой пользователь зашёл под вашим именем, отключаем." #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "Ð’Ñ‹ не подключены к IRC, ваш CTCP-Ð·Ð°Ð¿Ñ€Ð¾Ñ Ðº {1} утерÑн!" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "Ð’Ñ‹ не подключены к IRC, ваше Ñообщение к {1} утерÑно!" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "Убираю канал {1}" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "Ð’Ñ‹ не подключены к IRC, ваше Ñообщение к {1} утерÑно!" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "Привет, чем могу быть вам полезен?" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "ИÑпользование: /attach <#каналы>" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "{1} канал подходит под маÑку [{2}]" msgstr[1] "{1} канала подходÑÑ‚ под маÑку [{2}]" msgstr[2] "{1} каналов подходÑÑ‚ под маÑку [{2}]" msgstr[3] "{1} каналов подходÑÑ‚ под маÑку [{2}]" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "ПрицеплÑÑŽ {1} канал" msgstr[1] "ПрицеплÑÑŽ {1} канала" msgstr[2] "ПрицеплÑÑŽ {1} каналов" msgstr[3] "ПрицеплÑÑŽ {1} каналов" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "ИÑпользование: /detach <#каналы>" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "ОтцеплÑÑŽ {1} канал" msgstr[1] "ОтцеплÑÑŽ {1} канала" msgstr[2] "ОтцеплÑÑŽ {1} каналов" msgstr[3] "ОтцеплÑÑŽ {1} каналов" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "ВоÑпроизведение буфера..." #: Chan.cpp:676 msgid "Playback Complete." msgstr "ВоÑпроизведение завершено." #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "<поиÑк>" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "Показать Ñтот вывод" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "Ðе нашёл «{1}»" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "Этот модуль не принимает команды." #: Modules.cpp:693 msgid "Unknown command!" msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°!" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" "ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð¼Ð¾Ð¶ÐµÑ‚ Ñодержать только латинÑкие буквы, цифры и знак " "подчёркиваниÑ; [{1}] не ÑоответÑтвует требованиÑм" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "Модуль {1} уже загружен." #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "Ðе могу найти модуль {1}" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "Модуль {1} не поддерживает тип модулей «{2}»." #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "Модулю {1} необходим пользователь." #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "Модулю {1} необходима Ñеть." #: Modules.cpp:1707 msgid "Caught an exception" msgstr "Поймано иÑключение" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "Модуль {1} прервал: {2}" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "Модуль {1} прервал." #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "Модуль [{1}] не загружен." #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "Модуль {1} выгружен." #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "Ðе могу выгрузить модуль {1}." #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "Модуль {1} перезагружен." #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "Ðе могу найти модуль {1}." #: Modules.cpp:1963 msgid "Unknown error" msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "Ðе могу открыть модуль {1}: {2}" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "Ðе могу найти ZNCModuleEntry в модуле {1}" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" "Ядро имеет верÑию {2}, а модуль {1} Ñобран Ð´Ð»Ñ {3}. ПереÑоберите Ñтот модуль." #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" "Модуль {1} Ñобран не так: Ñдро — «{2}», а модуль — «{3}». ПереÑоберите Ñтот " "модуль." #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "Команда" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "ОпиÑание" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "Чтобы иÑпользовать Ñто команду, подключитеÑÑŒ к Ñети" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "ИÑпользование: ListNicks <#chan>" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "Ð’Ñ‹ не на [{1}]" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "Ð’Ñ‹ не на [{1}] (пытаюÑÑŒ войти)" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "Ðа [{1}] никого" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "Ðик" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "Идент" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "ХоÑÑ‚" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "ИÑпользование: Attach <#каналы>" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "ИÑпользование: Dettach <#chans>" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "Сообщение Ð´Ð½Ñ Ð½Ðµ уÑтановлено." #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "Готово!" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "Ошибка: {1}" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð¿Ð¸Ñана в {1}" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "При запиÑи конфигурации произошла ошибка." #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "ИÑпользование: ListChans" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "Ðет такого Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ [{1}]" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "У Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ [{1}] нет Ñети [{2}]" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "Ðи один канал не наÑтроен." #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "Ðазвание" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "СоÑтоÑние" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "Ð’ конфигурации" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "Буфер" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "ОчиÑтить" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "Режимы" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "Пользователи" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "Отцеплен" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "Ðа канале" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "Выключен" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "ПытаюÑÑŒ" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "да" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "Ð’Ñего: {1}, прицеплено: {2}, отцеплено: {3}, выключено: {4}" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "ДоÑтигнуто ограничение на количеÑтво Ñетей. ПопроÑите админиÑтратора поднÑть " "вам лимит или удалите ненужные Ñети Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ /znc DelNetwork <Ñеть>" #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "ИÑпользование: AddNetwork <Ñеть>" #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "Ðазвание Ñети может Ñодержать только цифры и латинÑкие буквы" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" "Сеть добавлена. Чтобы подÑоединитьÑÑ Ðº ней, введите /znc JumpNetwork {1} " "либо подключайтеÑÑŒ к ZNC Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ {2} вмеÑто {3}." #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "Ðе могу добавить Ñту Ñеть" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "ИÑпользование: DelNetwork <Ñеть>" #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "Сеть удалена" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "Ðе могу удалить Ñеть, возможно, она не ÑущеÑтвует" #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "Пользователь {1} не найден" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "Сеть" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "Ð’ Ñети" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "IRC-Ñервер" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "Пользователь в IRC" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "Каналов" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "Да" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "Ðет" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "Ðет Ñетей" #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "ДоÑтуп запрещён." #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" "ИÑпользование: MoveNetwork <Ñтарый пользователь> <ÑÑ‚Ð°Ñ€Ð°Ñ Ñеть> <новый " "пользователь> [Ð½Ð¾Ð²Ð°Ñ Ñеть]" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "Старый пользователь {1} не найден." #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "Ð¡Ñ‚Ð°Ñ€Ð°Ñ Ñеть {1} не найдена." #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "Ðовый пользователь {1} не найден." #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "У Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ {1} уже еÑть Ñеть {2}." #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "Ðекорректное Ð¸Ð¼Ñ Ñети [{1}]" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "" "Ð’ {1} оÑталиÑÑŒ какие-то файлы. Возможно, вам нужно перемеÑтить их в {2}" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "Ошибка при добавлении Ñети: {1}" #: ClientCommand.cpp:718 msgid "Success." msgstr "УÑпех." #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "Сеть Ñкопирована уÑпешно, но не могу удалить Ñтарую Ñеть" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "Сеть не указана." #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "Ð’Ñ‹ уже подключены к Ñтой Ñети." #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "Переключаю на {1}" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "У Ð²Ð°Ñ Ð½ÐµÑ‚ Ñети Ñ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸ÐµÐ¼ {1}" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "ИÑпользование: AddServer <хоÑÑ‚> [[+]порт] [пароль]" #: ClientCommand.cpp:759 msgid "Server added" msgstr "Сервер добавлен" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" "Ðе могу добавить Ñервер. Возможно, он уже в ÑпиÑке, или поддержка openssl " "выключена?" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "ИÑпользование: DelServer <хоÑÑ‚> [порт] [пароль]" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "Ð’Ñ‹ не наÑтроили ни один Ñервер." #: ClientCommand.cpp:787 msgid "Server removed" msgstr "Сервер удалён" #: ClientCommand.cpp:789 msgid "No such server" msgstr "Ðет такого Ñервера" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "ХоÑÑ‚" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "Порт" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "Пароль" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "ИÑпользование: AddTrustedServerFingerprint " #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "Готово." #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "ИÑпользование: DelTrustedServerFingerprint " #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "Отпечатки не добавлены." #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "Канал" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "УÑтановлена" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "Тема" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "Ðазвание" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "Параметры" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "Глобальные модули не загружены." #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "Глобальные модули:" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "У вашего Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½ÐµÑ‚ загруженных модулей." #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "ПользовательÑкие модули:" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "У Ñтой Ñети нет загруженных модулей." #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "Сетевые модули:" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "Ðазвание" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "ОпиÑание" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "Глобальные модули недоÑтупны." #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "ПользовательÑкие модули недоÑтупны." #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "Сетевые модули недоÑтупны." #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "Ðе могу загрузить {1}: доÑтуп запрещён." #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "" "ИÑпользование: LoadMod [--type=global|user|network] <модуль> [параметры]" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "Ðе могу загрузить {1}: {2}" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "Ðе могу загрузить глобальный модуль {1}: доÑтуп запрещён." #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "Ðе могу загрузить Ñетевой модуль {1}: клиент подключён без Ñети." #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "ÐеизвеÑтный тип модулÑ" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "Модуль {1} загружен" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "Модуль {1} загружен: {2}" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "Ðе могу загрузить модуль {1}: {2}" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "Ðе могу выгрузить {1}: доÑтуп запрещён." #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "ИÑпользование: UnloadMod [--type=global|user|network] <модуль>" #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "Ðе могу определить тип {1}: {2}" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "Ðе могу выгрузить глобальный модуль {1}: доÑтуп запрещён." #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "Ðе могу выгрузить Ñетевой модуль {1}: клиент подключён без Ñети." #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "Ðе могу выгрузить модуль {1}: неизвеÑтный тип модулÑ" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "Ðе могу перезагрузить модули: доÑтуп запрещён." #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "" "ИÑпользование: ReloadMod [--type=global|user|network] <модуль> [параметры]" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "Ðе могу перезагрузить {1}: {2}" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "Ðе могу перезагрузить глобальный модуль {1}: доÑтуп запрещён." #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "Ðе могу перезагрузить Ñетевой модуль {1}: клиент подключён без Ñети." #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "Ðе могу перезагрузить модуль {1}: неизвеÑтный тип модулÑ" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "ИÑпользование: UpdateMod <модуль>" #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "Перезагружаю {1} везде" #: ClientCommand.cpp:1242 msgid "Done" msgstr "Готово" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "Готово, но ÑлучилиÑÑŒ ошибки, модуль {1} перезагружен не везде." #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" "Чтобы иÑпользовать Ñту команду, нужна Ñеть. Попробуйте вмеÑто Ñтого " "SetUserBindHost" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "ИÑпользование: SetBindHost <хоÑÑ‚>" #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "У Ð’Ð°Ñ ÑƒÐ¶Ðµ уÑтановлен Ñтот хоÑÑ‚!" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "Ð¡Ð¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ Ñетью {1} будут идти через локальный Ð°Ð´Ñ€ÐµÑ {2}" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "ИÑпользование: SetUserBindHost <хоÑÑ‚>" #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "По умолчанию ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ идти через локальный Ð°Ð´Ñ€ÐµÑ {1}" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" "Чтобы иÑпользовать Ñту команду, нужна Ñеть. Попробуйте вмеÑто Ñтого " "ClearUserBindHost" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "ИÑходÑщий хоÑÑ‚ Ð´Ð»Ñ Ñтой Ñети очищен." #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "ИÑходÑщий хоÑÑ‚ Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¾Ñ‡Ð¸Ñ‰ÐµÐ½." #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "ИÑходÑщий хоÑÑ‚ по умолчанию Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½Ðµ уÑтановлен" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "ИÑходÑщий хоÑÑ‚ по умолчанию Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ пользователÑ: {1}" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "ИÑходÑщий хоÑÑ‚ Ð´Ð»Ñ Ñтой Ñети не уÑтановлен" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "ИÑходÑщий хоÑÑ‚ по умолчанию Ð´Ð»Ñ Ñтой Ñети: {1}" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "ИÑпользование: PlayBuffer <#канал|ÑобеÑедник>" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "Ð’Ñ‹ не на {1}" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "Ð’Ñ‹ не на {1} (пытаюÑÑŒ войти)" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "Буфер канала {1} пуÑÑ‚" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "Ðет активной беÑеды Ñ {1}" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "Буфер Ð´Ð»Ñ {1} пуÑÑ‚" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "ИÑпользование: ClearBuffer <#канал|ÑобеÑедник>" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "{1} буфер, подходÑщий под {2}, очищен" msgstr[1] "{1} буфера, подходÑщий под {2}, очищены" msgstr[2] "{1} буферов, подходÑщий под {2}, очищены" msgstr[3] "{1} буферов, подходÑщий под {2}, очищены" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "Буферы вÑех каналов очищены" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "Буферы вÑех беÑед очищены" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "Ð’Ñе буферы очищены" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "ИÑпользование: SetBuffer <#канал|ÑобеÑедник> [чиÑло_Ñтрок]" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "Ðе удалоÑÑŒ уÑтановить размер буфера Ð´Ð»Ñ {1} канала" msgstr[1] "Ðе удалоÑÑŒ уÑтановить размер буфера Ð´Ð»Ñ {1} каналов" msgstr[2] "Ðе удалоÑÑŒ уÑтановить размер буфера Ð´Ð»Ñ {1} каналов" msgstr[3] "Ðе удалоÑÑŒ уÑтановить размер буфера Ð´Ð»Ñ {1} каналов" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "Размер буфера не должен превышать {1} Ñтроку" msgstr[1] "Размер буфера не должен превышать {1} Ñтроки" msgstr[2] "Размер буфера не должен превышать {1} Ñтрок" msgstr[3] "Размер буфера не должен превышать {1} Ñтрок" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "Размер каждого буфера уÑтановлен в {1} Ñтроку" msgstr[1] "Размер каждого буфера уÑтановлен в {1} Ñтроки" msgstr[2] "Размер каждого буфера уÑтановлен в {1} Ñтрок" msgstr[3] "Размер каждого буфера уÑтановлен в {1} Ñтрок" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "Пришло" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "Ушло" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "Ð’Ñего" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "<Пользователи>" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "<Ð’Ñего>" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "Запущен {1}" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°, попробуйте 'Help'" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "Порт" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "BindHost" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "Протокол" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "IRC" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "Веб" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "да" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "нет" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "IPv4 и IPv6" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "IPv4" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "IPv6" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "да" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "нет" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "да, на {1}" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "нет" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" "ИÑпользование: AddPort <[+]port> [bindhost " "[uriprefix]]" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "Порт добавлен" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "Ðевозможно добавить порт" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "ИÑпользование: DelPort [bindhost]" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "Удалён порт" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "Ðе могу найти такой порт" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "Команда" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "ОпиÑание" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" "Ð’ Ñтом ÑпиÑке <#каналы> везде, кроме ListNicks, поддерживают шаблоны (* и ?)" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "Показывает верÑию ZNC" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "СпиÑок вÑех загруженных модулей" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "СпиÑок вÑех доÑтупных модулей" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "СпиÑок вÑех каналов" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "<#канал>" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "СпиÑок вÑех людей на канале" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "СпиÑок вÑех клиентов, подключенных к вашему пользователю ZNC" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "СпиÑок вÑех Ñерверов Ñтой Ñети IRC" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "<название>" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr "<Ñтарый пользователь> <ÑÑ‚Ð°Ñ€Ð°Ñ Ñеть> <новый пользователь> [Ð½Ð¾Ð²Ð°Ñ Ñеть]" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr "" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr "" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "" #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "" #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "<#каналы>" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "" #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr "" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" #: User.cpp:511 msgid "Network {1} already exists" msgstr "" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" #: User.cpp:907 msgid "Password is empty" msgstr "" #: User.cpp:912 msgid "Username is empty" msgstr "" #: User.cpp:917 msgid "Username is invalid" msgstr "" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "" znc-1.7.5/src/po/znc.de_DE.po0000644000175000017500000013717013542151610016047 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/src/po/znc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "Angemeldet als: {1}" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "Nicht angemeldet" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "Abmelden" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "Startseite" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "Globale Module" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "Benutzer-Module" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "Netzwerk-Module ({1})" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "Willkommen bei ZNCs Web-Oberfläche!" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" "Es wurden keine Web-fähigen Module geladen. Lade Module über IRC (\"/" "msg *status help\" und \"/msg *status loadmod <module>\"). Sobald einige Web-fähige Module geladen wurden, wird das Menü " "größer." #: znc.cpp:1563 msgid "User already exists" msgstr "Benutzer existiert bereits" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "IPv6 ist nicht aktiviert" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "SSL ist nicht aktiviert" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "Kann PEM-Datei nicht finden: {1}" #: znc.cpp:1706 msgid "Invalid port" msgstr "Ungültiger Port" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "Kann nicht horchen: {1}" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "" "Springe zu einem Server, da dieser Server nicht länger in der Liste ist" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "Willkommen bei ZNC" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "" "Du bist zur Zeit nicht mit dem IRC verbunden. Verwende 'connect' zum " "Verbinden." #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "" "Dieses Netzwerk wird gelöscht oder zu einem anderen Benutzer verschoben." #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "Der Kanal {1} konnte nicht betreten werden und wird deaktiviert." #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "Dein aktueller Server wurde entfernt, springe..." #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "" "Kann nicht zu {1} verbinden, da ZNC ohne SSL-Unterstützung gebaut wurde." #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "Ein Modul hat den Verbindungsversuch abgebrochen" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "Fehler vom Server: {1}" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "ZNC scheint zu sich selbst verbunden zu sein, trenne die Verbindung..." #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "Der Server {1} hat uns zu {2}:{3} umgeleitet mit der Begründung: {4}" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "Vielleicht möchtest du dies als einen neuen Server hinzufügen." #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "" "Kanal {1} ist mit einem anderen Kanal verbunden und wurde daher deaktiviert." #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "Zu SSL gewechselt (STARTTLS)" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "Du hast die Verbindung getrennt: {1}" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "IRC-Verbindung getrennt. Verbinde erneut..." #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "Kann nicht mit IRC verbinden ({1}). Versuche es erneut..." #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "IRC-Verbindung getrennt ({1}). Verbinde erneut..." #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" "Falls du diesem Zertifikat vertraust, mache /znc AddTrustedServerFingerprint " "{1}" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "Zeitüberschreitung der IRC-Verbindung. Verbinde erneut..." #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "Verbindung abgelehnt. Verbinde erneut..." #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "Eine zu lange Zeile wurde vom IRC-Server empfangen!" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "Kein freier Nick verfügbar" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "Kein freier Nick gefunden" #: Client.cpp:74 msgid "No such module {1}" msgstr "Kein solches Modul {1}" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "" "Ein Client hat versucht sich von {1} aus als dich anzumelden, aber wurde " "abgelehnt: {2}" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "Netzwerk {1} existiert nicht." #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" "Du hast mehrere Netzwerke, aber kein Netzwerk wurde für die Verbindung " "ausgewählt." #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" "Wähle Netzwerk {1}. Um eine Liste aller konfigurierten Netzwerke zu sehen, " "verwende /znc ListNetworks" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" "Falls du ein anderes Netzwerk wählen möchtest, verwende /znc JumpNetwork " ", oder verbinde dich zu ZNC mit dem Benutzernamen {1}/ " "(statt einfach nur {1})" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" "Du hast keine Netzwerke konfiguriert. Verwende /znc AddNetwork um " "eines hinzuzufügen." #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "Schließe Verbindung: Zeitüberschreitung" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "Schließe Verbindung: Überlange Rohzeile" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "" "Deine Verbindung wird getrennt, da ein anderen Benutzer sich als dich " "angemeldet hat." #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "Dein CTCP an {1} wurde verloren, du bist nicht mit dem IRC verbunden!" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "" "Deine Benachrichtigung an {1} wurde verloren, du bist nicht mit dem IRC " "verbunden!" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "Entferne Kanal {1}" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "" "Deine Nachricht an {1} wurde verloren, du bist nicht mit dem IRC verbunden!" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "Hallo. Wie kann ich dir helfen?" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "Verwendung: /attach <#Kanal>" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "Es gibt einen Kanal, der auf [{2}] passt" msgstr[1] "Es gibt {1} Kanäle, die auf [{2}] passen" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "Zu {1} Kanal verbunden" msgstr[1] "Zu {1} Kanälen verbunden" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "Verwendung: /detach <#Kanäle>" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "Von {1} Kanal getrennt" msgstr[1] "Von {1} Kanälen getrennt" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "Pufferwiedergabe..." #: Chan.cpp:676 msgid "Playback Complete." msgstr "Wiedergabe beendet." #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "Erzeuge diese Ausgabe" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "Keine Treffer für '{1}'" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "Dieses Modul implementiert keine Befehle." #: Modules.cpp:693 msgid "Unknown command!" msgstr "Unbekannter Befehl!" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" "Modulnamen können nur Buchstaben, Zahlen und Unterstriche enthalten, [{1}] " "ist ungültig" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "Modul {1} bereits geladen." #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "Kann Modul {1} nicht finden" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "Modul {1} unterstützt den Modultyp {2} nicht." #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "Modul {1} benötigt einen Benutzer." #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "Modul {1} benötigt ein Netzwerk." #: Modules.cpp:1707 msgid "Caught an exception" msgstr "Eine Ausnahme wurde gefangen" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "Modul {1} abgebrochen: {2}" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "Modul {1} abgebrochen." #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "Modul [{1}] ist nicht geladen." #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "Modul {1} entladen." #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "Kann Modul {1} nicht entladen." #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "Module {1} neu geladen." #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "Kann Modul {1} nicht finden." #: Modules.cpp:1963 msgid "Unknown error" msgstr "Unbekannter Fehler" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "Konnte Modul {1} nicht öffnen: {2}" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "Konnte ZNCModuleEntry im Modul {1} nicht finden" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" "Versionsfehler für Modul {1}: Kern ist {2}, Modul ist für {3} gebaut. " "Rekompiliere dieses Modul." #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" "Modul {1} ist inkompatibel gebaut: Kern ist '{2}', Modul ist '{3}'. Baue das " "Modul neu." #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "Befehl" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "Beschreibung" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "" "Sie müssen mit einem Netzwerk verbunden sein um diesen Befehl zu verwenden" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "Verwendung: ListNicks <#chan>" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "Sie sind nicht in [{1}]" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "Sie sind nicht in [{1}] (wird versucht)" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "Keine Nicks in [{1}]" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "Nick" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "Ident" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "Host" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "Verwendung: Attach <#Kanäle>" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "Verwendung: Detach <#Kanäle>" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "Es ist keine MOTD gesetzt." #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "Rehashen erfolgreich!" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "Rehashen fehlgeschlagen: {1}" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "Konfiguration nach {1} geschrieben" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "Fehler beim Schreiben der Konfiguration." #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "Verwendung: ListChans" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "Kein solcher Benutzer [{1}]" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "Benutzer [{1}] hat kein Netzwerk [{2}]" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "Es wurden noch keine Kanäle definiert." #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "Name" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "Status" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "In Konfig" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "Puffer" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "Lösche" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "Modi" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "Benutzer" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "Getrennt" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "Betreten" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "Deaktiviert" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "Versuche" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "ja" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "Gesamt: {1}, Betreten: {2}, Getrennt: {3}, Deaktiviert: {4}" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "Netzwerk-Anzahl-Limit erreicht. Bitte einen Administrator deinen Grenzwert " "zu erhöhen, oder lösche nicht benötigte Netzwerke mit /znc DelNetwork " #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "Verwendung: AddNetwork " #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "Netzwerknamen müssen alphanumerisch sein" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" "Netzwerk hinzugefügt. Verwende /znc JumpNetwork {1}, oder verbinde dich zu " "ZNC mit Benutzername {2} (statt nur {3}) um mit dem Netzwerk zu verbinden." #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "Dieses Netzwerk kann nicht hinzugefügt werden" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "Verwendung: DelNetwork " #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "Netzwerk gelöscht" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "Kann das Netzwerk nicht löschen, vielleicht existiert es nicht" #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "Benutzer {1} nicht gefunden" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "Netzwerk" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "Im IRC" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "IRC-Server" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "IRC-Benutzer" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "Kanäle" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "Ja" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "Nein" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "Keine Netzwerke" #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "Zugriff verweigert." #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" "Verwendung: MoveNetwork " "[neues Netzwerk]" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "Alter Benutzer {1} nicht gefunden." #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "Altes Netzwerk {1} nicht gefunden." #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "Neuer Benutzer {1} nicht gefunden." #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "Benutzer {1} hat bereits ein Netzwerk {2}." #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "Ungültiger Netzwerkname [{1}]" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "" "Einige Dateien scheinen in {1} zu sein. Du könntest sie nach {2} verschieben " "wollen" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "Fehler beim Netzwerk-Hinzufügen: {1}" #: ClientCommand.cpp:718 msgid "Success." msgstr "Geschafft." #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "" "Das Netzwerk wurde zum neuen Benutzer kopiert, aber das alte Netzwerk konnte " "nicht gelöscht werden" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "Kein Netzwerk angegeben." #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "Du bist bereits mit diesem Netzwerk verbunden." #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "Zu {1} gewechselt" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "Du hast kein Netzwerk namens {1}" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "Verwendung: AddServer [[+]Port] [Pass]" #: ClientCommand.cpp:759 msgid "Server added" msgstr "Server hinzugefügt" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" "Kann den Server nicht hinzufügen. Vielleicht ist dieser Server bereits " "hinzugefügt oder openssl ist deaktiviert?" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "Verwendung: DelServer [Port] [Pass]" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "Du hast keine Server hinzugefügt." #: ClientCommand.cpp:787 msgid "Server removed" msgstr "Server entfernt" #: ClientCommand.cpp:789 msgid "No such server" msgstr "Kein solcher Server" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "Host" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "Port" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "Passwort" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "Verwendung: AddTrustedServerFingerprint " #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "Erledigt." #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "Verwendung: DelTrustedServerFingerprint " #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "Keine Fingerabdrücke hinzugefügt." #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "Kanal" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "Gesetzt von" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "Thema" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "Name" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "Argumente" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "Keine globalen Module geladen." #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "Globale Module:" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "Dein Benutzer hat keine Module geladen." #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "Benutzer-Module:" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "Dieses Netzwerk hat keine Module geladen." #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "Netzwerk-Module:" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "Name" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "Beschreibung" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "Keine globalen Module verfügbar." #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "Keine Benutzer-Module verfügbar." #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "Keine Netzwerk-Module verfügbar." #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "Kann {1} nicht laden: Zugriff verweigert." #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "Verwendung: LoadMod [--type=global|user|network] [Argumente]" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "Kann {1} nicht laden: {2}" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "Kann globales Modul {1} nicht laden: Zugriff verweigert." #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "" "Kann Netzwerk-Module {1} nicht laden: Nicht mit einem Netzwerk verbunden." #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "Unbekannter Modul-Typ" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "Module {1} geladen" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "Modul {1} geladen: {2}" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "Kann Modul {1} nicht laden: {2}" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "Kann Modul {1} nicht entladen: Zugriff verweigert." #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "Verwendung: UnloadMod [--type=global|user|network] " #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "Kann Typ von {1} nicht feststellen: {2}" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "Kann globales Modul {1} nicht entladen: Zugriff verweigert." #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "" "Kann Netzwerk-Module {1} nicht entladen: Nicht mit einem Netzwerk verbunden." #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "Kann Modul {1} nicht entladen: Unbekannter Modul-Typ" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "Kann Module nicht neu laden: Zugriff verweigert." #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "Verwendung: ReloadMod [--type=global|user|network] [Argumente]" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "Kann {1} nicht neu laden: {2}" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "Kann globales Modul {1} nicht neu laden: Zugriff verweigert." #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "" "Kann Netzwerk-Module {1} nicht neu laden: Nicht mit einem Netzwerk verbunden." #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "Kann Modul {1} nicht neu laden: Unbekannter Modul-Typ" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "Verwendung: UpdateMod " #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "Lade {1} überall neu" #: ClientCommand.cpp:1242 msgid "Done" msgstr "Erledigt" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "" "Erledigt, aber es gab Fehler, Modul {1} konnte nicht überall neu geladen " "werden." #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" "Du musst mit einem Netzwerk verbunden sein um diesen Befehl zu verwenden. " "Versuche SetUserBindHost statt dessen" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "Verwendung: SetBindHost " #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "Du hast bereits diesen Bindhost!" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "Setze Bindhost für Netzwerk {1} auf {2}" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "Verwendung: SetUserBindHost " #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "Setze Standard-Bindhost auf {1}" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" "Du musst mit einem Netzwerk verbunden sein um diesen Befehl zu verwenden. " "Versuche ClearUserBindHost statt dessen" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "Bindhost für dieses Netzwerk gelöscht." #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "Standard-Bindhost für deinen Benutzer gelöscht." #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "Der Benutzer hat keinen Bindhost gesetzt" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "Der Standard-Bindhost des Benutzers ist {1}" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "Dieses Netzwerk hat keinen Standard-Bindhost gesetzt" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "Der Standard-Bindhost dieses Netzwerkes ist {1}" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "Verwendung: PlayBuffer <#chan|query>" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "Du bist nicht in {1}" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "Du bist nicht in {1} (versuche zu betreten)" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "Der Puffer für Kanal {1} ist leer" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "Kein aktivier Query mit {1}" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "Der Puffer für {1} ist leer" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "Verwendung: ClearBuffer <#chan|query>" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "{1} Puffer, der auf {2} passt, wurde gelöscht" msgstr[1] "{1} Puffer, die auf {2} passen, wurden gelöscht" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "Alle Kanalpuffer wurden gelöscht" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "Alle Querypuffer wurden gelöscht" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "Alle Puffer wurden gelöscht" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "Verwendung: SetBuffer <#chan|query> [Anzahl Zeilen]" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "Setzen der Puffergröße schlug für {1} Puffer fehl" msgstr[1] "Setzen der Puffergröße schlug für {1} Puffer fehl" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "Maximale Puffergröße ist {1} Zeile" msgstr[1] "Maximale Puffergröße ist {1} Zeilen" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "Größe jedes Puffers wurde auf {1} Zeile gesetzt" msgstr[1] "Größe jedes Puffers wurde auf {1} Zeilen gesetzt" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "Benutzername" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "Ein" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "Aus" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "Gesamt" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "Laufe seit {1}" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "Unbekanntes Kommando, versuche 'Help'" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "Port" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "Bindhost" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "Protokol" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "IRC" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "Web" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "ja" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "nein" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "IPv4 und IPv6" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "IPv4" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "IPv6" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "ja" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "nein" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "ja, unter {1}" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "nein" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" "Verwendung: AddPort <[+]port> [Bindhost " "[URIPrefix]]" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "Port hinzugefügt" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "Konnte Port nicht hinzufügen" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "Verwendung: DelPort [Bindhost]" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "Port gelöscht" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "Konnte keinen passenden Port finden" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "Befehl" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "Beschreibung" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" "In der folgenden Liste unterstützen alle vorkommen von <#chan> Wildcards (* " "und ?), außer ListNicks" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "Zeige die Version von ZNC an" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "Zeige alle geladenen Module" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "Zeige alle verfügbaren Module" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "Zeige alle Kanäle" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "<#Kanal>" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "Alle Nicks eines Kanals auflisten" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "Alle Clients auflisten, die zu deinem ZNC-Benutzer verbunden sind" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "Zeige alle Server des aktuellen IRC-Netzwerkes" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "Füge ein Netzwerk zu deinem Benutzer hinzu" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "Lösche ein Netzwerk von deinem Benutzer" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "Alle Netzwerke auflisten" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr " [neues Netzwerk]" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "Verschiebe ein IRC-Netzwerk von einem Benutzer zu einem anderen" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" "Springe zu einem anderen Netzwerk (alternativ kannst du auch mehrfach zu ZNC " "verbinden und `Benutzer/Netzwerk` als Benutzername verwenden)" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr " [[+]Port] [Pass]" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" "Füge einen Server zur Liste der alternativen/backup Server des aktuellen IRC-" "Netzwerkes hinzu." #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr " [Port] [Pass]" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" "Lösche einen Server von der Liste der alternativen/backup Server des " "aktuellen IRC-Netzwerkes" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" "Füge den Fingerabdruck (SHA-256) eines vertrauenswürdigen SSL-Zertifikates " "zum aktuellen IRC-Netzwerk hinzu." #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "" "Lösche ein vertrauenswürdiges Server-SSL-Zertifikat vom aktuellen IRC-" "Netzwerk." #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "" "Zeige alle vertrauenswürdigen Server-SSL-Zertifikate des aktuellen IRC-" "Netzwerkes an." #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "<#Kanäle>" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "Aktivierte Kanäle" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "<#Kanäle>" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "Deaktiviere Kanäle" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "<#Kanäle>" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "Verbinde zu Kanälen" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "<#Kanäle>" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "Trenne von Kanälen" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "Zeige die Themen aller deiner Kanäle" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "<#Kanal|Query>" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "Spiele den angegebenen Puffer ab" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "<#Kanal|Query>" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "Lösche den angegebenen Puffer" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "Lösche alle Kanal- und Querypuffer" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "Lösche alle Kanalpuffer" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "Lösche alle Querypuffer" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "<#Kanal|Query> [Zeilenzahl]" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "Setze die Puffergröße" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "Setze den Bindhost für dieses Netzwerk" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "Setze den Standard-Bindhost für diesen Benutzer" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "Lösche den Bindhost für dieses Netzwerk" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "Lösche den Standard-Bindhost für diesen Benutzer" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "Zeige den aktuell gewählten Bindhost" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "[Server]" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "Springe zum nächsten oder dem angegebenen Server" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "[Nachricht]" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "Trenne die IRC-Verbindung" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "Baue eine neue IRC-Verbindung auf" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "Zeige wie lange ZNC schon läuft" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "[--type=global|user|network] [args]" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "Lade ein Modul" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "[--type=global|user|network] " #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "Entlade ein Modul" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "[--type=global|user|network] [args]" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "Ein Modul neu laden" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "Lade ein Modul überall neu" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "Zeige ZNCs Nachricht des Tages an" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "Setze ZNCs Nachricht des Tages" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "Hänge an ZNCs MOTD an" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "Lösche ZNCs MOTD" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "Zeige alle aktiven Listener" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "<[+]Port> [Bindhost [uriprefix]]" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "Füge einen weiteren Port zum Horchen zu ZNC hinzu" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr " [Bindhost]" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "Entferne einen Port von ZNC" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "Lade globale Einstellungen, Module und Listener neu von znc.conf" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "Speichere die aktuellen Einstellungen auf der Festplatte" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "Zeige alle ZNC-Benutzer und deren Verbindungsstatus" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "Zeige alle ZNC-Benutzer und deren Netzwerke" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "[Benutzer ]" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "[Benutzer]" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "Zeige alle verbunden Klienten" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "Zeige grundlegende Verkehrsstatistiken aller ZNC-Benutzer an" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "[Nachricht]" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "Sende eine Nachricht an alle ZNC-Benutzer" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "[Nachricht]" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "Beende ZNC komplett" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "[Nachricht]" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "Starte ZNC neu" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "Kann den Hostnamen des Servers nicht auflösen" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" "Kann Binde-Hostnamen nicht auflösen. Versuche /znc ClearBindHost und /znc " "ClearUserBindHost" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "Server hat nur eine IPv4-Adresse, aber Binde-Hostname ist nur IPv6" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "Server hat nur eine IPv6-Adresse, aber Binde-Hostname ist nur IPv4" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "" "Eine Verbindung hat ihre maximale Puffergrenze erreicht und wurde " "geschlossen!" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "hostname passt nicht" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "fehlerhafter Hostname im Zertifikat" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "hostnamen-Überprüfung fehlgeschlagen" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" "Ungültiger Netzwerkname. Er sollte alpha-numerisch sein. Nicht mit Server-" "Namen verwechseln" #: User.cpp:511 msgid "Network {1} already exists" msgstr "Netzwerk {1} existiert bereits" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" "Deine Verbindung wird geschlossen da deine IP sich nicht länger zu diesem " "Benutzer verbinden darf" #: User.cpp:907 msgid "Password is empty" msgstr "Passwort ist leer" #: User.cpp:912 msgid "Username is empty" msgstr "Benutzername ist leer" #: User.cpp:917 msgid "Username is invalid" msgstr "Benutzername ist ungültig" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "Kann Modulinformationen für {1} nicht finden: {2}" znc-1.7.5/src/po/znc.fr_FR.po0000644000175000017500000014041313542151610016077 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/src/po/znc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "Connecté en tant que : {1}" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "Déconnecté" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "Déconnexion" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "Accueil" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "Modules généraux" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "Modules utilisateur" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "Modules du réseau ({1})" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "Bienvenue sur l'interface web de ZNC !" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" "Aucun module avec des capacités web n'a été chargé. Vous pouvez charger des " "modules depuis IRC (“/msg *status help†et “/msg *status " "loadmod <module>â€). Les modules avec des capacités web " "apparaîtront ci-dessous." #: znc.cpp:1563 msgid "User already exists" msgstr "Cet utilisateur existe déjà" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "IPv6 n'est pas activé" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "SSL n'est pas activé" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "Impossible de trouver le fichier pem : {1}" #: znc.cpp:1706 msgid "Invalid port" msgstr "Port invalide" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "Impossible d'utiliser le port : {1}" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "" "Connexion au serveur suivant, le serveur actuel n'est plus dans la liste" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "Bienvenue sur ZNC" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "" "Vous êtes actuellement déconnecté d'IRC. Utilisez 'connect' pour vous " "reconnecter." #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "" "Ce réseau est en train d'être supprimé ou déplacé vers un autre utilisateur." #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "Impossible de rejoindre le salon {1}, il est désormais désactivé." #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "Le serveur actuel a été supprimé. Changement en cours..." #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "" "Impossible de se connecter à {1}, car ZNC n'a pas été compilé avec le " "support SSL." #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "Un module a annulé la tentative de connexion" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "Erreur du serveur : {1}" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "ZNC semble s'être connecté à lui-même, déconnexion..." #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "Le serveur {1} redirige vers {2}:{3} avec pour motif : {4}" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "Vous souhaitez peut-être l'ajouter comme un nouveau server." #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "Le salon {1} est lié à un autre salon et est par conséquent désactivé." #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "Passage à SSL (STARTTLS)" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "Vous avez quitté : {1}" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "Déconnecté d'IRC. Reconnexion..." #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "Échec de la connexion à IRC ({1}). Nouvel essai..." #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "Déconnecté de IRC ({1}). Reconnexion..." #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" "Si vous avez confiance en ce certificat, tapez /znc " "AddTrustedServerFingerprint {1}" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "La connexion à IRC a expiré. Reconnexion..." #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "Connexion refusée. Reconnexion..." #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "Le serveur IRC a envoyé une ligne trop longue !" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "Aucun pseudonyme n'est disponible" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "Aucun pseudonyme disponible n'a été trouvé" #: Client.cpp:74 msgid "No such module {1}" msgstr "Le module {1} n'existe pas" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "" "Un client {1} a tenté de se connecter sous votre identifiant, mais a été " "refusé : {2}" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "Le réseau {1} n'existe pas." #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" "Plusieurs réseaux sont configurés, mais aucun n'a spécifié pour la connexion." #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" "Sélection du réseau {1}. Pour consulter la liste des réseaux configurés, " "tapez /znc ListNetworks" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" "Si vous souhaitez changer de réseau, tapez /znc JumpNetwork , ou " "connectez-vous à ZNC avec l'identifiant {1}/ (à la place de " "seulement {1})" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" "Vous n'avez configuré aucun réseau. Tapez /znc AddNetwork pour en " "ajouter un." #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "Fermeture de la connexion : expirée" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "Fermeture de la connexion : ligne trop longue" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "" "Vous avez été déconnecté car un autre utilisateur s'est authentifié avec le " "même identifiant." #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "" "Votre connexion CTCP vers {1} a été perdue, vous n'êtes plus connecté à IRC !" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "Votre notice vers {1} a été perdue, vous n'êtes plus connecté à IRC !" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "Suppression du salon {1}" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "Votre message à {1} a été perdu, vous n'êtes pas connecté à IRC !" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "Bonjour. Comment puis-je vous aider ?" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "Utilisation : /attach <#salons>" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "Il y avait {1} salon correspondant [{2}]" msgstr[1] "Il y avait {1} salons correspondant [{2}]" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "A attaché {1} salon" msgstr[1] "A attaché {1} salons" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "Utilisation : /detach <#salons>" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "A détaché {1} salon" msgstr[1] "A détaché {1} salons" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "Répétition du tampon..." #: Chan.cpp:676 msgid "Playback Complete." msgstr "Répétition terminée." #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "Générer cette sortie" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "Aucune correspondance pour '{1}'" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "Ce module n'implémente aucune commande." #: Modules.cpp:693 msgid "Unknown command!" msgstr "Commande inconnue !" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" "Les noms de module ne peuvent contenir que des lettres, des chiffres et des " "underscores, [{1}] est invalide" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "Le module {1} est déjà chargé." #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "Impossible de trouver le module {1}" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "Le module {1} le supporte pas le type {2}." #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "Le module {1} requiert un utilisateur." #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "Le module {1} requiert un réseau." #: Modules.cpp:1707 msgid "Caught an exception" msgstr "Une exception a été reçue" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "Le module {1} a annulé : {2}" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "Module {1} stoppé." #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "Le module [{1}] n'est pas chargé." #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "Le module {1} a été déchargé." #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "Impossible de décharger le module {1}." #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "Le module {1} a été rechargé." #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "Impossible de trouver le module {1}." #: Modules.cpp:1963 msgid "Unknown error" msgstr "Erreur inconnue" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "Impossible d'ouvrir le module {1} : {2}" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "Impossible de trouver ZNCModuleEntry dans le module {1}" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" "Les versions ne correspondent pas pour le module {1} : le cÅ“ur est {2}, le " "module est conçu pour {3}. Recompilez ce module." #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" "Le module {1} a été compilé de façon incompatible : le cÅ“ur est '{2}', le " "module est '{3}'. Recompilez ce module." #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "Commande" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "Description" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "Vous devez être connecté à un réseau pour utiliser cette commande" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "Utilisation : ListNicks <#salon>" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "Vous n'êtes pas sur [{1}]" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "Vous n'êtes pas sur [{1}] (essai)" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "Aucun pseudonyme sur [{1}]" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "Pseudonyme" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "Identité" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "Hôte" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "Utilisation : Attach <#salons>" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "Utilisation : Detach <#salons>" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "Aucun message du jour n'est défini." #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "Le rehachage a réussi !" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "Le réhachage a échoué : {1}" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "La configuration a été écrite dans {1}" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "Erreur lors de la sauvegarde de la configuration." #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "Utilisation : ListChans" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "L'utilisateur [{1}] n'existe pas" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "L'utilisateur [{1}] n'a pas de réseau [{2}]" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "Aucun salon n'a été configuré." #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "Nom" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "Statut" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "Configuré" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "Tampon" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "Vider" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "Modes" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "Utilisateurs" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "Détaché" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "Rejoint" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "Désactivé" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "Essai" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "oui" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "Total : {1}, Rejoint : {2}, Détaché : {3}, Désactivé : {4}" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "Le nombre maximal de réseaux a été atteint. Contactez un administrateur pour " "augmenter cette limite ou supprimez des réseaux obsolètes avec /znc " "DelNetwork " #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "Utilisation : AddNetwork " #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "Le nom du réseau ne doit contenir que des caractères alphanumériques" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" "Réseau ajouté. Utilisez /znc JumpNetwork {1} ou connectez-vous à ZNC avec " "l'identifiant {2} (au lieu de {3}) pour vous y connecter." #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "Ce réseau n'a pas pu être ajouté" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "Utilisation : DelNetwork " #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "Réseau supprimé" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "Le réseau n'a pas pu être supprimé, peut-être qu'il n'existe pas" #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "L'utilisateur {1} n'a pas été trouvé" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "Réseau" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "Sur IRC" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "Serveur IRC" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "Utilisateur IRC" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "Salons" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "Oui" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "Non" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "Aucun réseau" #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "Accès refusé." #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" "Utilisation : MoveNetwork [nouveau réseau]" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "L'ancien utilisateur {1} n'a pas été trouvé." #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "L'ancien réseau {1} n'a pas été trouvé." #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "Le nouvel utilisateur {1} n'a pas été trouvé." #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "L'utilisateur {1} possède déjà le réseau {2}." #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "Le nom de réseau [{1}] est invalide" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "" "Certains fichiers semblent être dans {1}. Vous pouvez les déplacer dans {2}" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "Erreur lors de l'ajout du réseau : {1}" #: ClientCommand.cpp:718 msgid "Success." msgstr "Succès." #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "" "Le réseau a bien été copié vers le nouvel utilisateur, mais l'ancien réseau " "n'a pas pu être supprimé" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "Aucun réseau spécifié." #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "Vous êtes déjà connecté à ce réseau." #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "Migration vers {1}" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "Vous n'avez aucun réseau nommé {1}" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "Utilisation : AddServer [[+]port] [pass]" #: ClientCommand.cpp:759 msgid "Server added" msgstr "Serveur ajouté" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" "Impossible d'ajouter ce serveur. Peut-être ce serveur existe déjà ou SSL est " "désactivé ?" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "Utilisation : DelServer [port] [pass]" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "Vous n'avez aucun serveur." #: ClientCommand.cpp:787 msgid "Server removed" msgstr "Serveur supprimé" #: ClientCommand.cpp:789 msgid "No such server" msgstr "Ce serveur n'existe pas" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "Hôte" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "Port" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "Mot de passe" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "Utilisation : AddTrustedServerFingerprint " #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "Fait." #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "Utilisation : DelTrustedServerFingerprint " #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "Aucune empreinte ajoutée." #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "Salon" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "Défini par" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "Sujet" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "Nom" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "Arguments" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "Aucun module global chargé." #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "Module globaux :" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "Votre utilisateur n'a chargé aucun module." #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "Modules utilisateur :" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "Ce réseau n'a chargé aucun module." #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "Modules de réseau :" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "Nom" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "Description" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "Aucun module global disponible." #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "Aucun module utilisateur disponible." #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "Aucun module de réseau disponible." #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "Impossible de charger {1} : accès refusé." #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "Utilisation : LoadMod [--type=global|user|network] [args]" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "Impossible de charger {1} : {2}" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "Impossible de charger le module global {1} : accès refusé." #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "" "Impossible de chargé le module de réseau {1} : aucune connexion à un réseau." #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "Type de module inconnu" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "Le module {1} a été chargé" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "Le module {1} a été chargé : {2}" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "Impossible de charger le module {1} : {2}" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "Impossible de décharger {1} : accès refusé." #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "Utilisation : UnloadMod [--type=global|user|network] " #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "Impossible de déterminer le type de {1} : {2}" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "Impossible de décharger le module global {1} : accès refusé." #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "" "Impossible de décharger le module de réseau {1} : aucune connexion à un " "réseau." #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "Impossible de décharger le module {1} : type de module inconnu" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "Impossible de recharger les modules : accès refusé." #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "Utilisation : ReloadMod [--type=global|user|network] [args]" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "Impossible de recharger {1} : {2}" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "Impossible de recharger le module global {1} : accès refusé." #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "" "Impossible de recharger le module de réseau {1} : vous n'êtes pas connecté à " "un réseau." #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "Impossible de recharger le module {1} : type de module inconnu" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "Utilisation : UpdateMod " #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "Rechargement de {1} partout" #: ClientCommand.cpp:1242 msgid "Done" msgstr "Fait" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "" "Fait, mais des erreurs ont eu lieu, le module {1} n'a pas pu être rechargé " "partout." #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" "Vous devez être connecté à un réseau pour utiliser cette commande. Essayez " "SetUserBindHost à la place" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "Utilisation : SetBindHost " #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "Vous êtes déjà lié à cet hôte !" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "Lie l'hôte {2} au réseau {1}" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "Utilisation : SetUserBindHost " #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "Définit l'hôte par défaut à {1}" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" "Vous devez être connecté à un réseau pour utiliser cette commande. Essayez " "ClearUserBindHost à la place" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "L'hôte lié à ce réseau a été supprimé." #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "L'hôte lié par défaut a été supprimé pour votre utilisateur." #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "L'hôte lié par défaut pour cet utilisateur n'a pas été configuré" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "L'hôte lié par défaut pour cet utilisateur est {1}" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "L'hôte lié pour ce réseau n'est pas défini" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "L'hôte lié par défaut pour ce réseau est {1}" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "Utilisation : PlayBuffer <#salon|privé>" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "Vous n'êtes pas sur {1}" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "Vous n'êtes pas sur {1} (en cours de connexion)" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "Le tampon du salon {1} est vide" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "Aucune session privée avec {1}" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "Le tampon pour {1} est vide" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "Utilisation : ClearBuffer <#salon|privé>" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "Le tampon {1} correspondant à {2} a été vidé" msgstr[1] "Les tampons {1} correspondant à {2} ont été vidés" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "Les tampons de tous les salons ont été vidés" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "Les tampons de toutes les sessions privées ont été vidés" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "Tous les tampons ont été vidés" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "Utilisation : SetBuffer <#salon|privé> [lignes]" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "La configuration de la taille du tampon a échoué pour {1}" msgstr[1] "La configuration de la taille du tampon a échoué pour {1}" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "La taille maximale du tampon est de {1} ligne" msgstr[1] "La taille maximale du tampon est de {1} lignes" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "La taille de tous les tampons a été définie à {1} ligne" msgstr[1] "La taille de tous les tampons a été définie à {1} lignes" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "Nom d'utilisateur" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "Entrée" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "Sortie" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "Total" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "Actif pour {1}" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "Commande inconnue, essayez 'Help'" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "Port" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "BindHost" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "Protocole" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "IRC" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "Web" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "oui" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "non" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "IPv4 et IPv6" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "IPv4" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "IPv6" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "oui" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "non" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "oui, sur {1}" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "non" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" "Utilisation : AddPort <[+]port> [bindhost " "[uriprefix]]" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "Port ajouté" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "Le port n'a pas pu être ajouté" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "Utilisation : DelPort [bindhost]" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "Port supprimé" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "Impossible de trouver un port correspondant" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "Commande" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "Description" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" "Dans la liste ci-dessous, les occurrences de <#salon> supportent les jokers " "(* et ?), sauf ListNicks" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "Affiche la version de ZNC" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "Liste les modules chargés" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "Liste les modules disponibles" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "Liste les salons" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "<#salon>" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "Liste les pseudonymes d'un salon" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "Liste les clients connectés à votre utilisateur ZNC" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "Liste les serveurs du réseau IRC actuel" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "Ajoute un réseau à votre utilisateur" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "Supprime un réseau de votre utilisateur" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "Liste les réseaux" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr "" " [nouveau réseau]" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "Migre un réseau IRC d'un utilisateur à l'autre" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" "Migre vers un autre réseau (alternativement, vous pouvez vous connectez à " "ZNC à plusieurs reprises en utilisant 'utilisateur/réseau' comme identifiant)" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr " [[+]port] [pass]" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" "Ajoute un serveur à la liste des serveurs alternatifs pour le réseau IRC " "actuel." #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr " [port] [pass]" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" "Supprime un serveur de la liste des serveurs alternatifs du réseau IRC actuel" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" "Ajoute l'empreinte (SHA-256) d'un certificat SSL de confiance au réseau IRC " "actuel." #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "Supprime un certificat SSL de confiance du réseau IRC actuel." #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "Liste les certificats SSL de confiance du réseau IRC actuel." #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "<#salons>" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "Active les salons" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "<#salons>" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "Désactive les salons" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "<#salons>" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "Attache les salons" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "<#salons>" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "Se détacher des salons" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "Afficher le sujet dans tous les salons" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "<#salon|privé>" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "Rejouer le tampon spécifié" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "<#salon|privé>" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "Vider le tampon spécifié" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "Vider tous les tampons de salons et de sessions privées" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "Vider tous les tampons de salon" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "Vider tous les tampons de session privée" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "<#salon|privé> [lignes]" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "Définir le nombre de tampons" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "Définir le bindhost pour ce réseau" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "Définir l'hôte lié pour cet utilisateur" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "Vider l'hôte lié pour ce réseau" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "Vider l'hôte lié pour cet utilisateur" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "Afficher l'hôte actuellement lié" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "[serveur]" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "Passer au serveur sélectionné ou au suivant" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "[message]" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "Déconnexion d'IRC" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "Reconnexion à IRC" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "Afficher le temps écoulé depuis le lancement de ZNC" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "[--type=global|utilisateur|réseau] [arguments]" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "Charger un module" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "[--type=global|user|network] " #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "Désactiver un module" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "[--type=global|utilisateur|réseau] [arguments]" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "Recharger un module" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "Recharger un module partout" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "Afficher le message du jour de ZNC" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "Configurer le message du jour de ZNC" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "Ajouter au message du jour de ZNC" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "Vider le message du jour de ZNC" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "Afficher tous les clients actifs" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "<[+]port> [bindhost [uriprefix]]" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "Ajouter un port d'écoute à ZNC" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr " [bindhost]" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "Supprimer un port de ZNC" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "" "Recharger la configuration globale, les modules et les clients de znc.conf" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "Sauvegarder la configuration sur le disque" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "Lister les utilisateurs de ZNC et leur statut" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "Lister les utilisateurs de ZNC et leurs réseaux" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "[utilisateur ]" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "[utilisateur]" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "Liste les clients connectés" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "Affiche des statistiques basiques de trafic pour les utilisateurs ZNC" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "[message]" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "Diffuse un message à tous les utilisateurs de ZNC" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "[message]" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "Éteint complètement ZNC" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "[message]" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "Redémarre ZNC" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "Impossible de résoudre le nom de domaine" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" "Impossible de résoudre le nom de domaine de l'hôte. Essayez /znc " "ClearBindHost et /znc ClearUserBindHost" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "" "L'adresse du serveur est IPv4 uniquement, mais l'hôte lié est IPv6 seulement" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "" "L'adresse du serveur est IPv6 uniquement, mais l'hôte lié est IPv4 seulement" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "Un socket a atteint sa limite maximale de tampon et s'est fermé !" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "le nom d'hôte ne correspond pas" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "le nom d'hôte du certificat est incorrect" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "erreur de vérification du nom d'hôte" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" "Nom de réseau invalide. Il devrait être alphanumérique. Ne pas confondre " "avec le nom du serveur" #: User.cpp:511 msgid "Network {1} already exists" msgstr "Le réseau {1} existe déjà" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" "Vous avez été déconnecté car votre adresse IP n'est plus autorisée à se " "connecter à cet utilisateur" #: User.cpp:907 msgid "Password is empty" msgstr "Le mot de passe est vide" #: User.cpp:912 msgid "Username is empty" msgstr "L'identifiant est vide" #: User.cpp:917 msgid "Username is invalid" msgstr "L'identifiant est invalide" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "Impossible de trouver d'information sur le module {1} : {2}" znc-1.7.5/src/po/znc.it_IT.po0000644000175000017500000013715413542151610016121 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/src/po/znc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "Collegato come: {1}" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "Non sei loggato" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "Disconnettersi" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "Home" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "Moduli globali" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "Moduli utente" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "Moduli del Network ({1})" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "Benvenuti nell'interfaccia web dello ZNC's!" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" "Nessuno dei moduli abilitati al web sono stati caricati. Carica i moduli da " "IRC (“/msg *status help†e “/msg *status loadmod <nome " "del modulo>â€). Dopo aver caricato alcuni moduli abilitati per al " "Web, il menù si espanderà." #: znc.cpp:1563 msgid "User already exists" msgstr "Utente già esistente" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "IPv6 non è abilitato" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "SSL non è abilitata" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "Impossibile localizzare il file pem: {1}" #: znc.cpp:1706 msgid "Invalid port" msgstr "Porta non valida" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "Impossibile associare: {1}" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "Salta il server perché non è più in elenco" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "Benvenuti nello ZNC" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "Sei attualmente disconnesso da IRC. Usa 'connect' per riconnetterti." #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "Questo network può essere eliminato o spostato ad un altro utente." #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "Disabilitandolo, il canale {1} potrebbe non essere più accessibile." #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "Il server attuale è stato rimosso, salta..." #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "" "Non posso collegarmi a {1}, perché lo ZNC non è compilato con il supporto " "SSL." #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "Qualche modulo ha annullato il tentativo di connessione" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "Errore dal server: {1}" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "" "Lo ZNC sembra essere collegato a se stesso. La connessione verrà " "interrotta..." #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "Il server {1} reindirizza a {2}:{3} con motivazione: {4}" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "Forse vuoi aggiungerlo come nuovo server." #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "Il canale {1} è collegato ad un altro canale ed è quindi disabilitato." #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "Passato ad una connessione SSL protetta (STARTTLS)" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "Il tuo quit: {1}" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "Disconnesso da IRC. Riconnessione..." #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "Impossibile connettersi a IRC ({1}). Riprovo..." #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "Disconnesso da IRC ({1}). Riconnessione..." #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" "Se ti fidi di questo certificato, scrivi /znc AddTrustedServerFingerprint {1}" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "La connessione ad IRC è scaduta (timed out). Tento la riconnessione..." #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "Connessione rifiutata. Riconnessione..." #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "Ricevuta una linea troppo lunga dal server IRC!" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "Nessun nickname disponibile" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "Nessun nick trovato" #: Client.cpp:74 msgid "No such module {1}" msgstr "Modulo non trovato {1}" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "" "Un client da {1} ha tentato di accedere al posto tuo, ma è stato rifiutato: " "{2}" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "Il network {1} non esiste." #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" "Hai configurato alcuni networks, ma nessuno è stato specificato per la " "connessione." #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" "Selezione del network {1}. Per visualizzare l'elenco di tutte le reti " "configurate, scrivi /znc ListNetworks" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" "Se vuoi scegliere un altro network, usa /znc JumpNetwork , " "o collegati allo ZNC con username {1}/ (al posto di {1})" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" "Non hai configurato nessun networks. Usa /znc AddNetwork " "per aggiungerne uno." #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "Connessione persa: Timeout" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "Connessione persa: Linea raw troppo lunga" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "" "Stai per essere disconnesso perché un altro utente si è appena autenticato " "come te." #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "Il tuo CTCP a {1} è andato perso, non sei connesso ad IRC!" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "Il tuo NOTICE a {1} è andato perso, non sei connesso ad IRC!" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "Rimozione del canle {1}" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "Il tuo messaggio a {1} è andato perso, non sei connesso ad IRC!" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "Ciao! Come posso aiutarti? Puoi iniziare a scrivere help" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "Usa: /attach <#canali>" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "Trovato {1} canale corrispondente a [{2}]" msgstr[1] "Trovati {1} canali corrispondenti a [{2}]" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "Agganciato {1} canale (Attached)" msgstr[1] "Agganciati {1} canali (Attached)" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "Usa: /detach <#canali>" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "Scollegato {1} canale (Detached)" msgstr[1] "Scollegati {1} canali (Detached)" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "Riproduzione del Buffer avviata..." #: Chan.cpp:676 msgid "Playback Complete." msgstr "Riproduzione del Buffer completata." #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "Genera questo output" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "Nessuna corrispondenza per '{1}'" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "Questo modulo non implementa nessun comando." #: Modules.cpp:693 msgid "Unknown command!" msgstr "Comando sconosciuto!" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" "I nomi dei moduli possono contenere solo lettere, numeri e underscore. [{1}] " "non è valido" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "Il modulo {1} è già stato caricato." #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "Impossibile trovare il modulo {1}" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "Il modulo {1} non supporta il tipo di modulo {2}." #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "Il modulo {1} richiede un utente." #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "Il modulo {1} richiede un network." #: Modules.cpp:1707 msgid "Caught an exception" msgstr "È stata rilevata un'eccezione" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "Modulo {1} interrotto: {2}" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "Modulo {1} interrotto." #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "Modulo [{1}] non caricato." #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "Modulo {1} rimosso." #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "Impossibile scaricare il modulo {1}." #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "Ricaricato il modulo {1}." #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "Impossibile trovare il modulo {1}." #: Modules.cpp:1963 msgid "Unknown error" msgstr "Errore sconosciuto" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "Impossibile aprire il modulo {1}: {2}" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "Impossibile trovare ZNCModuleEntry nel modulo {1}" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" "Versione non corrispondente per il modulo {1}: il cuore è {2}, il modulo è " "creato per {3}. Ricompila questo modulo." #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" "Modulo {1} è costruito in modo incompatibile: il nucleo è '{2}', modulo è " "'{3}'. Ricompilare questo modulo." #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "Comando" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "Descrizione" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "Devi essere connesso ad un network per usare questo comando" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "Usa: ListNicks <#canale>" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "Non sei su [{1}]" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "Non sei su [{1}] (prova)" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "Nessun nick su [{1}]" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "Nick" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "Ident" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "Host" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "Usa: Attach <#canali>" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "Usa: Detach <#canali>" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "Non è stato impostato il MOTD." #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "Ricarica corretta della configurazione!" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "Rehashing fallito: {1}" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "Scritto config a {1}" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "Errore durante il tentativo di scrivere la configurazione." #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "Usa: ListChans" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "Nessun utente [{1}]" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "L'utente [{1}] non ha network [{2}]" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "Non ci sono canali definiti." #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "Nome" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "Stato" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "In configurazione" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "Buffer" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "Annulla" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "Modi" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "Utenti" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "Scollegati" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "Dentro" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "Disabilitati" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "Provando" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "si" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "Totale: {1}, Joined: {2}, Scollegati: {3}, Disabilitati: {4}" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "Numero limite per network raggiunto. Chiedi ad un amministratore di " "aumentare il limite per te o elimina i networks usando /znc DelNetwork " #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "Usa: AddNetwork " #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "Il nome del network deve essere alfanumerico" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" "Network aggiunto. Usa /znc JumpNetwork {1}, o connettiti allo ZNC con " "username {2} (al posto di {3}) per connetterlo." #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "Impossibile aggiungerge questo network" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "Usa: DelNetwork " #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "Network cancellato" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "Impossibile eliminare il network, forse questo network non esiste" #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "Utente {1} non trovato" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "Rete (Network)" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "Su IRC" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "Server IRC" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "Utente IRC" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "Canali" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "Si" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "No" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "Nessun networks" #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "Accesso negato." #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" "Usa: MoveNetwork [nuovo " "network]" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "Vecchio utente {1} non trovato." #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "Vecchio network {1} non trovato." #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "Nuovo utente {1} non trovato." #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "L'utente {1} ha già un network chiamato {2}." #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "Nome del network [{1}] non valido" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "Alcuni files sembrano essere in {1}. Forse dovresti spostarli in {2}" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "Errore durante l'aggiunta del network: {1}" #: ClientCommand.cpp:718 msgid "Success." msgstr "Completato." #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "" "Il network è stato copiato nel nuovo utente, ma non è stato possibile " "eliminare il vecchio network" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "Nessun network fornito." #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "Sei già connesso con questo network." #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "Passato a {1}" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "Non hai un network chiamato {1}" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "Usa: AddServer [[+]porta] [password]" #: ClientCommand.cpp:759 msgid "Server added" msgstr "Server aggiunto" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" "Impossibile aggiungere il server. Forse il server è già aggiunto oppure " "openssl è disabilitato?" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "Usa: DelServer [porta] [password]" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "Non hai nessun server aggiunto." #: ClientCommand.cpp:787 msgid "Server removed" msgstr "Server rimosso" #: ClientCommand.cpp:789 msgid "No such server" msgstr "Nessun server" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "Host" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "Porta" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "Password" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "Usa: AddTrustedServerFingerprint " #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "Fatto." #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "Usa: DelTrustedServerFingerprint " #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "Nessun fingerprints aggiunto." #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "Canale" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "Impostato da" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "Topic" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "Nome" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "Argomenti" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "Nessun modulo globale caricato." #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "Moduli globali:" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "Il tuo utente non ha moduli caricati." #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "Moduli per l'utente:" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "Questo network non ha moduli caricati." #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "Moduli per il network:" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "Nome" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "Descrizione" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "Nessun modulo globale disponibile." #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "Nessun modulo utente disponibile." #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "Nessun modulo per network disponibile." #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "Impossibile caricare {1}: Accesso negato." #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "Usa: LoadMod [--type=global|user|network] [argomenti]" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "Impossibile caricare {1}: {2}" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "Impossibile caricare il modulo globale {1}: Accesso negato." #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "" "Impossibile caricare il modulo di tipo network {1}: Non sei connesso ad " "alcun network." #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "Tipo di modulo sconosciuto" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "Modulo caricato {1}" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "Modulo caricato {1}: {2}" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "Impossibile caricare il modulo {1}: {2}" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "Impossibile scaricare {1}: Accesso negato." #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "Usa: UnloadMod [--type=global|user|network] " #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "Impossibile determinare tipo di {1}: {2}" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "Impossibile rimuovere il modulo di tipo globale {1}: Accesso negato." #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "" "Impossibile rimuovere il modulo di tipo network {1}: Non sei connesso ad " "alcun network." #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "Impossibile rimuovere il modulo {1}: Tipo di modulo sconosciuto" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "Impossibile ricaricare i moduli. Accesso negato." #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "Usa: ReloadMod [--type=global|user|network] [argomenti]" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "Impossibile ricaricare {1}: {2}" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "Impossibile ricaricare il modulo tipo globale {1}: Accesso negato." #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "" "Impossibile ricaricare il modulo di tipo network {1}: Non sei connesso ad " "alcun network." #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "Impossibile ricaricare il modulo {1}: Tipo di modulo sconosciuto" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "Usa: UpdateMod " #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "Ricarica {1} ovunque" #: ClientCommand.cpp:1242 msgid "Done" msgstr "Fatto" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "" "Fatto, si sono verificati errori. Il modulo {1} non può essere ricaricato " "ovunque." #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" "Devi essere connesso ad un network per usare questo comando. Prova invece " "SetUserBindHost" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "Usa: SetBindHost " #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "Hai già questo bind host!" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "Impostato il bind host per il network {1} a {2}" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "Usa: SetUserBindHost " #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "Imposta il bind host di default a {1}" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" "Devi essere connesso ad un network per usare questo comando. Prova invece " "ClearUserBindHost" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "Bind host cancellato per questo network." #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "Bind host di default cancellato per questo utente." #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "Il bind host predefinito per questo utente non è stato configurato" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "Il bind host predefinito per questo utente è {1}" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "Il bind host di questo network non è impostato" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "Il bind host predefinito per questo network è {1}" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "Usa: PlayBuffer <#canale|query>" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "Non sei su {1}" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "Non sei su {1} (prova ad entrare)" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "Il buffer del canale {1} è vuoto" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "Nessuna query attiva per {1}" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "Il buffer per {1} è vuoto" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "Usa: ClearBuffer <#canale|query>" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "{1} corrispondenza del buffer {2} è stato cancellata" msgstr[1] "{1} corrispondenze del buffers {2} sono state cancellate" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "I buffers di tutti i canali sono stati cancellati" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "I buffers di tutte le query sono state cancellate" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "Tutti i buffers sono stati cancellati" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "Usa: SetBuffer <#canale|query> [numero linee]" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "" "Impostazione della dimensione del buffer non riuscita per il buffer {1}" msgstr[1] "" "Impostazione della dimensione del buffer non riuscita per i buffers {1}" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "La dimensione massima del buffer è {1} linea" msgstr[1] "La dimensione massima del buffer è {1} linee" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "La dimensione di tutti i buffer è stata impostata a {1} linea" msgstr[1] "La dimensione di tutti i buffer è stata impostata a {1} linee" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "Nome Utente" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "Dentro (In)" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "Fuori (Out)" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "Totale" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "Opertivo da {1}" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "Comando sconosciuto, prova 'Help'" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "Porta" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "BindHost" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "Protocollo" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "IRC" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "Web" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "si" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "no" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "IPv4 e IPv6" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "IPv4" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "IPv6" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "si" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "no" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "si, su {1}" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "no" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" "Usa: AddPort <[+]porta> [bindhost [uriprefix]]" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "Porta aggiunta" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "Impossibile aggiungere la porta" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "Usa: DelPort [bindhost]" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "Porta eliminata" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "Impossibile trovare una porta corrispondente" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "Comando" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "Descrizione" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" "Nella seguente lista tutte le occorrenze di <#canale> supportano le " "wildcards (* e ?) eccetto ListNicks" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "Mostra la versione di questo ZNC" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "Elenca tutti i moduli caricati" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "Elenca tutti i moduli disponibili" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "Elenca tutti i canali" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "<#canale>" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "Elenca tutti i nickname su un canale" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "Elenca tutti i client connessi al tuo utente ZNC" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "Elenca tutti i servers del network IRC corrente" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "Aggiungi un network al tuo account" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "Elimina un network dal tuo utente" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "Elenca tutti i networks" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr " [nuovo network]" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "Sposta un network IRC da un utente ad un altro" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" "Passa ad un altro network (Alternativamente, puoi connetterti più volte allo " "ZNC, usando `user/network` come username)" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr " [[+]porta] [password]" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" "Aggiunge un server all'elenco server alternativi/backup del network IRC " "corrente." #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr " [porta] [password]" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" "Rimuove un server all'elenco server alternativi/backup dell'IRC network " "corrente" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" "Aggiunge un'impronta digitale attendibile del certificato SSL del server " "(SHA-256) al network IRC corrente." #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "Elimina un certificato SSL attendibile dal network IRC corrente." #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "" "Elenca tutti i certificati SSL fidati del server per il corrente network IRC." #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "<#canali>" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "Abilita canali" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "<#canali>" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "Disabilita canali" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "<#canali>" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "Ricollega ai canali (attach)" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "<#canali>" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "Scollega dai cananli (detach)" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "Mostra i topics di tutti i tuoi canali" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "<#canale|query>" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "Riproduce il buffer specificato" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "<#canale|query>" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "Cancella il buffer specificato" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "Cancella il buffers da tutti i canali e tute le query" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "Cancella il buffer del canale" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "Cancella il buffer della query" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "<#canale|query> [linecount]" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "Imposta il conteggio del buffer" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "Imposta il bind host per questo network" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "Imposta il bind host di default per questo utente" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "Cancella il bind host per questo network" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "Cancella il bind host di default per questo utente" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "Mostra il bind host attualmente selezionato" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "[server]" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "Passa al server successivo o a quello indicato" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "[messaggio]" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "Disconnetti da IRC" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "Riconnette ad IRC" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "Mostra da quanto tempo lo ZNC è in esecuzione" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "[--type=global|user|network] [argomenti]" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "Carica un modulo" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "[--type=global|user|network] " #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "Scarica un modulo" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "[--type=global|user|network] [argomenti]" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "Ricarica un modulo" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "Ricarica un modulo ovunque" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "Mostra il messaggio del giorno dello ZNC's" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "Imposta il messaggio del giorno dello ZNC's" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "Aggiungi al MOTD dello ZNC's" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "Cancella il MOTD dello ZNC's" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "Mostra tutti gli ascoltatori attivi" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "<[+]porta> [bindhost [uriprefix]]" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "Aggiunge un'altra porta di ascolto allo ZNC" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr " [bindhost]" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "Rimuove una porta dallo ZNC" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "" "Ricarica le impostazioni globali, i moduli e le porte di ascolto dallo znc." "conf" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "Salve le impostazioni correnti sul disco" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "Elenca tutti gli utenti dello ZNC e lo stato della loro connessione" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "Elenca tutti gli utenti dello ZNC ed i loro networks" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "[utente ]" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "[utente]" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "Elenca tutti i client connessi" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "Mostra le statistiche base sul traffico di tutti gli utenti dello ZNC" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "[messaggio]" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "Trasmetti un messaggio a tutti gli utenti dello ZNC" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "[messaggio]" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "Spegni completamente lo ZNC" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "[messaggio]" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "Riavvia lo ZNC" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "Impossibile risolvere il nome dell'host del server" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" "Impossibile risolvere l'hostname allegato. Prova /znc ClearBindHost e /znc " "ClearUserBindHost" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "L'indirizzo del server è IPv4-only, ma il bindhost è IPv6-only" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "L'indirizzo del server è IPv6-only, ma il bindhost è IPv4-only" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "" "Alcuni socket hanno raggiunto il limite massimo di buffer e sono stati " "chiusi!" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "il nome dell'host non corrisponde" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "hostname malformato nel certificato" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "errore di verifica dell'hostname" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" "Nome del network non valido. Deve essere alfanumerico. Da non confondere con " "il nome del server" #: User.cpp:511 msgid "Network {1} already exists" msgstr "Network {1} già esistente" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" "Sei stato disconnesso perché il tuo indirizzo IP non è più autorizzato a " "connettersi a questo utente" #: User.cpp:907 msgid "Password is empty" msgstr "Password è vuota" #: User.cpp:912 msgid "Username is empty" msgstr "Username è vuoto" #: User.cpp:917 msgid "Username is invalid" msgstr "Username non è valido" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "Impossibile trovare modinfo {1}: {2}" znc-1.7.5/src/po/znc.nl_NL.po0000644000175000017500000013730013542151610016104 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/src/po/znc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: webskins/_default_/tmpl/InfoBar.tmpl:6 msgid "Logged in as: {1}" msgstr "Ingelogd als: {1}" #: webskins/_default_/tmpl/InfoBar.tmpl:8 msgid "Not logged in" msgstr "Niet ingelogd" #: webskins/_default_/tmpl/LoginBar.tmpl:3 msgid "Logout" msgstr "Afmelden" #: webskins/_default_/tmpl/Menu.tmpl:4 msgid "Home" msgstr "Home" #: webskins/_default_/tmpl/Menu.tmpl:7 msgid "Global Modules" msgstr "Algemene modulen" #: webskins/_default_/tmpl/Menu.tmpl:20 msgid "User Modules" msgstr "Gebruikers modulen" #: webskins/_default_/tmpl/Menu.tmpl:35 msgid "Network Modules ({1})" msgstr "Netwerk modulen ({1})" #: webskins/_default_/tmpl/index.tmpl:6 msgid "Welcome to ZNC's web interface!" msgstr "Welkom bij ZNC's webinterface!" #: webskins/_default_/tmpl/index.tmpl:11 msgid "" "No Web-enabled modules have been loaded. Load modules from IRC (“/msg " "*status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." msgstr "" "Geen web-ingeschakelde modulen zijn geladen. Laad modulen van IRC (“/" "msg *status help†en “/msg *status loadmod <module>â€). Zodra je deze geladen hebt zal dit menu zich uitbreiden." #: znc.cpp:1563 msgid "User already exists" msgstr "Gebruiker bestaat al" #: znc.cpp:1671 msgid "IPv6 is not enabled" msgstr "IPv6 is niet ingeschakeld" #: znc.cpp:1679 msgid "SSL is not enabled" msgstr "SSL is niet ingeschakeld" #: znc.cpp:1687 msgid "Unable to locate pem file: {1}" msgstr "Kan PEM bestand niet vinden: {1}" #: znc.cpp:1706 msgid "Invalid port" msgstr "Ongeldige poort" #: znc.cpp:1822 ClientCommand.cpp:1629 msgid "Unable to bind: {1}" msgstr "Kan niet binden: {1}" #: IRCNetwork.cpp:235 msgid "Jumping servers because this server is no longer in the list" msgstr "" "We schakelen over naar een andere server omdat deze server niet langer in de " "lijst staat" #: IRCNetwork.cpp:640 User.cpp:678 msgid "Welcome to ZNC" msgstr "Welkom bij ZNC" #: IRCNetwork.cpp:728 msgid "You are currently disconnected from IRC. Use 'connect' to reconnect." msgstr "" "Op dit moment ben je niet verbonden met IRC. Gebruik 'connect' om opnieuw " "verbinding te maken." #: IRCNetwork.cpp:758 msgid "This network is being deleted or moved to another user." msgstr "" "Dit netwerk wordt op dit moment verwijderd of verplaatst door een andere " "gebruiker." #: IRCNetwork.cpp:987 msgid "The channel {1} could not be joined, disabling it." msgstr "Het kanaal {1} kan niet toegetreden worden, deze wordt uitgeschakeld." #: IRCNetwork.cpp:1116 msgid "Your current server was removed, jumping..." msgstr "" "Je huidige server was verwijderd, we schakelen over naar een andere server..." #: IRCNetwork.cpp:1279 msgid "Cannot connect to {1}, because ZNC is not compiled with SSL support." msgstr "" "Kan niet verbinden naar {1} omdat ZNC niet gecompileerd is met SSL " "ondersteuning." #: IRCNetwork.cpp:1300 msgid "Some module aborted the connection attempt" msgstr "Een module heeft de verbindingspoging afgebroken" #: IRCSock.cpp:490 msgid "Error from server: {1}" msgstr "Fout van server: {1}" #: IRCSock.cpp:692 msgid "ZNC seems to be connected to itself, disconnecting..." msgstr "" "ZNC blijkt verbonden te zijn met zichzelf... De verbinding zal verbroken " "worden..." #: IRCSock.cpp:739 msgid "Server {1} redirects us to {2}:{3} with reason: {4}" msgstr "Server {1} stuurt ons door naar {2}:{3} met reden: {4}" #: IRCSock.cpp:743 msgid "Perhaps you want to add it as a new server." msgstr "Misschien wil je het toevoegen als nieuwe server." #: IRCSock.cpp:973 msgid "Channel {1} is linked to another channel and was thus disabled." msgstr "" "Kanaal {1} is verbonden naar een andere kanaal en is daarom uitgeschakeld." #: IRCSock.cpp:985 msgid "Switched to SSL (STARTTLS)" msgstr "Omgeschakeld naar een veilige verbinding (STARTTLS)" #: IRCSock.cpp:1038 msgid "You quit: {1}" msgstr "Je hebt het netwerk verlaten: {1}" #: IRCSock.cpp:1244 msgid "Disconnected from IRC. Reconnecting..." msgstr "Verbinding met IRC verbroken. We proberen opnieuw te verbinden..." #: IRCSock.cpp:1275 msgid "Cannot connect to IRC ({1}). Retrying..." msgstr "Kan niet verbinden met IRC ({1}). We proberen opnieuw te verbinden..." #: IRCSock.cpp:1278 msgid "Disconnected from IRC ({1}). Reconnecting..." msgstr "" "Verbinding met IRC verbroken ({1}). We proberen opnieuw te verbinden..." #: IRCSock.cpp:1308 msgid "If you trust this certificate, do /znc AddTrustedServerFingerprint {1}" msgstr "" "Als je dit certificaat vertrouwt, doe: /znc AddTrustedServerFingerprint {1}" #: IRCSock.cpp:1325 msgid "IRC connection timed out. Reconnecting..." msgstr "IRC verbinding time-out. We proberen opnieuw te verbinden..." #: IRCSock.cpp:1337 msgid "Connection Refused. Reconnecting..." msgstr "Verbinding geweigerd. We proberen opnieuw te verbinden..." #: IRCSock.cpp:1345 msgid "Received a too long line from the IRC server!" msgstr "Een te lange regel ontvangen van de IRC server!" #: IRCSock.cpp:1449 msgid "No free nick available" msgstr "Geen beschikbare bijnaam" #: IRCSock.cpp:1457 msgid "No free nick found" msgstr "Geen beschikbare bijnaam gevonden" #: Client.cpp:74 msgid "No such module {1}" msgstr "Geen dergelijke module {1}" #: Client.cpp:359 msgid "A client from {1} attempted to login as you, but was rejected: {2}" msgstr "" "Een client van {1} heeft geprobeerd als jou in te loggen maar werd " "geweigerd: {2}" #: Client.cpp:394 msgid "Network {1} doesn't exist." msgstr "Netwerk {1} bestaat niet." #: Client.cpp:408 msgid "" "You have several networks configured, but no network was specified for the " "connection." msgstr "" "Je hebt meerdere netwerken geconfigureerd maar je hebt er geen gekozen om " "verbinding mee te maken." #: Client.cpp:411 msgid "" "Selecting network {1}. To see list of all configured networks, use /znc " "ListNetworks" msgstr "" "Netwerk {1} geselecteerd. Om een lijst te tonen van alle geconfigureerde " "netwerken, gebruik /znc ListNetworks" #: Client.cpp:414 msgid "" "If you want to choose another network, use /znc JumpNetwork , or " "connect to ZNC with username {1}/ (instead of just {1})" msgstr "" "Als je een ander netwerk wilt kiezen, gebruik /znc JumpNetwork , of " "verbind naar ZNC met gebruikersnaam {1}/ (in plaats van alleen {1})" #: Client.cpp:420 msgid "" "You have no networks configured. Use /znc AddNetwork to add one." msgstr "" "Je hebt geen netwerken geconfigureerd. Gebruiker /znc AddNetwork " "om er een toe te voegen." #: Client.cpp:431 msgid "Closing link: Timeout" msgstr "Verbinding verbroken: Time-out" #: Client.cpp:453 msgid "Closing link: Too long raw line" msgstr "Verbinding verbroken: Te lange onbewerkte regel" #: Client.cpp:460 msgid "" "You are being disconnected because another user just authenticated as you." msgstr "" "Je verbinding wordt verbroken omdat een andere gebruiker zich net aangemeld " "heeft als jou." #: Client.cpp:1015 msgid "Your CTCP to {1} got lost, you are not connected to IRC!" msgstr "Je CTCP naar {1} is verloren geraakt, je bent niet verbonden met IRC!" #: Client.cpp:1142 msgid "Your notice to {1} got lost, you are not connected to IRC!" msgstr "" "Je notice naar {1} is verloren geraakt, je bent niet verbonden met IRC!" #: Client.cpp:1181 msgid "Removing channel {1}" msgstr "Kanaal verwijderen: {1}" #: Client.cpp:1257 msgid "Your message to {1} got lost, you are not connected to IRC!" msgstr "" "Je bericht naar {1} is verloren geraakt, je bent niet verbonden met IRC!" #: Client.cpp:1310 Client.cpp:1316 msgid "Hello. How may I help you?" msgstr "Hallo. Hoe kan ik je helpen?" #: Client.cpp:1330 msgid "Usage: /attach <#chans>" msgstr "Gebruik: /attach <#kanalen>" #: Client.cpp:1337 Client.cpp:1359 ClientCommand.cpp:129 ClientCommand.cpp:151 msgid "There was {1} channel matching [{2}]" msgid_plural "There were {1} channels matching [{2}]" msgstr[0] "Er was {1} kanaal overeenkomend met [{2}]" msgstr[1] "Er waren {1} kanalen overeenkomend met [{2}]" #: Client.cpp:1340 ClientCommand.cpp:132 msgid "Attached {1} channel" msgid_plural "Attached {1} channels" msgstr[0] "Gekoppeld aan {1} kanaal" msgstr[1] "Gekoppeld aan {1} kanalen" #: Client.cpp:1352 msgid "Usage: /detach <#chans>" msgstr "Gebruik: /detach <#kanalen>" #: Client.cpp:1362 ClientCommand.cpp:154 msgid "Detached {1} channel" msgid_plural "Detached {1} channels" msgstr[0] "Losgekoppeld van {1} kanaal" msgstr[1] "Losgekoppeld van {1} kanalen" #: Chan.cpp:638 msgid "Buffer Playback..." msgstr "Buffer afspelen..." #: Chan.cpp:676 msgid "Playback Complete." msgstr "Afspelen compleet." #: Modules.cpp:528 msgctxt "modhelpcmd" msgid "" msgstr "" #: Modules.cpp:529 msgctxt "modhelpcmd" msgid "Generate this output" msgstr "Genereer deze output" #: Modules.cpp:573 ClientCommand.cpp:1894 msgid "No matches for '{1}'" msgstr "Geen overeenkomsten voor '{1}'" #: Modules.cpp:691 msgid "This module doesn't implement any commands." msgstr "Deze module heeft geen commando's geimplementeerd." #: Modules.cpp:693 msgid "Unknown command!" msgstr "Onbekend commando!" #: Modules.cpp:1633 msgid "" "Module names can only contain letters, numbers and underscores, [{1}] is " "invalid" msgstr "" "Module namen kunnen alleen letters, nummers en lage streepts bevatten, [{1}] " "is ongeldig" #: Modules.cpp:1652 msgid "Module {1} already loaded." msgstr "Module {1} is al geladen." #: Modules.cpp:1666 msgid "Unable to find module {1}" msgstr "Kon module {1} niet vinden" #: Modules.cpp:1678 msgid "Module {1} does not support module type {2}." msgstr "Module {1} ondersteund het type {2} niet." #: Modules.cpp:1685 msgid "Module {1} requires a user." msgstr "Module {1} vereist een gebruiker." #: Modules.cpp:1691 msgid "Module {1} requires a network." msgstr "Module {1} vereist een netwerk." #: Modules.cpp:1707 msgid "Caught an exception" msgstr "Uitzondering geconstateerd" #: Modules.cpp:1713 msgid "Module {1} aborted: {2}" msgstr "Module {1} afgebroken: {2}" #: Modules.cpp:1715 msgid "Module {1} aborted." msgstr "Module {1} afgebroken." #: Modules.cpp:1739 Modules.cpp:1781 msgid "Module [{1}] not loaded." msgstr "Module [{1}] niet geladen." #: Modules.cpp:1763 msgid "Module {1} unloaded." msgstr "Module {1} gestopt." #: Modules.cpp:1768 msgid "Unable to unload module {1}." msgstr "Niet mogelijk om module {1} te stoppen." #: Modules.cpp:1797 msgid "Reloaded module {1}." msgstr "Module {1} hergeladen." #: Modules.cpp:1816 msgid "Unable to find module {1}." msgstr "Module {1} niet gevonden." #: Modules.cpp:1963 msgid "Unknown error" msgstr "Onbekende fout" #: Modules.cpp:1964 msgid "Unable to open module {1}: {2}" msgstr "Niet mogelijk om module te openen, {1}: {2}" #: Modules.cpp:1973 msgid "Could not find ZNCModuleEntry in module {1}" msgstr "Kon ZNCModuleEntry niet vinden in module {1}" #: Modules.cpp:1981 msgid "" "Version mismatch for module {1}: core is {2}, module is built for {3}. " "Recompile this module." msgstr "" "Verkeerde versie voor module {1}, kern is {2}, module is gecompileerd voor " "{3}. Hercompileer deze module." #: Modules.cpp:1992 msgid "" "Module {1} is built incompatibly: core is '{2}', module is '{3}'. Recompile " "this module." msgstr "" "Module {1} is niet compatible gecompileerd: kern is '{2}', module is '{3}'. " "Hercompileer deze module." #: Modules.cpp:2022 Modules.cpp:2028 msgctxt "modhelpcmd" msgid "Command" msgstr "Commando" #: Modules.cpp:2023 Modules.cpp:2029 msgctxt "modhelpcmd" msgid "Description" msgstr "Beschrijving" #: ClientCommand.cpp:51 ClientCommand.cpp:115 ClientCommand.cpp:137 #: ClientCommand.cpp:749 ClientCommand.cpp:768 ClientCommand.cpp:794 #: ClientCommand.cpp:827 ClientCommand.cpp:840 ClientCommand.cpp:853 #: ClientCommand.cpp:868 ClientCommand.cpp:1321 ClientCommand.cpp:1369 #: ClientCommand.cpp:1401 ClientCommand.cpp:1412 ClientCommand.cpp:1421 #: ClientCommand.cpp:1433 msgid "You must be connected with a network to use this command" msgstr "Je moet verbonden zijn met een netwerk om dit commando te gebruiken" #: ClientCommand.cpp:58 msgid "Usage: ListNicks <#chan>" msgstr "Gebruik: ListNicks <#kanaal>" #: ClientCommand.cpp:65 msgid "You are not on [{1}]" msgstr "Je bent niet in [{1}]" #: ClientCommand.cpp:70 msgid "You are not on [{1}] (trying)" msgstr "Je bent niet in {1} (probeer toe te treden)" #: ClientCommand.cpp:79 msgid "No nicks on [{1}]" msgstr "Geen bijnamen in [{1}]" #: ClientCommand.cpp:91 ClientCommand.cpp:106 msgid "Nick" msgstr "Bijnaam" #: ClientCommand.cpp:92 ClientCommand.cpp:107 msgid "Ident" msgstr "Identiteit" #: ClientCommand.cpp:93 ClientCommand.cpp:108 msgid "Host" msgstr "Host" #: ClientCommand.cpp:122 msgid "Usage: Attach <#chans>" msgstr "Gebruik: Attach <#kanalen>" #: ClientCommand.cpp:144 msgid "Usage: Detach <#chans>" msgstr "Gebruik: Detach <#kanalen>" #: ClientCommand.cpp:161 msgid "There is no MOTD set." msgstr "Er is geen bericht van de dag ingesteld." #: ClientCommand.cpp:167 msgid "Rehashing succeeded!" msgstr "Opnieuw laden van configuratie geslaagd!" #: ClientCommand.cpp:169 msgid "Rehashing failed: {1}" msgstr "Opnieuw laden van configuratie mislukt: {1}" #: ClientCommand.cpp:173 msgid "Wrote config to {1}" msgstr "Configuratie geschreven naar {1}" #: ClientCommand.cpp:175 msgid "Error while trying to write config." msgstr "Fout tijdens het proberen te schrijven naar het configuratiebestand." #: ClientCommand.cpp:455 msgid "Usage: ListChans" msgstr "Gebruik: ListChans" #: ClientCommand.cpp:462 msgid "No such user [{1}]" msgstr "Gebruiker onbekend [{1}]" #: ClientCommand.cpp:468 msgid "User [{1}] doesn't have network [{2}]" msgstr "Gebruiker [{1}] heeft geen netwerk genaamd [{2}]" #: ClientCommand.cpp:479 msgid "There are no channels defined." msgstr "Er zijn geen kanalen geconfigureerd." #: ClientCommand.cpp:484 ClientCommand.cpp:500 msgctxt "listchans" msgid "Name" msgstr "Naam" #: ClientCommand.cpp:485 ClientCommand.cpp:503 msgctxt "listchans" msgid "Status" msgstr "Status" #: ClientCommand.cpp:486 ClientCommand.cpp:510 msgctxt "listchans" msgid "In config" msgstr "In configuratie" #: ClientCommand.cpp:487 ClientCommand.cpp:512 msgctxt "listchans" msgid "Buffer" msgstr "Buffer" #: ClientCommand.cpp:488 ClientCommand.cpp:516 msgctxt "listchans" msgid "Clear" msgstr "Wissen" #: ClientCommand.cpp:489 ClientCommand.cpp:521 msgctxt "listchans" msgid "Modes" msgstr "Modes" #: ClientCommand.cpp:490 ClientCommand.cpp:522 msgctxt "listchans" msgid "Users" msgstr "Gebruikers" #: ClientCommand.cpp:505 msgctxt "listchans" msgid "Detached" msgstr "Losgekoppeld" #: ClientCommand.cpp:506 msgctxt "listchans" msgid "Joined" msgstr "Toegetreden" #: ClientCommand.cpp:507 msgctxt "listchans" msgid "Disabled" msgstr "Uitgeschakeld" #: ClientCommand.cpp:508 msgctxt "listchans" msgid "Trying" msgstr "Proberen" #: ClientCommand.cpp:511 ClientCommand.cpp:519 msgctxt "listchans" msgid "yes" msgstr "ja" #: ClientCommand.cpp:536 msgid "Total: {1}, Joined: {2}, Detached: {3}, Disabled: {4}" msgstr "Totaal: {1}, toegetreden: {2}, losgekoppeld: {3}, uitgeschakeld: {4}" #: ClientCommand.cpp:541 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "Limiet van aantal netwerken bereikt. Vraag een beheerder om deze limit aan " "te passen voor je, of verwijder onnodige netwerken door middel van /znc " "DelNetwork " #: ClientCommand.cpp:550 msgid "Usage: AddNetwork " msgstr "Gebruik: AddNetwork " #: ClientCommand.cpp:554 msgid "Network name should be alphanumeric" msgstr "Netwerk naam moet alfanumeriek zijn" #: ClientCommand.cpp:561 msgid "" "Network added. Use /znc JumpNetwork {1}, or connect to ZNC with username {2} " "(instead of just {3}) to connect to it." msgstr "" "Netwerk toegevoegd. Gebruik /znc JumpNetwork {1} of verbind naar ZNC met " "gebruikersnaam {2} (in plaats van alleen {3}) om hier verbinding mee te " "maken." #: ClientCommand.cpp:566 msgid "Unable to add that network" msgstr "Kan dat netwerk niet toevoegen" #: ClientCommand.cpp:573 msgid "Usage: DelNetwork " msgstr "Gebruik: DelNetwork " #: ClientCommand.cpp:582 msgid "Network deleted" msgstr "Netwerk verwijderd" #: ClientCommand.cpp:585 msgid "Failed to delete network, perhaps this network doesn't exist" msgstr "Mislukt om netwerk te verwijderen, misschien bestaat dit netwerk niet" #: ClientCommand.cpp:595 msgid "User {1} not found" msgstr "Gebruiker {1} niet gevonden" #: ClientCommand.cpp:603 ClientCommand.cpp:611 msgctxt "listnetworks" msgid "Network" msgstr "Netwerk" #: ClientCommand.cpp:604 ClientCommand.cpp:613 ClientCommand.cpp:622 msgctxt "listnetworks" msgid "On IRC" msgstr "Op IRC" #: ClientCommand.cpp:605 ClientCommand.cpp:615 msgctxt "listnetworks" msgid "IRC Server" msgstr "IRC Server" #: ClientCommand.cpp:606 ClientCommand.cpp:617 msgctxt "listnetworks" msgid "IRC User" msgstr "IRC Gebruiker" #: ClientCommand.cpp:607 ClientCommand.cpp:619 msgctxt "listnetworks" msgid "Channels" msgstr "Kanalen" #: ClientCommand.cpp:614 msgctxt "listnetworks" msgid "Yes" msgstr "Ja" #: ClientCommand.cpp:623 msgctxt "listnetworks" msgid "No" msgstr "Nee" #: ClientCommand.cpp:628 msgctxt "listnetworks" msgid "No networks" msgstr "Geen netwerken" #: ClientCommand.cpp:632 ClientCommand.cpp:932 msgid "Access denied." msgstr "Toegang geweigerd." #: ClientCommand.cpp:643 msgid "Usage: MoveNetwork [new network]" msgstr "" "Gebruik: MoveNetwerk " "[nieuw netwerk]" #: ClientCommand.cpp:653 msgid "Old user {1} not found." msgstr "Oude gebruiker {1} niet gevonden." #: ClientCommand.cpp:659 msgid "Old network {1} not found." msgstr "Oud netwerk {1} niet gevonden." #: ClientCommand.cpp:665 msgid "New user {1} not found." msgstr "Nieuwe gebruiker {1} niet gevonden." #: ClientCommand.cpp:670 msgid "User {1} already has network {2}." msgstr "Gebruiker {1} heeft al een netwerk genaamd {2}." #: ClientCommand.cpp:676 msgid "Invalid network name [{1}]" msgstr "Ongeldige netwerknaam [{1}]" #: ClientCommand.cpp:692 msgid "Some files seem to be in {1}. You might want to move them to {2}" msgstr "" "Sommige bestanden lijken in {1} te zijn. Misschien wil je ze verplaatsen " "naar {2}" #: ClientCommand.cpp:706 msgid "Error adding network: {1}" msgstr "Fout bij het toevoegen van netwerk: {1}" #: ClientCommand.cpp:718 msgid "Success." msgstr "Geslaagd." #: ClientCommand.cpp:721 msgid "Copied the network to new user, but failed to delete old network" msgstr "" "Netwerk gekopieërd naar nieuwe gebruiker maar mislukt om het oude netwerk te " "verwijderen" #: ClientCommand.cpp:728 msgid "No network supplied." msgstr "Geen netwerk ingevoerd." #: ClientCommand.cpp:733 msgid "You are already connected with this network." msgstr "Je bent al verbonden met dit netwerk." #: ClientCommand.cpp:739 msgid "Switched to {1}" msgstr "Geschakeld naar {1}" #: ClientCommand.cpp:742 msgid "You don't have a network named {1}" msgstr "Je hebt geen netwerk genaamd {1}" #: ClientCommand.cpp:754 msgid "Usage: AddServer [[+]port] [pass]" msgstr "Gebruik: AddServer [[+]poort] [wachtwoord]" #: ClientCommand.cpp:759 msgid "Server added" msgstr "Server toegevoegd" #: ClientCommand.cpp:762 msgid "" "Unable to add that server. Perhaps the server is already added or openssl is " "disabled?" msgstr "" "Niet mogelijk die server toe te voegen. Misschien is de server al toegevoegd " "of is OpenSSL uitgeschakeld?" #: ClientCommand.cpp:777 msgid "Usage: DelServer [port] [pass]" msgstr "Gebruik: DelServer [poort] [wachtwoord]" #: ClientCommand.cpp:782 ClientCommand.cpp:822 msgid "You don't have any servers added." msgstr "Je hebt geen servers toegevoegd." #: ClientCommand.cpp:787 msgid "Server removed" msgstr "Server verwijderd" #: ClientCommand.cpp:789 msgid "No such server" msgstr "Server niet gevonden" #: ClientCommand.cpp:802 ClientCommand.cpp:809 msgctxt "listservers" msgid "Host" msgstr "Host" #: ClientCommand.cpp:803 ClientCommand.cpp:811 msgctxt "listservers" msgid "Port" msgstr "Poort" #: ClientCommand.cpp:804 ClientCommand.cpp:814 msgctxt "listservers" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:805 ClientCommand.cpp:816 msgctxt "listservers" msgid "Password" msgstr "Wachtwoord" #: ClientCommand.cpp:815 msgctxt "listservers|cell" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:832 msgid "Usage: AddTrustedServerFingerprint " msgstr "Gebruik: AddTrustedServerFingerprint " #: ClientCommand.cpp:836 ClientCommand.cpp:849 msgid "Done." msgstr "Klaar." #: ClientCommand.cpp:845 msgid "Usage: DelTrustedServerFingerprint " msgstr "Gebruik: DelTrustedServerFingerprint " #: ClientCommand.cpp:858 msgid "No fingerprints added." msgstr "Geen vingerafdrukken toegevoegd." #: ClientCommand.cpp:874 ClientCommand.cpp:880 msgctxt "topicscmd" msgid "Channel" msgstr "Kanaal" #: ClientCommand.cpp:875 ClientCommand.cpp:881 msgctxt "topicscmd" msgid "Set By" msgstr "Ingesteld door" #: ClientCommand.cpp:876 ClientCommand.cpp:882 msgctxt "topicscmd" msgid "Topic" msgstr "Onderwerp" #: ClientCommand.cpp:889 ClientCommand.cpp:893 msgctxt "listmods" msgid "Name" msgstr "Naam" #: ClientCommand.cpp:890 ClientCommand.cpp:894 msgctxt "listmods" msgid "Arguments" msgstr "Argumenten" #: ClientCommand.cpp:902 msgid "No global modules loaded." msgstr "Geen algemene modules geladen." #: ClientCommand.cpp:904 ClientCommand.cpp:964 msgid "Global modules:" msgstr "Algemene modules:" #: ClientCommand.cpp:912 msgid "Your user has no modules loaded." msgstr "Je gebruiker heeft geen modules geladen." #: ClientCommand.cpp:914 ClientCommand.cpp:975 msgid "User modules:" msgstr "Gebruiker modules:" #: ClientCommand.cpp:921 msgid "This network has no modules loaded." msgstr "Dit netwerk heeft geen modules geladen." #: ClientCommand.cpp:923 ClientCommand.cpp:986 msgid "Network modules:" msgstr "Netwerk modules:" #: ClientCommand.cpp:938 ClientCommand.cpp:944 msgctxt "listavailmods" msgid "Name" msgstr "Naam" #: ClientCommand.cpp:939 ClientCommand.cpp:949 msgctxt "listavailmods" msgid "Description" msgstr "Beschrijving" #: ClientCommand.cpp:962 msgid "No global modules available." msgstr "Geen algemene modules beschikbaar." #: ClientCommand.cpp:973 msgid "No user modules available." msgstr "Geen gebruikermodules beschikbaar." #: ClientCommand.cpp:984 msgid "No network modules available." msgstr "Geen netwerkmodules beschikbaar." #: ClientCommand.cpp:1012 msgid "Unable to load {1}: Access denied." msgstr "Niet mogelijk om {1} te laden: Toegang geweigerd." #: ClientCommand.cpp:1018 msgid "Usage: LoadMod [--type=global|user|network] [args]" msgstr "Gebruik: LoadMod [--type=global|user|network] [argumenten]" #: ClientCommand.cpp:1025 msgid "Unable to load {1}: {2}" msgstr "Niet mogelijk module te laden {1}: {2}" #: ClientCommand.cpp:1035 msgid "Unable to load global module {1}: Access denied." msgstr "Niet mogelijk algemene module te laden {1}: Toegang geweigerd." #: ClientCommand.cpp:1041 msgid "Unable to load network module {1}: Not connected with a network." msgstr "" "Niet mogelijk netwerk module te laden {1}: Niet verbonden met een netwerk." #: ClientCommand.cpp:1063 msgid "Unknown module type" msgstr "Onbekend type module" #: ClientCommand.cpp:1068 msgid "Loaded module {1}" msgstr "Module {1} geladen" #: ClientCommand.cpp:1070 msgid "Loaded module {1}: {2}" msgstr "Module {1} geladen: {2}" #: ClientCommand.cpp:1073 msgid "Unable to load module {1}: {2}" msgstr "Niet mogelijk module te laden {1}: {2}" #: ClientCommand.cpp:1096 msgid "Unable to unload {1}: Access denied." msgstr "Niet mogelijk om {1} te stoppen: Toegang geweigerd." #: ClientCommand.cpp:1102 msgid "Usage: UnloadMod [--type=global|user|network] " msgstr "Gebruik: UnloadMod [--type=global|user|network] " #: ClientCommand.cpp:1111 msgid "Unable to determine type of {1}: {2}" msgstr "Niet mogelijk om het type te bepalen van {1}: {2}" #: ClientCommand.cpp:1119 msgid "Unable to unload global module {1}: Access denied." msgstr "Niet mogelijk algemene module te stoppen {1}: Toegang geweigerd." #: ClientCommand.cpp:1126 msgid "Unable to unload network module {1}: Not connected with a network." msgstr "" "Niet mogelijk netwerk module te stoppen {1}: Niet verbonden met een netwerk." #: ClientCommand.cpp:1145 msgid "Unable to unload module {1}: Unknown module type" msgstr "Niet mogelijk module te stopped {1}: Onbekend type module" #: ClientCommand.cpp:1158 msgid "Unable to reload modules. Access denied." msgstr "Niet mogelijk modules te herladen. Toegang geweigerd." #: ClientCommand.cpp:1179 msgid "Usage: ReloadMod [--type=global|user|network] [args]" msgstr "Gebruik: ReloadMod [--type=global|user|network] [argumenten]" #: ClientCommand.cpp:1188 msgid "Unable to reload {1}: {2}" msgstr "Niet mogelijk module te herladen {1}: {2}" #: ClientCommand.cpp:1196 msgid "Unable to reload global module {1}: Access denied." msgstr "Niet mogelijk algemene module te herladen {1}: Toegang geweigerd." #: ClientCommand.cpp:1203 msgid "Unable to reload network module {1}: Not connected with a network." msgstr "" "Niet mogelijk netwerk module te herladen {1}: Niet verbonden met een netwerk." #: ClientCommand.cpp:1225 msgid "Unable to reload module {1}: Unknown module type" msgstr "Niet mogelijk module te herladen {1}: Onbekend type module" #: ClientCommand.cpp:1236 msgid "Usage: UpdateMod " msgstr "Gebruik: UpdateMod " #: ClientCommand.cpp:1240 msgid "Reloading {1} everywhere" msgstr "Overal {1} herladen" #: ClientCommand.cpp:1242 msgid "Done" msgstr "Klaar" #: ClientCommand.cpp:1245 msgid "" "Done, but there were errors, module {1} could not be reloaded everywhere." msgstr "" "Klaar, maar er waren fouten, module {1} kon niet overal herladen worden." #: ClientCommand.cpp:1253 msgid "" "You must be connected with a network to use this command. Try " "SetUserBindHost instead" msgstr "" "Je moet verbonden zijn met een netwerk om dit commando te gebruiken. Probeer " "in plaats hiervan SetUserBindHost" #: ClientCommand.cpp:1260 msgid "Usage: SetBindHost " msgstr "Gebruik: SetBindHost " #: ClientCommand.cpp:1265 ClientCommand.cpp:1282 msgid "You already have this bind host!" msgstr "Je hebt deze bindhost al!" #: ClientCommand.cpp:1270 msgid "Set bind host for network {1} to {2}" msgstr "Stel bindhost voor netwerk {1} in naar {2}" #: ClientCommand.cpp:1277 msgid "Usage: SetUserBindHost " msgstr "Gebruik: SetUserBindHost " #: ClientCommand.cpp:1287 msgid "Set default bind host to {1}" msgstr "Standaard bindhost ingesteld naar {1}" #: ClientCommand.cpp:1293 msgid "" "You must be connected with a network to use this command. Try " "ClearUserBindHost instead" msgstr "" "Je moet verbonden zijn met een netwerk om dit commando te gebruiken. Probeer " "in plaats hiervan ClearUserBindHost" #: ClientCommand.cpp:1298 msgid "Bind host cleared for this network." msgstr "Bindhost gewist voor dit netwerk." #: ClientCommand.cpp:1302 msgid "Default bind host cleared for your user." msgstr "Standaard bindhost gewist voor jouw gebruiker." #: ClientCommand.cpp:1305 msgid "This user's default bind host not set" msgstr "Er is geen standaard bindhost voor deze gebruiker ingesteld" #: ClientCommand.cpp:1307 msgid "This user's default bind host is {1}" msgstr "De standaard bindhost voor deze gebruiker is {1}" #: ClientCommand.cpp:1312 msgid "This network's bind host not set" msgstr "Er is geen bindhost ingesteld voor dit netwerk" #: ClientCommand.cpp:1314 msgid "This network's default bind host is {1}" msgstr "De standaard bindhost voor dit netwerk is {1}" #: ClientCommand.cpp:1328 msgid "Usage: PlayBuffer <#chan|query>" msgstr "Gebruik: PlayBuffer <#kanaal|privé bericht>" #: ClientCommand.cpp:1336 msgid "You are not on {1}" msgstr "Je bent niet in {1}" #: ClientCommand.cpp:1341 msgid "You are not on {1} (trying to join)" msgstr "Je bent niet in {1} (probeer toe te treden)" #: ClientCommand.cpp:1346 msgid "The buffer for channel {1} is empty" msgstr "De buffer voor kanaal {1} is leeg" #: ClientCommand.cpp:1355 msgid "No active query with {1}" msgstr "Geen actieve privé berichten met {1}" #: ClientCommand.cpp:1360 msgid "The buffer for {1} is empty" msgstr "De buffer voor {1} is leeg" #: ClientCommand.cpp:1376 msgid "Usage: ClearBuffer <#chan|query>" msgstr "Gebruik: ClearBuffer <#kanaal|privé bericht>" #: ClientCommand.cpp:1395 msgid "{1} buffer matching {2} has been cleared" msgid_plural "{1} buffers matching {2} have been cleared" msgstr[0] "{1} buffer overeenkomend met {2} is gewist" msgstr[1] "{1} buffers overeenkomend met {2} zijn gewist" #: ClientCommand.cpp:1408 msgid "All channel buffers have been cleared" msgstr "Alle kanaalbuffers zijn gewist" #: ClientCommand.cpp:1417 msgid "All query buffers have been cleared" msgstr "Alle privéberichtenbuffers zijn gewist" #: ClientCommand.cpp:1429 msgid "All buffers have been cleared" msgstr "Alle buffers zijn gewist" #: ClientCommand.cpp:1440 msgid "Usage: SetBuffer <#chan|query> [linecount]" msgstr "Gebruik: SetBuffer <#kanaal|privé bericht> [regelaantal]" #: ClientCommand.cpp:1461 msgid "Setting buffer size failed for {1} buffer" msgid_plural "Setting buffer size failed for {1} buffers" msgstr[0] "Instellen van buffergrootte mislukt voor {1} buffer" msgstr[1] "Instellen van buffergrootte mislukt voor {1} buffers" #: ClientCommand.cpp:1464 msgid "Maximum buffer size is {1} line" msgid_plural "Maximum buffer size is {1} lines" msgstr[0] "Maximale buffergrootte is {1} regel" msgstr[1] "Maximale buffergrootte is {1} regels" #: ClientCommand.cpp:1469 msgid "Size of every buffer was set to {1} line" msgid_plural "Size of every buffer was set to {1} lines" msgstr[0] "Grootte van alle buffers is ingesteld op {1} regel" msgstr[1] "Grootte van alle buffers is ingesteld op {1} regels" #: ClientCommand.cpp:1479 ClientCommand.cpp:1486 ClientCommand.cpp:1497 #: ClientCommand.cpp:1506 ClientCommand.cpp:1514 msgctxt "trafficcmd" msgid "Username" msgstr "Gebruikersnaam" #: ClientCommand.cpp:1480 ClientCommand.cpp:1487 ClientCommand.cpp:1499 #: ClientCommand.cpp:1508 ClientCommand.cpp:1516 msgctxt "trafficcmd" msgid "In" msgstr "In" #: ClientCommand.cpp:1481 ClientCommand.cpp:1489 ClientCommand.cpp:1500 #: ClientCommand.cpp:1509 ClientCommand.cpp:1517 msgctxt "trafficcmd" msgid "Out" msgstr "Uit" #: ClientCommand.cpp:1482 ClientCommand.cpp:1492 ClientCommand.cpp:1502 #: ClientCommand.cpp:1510 ClientCommand.cpp:1519 msgctxt "trafficcmd" msgid "Total" msgstr "Totaal" #: ClientCommand.cpp:1498 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1507 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1515 msgctxt "trafficcmd" msgid "" msgstr "" #: ClientCommand.cpp:1524 msgid "Running for {1}" msgstr "Draaiend voor {1}" #: ClientCommand.cpp:1530 msgid "Unknown command, try 'Help'" msgstr "Onbekend commando, probeer 'Help'" #: ClientCommand.cpp:1539 ClientCommand.cpp:1550 msgctxt "listports" msgid "Port" msgstr "Poort" #: ClientCommand.cpp:1540 ClientCommand.cpp:1551 msgctxt "listports" msgid "BindHost" msgstr "BindHost" #: ClientCommand.cpp:1541 ClientCommand.cpp:1554 msgctxt "listports" msgid "SSL" msgstr "SSL" #: ClientCommand.cpp:1542 ClientCommand.cpp:1559 msgctxt "listports" msgid "Protocol" msgstr "Protocol" #: ClientCommand.cpp:1543 ClientCommand.cpp:1566 msgctxt "listports" msgid "IRC" msgstr "IRC" #: ClientCommand.cpp:1544 ClientCommand.cpp:1571 msgctxt "listports" msgid "Web" msgstr "Web" #: ClientCommand.cpp:1555 msgctxt "listports|ssl" msgid "yes" msgstr "ja" #: ClientCommand.cpp:1556 msgctxt "listports|ssl" msgid "no" msgstr "nee" #: ClientCommand.cpp:1560 msgctxt "listports" msgid "IPv4 and IPv6" msgstr "IPv4 en IPv6" #: ClientCommand.cpp:1562 msgctxt "listports" msgid "IPv4" msgstr "IPv4" #: ClientCommand.cpp:1563 msgctxt "listports" msgid "IPv6" msgstr "IPv6" #: ClientCommand.cpp:1569 msgctxt "listports|irc" msgid "yes" msgstr "ja" #: ClientCommand.cpp:1570 msgctxt "listports|irc" msgid "no" msgstr "nee" #: ClientCommand.cpp:1574 msgctxt "listports|irc" msgid "yes, on {1}" msgstr "ja, in {1}" #: ClientCommand.cpp:1576 msgctxt "listports|web" msgid "no" msgstr "nee" #: ClientCommand.cpp:1616 msgid "" "Usage: AddPort <[+]port> [bindhost [uriprefix]]" msgstr "" "Gebruik: AddPort <[+]poort> [bindhost " "[urivoorvoegsel]]" #: ClientCommand.cpp:1632 msgid "Port added" msgstr "Poort toegevoegd" #: ClientCommand.cpp:1634 msgid "Couldn't add port" msgstr "Kon poort niet toevoegen" #: ClientCommand.cpp:1640 msgid "Usage: DelPort [bindhost]" msgstr "Gebruik: DelPort [bindhost]" #: ClientCommand.cpp:1649 msgid "Deleted Port" msgstr "Poort verwijderd" #: ClientCommand.cpp:1651 msgid "Unable to find a matching port" msgstr "Niet mogelijk om een overeenkomende poort te vinden" #: ClientCommand.cpp:1659 ClientCommand.cpp:1673 msgctxt "helpcmd" msgid "Command" msgstr "Commando" #: ClientCommand.cpp:1660 ClientCommand.cpp:1674 msgctxt "helpcmd" msgid "Description" msgstr "Beschrijving" #: ClientCommand.cpp:1664 msgid "" "In the following list all occurrences of <#chan> support wildcards (* and ?) " "except ListNicks" msgstr "" "In de volgende lijst ondersteunen alle voorvallen van <#kanaal> jokers (* " "en ?) behalve ListNicks" #: ClientCommand.cpp:1680 msgctxt "helpcmd|Version|desc" msgid "Print which version of ZNC this is" msgstr "Toon welke versie van ZNC dit is" #: ClientCommand.cpp:1683 msgctxt "helpcmd|ListMods|desc" msgid "List all loaded modules" msgstr "Toon een lijst van alle geladen modules" #: ClientCommand.cpp:1686 msgctxt "helpcmd|ListAvailMods|desc" msgid "List all available modules" msgstr "Toon alle beschikbare modules" #: ClientCommand.cpp:1690 ClientCommand.cpp:1876 msgctxt "helpcmd|ListChans|desc" msgid "List all channels" msgstr "Toon alle kanalen" #: ClientCommand.cpp:1693 msgctxt "helpcmd|ListNicks|args" msgid "<#chan>" msgstr "<#kanaal>" #: ClientCommand.cpp:1694 msgctxt "helpcmd|ListNicks|desc" msgid "List all nicks on a channel" msgstr "Toon alle bijnamen op een kanaal" #: ClientCommand.cpp:1697 msgctxt "helpcmd|ListClients|desc" msgid "List all clients connected to your ZNC user" msgstr "Toon alle clients verbonden met jouw ZNC gebruiker" #: ClientCommand.cpp:1701 msgctxt "helpcmd|ListServers|desc" msgid "List all servers of current IRC network" msgstr "Toon alle servers van het huidige IRC netwerk" #: ClientCommand.cpp:1705 msgctxt "helpcmd|AddNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1706 msgctxt "helpcmd|AddNetwork|desc" msgid "Add a network to your user" msgstr "Voeg een netwerk toe aan jouw gebruiker" #: ClientCommand.cpp:1708 msgctxt "helpcmd|DelNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1709 msgctxt "helpcmd|DelNetwork|desc" msgid "Delete a network from your user" msgstr "Verwijder een netwerk van jouw gebruiker" #: ClientCommand.cpp:1711 msgctxt "helpcmd|ListNetworks|desc" msgid "List all networks" msgstr "Toon alle netwerken" #: ClientCommand.cpp:1714 msgctxt "helpcmd|MoveNetwork|args" msgid " [new network]" msgstr " [nieuw netwerk]" #: ClientCommand.cpp:1716 msgctxt "helpcmd|MoveNetwork|desc" msgid "Move an IRC network from one user to another" msgstr "Verplaats een IRC netwerk van een gebruiker naar een andere gebruiker" #: ClientCommand.cpp:1720 msgctxt "helpcmd|JumpNetwork|args" msgid "" msgstr "" #: ClientCommand.cpp:1721 msgctxt "helpcmd|JumpNetwork|desc" msgid "" "Jump to another network (Alternatively, you can connect to ZNC several " "times, using `user/network` as username)" msgstr "" "Spring naar een ander netwerk (Je kan ook meerdere malen naar ZNC verbinden " "door `gebruiker/netwerk` als gebruikersnaam te gebruiken)" #: ClientCommand.cpp:1726 msgctxt "helpcmd|AddServer|args" msgid " [[+]port] [pass]" msgstr " [[+]poort] [wachtwoord]" #: ClientCommand.cpp:1727 msgctxt "helpcmd|AddServer|desc" msgid "" "Add a server to the list of alternate/backup servers of current IRC network." msgstr "" "Voeg een server toe aan de lijst van alternatieve/backup servers van het " "huidige IRC netwerk." #: ClientCommand.cpp:1731 msgctxt "helpcmd|DelServer|args" msgid " [port] [pass]" msgstr " [poort] [wachtwoord]" #: ClientCommand.cpp:1732 msgctxt "helpcmd|DelServer|desc" msgid "" "Remove a server from the list of alternate/backup servers of current IRC " "network" msgstr "" "Verwijder een server van de lijst van alternatieve/backup servers van het " "huidige IRC netwerk" #: ClientCommand.cpp:1738 msgctxt "helpcmd|AddTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1739 msgctxt "helpcmd|AddTrustedServerFingerprint|desc" msgid "" "Add a trusted server SSL certificate fingerprint (SHA-256) to current IRC " "network." msgstr "" "Voeg een vertrouwd SSL certificaat vingerafdruk (SHA-256) toe aan het " "huidige netwerk." #: ClientCommand.cpp:1744 msgctxt "helpcmd|DelTrustedServerFingerprint|args" msgid "" msgstr "" #: ClientCommand.cpp:1745 msgctxt "helpcmd|DelTrustedServerFingerprint|desc" msgid "Delete a trusted server SSL certificate from current IRC network." msgstr "Verwijder een vertrouwd SSL certificaat van het huidige netwerk." #: ClientCommand.cpp:1749 msgctxt "helpcmd|ListTrustedServerFingerprints|desc" msgid "List all trusted server SSL certificates of current IRC network." msgstr "Toon alle vertrouwde SSL certificaten van het huidige netwerk." #: ClientCommand.cpp:1752 msgctxt "helpcmd|EnableChan|args" msgid "<#chans>" msgstr "<#kanalen>" #: ClientCommand.cpp:1753 msgctxt "helpcmd|EnableChan|desc" msgid "Enable channels" msgstr "Kanalen inschakelen" #: ClientCommand.cpp:1754 msgctxt "helpcmd|DisableChan|args" msgid "<#chans>" msgstr "<#kanalen>" #: ClientCommand.cpp:1755 msgctxt "helpcmd|DisableChan|desc" msgid "Disable channels" msgstr "Kanalen uitschakelen" #: ClientCommand.cpp:1756 msgctxt "helpcmd|Attach|args" msgid "<#chans>" msgstr "<#kanalen>" #: ClientCommand.cpp:1757 msgctxt "helpcmd|Attach|desc" msgid "Attach to channels" msgstr "Koppel aan kanalen" #: ClientCommand.cpp:1758 msgctxt "helpcmd|Detach|args" msgid "<#chans>" msgstr "<#kanalen>" #: ClientCommand.cpp:1759 msgctxt "helpcmd|Detach|desc" msgid "Detach from channels" msgstr "Loskoppelen van kanalen" #: ClientCommand.cpp:1762 msgctxt "helpcmd|Topics|desc" msgid "Show topics in all your channels" msgstr "Laat topics in al je kanalen zien" #: ClientCommand.cpp:1765 msgctxt "helpcmd|PlayBuffer|args" msgid "<#chan|query>" msgstr "<#kanaal|privé bericht>" #: ClientCommand.cpp:1766 msgctxt "helpcmd|PlayBuffer|desc" msgid "Play back the specified buffer" msgstr "Speel the gekozen buffer terug" #: ClientCommand.cpp:1768 msgctxt "helpcmd|ClearBuffer|args" msgid "<#chan|query>" msgstr "<#kanaal|privé bericht>" #: ClientCommand.cpp:1769 msgctxt "helpcmd|ClearBuffer|desc" msgid "Clear the specified buffer" msgstr "Wis de gekozen buffer" #: ClientCommand.cpp:1771 msgctxt "helpcmd|ClearAllBuffers|desc" msgid "Clear all channel and query buffers" msgstr "Wis alle kanaal en privé berichtenbuffers" #: ClientCommand.cpp:1774 msgctxt "helpcmd|ClearAllChannelBuffers|desc" msgid "Clear the channel buffers" msgstr "Wis de kanaal buffers" #: ClientCommand.cpp:1778 msgctxt "helpcmd|ClearAllQueryBuffers|desc" msgid "Clear the query buffers" msgstr "Wis de privéberichtenbuffers" #: ClientCommand.cpp:1780 msgctxt "helpcmd|SetBuffer|args" msgid "<#chan|query> [linecount]" msgstr "<#kanaal|privé bericht> [regelaantal]" #: ClientCommand.cpp:1781 msgctxt "helpcmd|SetBuffer|desc" msgid "Set the buffer count" msgstr "Stel het buffer aantal in" #: ClientCommand.cpp:1785 msgctxt "helpcmd|SetBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1786 msgctxt "helpcmd|SetBindHost|desc" msgid "Set the bind host for this network" msgstr "Stel de bindhost in voor dit netwerk" #: ClientCommand.cpp:1790 msgctxt "helpcmd|SetUserBindHost|args" msgid "" msgstr "" #: ClientCommand.cpp:1791 msgctxt "helpcmd|SetUserBindHost|desc" msgid "Set the default bind host for this user" msgstr "Stel de bindhost in voor deze gebruiker" #: ClientCommand.cpp:1794 msgctxt "helpcmd|ClearBindHost|desc" msgid "Clear the bind host for this network" msgstr "Wis de bindhost voor dit netwerk" #: ClientCommand.cpp:1797 msgctxt "helpcmd|ClearUserBindHost|desc" msgid "Clear the default bind host for this user" msgstr "Wis de standaard bindhost voor deze gebruiker" #: ClientCommand.cpp:1803 msgctxt "helpcmd|ShowBindHost|desc" msgid "Show currently selected bind host" msgstr "Toon huidig geselecteerde bindhost" #: ClientCommand.cpp:1805 msgctxt "helpcmd|Jump|args" msgid "[server]" msgstr "[server]" #: ClientCommand.cpp:1806 msgctxt "helpcmd|Jump|desc" msgid "Jump to the next or the specified server" msgstr "Spring naar de volgende of de gekozen server" #: ClientCommand.cpp:1807 msgctxt "helpcmd|Disconnect|args" msgid "[message]" msgstr "[bericht]" #: ClientCommand.cpp:1808 msgctxt "helpcmd|Disconnect|desc" msgid "Disconnect from IRC" msgstr "Verbreek verbinding met IRC" #: ClientCommand.cpp:1810 msgctxt "helpcmd|Connect|desc" msgid "Reconnect to IRC" msgstr "Verbind opnieuw met IRC" #: ClientCommand.cpp:1813 msgctxt "helpcmd|Uptime|desc" msgid "Show for how long ZNC has been running" msgstr "Laat zien hoe lang ZNC al draait" #: ClientCommand.cpp:1817 msgctxt "helpcmd|LoadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1819 msgctxt "helpcmd|LoadMod|desc" msgid "Load a module" msgstr "Laad een module" #: ClientCommand.cpp:1821 msgctxt "helpcmd|UnloadMod|args" msgid "[--type=global|user|network] " msgstr "[--type=global|user|network] " #: ClientCommand.cpp:1823 msgctxt "helpcmd|UnloadMod|desc" msgid "Unload a module" msgstr "Stop een module" #: ClientCommand.cpp:1825 msgctxt "helpcmd|ReloadMod|args" msgid "[--type=global|user|network] [args]" msgstr "" #: ClientCommand.cpp:1827 msgctxt "helpcmd|ReloadMod|desc" msgid "Reload a module" msgstr "Herlaad een module" #: ClientCommand.cpp:1830 msgctxt "helpcmd|UpdateMod|args" msgid "" msgstr "" #: ClientCommand.cpp:1831 msgctxt "helpcmd|UpdateMod|desc" msgid "Reload a module everywhere" msgstr "Herlaad een module overal" #: ClientCommand.cpp:1837 msgctxt "helpcmd|ShowMOTD|desc" msgid "Show ZNC's message of the day" msgstr "Laat ZNC's bericht van de dag zien" #: ClientCommand.cpp:1841 msgctxt "helpcmd|SetMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1842 msgctxt "helpcmd|SetMOTD|desc" msgid "Set ZNC's message of the day" msgstr "Stel ZNC's bericht van de dag in" #: ClientCommand.cpp:1844 msgctxt "helpcmd|AddMOTD|args" msgid "" msgstr "" #: ClientCommand.cpp:1845 msgctxt "helpcmd|AddMOTD|desc" msgid "Append to ZNC's MOTD" msgstr "Voeg toe aan ZNC's bericht van de dag" #: ClientCommand.cpp:1847 msgctxt "helpcmd|ClearMOTD|desc" msgid "Clear ZNC's MOTD" msgstr "Wis ZNC's bericht van de dag" #: ClientCommand.cpp:1850 msgctxt "helpcmd|ListPorts|desc" msgid "Show all active listeners" msgstr "Laat alle actieve luisteraars zien" #: ClientCommand.cpp:1852 msgctxt "helpcmd|AddPort|args" msgid "<[+]port> [bindhost [uriprefix]]" msgstr "<[+]poort> [bindhost [urivoorvoegsel]]" #: ClientCommand.cpp:1855 msgctxt "helpcmd|AddPort|desc" msgid "Add another port for ZNC to listen on" msgstr "Voeg nog een poort toe voor ZNC om te luisteren" #: ClientCommand.cpp:1859 msgctxt "helpcmd|DelPort|args" msgid " [bindhost]" msgstr " [bindhost]" #: ClientCommand.cpp:1860 msgctxt "helpcmd|DelPort|desc" msgid "Remove a port from ZNC" msgstr "Haal een poort weg van ZNC" #: ClientCommand.cpp:1863 msgctxt "helpcmd|Rehash|desc" msgid "Reload global settings, modules, and listeners from znc.conf" msgstr "Herlaad algemene instelling, modules en luisteraars van znc.conf" #: ClientCommand.cpp:1866 msgctxt "helpcmd|SaveConfig|desc" msgid "Save the current settings to disk" msgstr "Huidige instellingen opslaan in bestand" #: ClientCommand.cpp:1869 msgctxt "helpcmd|ListUsers|desc" msgid "List all ZNC users and their connection status" msgstr "Toon alle ZNC gebruikers en hun verbinding status" #: ClientCommand.cpp:1872 msgctxt "helpcmd|ListAllUserNetworks|desc" msgid "List all ZNC users and their networks" msgstr "Toon alle ZNC gebruikers en hun netwerken" #: ClientCommand.cpp:1875 msgctxt "helpcmd|ListChans|args" msgid "[user ]" msgstr "[gebruiker ]" #: ClientCommand.cpp:1878 msgctxt "helpcmd|ListClients|args" msgid "[user]" msgstr "[gebruiker]" #: ClientCommand.cpp:1879 msgctxt "helpcmd|ListClients|desc" msgid "List all connected clients" msgstr "Toon alle verbonden clients" #: ClientCommand.cpp:1881 msgctxt "helpcmd|Traffic|desc" msgid "Show basic traffic stats for all ZNC users" msgstr "Toon basis verkeer statistieken voor alle ZNC gebruikers" #: ClientCommand.cpp:1883 msgctxt "helpcmd|Broadcast|args" msgid "[message]" msgstr "[bericht]" #: ClientCommand.cpp:1884 msgctxt "helpcmd|Broadcast|desc" msgid "Broadcast a message to all ZNC users" msgstr "Zend een bericht naar alle ZNC gebruikers" #: ClientCommand.cpp:1887 msgctxt "helpcmd|Shutdown|args" msgid "[message]" msgstr "[bericht]" #: ClientCommand.cpp:1888 msgctxt "helpcmd|Shutdown|desc" msgid "Shut down ZNC completely" msgstr "Sluit ZNC in zijn geheel af" #: ClientCommand.cpp:1889 msgctxt "helpcmd|Restart|args" msgid "[message]" msgstr "[bericht]" #: ClientCommand.cpp:1890 msgctxt "helpcmd|Restart|desc" msgid "Restart ZNC" msgstr "Herstart ZNC" #: Socket.cpp:336 msgid "Can't resolve server hostname" msgstr "Kan server hostnaam niet oplossen" #: Socket.cpp:343 msgid "" "Can't resolve bind hostname. Try /znc ClearBindHost and /znc " "ClearUserBindHost" msgstr "" "Kan bindhostnaam niet oplossen. Probeer /znc ClearBindHost en /znc " "ClearUserBindHost" #: Socket.cpp:348 msgid "Server address is IPv4-only, but bindhost is IPv6-only" msgstr "Server adres is alleen IPv4, maar de bindhost is alleen IPv6" #: Socket.cpp:357 msgid "Server address is IPv6-only, but bindhost is IPv4-only" msgstr "Server adres is alleen IPv6, maar de bindhost is alleen IPv4" #: Socket.cpp:515 msgid "Some socket reached its max buffer limit and was closed!" msgstr "" "Een of andere socket heeft de maximale buffer limiet bereikt en was " "afgesloten!" #: SSLVerifyHost.cpp:448 msgid "hostname doesn't match" msgstr "Hostnaam komt niet overeen" #: SSLVerifyHost.cpp:452 msgid "malformed hostname in certificate" msgstr "misvormde hostnaam in certificaat" #: SSLVerifyHost.cpp:456 msgid "hostname verification error" msgstr "hostnaam verificatiefout" #: User.cpp:507 msgid "" "Invalid network name. It should be alphanumeric. Not to be confused with " "server name" msgstr "" "Ongeldige netwerknaam. Deze moet alfanumeriek zijn. Niet te verwarren met " "server naam" #: User.cpp:511 msgid "Network {1} already exists" msgstr "Netwerk {1} bestaat al" #: User.cpp:777 msgid "" "You are being disconnected because your IP is no longer allowed to connect " "to this user" msgstr "" "Je verbinding wordt verbroken omdat het niet meer toegestaan is om met jouw " "IP-adres naar deze gebruiker te verbinden" #: User.cpp:907 msgid "Password is empty" msgstr "Wachtwoord is leeg" #: User.cpp:912 msgid "Username is empty" msgstr "Gebruikersnaam is leeg" #: User.cpp:917 msgid "Username is invalid" msgstr "Gebruikersnaam is ongeldig" #: User.cpp:1188 msgid "Unable to find modinfo {1}: {2}" msgstr "Kan modinfo niet vinden {1}: {2}" znc-1.7.5/src/version.cpp0000644000175000017500000000011313542151642015520 0ustar somebodysomebody#include const char* ZNC_VERSION_EXTRA = VERSION_EXTRA ""; znc-1.7.5/src/MD5.cpp0000644000175000017500000001674013542151610014430 0ustar somebodysomebody/* * RFC 1321 compliant MD5 implementation * * Copyright (C) 2001-2003 Christophe Devine * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include CMD5::CMD5() { *m_szMD5 = '\0'; } CMD5::CMD5(const string& sText) { MakeHash(sText.c_str(), sText.length()); } CMD5::CMD5(const char* szText, uint32 nTextLen) { MakeHash(szText, nTextLen); } CMD5::~CMD5() {} #define GET_UINT32(n, b, i) \ { \ (n) = ((uint32)(b)[(i)]) | ((uint32)(b)[(i)+1] << 8) | \ ((uint32)(b)[(i)+2] << 16) | ((uint32)(b)[(i)+3] << 24); \ } #define PUT_UINT32(n, b, i) \ { \ (b)[(i)] = (uint8)((n)); \ (b)[(i)+1] = (uint8)((n) >> 8); \ (b)[(i)+2] = (uint8)((n) >> 16); \ (b)[(i)+3] = (uint8)((n) >> 24); \ } void CMD5::md5_starts(md5_context* ctx) const { ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; } void CMD5::md5_process(md5_context* ctx, const uint8 data[64]) const { uint32 X[16], A, B, C, D; GET_UINT32(X[0], data, 0); GET_UINT32(X[1], data, 4); GET_UINT32(X[2], data, 8); GET_UINT32(X[3], data, 12); GET_UINT32(X[4], data, 16); GET_UINT32(X[5], data, 20); GET_UINT32(X[6], data, 24); GET_UINT32(X[7], data, 28); GET_UINT32(X[8], data, 32); GET_UINT32(X[9], data, 36); GET_UINT32(X[10], data, 40); GET_UINT32(X[11], data, 44); GET_UINT32(X[12], data, 48); GET_UINT32(X[13], data, 52); GET_UINT32(X[14], data, 56); GET_UINT32(X[15], data, 60); #define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define P(a, b, c, d, k, s, t) \ a += F(b, c, d) + X[k] + t; \ a = S(a, s) + b; A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; #define F(x, y, z) (z ^ (x & (y ^ z))) P(A, B, C, D, 0, 7, 0xD76AA478); P(D, A, B, C, 1, 12, 0xE8C7B756); P(C, D, A, B, 2, 17, 0x242070DB); P(B, C, D, A, 3, 22, 0xC1BDCEEE); P(A, B, C, D, 4, 7, 0xF57C0FAF); P(D, A, B, C, 5, 12, 0x4787C62A); P(C, D, A, B, 6, 17, 0xA8304613); P(B, C, D, A, 7, 22, 0xFD469501); P(A, B, C, D, 8, 7, 0x698098D8); P(D, A, B, C, 9, 12, 0x8B44F7AF); P(C, D, A, B, 10, 17, 0xFFFF5BB1); P(B, C, D, A, 11, 22, 0x895CD7BE); P(A, B, C, D, 12, 7, 0x6B901122); P(D, A, B, C, 13, 12, 0xFD987193); P(C, D, A, B, 14, 17, 0xA679438E); P(B, C, D, A, 15, 22, 0x49B40821); #undef F #define F(x, y, z) (y ^ (z & (x ^ y))) P(A, B, C, D, 1, 5, 0xF61E2562); P(D, A, B, C, 6, 9, 0xC040B340); P(C, D, A, B, 11, 14, 0x265E5A51); P(B, C, D, A, 0, 20, 0xE9B6C7AA); P(A, B, C, D, 5, 5, 0xD62F105D); P(D, A, B, C, 10, 9, 0x02441453); P(C, D, A, B, 15, 14, 0xD8A1E681); P(B, C, D, A, 4, 20, 0xE7D3FBC8); P(A, B, C, D, 9, 5, 0x21E1CDE6); P(D, A, B, C, 14, 9, 0xC33707D6); P(C, D, A, B, 3, 14, 0xF4D50D87); P(B, C, D, A, 8, 20, 0x455A14ED); P(A, B, C, D, 13, 5, 0xA9E3E905); P(D, A, B, C, 2, 9, 0xFCEFA3F8); P(C, D, A, B, 7, 14, 0x676F02D9); P(B, C, D, A, 12, 20, 0x8D2A4C8A); #undef F #define F(x, y, z) (x ^ y ^ z) P(A, B, C, D, 5, 4, 0xFFFA3942); P(D, A, B, C, 8, 11, 0x8771F681); P(C, D, A, B, 11, 16, 0x6D9D6122); P(B, C, D, A, 14, 23, 0xFDE5380C); P(A, B, C, D, 1, 4, 0xA4BEEA44); P(D, A, B, C, 4, 11, 0x4BDECFA9); P(C, D, A, B, 7, 16, 0xF6BB4B60); P(B, C, D, A, 10, 23, 0xBEBFBC70); P(A, B, C, D, 13, 4, 0x289B7EC6); P(D, A, B, C, 0, 11, 0xEAA127FA); P(C, D, A, B, 3, 16, 0xD4EF3085); P(B, C, D, A, 6, 23, 0x04881D05); P(A, B, C, D, 9, 4, 0xD9D4D039); P(D, A, B, C, 12, 11, 0xE6DB99E5); P(C, D, A, B, 15, 16, 0x1FA27CF8); P(B, C, D, A, 2, 23, 0xC4AC5665); #undef F #define F(x, y, z) (y ^ (x | ~z)) P(A, B, C, D, 0, 6, 0xF4292244); P(D, A, B, C, 7, 10, 0x432AFF97); P(C, D, A, B, 14, 15, 0xAB9423A7); P(B, C, D, A, 5, 21, 0xFC93A039); P(A, B, C, D, 12, 6, 0x655B59C3); P(D, A, B, C, 3, 10, 0x8F0CCC92); P(C, D, A, B, 10, 15, 0xFFEFF47D); P(B, C, D, A, 1, 21, 0x85845DD1); P(A, B, C, D, 8, 6, 0x6FA87E4F); P(D, A, B, C, 15, 10, 0xFE2CE6E0); P(C, D, A, B, 6, 15, 0xA3014314); P(B, C, D, A, 13, 21, 0x4E0811A1); P(A, B, C, D, 4, 6, 0xF7537E82); P(D, A, B, C, 11, 10, 0xBD3AF235); P(C, D, A, B, 2, 15, 0x2AD7D2BB); P(B, C, D, A, 9, 21, 0xEB86D391); #undef F ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; } void CMD5::md5_update(md5_context* ctx, const uint8* input, uint32 length) const { uint32 left, fill; if (!length) return; left = ctx->total[0] & 0x3F; fill = 64 - left; ctx->total[0] += length; ctx->total[0] &= 0xFFFFFFFF; if (ctx->total[0] < length) ctx->total[1]++; if (left && length >= fill) { memcpy((void*)(ctx->buffer + left), (void*)input, fill); md5_process(ctx, ctx->buffer); length -= fill; input += fill; left = 0; } while (length >= 64) { md5_process(ctx, input); length -= 64; input += 64; } if (length) { memcpy((void*)(ctx->buffer + left), (void*)input, length); } } static const uint8 md5_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; void CMD5::md5_finish(md5_context* ctx, uint8 digest[16]) const { uint32 last, padn; uint32 high, low; uint8 msglen[8]; high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); low = (ctx->total[0] << 3); PUT_UINT32(low, msglen, 0); PUT_UINT32(high, msglen, 4); last = ctx->total[0] & 0x3F; padn = (last < 56) ? (56 - last) : (120 - last); md5_update(ctx, md5_padding, padn); md5_update(ctx, msglen, 8); PUT_UINT32(ctx->state[0], digest, 0); PUT_UINT32(ctx->state[1], digest, 4); PUT_UINT32(ctx->state[2], digest, 8); PUT_UINT32(ctx->state[3], digest, 12); } char* CMD5::MakeHash(const char* szText, uint32 nTextLen) { md5_context ctx; unsigned char md5sum[16]; md5_starts(&ctx); md5_update(&ctx, (uint8*)szText, nTextLen); md5_finish(&ctx, md5sum); sprintf(m_szMD5, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", md5sum[0], md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5], md5sum[6], md5sum[7], md5sum[8], md5sum[9], md5sum[10], md5sum[11], md5sum[12], md5sum[13], md5sum[14], md5sum[15]); return m_szMD5; } znc-1.7.5/src/Server.cpp0000644000175000017500000000275613542151610015313 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include CServer::CServer(const CString& sName, unsigned short uPort, const CString& sPass, bool bSSL) : m_sName(sName), m_uPort((uPort) ? uPort : (unsigned short)6667), m_sPass(sPass), m_bSSL(bSSL) {} CServer::~CServer() {} bool CServer::IsValidHostName(const CString& sHostName) { return (!sHostName.empty() && !sHostName.Contains(" ")); } const CString& CServer::GetName() const { return m_sName; } unsigned short CServer::GetPort() const { return m_uPort; } const CString& CServer::GetPass() const { return m_sPass; } bool CServer::IsSSL() const { return m_bSSL; } CString CServer::GetString(bool bIncludePassword) const { return m_sName + " " + CString(m_bSSL ? "+" : "") + CString(m_uPort) + CString(bIncludePassword ? (m_sPass.empty() ? "" : " " + m_sPass) : ""); } znc-1.7.5/src/SHA256.cpp0000644000175000017500000001663113542151610014712 0ustar somebodysomebody/* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Copyright (C) 2005, 2007 Olivier Gay * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #define SHFR(x, n) (x >> n) #define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) #define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) #define CH(x, y, z) ((x & y) ^ (~x & z)) #define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) #define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) #define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) #define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) #define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) #define UNPACK32(x, str) \ { \ *((str)+3) = (uint8_t)((x)); \ *((str)+2) = (uint8_t)((x) >> 8); \ *((str)+1) = (uint8_t)((x) >> 16); \ *((str)+0) = (uint8_t)((x) >> 24); \ } #define PACK32(str, x) \ { \ *(x) = ((uint32_t) * ((str)+3)) | ((uint32_t) * ((str)+2) << 8) | \ ((uint32_t) * ((str)+1) << 16) | \ ((uint32_t) * ((str)+0) << 24); \ } /* Macros used for loops unrolling */ #define SHA256_SCR(i) \ { \ w[i] = \ SHA256_F4(w[i - 2]) + w[i - 7] + SHA256_F3(w[i - 15]) + w[i - 16]; \ } #define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ { \ t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) + \ sha256_k[j] + w[j]; \ t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ wv[d] += t1; \ wv[h] = t1 + t2; \ } uint32_t sha256_h0[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; uint32_t sha256_k[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; /* SHA-256 functions */ static void sha256_transf(sha256_ctx* ctx, const unsigned char* message, size_t block_nb) { uint32_t w[64]; uint32_t wv[8]; uint32_t t1, t2; const unsigned char* sub_block; int i; int j; for (i = 0; i < (int)block_nb; i++) { sub_block = message + (i << 6); for (j = 0; j < 16; j++) { PACK32(&sub_block[j << 2], &w[j]); } for (j = 16; j < 64; j++) { SHA256_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 64; j++) { t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } } } void sha256(const unsigned char* message, size_t len, unsigned char* digest) { sha256_ctx ctx; sha256_init(&ctx); sha256_update(&ctx, message, len); sha256_final(&ctx, digest); } void sha256_init(sha256_ctx* ctx) { int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha256_h0[i]; } ctx->len = 0; ctx->tot_len = 0; } void sha256_update(sha256_ctx* ctx, const unsigned char* message, size_t len) { size_t block_nb; size_t new_len, rem_len, tmp_len; const unsigned char* shifted_message; tmp_len = SHA256_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA256_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA256_BLOCK_SIZE; shifted_message = message + rem_len; sha256_transf(ctx, ctx->block, 1); sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA256_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } void sha256_final(sha256_ctx* ctx, unsigned char* digest) { unsigned int block_nb; unsigned int pm_len; size_t len_b; int i; block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha256_transf(ctx, ctx->block, block_nb); for (i = 0; i < 8; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } } znc-1.7.5/src/Template.cpp0000644000175000017500000010134413542151610015611 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include using std::stringstream; using std::vector; using std::list; using std::ostream; using std::pair; using std::map; void CTemplateOptions::Parse(const CString& sLine) { CString sName = sLine.Token(0, false, "=").Trim_n().AsUpper(); CString sValue = sLine.Token(1, true, "=").Trim_n(); if (sName == "ESC") { m_eEscapeTo = CString::ToEscape(sValue); } else if (sName == "ESCFROM") { m_eEscapeFrom = CString::ToEscape(sValue); } } CTemplate* CTemplateLoopContext::GetRow(unsigned int uIndex) { size_t uSize = m_pvRows->size(); if (uIndex < uSize) { if (m_bReverse) { return (*m_pvRows)[uSize - uIndex - 1]; } else { return (*m_pvRows)[uIndex]; } } return nullptr; } CString CTemplateLoopContext::GetValue(const CString& sName, bool bFromIf) { CTemplate* pTemplate = GetCurRow(); if (!pTemplate) { DEBUG("Loop [" + GetName() + "] has no row index [" + CString(GetRowIndex()) + "]"); return ""; } if (sName.Equals("__ID__")) { return CString(GetRowIndex() + 1); } else if (sName.Equals("__COUNT__")) { return CString(GetRowCount()); } else if (sName.Equals("__ODD__")) { return ((GetRowIndex() % 2) ? "" : "1"); } else if (sName.Equals("__EVEN__")) { return ((GetRowIndex() % 2) ? "1" : ""); } else if (sName.Equals("__FIRST__")) { return ((GetRowIndex() == 0) ? "1" : ""); } else if (sName.Equals("__LAST__")) { return ((GetRowIndex() == m_pvRows->size() - 1) ? "1" : ""); } else if (sName.Equals("__OUTER__")) { return ((GetRowIndex() == 0 || GetRowIndex() == m_pvRows->size() - 1) ? "1" : ""); } else if (sName.Equals("__INNER__")) { return ((GetRowIndex() == 0 || GetRowIndex() == m_pvRows->size() - 1) ? "" : "1"); } return pTemplate->GetValue(sName, bFromIf); } CTemplate::~CTemplate() { for (const auto& it : m_mvLoops) { const vector& vLoop = it.second; for (CTemplate* pTemplate : vLoop) { delete pTemplate; } } for (CTemplateLoopContext* pContext : m_vLoopContexts) { delete pContext; } } void CTemplate::Init() { /* We have no CConfig in ZNC land * Hmm... Actually, we do have it now. CString sPath(CConfig::GetValue("WebFilesPath")); if (!sPath.empty()) { SetPath(sPath); } */ ClearPaths(); m_pParent = nullptr; } CString CTemplate::ExpandFile(const CString& sFilename, bool bFromInc) { /*if (sFilename.StartsWith("/") || sFilename.StartsWith("./")) { return sFilename; }*/ CString sFile(ResolveLiteral(sFilename).TrimLeft_n("/")); for (auto& it : m_lsbPaths) { CString& sRoot = it.first; CString sFilePath(CDir::ChangeDir(sRoot, sFile)); // Make sure path ends with a slash because "/foo/pub*" matches // "/foo/public_keep_out/" but "/foo/pub/*" doesn't if (!sRoot.empty() && !sRoot.EndsWith("/")) { sRoot += "/"; } if (it.second && !bFromInc) { DEBUG("\t\tSkipping path (not from INC) [" + sFilePath + "]"); continue; } if (CFile::Exists(sFilePath)) { if (sRoot.empty() || sFilePath.StartsWith(sRoot)) { DEBUG(" Found [" + sFilePath + "]"); return sFilePath; } else { DEBUG("\t\tOutside of root [" + sFilePath + "] !~ [" + sRoot + "]"); } } } switch (m_lsbPaths.size()) { case 0: DEBUG("Unable to find [" + sFile + "] using the current directory"); break; case 1: DEBUG("Unable to find [" + sFile + "] in the defined path [" + m_lsbPaths.begin()->first + "]"); break; default: DEBUG("Unable to find [" + sFile + "] in any of the " + CString(m_lsbPaths.size()) + " defined paths"); } return ""; } void CTemplate::SetPath(const CString& sPaths) { VCString vsDirs; sPaths.Split(":", vsDirs, false); for (const CString& sDir : vsDirs) { AppendPath(sDir, false); } } CString CTemplate::MakePath(const CString& sPath) const { CString sRet(CDir::ChangeDir("./", sPath + "/")); if (!sRet.empty() && !sRet.EndsWith("/")) { sRet += "/"; } return sRet; } void CTemplate::PrependPath(const CString& sPath, bool bIncludesOnly) { DEBUG("CTemplate::PrependPath(" + sPath + ") == [" + MakePath(sPath) + "]"); m_lsbPaths.push_front(make_pair(MakePath(sPath), bIncludesOnly)); } void CTemplate::AppendPath(const CString& sPath, bool bIncludesOnly) { DEBUG("CTemplate::AppendPath(" + sPath + ") == [" + MakePath(sPath) + "]"); m_lsbPaths.push_back(make_pair(MakePath(sPath), bIncludesOnly)); } void CTemplate::RemovePath(const CString& sPath) { DEBUG("CTemplate::RemovePath(" + sPath + ") == [" + CDir::ChangeDir("./", sPath + "/") + "]"); for (const auto& it : m_lsbPaths) { if (it.first == sPath) { m_lsbPaths.remove(it); RemovePath( sPath); // @todo probably shouldn't use recursion, being lazy return; } } } void CTemplate::ClearPaths() { m_lsbPaths.clear(); } bool CTemplate::SetFile(const CString& sFileName) { m_sFileName = ExpandFile(sFileName, false); PrependPath(sFileName + "/.."); if (sFileName.empty()) { DEBUG("CTemplate::SetFile() - Filename is empty"); return false; } if (m_sFileName.empty()) { DEBUG("CTemplate::SetFile() - [" + sFileName + "] does not exist"); return false; } DEBUG("Set template file to [" + m_sFileName + "]"); return true; } class CLoopSorter { CString m_sType; public: CLoopSorter(const CString& sType) : m_sType(sType) {} bool operator()(CTemplate* pTemplate1, CTemplate* pTemplate2) { return (pTemplate1->GetValue(m_sType, false) < pTemplate2->GetValue(m_sType, false)); } }; CTemplate& CTemplate::AddRow(const CString& sName) { CTemplate* pTmpl = new CTemplate(m_spOptions, this); m_mvLoops[sName].push_back(pTmpl); return *pTmpl; } CTemplate* CTemplate::GetRow(const CString& sName, unsigned int uIndex) { vector* pvLoop = GetLoop(sName); if (pvLoop) { if (pvLoop->size() > uIndex) { return (*pvLoop)[uIndex]; } } return nullptr; } vector* CTemplate::GetLoop(const CString& sName) { CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { CTemplate* pTemplate = pContext->GetCurRow(); if (pTemplate) { return pTemplate->GetLoop(sName); } } map>::iterator it = m_mvLoops.find(sName); if (it != m_mvLoops.end()) { return &(it->second); } return nullptr; } bool CTemplate::PrintString(CString& sRet) { sRet.clear(); stringstream sStream; bool bRet = Print(sStream); sRet = sStream.str(); return bRet; } bool CTemplate::Print(ostream& oOut) { return Print(m_sFileName, oOut); } bool CTemplate::Print(const CString& sFileName, ostream& oOut) { if (sFileName.empty()) { DEBUG("Empty filename in CTemplate::Print()"); return false; } CFile File(sFileName); if (!File.Open()) { DEBUG("Unable to open file [" + sFileName + "] in CTemplate::Print()"); return false; } CString sLine; CString sSetBlockVar; bool bValidLastIf = false; bool bInSetBlock = false; unsigned long uFilePos = 0; unsigned long uCurPos = 0; unsigned int uLineNum = 0; unsigned int uNestedIfs = 0; unsigned int uSkip = 0; bool bLoopCont = false; bool bLoopBreak = false; bool bExit = false; // Single template works across multiple translation domains, e.g. .tmpl of // a module can INC'lude Footer.tmpl from core CString sI18N; while (File.ReadLine(sLine)) { CString sOutput; bool bFoundATag = false; bool bTmplLoopHasData = false; uLineNum++; CString::size_type iPos = 0; uCurPos = uFilePos; CString::size_type uLineSize = sLine.size(); bool bBroke = false; while (1) { iPos = sLine.find(""); // Make sure our tmpl tag is ended properly if (iPos2 == CString::npos) { DEBUG("Template tag not ended properly in file [" + sFileName + "] [Parse(sArgs); } else if (sAction.Equals("ADDROW")) { CString sLoopName = sArgs.Token(0); MCString msRow; if (sArgs.Token(1, true, " ").OptionSplit(msRow)) { CTemplate& NewRow = AddRow(sLoopName); for (const auto& it : msRow) { NewRow[it.first] = it.second; } } } else if (sAction.Equals("SET")) { CString sName = sArgs.Token(0); CString sValue = sArgs.Token(1, true); (*this)[sName] = sValue; } else if (sAction.Equals("JOIN")) { VCString vsArgs; // sArgs.Split(" ", vsArgs, false, "\"", "\""); sArgs.QuoteSplit(vsArgs); if (vsArgs.size() > 1) { CString sDelim = vsArgs[0]; bool bFoundOne = false; CString::EEscape eEscape = CString::EASCII; for (const CString& sArg : vsArgs) { if (sArg.StartsWith("ESC=")) { eEscape = CString::ToEscape(sArg.LeftChomp_n(4)); } else { CString sValue = GetValue(sArg); if (!sValue.empty()) { if (bFoundOne) { sOutput += sDelim; } sOutput += sValue.Escape_n(eEscape); bFoundOne = true; } } } } } else if (sAction.Equals("SETBLOCK")) { sSetBlockVar = sArgs; bInSetBlock = true; } else if (sAction.Equals("ENDSETBLOCK")) { CString sName = sSetBlockVar.Token(0); (*this)[sName] += sOutput; sOutput = ""; bInSetBlock = false; sSetBlockVar = ""; } else if (sAction.Equals("EXPAND")) { sOutput += ExpandFile(sArgs, true); } else if (sAction.Equals("VAR")) { sOutput += GetValue(sArgs); } else if (sAction.Equals("LT")) { sOutput += ""; } else if (sAction.Equals("CONTINUE")) { CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { uSkip++; bLoopCont = true; break; } else { DEBUG("[" + sFileName + ":" + CString(uCurPos - iPos2 - 4) + "] must be used inside of a " "loop!"); } } else if (sAction.Equals("BREAK")) { // break from loop CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { uSkip++; bLoopBreak = true; break; } else { DEBUG( "[" + sFileName + ":" + CString(uCurPos - iPos2 - 4) + "] must be used inside of a loop!"); } } else if (sAction.Equals("EXIT")) { bExit = true; } else if (sAction.Equals("DEBUG")) { DEBUG("CTemplate DEBUG [" + sFileName + "@" + CString(uCurPos - iPos2 - 4) + "b] -> [" + sArgs + "]"); } else if (sAction.Equals("LOOP")) { CTemplateLoopContext* pContext = GetCurLoopContext(); if (!pContext || pContext->GetFilePosition() != uCurPos) { // we are at a brand new loop (be it new or a first // pass at an inner loop) CString sLoopName = sArgs.Token(0); bool bReverse = (sArgs.Token(1).Equals("REVERSE")); bool bSort = (sArgs.Token(1).StartsWith("SORT")); vector* pvLoop = GetLoop(sLoopName); if (bSort && pvLoop != nullptr && pvLoop->size() > 1) { CString sKey; if (sArgs.Token(1) .TrimPrefix_n("SORT") .StartsWith("ASC=")) { sKey = sArgs.Token(1).TrimPrefix_n("SORTASC="); } else if (sArgs.Token(1) .TrimPrefix_n("SORT") .StartsWith("DESC=")) { sKey = sArgs.Token(1) .TrimPrefix_n("SORTDESC="); bReverse = true; } if (!sKey.empty()) { std::sort(pvLoop->begin(), pvLoop->end(), CLoopSorter(sKey)); } } if (pvLoop) { // If we found data for this loop, add it to our // context vector // unsigned long uBeforeLoopTag = uCurPos - // iPos2 - 4; unsigned long uAfterLoopTag = uCurPos; for (CString::size_type t = 0; t < sLine.size(); t++) { char c = sLine[t]; if (c == '\r' || c == '\n') { uAfterLoopTag++; } else { break; } } m_vLoopContexts.push_back( new CTemplateLoopContext(uAfterLoopTag, sLoopName, bReverse, pvLoop)); } else { // If we don't have data, just skip this loop // and everything inside uSkip++; } } } else if (sAction.Equals("IF")) { if (ValidIf(sArgs)) { uNestedIfs++; bValidLastIf = true; } else { uSkip++; bValidLastIf = false; } } else if (sAction.Equals("REM")) { uSkip++; } else if (sAction.Equals("I18N")) { sI18N = sArgs; } else if (sAction.Equals("FORMAT") || sAction.Equals("PLURAL")) { bool bHaveContext = false; if (sArgs.TrimPrefix("CTX=")) { bHaveContext = true; } VCString vsArgs; sArgs.QuoteSplit(vsArgs); CString sEnglish, sContext; size_type idx = 0; if (bHaveContext && vsArgs.size() > idx) { sContext = vsArgs[idx]; idx++; } if (vsArgs.size() > idx) { sEnglish = vsArgs[idx]; idx++; } CString sFormat; if (sAction.Equals("PLURAL")) { CString sEnglishes; int iNum = 0; if (vsArgs.size() > idx) { sEnglishes = vsArgs[idx]; idx++; } if (vsArgs.size() > idx) { iNum = GetValue(vsArgs[idx], true).ToInt(); idx++; } sFormat = CTranslation::Get().Plural( sI18N, sContext, sEnglish, sEnglishes, iNum); } else { sFormat = CTranslation::Get().Singular( sI18N, sContext, sEnglish); } MCString msParams; for (size_type i = 0; i + idx < vsArgs.size(); ++i) { msParams[CString(i + 1)] = GetValue(vsArgs[i + idx], false); } sOutput += CString::NamedFormat(sFormat, msParams); } else { bNotFound = true; } } else if (sAction.Equals("REM")) { uSkip++; } else if (sAction.Equals("IF")) { uSkip++; } else if (sAction.Equals("LOOP")) { uSkip++; } if (sAction.Equals("ENDIF")) { if (uSkip) { uSkip--; } else { uNestedIfs--; } } else if (sAction.Equals("ENDREM")) { if (uSkip) { uSkip--; } } else if (sAction.Equals("ENDLOOP")) { if (bLoopCont && uSkip == 1) { uSkip--; bLoopCont = false; } if (bLoopBreak && uSkip == 1) { uSkip--; } if (uSkip) { uSkip--; } else { // We are at the end of the loop so we need to inc the // index CTemplateLoopContext* pContext = GetCurLoopContext(); if (pContext) { pContext->IncRowIndex(); // If we didn't go out of bounds we need to seek // back to the top of our loop if (!bLoopBreak && pContext->GetCurRow()) { uCurPos = pContext->GetFilePosition(); uFilePos = uCurPos; uLineSize = 0; File.Seek(uCurPos); bBroke = true; if (!sOutput.Trim_n().empty()) { pContext->SetHasData(); } break; } else { if (sOutput.Trim_n().empty()) { sOutput.clear(); } bTmplLoopHasData = pContext->HasData(); DelCurLoopContext(); bLoopBreak = false; } } } } else if (sAction.Equals("ELSE")) { if (!bValidLastIf && uSkip == 1) { CString sArg = sArgs.Token(0); if (sArg.empty() || (sArg.Equals("IF") && ValidIf(sArgs.Token(1, true)))) { uSkip = 0; bValidLastIf = true; } } else if (!uSkip) { uSkip = 1; } } else if (bNotFound) { // Unknown tag that isn't being skipped... vector>& vspTagHandlers = GetTagHandlers(); if (!vspTagHandlers.empty()) { // @todo this should go up to the top to grab handlers CTemplate* pTmpl = GetCurTemplate(); CString sCustomOutput; for (const auto& spTagHandler : vspTagHandlers) { if (spTagHandler->HandleTag(*pTmpl, sAction, sArgs, sCustomOutput)) { sOutput += sCustomOutput; bNotFound = false; break; } } if (bNotFound) { DEBUG("Unknown/Unhandled tag [" + sAction + "]"); } } } continue; } DEBUG("Malformed tag on line " + CString(uLineNum) + " of [" << File.GetLongName() + "]"); DEBUG("--------------- [" + sLine + "]"); } if (!bBroke) { uFilePos += uLineSize; if (!uSkip) { sOutput += sLine; } } if (!bFoundATag || bTmplLoopHasData || sOutput.find_first_not_of(" \t\r\n") != CString::npos) { if (bInSetBlock) { CString sName = sSetBlockVar.Token(0); // CString sValue = sSetBlockVar.Token(1, true); (*this)[sName] += sOutput; } else { oOut << sOutput; } } if (bExit) { break; } } oOut.flush(); return true; } void CTemplate::DelCurLoopContext() { if (m_vLoopContexts.empty()) { return; } delete m_vLoopContexts.back(); m_vLoopContexts.pop_back(); } CTemplateLoopContext* CTemplate::GetCurLoopContext() { if (!m_vLoopContexts.empty()) { return m_vLoopContexts.back(); } return nullptr; } bool CTemplate::ValidIf(const CString& sArgs) { CString sArgStr = sArgs; // sArgStr.Replace(" ", "", "\"", "\"", true); sArgStr.Replace(" &&", "&&", "\"", "\"", false); sArgStr.Replace("&& ", "&&", "\"", "\"", false); sArgStr.Replace(" ||", "||", "\"", "\"", false); sArgStr.Replace("|| ", "||", "\"", "\"", false); CString::size_type uOrPos = sArgStr.find("||"); CString::size_type uAndPos = sArgStr.find("&&"); while (uOrPos != CString::npos || uAndPos != CString::npos || !sArgStr.empty()) { bool bAnd = false; if (uAndPos < uOrPos) { bAnd = true; } CString sExpr = sArgStr.Token(0, false, ((bAnd) ? "&&" : "||")); sArgStr = sArgStr.Token(1, true, ((bAnd) ? "&&" : "||")); if (ValidExpr(sExpr)) { if (!bAnd) { return true; } } else { if (bAnd) { return false; } } uOrPos = sArgStr.find("||"); uAndPos = sArgStr.find("&&"); } return false; } bool CTemplate::ValidExpr(const CString& sExpression) { bool bNegate = false; CString sExpr(sExpression); CString sName; CString sValue; if (sExpr.TrimPrefix("!")) { bNegate = true; } if (sExpr.Contains("!=")) { sName = sExpr.Token(0, false, "!=").Trim_n(); sValue = sExpr.Token(1, true, "!=", false, "\"", "\"", true).Trim_n(); bNegate = !bNegate; } else if (sExpr.Contains("==")) { sName = sExpr.Token(0, false, "==").Trim_n(); sValue = sExpr.Token(1, true, "==", false, "\"", "\"", true).Trim_n(); } else if (sExpr.Contains(">=")) { sName = sExpr.Token(0, false, ">=").Trim_n(); sValue = sExpr.Token(1, true, ">=", false, "\"", "\"", true).Trim_n(); return (GetValue(sName, true).ToLong() >= sValue.ToLong()); } else if (sExpr.Contains("<=")) { sName = sExpr.Token(0, false, "<=").Trim_n(); sValue = sExpr.Token(1, true, "<=", false, "\"", "\"", true).Trim_n(); return (GetValue(sName, true).ToLong() <= sValue.ToLong()); } else if (sExpr.Contains(">")) { sName = sExpr.Token(0, false, ">").Trim_n(); sValue = sExpr.Token(1, true, ">", false, "\"", "\"", true).Trim_n(); return (GetValue(sName, true).ToLong() > sValue.ToLong()); } else if (sExpr.Contains("<")) { sName = sExpr.Token(0, false, "<").Trim_n(); sValue = sExpr.Token(1, true, "<", false, "\"", "\"", true).Trim_n(); return (GetValue(sName, true).ToLong() < sValue.ToLong()); } else { sName = sExpr.Trim_n(); } if (sValue.empty()) { return (bNegate != IsTrue(sName)); } sValue = ResolveLiteral(sValue); return (bNegate != GetValue(sName, true).Equals(sValue)); } bool CTemplate::IsTrue(const CString& sName) { if (HasLoop(sName)) { return true; } return GetValue(sName, true).ToBool(); } bool CTemplate::HasLoop(const CString& sName) { return (GetLoop(sName) != nullptr); } CTemplate* CTemplate::GetParent(bool bRoot) { if (!bRoot) { return m_pParent; } return (m_pParent) ? m_pParent->GetParent(bRoot) : this; } CTemplate* CTemplate::GetCurTemplate() { CTemplateLoopContext* pContext = GetCurLoopContext(); if (!pContext) { return this; } return pContext->GetCurRow(); } CString CTemplate::ResolveLiteral(const CString& sString) { if (sString.StartsWith("**")) { // Allow string to start with a literal * by using two in a row return sString.substr(1); } else if (sString.StartsWith("*")) { // If it starts with only one * then treat it as a var and do a lookup return GetValue(sString.substr(1)); } return sString; } CString CTemplate::GetValue(const CString& sArgs, bool bFromIf) { CTemplateLoopContext* pContext = GetCurLoopContext(); CString sName = sArgs.Token(0); CString sRest = sArgs.Token(1, true); CString sRet; while (sRest.Replace(" =", "=", "\"", "\"")) { } while (sRest.Replace("= ", "=", "\"", "\"")) { } VCString vArgs; MCString msArgs; // sRest.Split(" ", vArgs, false, "\"", "\""); sRest.QuoteSplit(vArgs); for (const CString& sArg : vArgs) { msArgs[sArg.Token(0, false, "=").AsUpper()] = sArg.Token(1, true, "="); } /* We have no CConfig in ZNC land * Hmm... Actually, we do have it now. if (msArgs.find("CONFIG") != msArgs.end()) { sRet = CConfig::GetValue(sName); } else*/ if (msArgs.find("ROWS") != msArgs.end()) { vector* pLoop = GetLoop(sName); sRet = CString((pLoop) ? pLoop->size() : 0); } else if (msArgs.find("TOP") == msArgs.end() && pContext) { sRet = pContext->GetValue(sArgs, bFromIf); if (!sRet.empty()) { return sRet; } } else { if (sName.TrimPrefix("*")) { MCString::iterator it = find(sName); sName = (it != end()) ? it->second : ""; } MCString::iterator it = find(sName); sRet = (it != end()) ? it->second : ""; } vector>& vspTagHandlers = GetTagHandlers(); if (!vspTagHandlers .empty()) { // @todo this should go up to the top to grab handlers CTemplate* pTmpl = GetCurTemplate(); if (sRet.empty()) { for (const auto& spTagHandler : vspTagHandlers) { CString sCustomOutput; if (!bFromIf && spTagHandler->HandleVar(*pTmpl, sArgs.Token(0), sArgs.Token(1, true), sCustomOutput)) { sRet = sCustomOutput; break; } else if (bFromIf && spTagHandler->HandleIf(*pTmpl, sArgs.Token(0), sArgs.Token(1, true), sCustomOutput)) { sRet = sCustomOutput; break; } } } for (const auto& spTagHandler : vspTagHandlers) { if (spTagHandler->HandleValue(*pTmpl, sRet, msArgs)) { break; } } } if (!bFromIf) { if (sRet.empty()) { sRet = ResolveLiteral(msArgs["DEFAULT"]); } MCString::iterator it = msArgs.find("ESC"); if (it != msArgs.end()) { VCString vsEscs; it->second.Split(",", vsEscs, false); for (const CString& sEsc : vsEscs) { sRet.Escape(CString::ToEscape(sEsc)); } } else { sRet.Escape(m_spOptions->GetEscapeFrom(), m_spOptions->GetEscapeTo()); } } return sRet; } znc-1.7.5/src/SSLVerifyHost.cpp0000644000175000017500000003721213542151610016524 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #ifdef HAVE_LIBSSL #if defined(OPENSSL_VERSION_NUMBER) && !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100007 # define CONST_ASN1_STRING_DATA const /* 1.1.0-pre7: openssl/openssl@17ebf85abda18c3875b1ba6670fe7b393bc1f297 */ #else # define ASN1_STRING_get0_data( x ) ASN1_STRING_data( x ) # define CONST_ASN1_STRING_DATA #endif #include namespace ZNC_Curl { /////////////////////////////////////////////////////////////////////////// // // This block is from https://github.com/bagder/curl/blob/master/lib/ // Copyright: Daniel Stenberg, , license: MIT // /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because its behavior is altered by the current locale. */ inline char Curl_raw_toupper(char in) { switch (in) { case 'a': return 'A'; case 'b': return 'B'; case 'c': return 'C'; case 'd': return 'D'; case 'e': return 'E'; case 'f': return 'F'; case 'g': return 'G'; case 'h': return 'H'; case 'i': return 'I'; case 'j': return 'J'; case 'k': return 'K'; case 'l': return 'L'; case 'm': return 'M'; case 'n': return 'N'; case 'o': return 'O'; case 'p': return 'P'; case 'q': return 'Q'; case 'r': return 'R'; case 's': return 'S'; case 't': return 'T'; case 'u': return 'U'; case 'v': return 'V'; case 'w': return 'W'; case 'x': return 'X'; case 'y': return 'Y'; case 'z': return 'Z'; } return in; } /* * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant * to be locale independent and only compare strings we know are safe for * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for * some further explanation to why this function is necessary. * * The function is capable of comparing a-z case insensitively even for * non-ascii. */ static int Curl_raw_equal(const char* first, const char* second) { while (*first && *second) { if (Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) /* get out of the loop as soon as they don't match */ break; first++; second++; } /* we do the comparison here (possibly again), just to make sure that if the loop above is skipped because one of the strings reached zero, we must not return this as a successful match */ return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); } static int Curl_raw_nequal(const char* first, const char* second, size_t max) { while (*first && *second && max) { if (Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) { break; } max--; first++; second++; } if (0 == max) return 1; /* they are equal this far */ return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); } static const int CURL_HOST_NOMATCH = 0; static const int CURL_HOST_MATCH = 1; /* * Match a hostname against a wildcard pattern. * E.g. * "foo.host.com" matches "*.host.com". * * We use the matching rule described in RFC6125, section 6.4.3. * http://tools.ietf.org/html/rfc6125#section-6.4.3 * * In addition: ignore trailing dots in the host names and wildcards, so that * the names are used normalized. This is what the browsers do. * * Do not allow wildcard matching on IP numbers. There are apparently * certificates being used with an IP address in the CN field, thus making no * apparent distinction between a name and an IP. We need to detect the use of * an IP address and not wildcard match on such names. * * NOTE: hostmatch() gets called with copied buffers so that it can modify the * contents at will. */ static int hostmatch(char* hostname, char* pattern) { const char* pattern_label_end, *pattern_wildcard, *hostname_label_end; int wildcard_enabled; size_t prefixlen, suffixlen; struct in_addr ignored; #ifdef ENABLE_IPV6 struct sockaddr_in6 si6; #endif /* normalize pattern and hostname by stripping off trailing dots */ size_t len = strlen(hostname); if (hostname[len - 1] == '.') hostname[len - 1] = 0; len = strlen(pattern); if (pattern[len - 1] == '.') pattern[len - 1] = 0; pattern_wildcard = strchr(pattern, '*'); if (pattern_wildcard == nullptr) return Curl_raw_equal(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; /* detect IP address as hostname and fail the match if so */ if (inet_pton(AF_INET, hostname, &ignored) > 0) return CURL_HOST_NOMATCH; #ifdef ENABLE_IPV6 else if (Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0) return CURL_HOST_NOMATCH; #endif /* We require at least 2 dots in pattern to avoid too wide wildcard match. */ wildcard_enabled = 1; pattern_label_end = strchr(pattern, '.'); if (pattern_label_end == nullptr || strchr(pattern_label_end + 1, '.') == nullptr || pattern_wildcard > pattern_label_end || Curl_raw_nequal(pattern, "xn--", 4)) { wildcard_enabled = 0; } if (!wildcard_enabled) return Curl_raw_equal(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; hostname_label_end = strchr(hostname, '.'); if (hostname_label_end == nullptr || !Curl_raw_equal(pattern_label_end, hostname_label_end)) return CURL_HOST_NOMATCH; /* The wildcard must match at least one character, so the left-most label of the hostname is at least as large as the left-most label of the pattern. */ if (hostname_label_end - hostname < pattern_label_end - pattern) return CURL_HOST_NOMATCH; prefixlen = pattern_wildcard - pattern; suffixlen = pattern_label_end - (pattern_wildcard + 1); return Curl_raw_nequal(pattern, hostname, prefixlen) && Curl_raw_nequal(pattern_wildcard + 1, hostname_label_end - suffixlen, suffixlen) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; } static int Curl_cert_hostcheck(const char* match_pattern, const char* hostname) { char* matchp; char* hostp; int res = 0; if (!match_pattern || !*match_pattern || !hostname || !*hostname) /* sanity check */ ; else { matchp = strdup(match_pattern); if (matchp) { hostp = strdup(hostname); if (hostp) { if (hostmatch(hostp, matchp) == CURL_HOST_MATCH) res = 1; free(hostp); } free(matchp); } } return res; } // // End of https://github.com/bagder/curl/blob/master/lib/ // /////////////////////////////////////////////////////////////////////////// } // namespace ZNC_Curl namespace ZNC_iSECPartners { /////////////////////////////////////////////////////////////////////////// // // This block is from https://github.com/iSECPartners/ssl-conservatory/ // Copyright: Alban Diquet, license: MIT // /* * Helper functions to perform basic hostname validation using OpenSSL. * * Please read "everything-you-wanted-to-know-about-openssl.pdf" before * attempting to use this code. This whitepaper describes how the code works, * how it should be used, and what its limitations are. * * Author: Alban Diquet * License: See LICENSE * */ typedef enum { MatchFound, MatchNotFound, NoSANPresent, MalformedCertificate, Error } HostnameValidationResult; #define HOSTNAME_MAX_SIZE 255 /** * Tries to find a match for hostname in the certificate's Common Name field. * * Returns MatchFound if a match was found. * Returns MatchNotFound if no matches were found. * Returns MalformedCertificate if the Common Name had a NUL character embedded in it. * Returns Error if the Common Name could not be extracted. */ static HostnameValidationResult matches_common_name(const char* hostname, const X509* server_cert) { int common_name_loc = -1; X509_NAME_ENTRY* common_name_entry = nullptr; ASN1_STRING* common_name_asn1 = nullptr; CONST_ASN1_STRING_DATA char* common_name_str = nullptr; // Find the position of the CN field in the Subject field of the certificate common_name_loc = X509_NAME_get_index_by_NID( X509_get_subject_name((X509*)server_cert), NID_commonName, -1); if (common_name_loc < 0) { return Error; } // Extract the CN field common_name_entry = X509_NAME_get_entry( X509_get_subject_name((X509*)server_cert), common_name_loc); if (common_name_entry == nullptr) { return Error; } // Convert the CN field to a C string common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry); if (common_name_asn1 == nullptr) { return Error; } common_name_str = (CONST_ASN1_STRING_DATA char*)ASN1_STRING_get0_data(common_name_asn1); // Make sure there isn't an embedded NUL character in the CN if (ASN1_STRING_length(common_name_asn1) != static_cast(strlen(common_name_str))) { return MalformedCertificate; } DEBUG("SSLVerifyHost: Found CN " << common_name_str); // Compare expected hostname with the CN if (ZNC_Curl::Curl_cert_hostcheck(common_name_str, hostname)) { return MatchFound; } else { return MatchNotFound; } } /** * Tries to find a match for hostname in the certificate's Subject Alternative Name extension. * * Returns MatchFound if a match was found. * Returns MatchNotFound if no matches were found. * Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it. * Returns NoSANPresent if the SAN extension was not present in the certificate. */ static HostnameValidationResult matches_subject_alternative_name( const char* hostname, const X509* server_cert) { HostnameValidationResult result = MatchNotFound; int i; int san_names_nb = -1; STACK_OF(GENERAL_NAME)* san_names = nullptr; // Try to extract the names within the SAN extension from the certificate san_names = reinterpret_cast(X509_get_ext_d2i( (X509*)server_cert, NID_subject_alt_name, nullptr, nullptr)); if (san_names == nullptr) { return NoSANPresent; } san_names_nb = sk_GENERAL_NAME_num(san_names); // Check each name within the extension for (i = 0; i < san_names_nb; i++) { const GENERAL_NAME* current_name = sk_GENERAL_NAME_value(san_names, i); if (current_name->type == GEN_DNS) { // Current name is a DNS name, let's check it CONST_ASN1_STRING_DATA char* dns_name = (CONST_ASN1_STRING_DATA char*)ASN1_STRING_get0_data( current_name->d.dNSName); // Make sure there isn't an embedded NUL character in the DNS name if (ASN1_STRING_length(current_name->d.dNSName) != static_cast(strlen(dns_name))) { result = MalformedCertificate; break; } else { // Compare expected hostname with the DNS name DEBUG("SSLVerifyHost: Found SAN " << dns_name); if (ZNC_Curl::Curl_cert_hostcheck(dns_name, hostname)) { result = MatchFound; break; } } } } sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); return result; } /** * Validates the server's identity by looking for the expected hostname in the * server's certificate. As described in RFC 6125, it first tries to find a match * in the Subject Alternative Name extension. If the extension is not present in * the certificate, it checks the Common Name instead. * * Returns MatchFound if a match was found. * Returns MatchNotFound if no matches were found. * Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it. * Returns Error if there was an error. */ static HostnameValidationResult validate_hostname(const char* hostname, const X509* server_cert) { HostnameValidationResult result; if ((hostname == nullptr) || (server_cert == nullptr)) return Error; // First try the Subject Alternative Names extension result = matches_subject_alternative_name(hostname, server_cert); if (result == NoSANPresent) { // Extension was not found: try the Common Name result = matches_common_name(hostname, server_cert); } return result; } // // End of https://github.com/iSECPartners/ssl-conservatory/ // /////////////////////////////////////////////////////////////////////////// } // namespace ZNC_iSECPartners bool ZNC_SSLVerifyHost(const CString& sHost, const X509* pCert, CString& sError) { struct Tr : CCoreTranslationMixin { using CCoreTranslationMixin::t_s; }; DEBUG("SSLVerifyHost: checking " << sHost); ZNC_iSECPartners::HostnameValidationResult eResult = ZNC_iSECPartners::validate_hostname(sHost.c_str(), pCert); switch (eResult) { case ZNC_iSECPartners::MatchFound: DEBUG("SSLVerifyHost: verified"); return true; case ZNC_iSECPartners::MatchNotFound: DEBUG("SSLVerifyHost: host doesn't match"); sError = Tr::t_s("hostname doesn't match"); return false; case ZNC_iSECPartners::MalformedCertificate: DEBUG("SSLVerifyHost: malformed cert"); sError = Tr::t_s("malformed hostname in certificate"); return false; default: DEBUG("SSLVerifyHost: error"); sError = Tr::t_s("hostname verification error"); return false; } } #endif /* HAVE_LIBSSL */ znc-1.7.5/src/Config.cpp0000644000175000017500000001500713542151610015243 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include struct ConfigStackEntry { CString sTag; CString sName; CConfig Config; ConfigStackEntry(const CString& Tag, const CString Name) : sTag(Tag), sName(Name), Config() {} }; CConfigEntry::CConfigEntry() : m_pSubConfig(nullptr) {} CConfigEntry::CConfigEntry(const CConfig& Config) : m_pSubConfig(new CConfig(Config)) {} CConfigEntry::CConfigEntry(const CConfigEntry& other) : m_pSubConfig(nullptr) { if (other.m_pSubConfig) m_pSubConfig = new CConfig(*other.m_pSubConfig); } CConfigEntry::~CConfigEntry() { delete m_pSubConfig; } CConfigEntry& CConfigEntry::operator=(const CConfigEntry& other) { delete m_pSubConfig; if (other.m_pSubConfig) m_pSubConfig = new CConfig(*other.m_pSubConfig); else m_pSubConfig = nullptr; return *this; } bool CConfig::Parse(CFile& file, CString& sErrorMsg) { CString sLine; unsigned int uLineNum = 0; CConfig* pActiveConfig = this; std::stack ConfigStack; bool bCommented = false; // support for /**/ style comments if (!file.Seek(0)) { sErrorMsg = "Could not seek to the beginning of the config."; return false; } while (file.ReadLine(sLine)) { uLineNum++; #define ERROR(arg) \ do { \ std::stringstream stream; \ stream << "Error on line " << uLineNum << ": " << arg; \ sErrorMsg = stream.str(); \ m_SubConfigs.clear(); \ m_ConfigEntries.clear(); \ return false; \ } while (0) // Remove all leading spaces and trailing line endings sLine.TrimLeft(); sLine.TrimRight("\r\n"); if (bCommented || sLine.StartsWith("/*")) { /* Does this comment end on the same line again? */ bCommented = (!sLine.EndsWith("*/")); continue; } if ((sLine.empty()) || (sLine.StartsWith("#")) || (sLine.StartsWith("//"))) { continue; } if ((sLine.StartsWith("<")) && (sLine.EndsWith(">"))) { sLine.LeftChomp(); sLine.RightChomp(); sLine.Trim(); CString sTag = sLine.Token(0); CString sValue = sLine.Token(1, true); sTag.Trim(); sValue.Trim(); if (sTag.TrimPrefix("/")) { if (!sValue.empty()) ERROR("Malformated closing tag. Expected \"\"."); if (ConfigStack.empty()) ERROR("Closing tag \"" << sTag << "\" which is not open."); const struct ConfigStackEntry& entry = ConfigStack.top(); CConfig myConfig(entry.Config); CString sName(entry.sName); if (!sTag.Equals(entry.sTag)) ERROR("Closing tag \"" << sTag << "\" which is not open."); // This breaks entry ConfigStack.pop(); if (ConfigStack.empty()) pActiveConfig = this; else pActiveConfig = &ConfigStack.top().Config; SubConfig& conf = pActiveConfig->m_SubConfigs[sTag.AsLower()]; SubConfig::const_iterator it = conf.find(sName); if (it != conf.end()) ERROR("Duplicate entry for tag \"" << sTag << "\" name \"" << sName << "\"."); conf[sName] = CConfigEntry(myConfig); } else { if (sValue.empty()) ERROR("Empty block name at begin of block."); ConfigStack.push(ConfigStackEntry(sTag.AsLower(), sValue)); pActiveConfig = &ConfigStack.top().Config; } continue; } // If we have a regular line, figure out where it goes CString sName = sLine.Token(0, false, "="); CString sValue = sLine.Token(1, true, "="); // Only remove the first space, people might want // leading spaces (e.g. in the MOTD). sValue.TrimPrefix(" "); // We don't have any names with spaces, trim all // leading/trailing spaces. sName.Trim(); if (sName.empty() || sValue.empty()) ERROR("Malformed line"); CString sNameLower = sName.AsLower(); pActiveConfig->m_ConfigEntries[sNameLower].push_back(sValue); } if (bCommented) ERROR("Comment not closed at end of file."); if (!ConfigStack.empty()) { const CString& sTag = ConfigStack.top().sTag; ERROR( "Not all tags are closed at the end of the file. Inner-most open " "tag is \"" << sTag << "\"."); } return true; } void CConfig::Write(CFile& File, unsigned int iIndentation) { CString sIndentation = CString(iIndentation, '\t'); auto SingleLine = [](const CString& s) { return s.Replace_n("\r", "").Replace_n("\n", ""); }; for (const auto& it : m_ConfigEntries) { for (const CString& sValue : it.second) { File.Write(SingleLine(sIndentation + it.first + " = " + sValue) + "\n"); } } for (const auto& it : m_SubConfigs) { for (const auto& it2 : it.second) { File.Write("\n"); File.Write(SingleLine(sIndentation + "<" + it.first + " " + it2.first + ">") + "\n"); it2.second.m_pSubConfig->Write(File, iIndentation + 1); File.Write(SingleLine(sIndentation + "") + "\n"); } } } znc-1.7.5/src/IRCNetwork.cpp0000644000175000017500000012202513542151610016024 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include using std::vector; using std::set; class CIRCNetworkPingTimer : public CCron { public: CIRCNetworkPingTimer(CIRCNetwork* pNetwork) : CCron(), m_pNetwork(pNetwork) { SetName("CIRCNetworkPingTimer::" + m_pNetwork->GetUser()->GetUserName() + "::" + m_pNetwork->GetName()); Start(m_pNetwork->GetUser()->GetPingSlack()); } ~CIRCNetworkPingTimer() override {} CIRCNetworkPingTimer(const CIRCNetworkPingTimer&) = delete; CIRCNetworkPingTimer& operator=(const CIRCNetworkPingTimer&) = delete; protected: void RunJob() override { CIRCSock* pIRCSock = m_pNetwork->GetIRCSock(); auto uFrequency = m_pNetwork->GetUser()->GetPingFrequency(); if (pIRCSock && pIRCSock->GetTimeSinceLastDataTransaction() >= uFrequency) { pIRCSock->PutIRC("PING :ZNC"); } const vector& vClients = m_pNetwork->GetClients(); for (CClient* pClient : vClients) { if (pClient->GetTimeSinceLastDataTransaction() >= uFrequency) { pClient->PutClient("PING :ZNC"); } } // Restart timer for the case if the period had changed. Usually this is // noop Start(m_pNetwork->GetUser()->GetPingSlack()); } private: CIRCNetwork* m_pNetwork; }; class CIRCNetworkJoinTimer : public CCron { constexpr static int JOIN_FREQUENCY = 30 /* seconds */; public: CIRCNetworkJoinTimer(CIRCNetwork* pNetwork) : CCron(), m_bDelayed(false), m_pNetwork(pNetwork) { SetName("CIRCNetworkJoinTimer::" + m_pNetwork->GetUser()->GetUserName() + "::" + m_pNetwork->GetName()); Start(JOIN_FREQUENCY); } ~CIRCNetworkJoinTimer() override {} CIRCNetworkJoinTimer(const CIRCNetworkJoinTimer&) = delete; CIRCNetworkJoinTimer& operator=(const CIRCNetworkJoinTimer&) = delete; void Delay(unsigned short int uDelay) { m_bDelayed = true; Start(uDelay); } protected: void RunJob() override { if (m_bDelayed) { m_bDelayed = false; Start(JOIN_FREQUENCY); } if (m_pNetwork->IsIRCConnected()) { m_pNetwork->JoinChans(); } } private: bool m_bDelayed; CIRCNetwork* m_pNetwork; }; bool CIRCNetwork::IsValidNetwork(const CString& sNetwork) { // ^[-\w]+$ if (sNetwork.empty()) { return false; } const char* p = sNetwork.c_str(); while (*p) { if (*p != '_' && *p != '-' && !isalnum(*p)) { return false; } p++; } return true; } CIRCNetwork::CIRCNetwork(CUser* pUser, const CString& sName) : m_sName(sName), m_pUser(nullptr), m_sNick(""), m_sAltNick(""), m_sIdent(""), m_sRealName(""), m_sBindHost(""), m_sEncoding(""), m_sQuitMsg(""), m_ssTrustedFingerprints(), m_pModules(new CModules), m_vClients(), m_pIRCSock(nullptr), m_vChans(), m_vQueries(), m_sChanPrefixes(""), m_bIRCConnectEnabled(true), m_bTrustAllCerts(false), m_bTrustPKI(true), m_sIRCServer(""), m_vServers(), m_uServerIdx(0), m_IRCNick(), m_bIRCAway(false), m_fFloodRate(2), m_uFloodBurst(9), m_RawBuffer(), m_MotdBuffer(), m_NoticeBuffer(), m_pPingTimer(nullptr), m_pJoinTimer(nullptr), m_uJoinDelay(0), m_uBytesRead(0), m_uBytesWritten(0) { SetUser(pUser); // This should be more than enough raws, especially since we are buffering // the MOTD separately m_RawBuffer.SetLineCount(100, true); // This should be more than enough motd lines m_MotdBuffer.SetLineCount(200, true); m_NoticeBuffer.SetLineCount(250, true); m_pPingTimer = new CIRCNetworkPingTimer(this); CZNC::Get().GetManager().AddCron(m_pPingTimer); m_pJoinTimer = new CIRCNetworkJoinTimer(this); CZNC::Get().GetManager().AddCron(m_pJoinTimer); SetIRCConnectEnabled(true); } CIRCNetwork::CIRCNetwork(CUser* pUser, const CIRCNetwork& Network) : CIRCNetwork(pUser, "") { Clone(Network); } void CIRCNetwork::Clone(const CIRCNetwork& Network, bool bCloneName) { if (bCloneName) { m_sName = Network.GetName(); } m_fFloodRate = Network.GetFloodRate(); m_uFloodBurst = Network.GetFloodBurst(); m_uJoinDelay = Network.GetJoinDelay(); SetNick(Network.GetNick()); SetAltNick(Network.GetAltNick()); SetIdent(Network.GetIdent()); SetRealName(Network.GetRealName()); SetBindHost(Network.GetBindHost()); SetEncoding(Network.GetEncoding()); SetQuitMsg(Network.GetQuitMsg()); m_ssTrustedFingerprints = Network.m_ssTrustedFingerprints; // Servers const vector& vServers = Network.GetServers(); CString sServer; CServer* pCurServ = GetCurrentServer(); if (pCurServ) { sServer = pCurServ->GetName(); } DelServers(); for (CServer* pServer : vServers) { AddServer(pServer->GetName(), pServer->GetPort(), pServer->GetPass(), pServer->IsSSL()); } m_uServerIdx = 0; for (size_t a = 0; a < m_vServers.size(); a++) { if (sServer.Equals(m_vServers[a]->GetName())) { m_uServerIdx = a + 1; break; } } if (m_uServerIdx == 0) { m_uServerIdx = m_vServers.size(); CIRCSock* pSock = GetIRCSock(); if (pSock) { PutStatus( t_s("Jumping servers because this server is no longer in the " "list")); pSock->Quit(); } } // !Servers // Chans const vector& vChans = Network.GetChans(); for (CChan* pNewChan : vChans) { CChan* pChan = FindChan(pNewChan->GetName()); if (pChan) { pChan->SetInConfig(pNewChan->InConfig()); } else { AddChan(pNewChan->GetName(), pNewChan->InConfig()); } } for (CChan* pChan : m_vChans) { CChan* pNewChan = Network.FindChan(pChan->GetName()); if (!pNewChan) { pChan->SetInConfig(false); } else { pChan->Clone(*pNewChan); } } // !Chans // Modules set ssUnloadMods; CModules& vCurMods = GetModules(); const CModules& vNewMods = Network.GetModules(); for (CModule* pNewMod : vNewMods) { CString sModRet; CModule* pCurMod = vCurMods.FindModule(pNewMod->GetModName()); if (!pCurMod) { vCurMods.LoadModule(pNewMod->GetModName(), pNewMod->GetArgs(), CModInfo::NetworkModule, m_pUser, this, sModRet); } else if (pNewMod->GetArgs() != pCurMod->GetArgs()) { vCurMods.ReloadModule(pNewMod->GetModName(), pNewMod->GetArgs(), m_pUser, this, sModRet); } } for (CModule* pCurMod : vCurMods) { CModule* pNewMod = vNewMods.FindModule(pCurMod->GetModName()); if (!pNewMod) { ssUnloadMods.insert(pCurMod->GetModName()); } } for (const CString& sMod : ssUnloadMods) { vCurMods.UnloadModule(sMod); } // !Modules SetIRCConnectEnabled(Network.GetIRCConnectEnabled()); } CIRCNetwork::~CIRCNetwork() { if (m_pIRCSock) { CZNC::Get().GetManager().DelSockByAddr(m_pIRCSock); m_pIRCSock = nullptr; } // Delete clients while (!m_vClients.empty()) { CZNC::Get().GetManager().DelSockByAddr(m_vClients[0]); } m_vClients.clear(); // Delete servers DelServers(); // Delete modules (this unloads all modules) delete m_pModules; m_pModules = nullptr; // Delete Channels for (CChan* pChan : m_vChans) { delete pChan; } m_vChans.clear(); // Delete Queries for (CQuery* pQuery : m_vQueries) { delete pQuery; } m_vQueries.clear(); CUser* pUser = GetUser(); SetUser(nullptr); // Make sure we are not in the connection queue CZNC::Get().GetConnectionQueue().remove(this); CZNC::Get().GetManager().DelCronByAddr(m_pPingTimer); CZNC::Get().GetManager().DelCronByAddr(m_pJoinTimer); if (pUser) { pUser->AddBytesRead(m_uBytesRead); pUser->AddBytesWritten(m_uBytesWritten); } else { CZNC::Get().AddBytesRead(m_uBytesRead); CZNC::Get().AddBytesWritten(m_uBytesWritten); } } void CIRCNetwork::DelServers() { for (CServer* pServer : m_vServers) { delete pServer; } m_vServers.clear(); } CString CIRCNetwork::GetNetworkPath() const { CString sNetworkPath = m_pUser->GetUserPath() + "/networks/" + m_sName; if (!CFile::Exists(sNetworkPath)) { CDir::MakeDir(sNetworkPath); } return sNetworkPath; } template struct TOption { const char* name; void (CIRCNetwork::*pSetter)(T); }; bool CIRCNetwork::ParseConfig(CConfig* pConfig, CString& sError, bool bUpgrade) { VCString vsList; if (!bUpgrade) { TOption StringOptions[] = { {"nick", &CIRCNetwork::SetNick}, {"altnick", &CIRCNetwork::SetAltNick}, {"ident", &CIRCNetwork::SetIdent}, {"realname", &CIRCNetwork::SetRealName}, {"bindhost", &CIRCNetwork::SetBindHost}, {"encoding", &CIRCNetwork::SetEncoding}, {"quitmsg", &CIRCNetwork::SetQuitMsg}, }; TOption BoolOptions[] = { {"ircconnectenabled", &CIRCNetwork::SetIRCConnectEnabled}, {"trustallcerts", &CIRCNetwork::SetTrustAllCerts}, {"trustpki", &CIRCNetwork::SetTrustPKI}, }; TOption DoubleOptions[] = { {"floodrate", &CIRCNetwork::SetFloodRate}, }; TOption SUIntOptions[] = { {"floodburst", &CIRCNetwork::SetFloodBurst}, {"joindelay", &CIRCNetwork::SetJoinDelay}, }; for (const auto& Option : StringOptions) { CString sValue; if (pConfig->FindStringEntry(Option.name, sValue)) (this->*Option.pSetter)(sValue); } for (const auto& Option : BoolOptions) { CString sValue; if (pConfig->FindStringEntry(Option.name, sValue)) (this->*Option.pSetter)(sValue.ToBool()); } for (const auto& Option : DoubleOptions) { double fValue; if (pConfig->FindDoubleEntry(Option.name, fValue)) (this->*Option.pSetter)(fValue); } for (const auto& Option : SUIntOptions) { unsigned short value; if (pConfig->FindUShortEntry(Option.name, value)) (this->*Option.pSetter)(value); } pConfig->FindStringVector("loadmodule", vsList); for (const CString& sValue : vsList) { CString sModName = sValue.Token(0); CString sNotice = "Loading network module [" + sModName + "]"; // XXX Legacy crap, added in ZNC 0.203, modified in 0.207 // Note that 0.203 == 0.207 if (sModName == "away") { sNotice = "NOTICE: [away] was renamed, loading [awaystore] instead"; sModName = "awaystore"; } // XXX Legacy crap, added in ZNC 0.207 if (sModName == "autoaway") { sNotice = "NOTICE: [autoaway] was renamed, loading [awaystore] " "instead"; sModName = "awaystore"; } // XXX Legacy crap, added in 1.1; fakeonline module was dropped in // 1.0 and returned in 1.1 if (sModName == "fakeonline") { sNotice = "NOTICE: [fakeonline] was renamed, loading " "[modules_online] instead"; sModName = "modules_online"; } CString sModRet; CString sArgs = sValue.Token(1, true); bool bModRet = LoadModule(sModName, sArgs, sNotice, sModRet); if (!bModRet) { // XXX The awaynick module was retired in 1.6 (still available // as external module) if (sModName == "awaynick") { // load simple_away instead, unless it's already on the list bool bFound = false; for (const CString& sLoadMod : vsList) { if (sLoadMod.Token(0).Equals("simple_away")) { bFound = true; } } if (!bFound) { sNotice = "NOTICE: awaynick was retired, loading network " "module [simple_away] instead; if you still need " "awaynick, install it as an external module"; sModName = "simple_away"; // not a fatal error if simple_away is not available LoadModule(sModName, sArgs, sNotice, sModRet); } } else { sError = sModRet; return false; } } } } pConfig->FindStringVector("server", vsList); for (const CString& sServer : vsList) { CUtils::PrintAction("Adding server [" + sServer + "]"); CUtils::PrintStatus(AddServer(sServer)); } pConfig->FindStringVector("trustedserverfingerprint", vsList); for (const CString& sFP : vsList) { AddTrustedFingerprint(sFP); } pConfig->FindStringVector("chan", vsList); for (const CString& sChan : vsList) { AddChan(sChan, true); } CConfig::SubConfig subConf; CConfig::SubConfig::const_iterator subIt; pConfig->FindSubConfig("chan", subConf); for (subIt = subConf.begin(); subIt != subConf.end(); ++subIt) { const CString& sChanName = subIt->first; CConfig* pSubConf = subIt->second.m_pSubConfig; CChan* pChan = new CChan(sChanName, this, true, pSubConf); if (!pSubConf->empty()) { sError = "Unhandled lines in config for User [" + m_pUser->GetUserName() + "], Network [" + GetName() + "], Channel [" + sChanName + "]!"; CUtils::PrintError(sError); CZNC::DumpConfig(pSubConf); delete pChan; return false; } // Save the channel name, because AddChan // deletes the CChannel*, if adding fails sError = pChan->GetName(); if (!AddChan(pChan)) { sError = "Channel [" + sError + "] defined more than once"; CUtils::PrintError(sError); return false; } sError.clear(); } return true; } CConfig CIRCNetwork::ToConfig() const { CConfig config; if (!m_sNick.empty()) { config.AddKeyValuePair("Nick", m_sNick); } if (!m_sAltNick.empty()) { config.AddKeyValuePair("AltNick", m_sAltNick); } if (!m_sIdent.empty()) { config.AddKeyValuePair("Ident", m_sIdent); } if (!m_sRealName.empty()) { config.AddKeyValuePair("RealName", m_sRealName); } if (!m_sBindHost.empty()) { config.AddKeyValuePair("BindHost", m_sBindHost); } config.AddKeyValuePair("IRCConnectEnabled", CString(GetIRCConnectEnabled())); config.AddKeyValuePair("TrustAllCerts", CString(GetTrustAllCerts())); config.AddKeyValuePair("TrustPKI", CString(GetTrustPKI())); config.AddKeyValuePair("FloodRate", CString(GetFloodRate())); config.AddKeyValuePair("FloodBurst", CString(GetFloodBurst())); config.AddKeyValuePair("JoinDelay", CString(GetJoinDelay())); config.AddKeyValuePair("Encoding", m_sEncoding); if (!m_sQuitMsg.empty()) { config.AddKeyValuePair("QuitMsg", m_sQuitMsg); } // Modules const CModules& Mods = GetModules(); if (!Mods.empty()) { for (CModule* pMod : Mods) { CString sArgs = pMod->GetArgs(); if (!sArgs.empty()) { sArgs = " " + sArgs; } config.AddKeyValuePair("LoadModule", pMod->GetModName() + sArgs); } } // Servers for (CServer* pServer : m_vServers) { config.AddKeyValuePair("Server", pServer->GetString()); } for (const CString& sFP : m_ssTrustedFingerprints) { config.AddKeyValuePair("TrustedServerFingerprint", sFP); } // Chans for (CChan* pChan : m_vChans) { if (pChan->InConfig()) { config.AddSubConfig("Chan", pChan->GetName(), pChan->ToConfig()); } } return config; } void CIRCNetwork::BounceAllClients() { for (CClient* pClient : m_vClients) { pClient->BouncedOff(); } m_vClients.clear(); } bool CIRCNetwork::IsUserOnline() const { for (CClient* pClient : m_vClients) { if (!pClient->IsAway()) { return true; } } return false; } void CIRCNetwork::ClientConnected(CClient* pClient) { if (!m_pUser->MultiClients()) { BounceAllClients(); } m_vClients.push_back(pClient); size_t uIdx, uSize; if (m_pIRCSock) { pClient->NotifyServerDependentCaps(m_pIRCSock->GetAcceptedCaps()); } pClient->SetPlaybackActive(true); if (m_RawBuffer.IsEmpty()) { pClient->PutClient(":irc.znc.in 001 " + pClient->GetNick() + " :" + t_s("Welcome to ZNC")); } else { const CString& sClientNick = pClient->GetNick(false); MCString msParams; msParams["target"] = sClientNick; uSize = m_RawBuffer.Size(); for (uIdx = 0; uIdx < uSize; uIdx++) { pClient->PutClient(m_RawBuffer.GetLine(uIdx, *pClient, msParams)); } const CNick& Nick = GetIRCNick(); if (sClientNick != Nick.GetNick()) { // case-sensitive match pClient->PutClient(":" + sClientNick + "!" + Nick.GetIdent() + "@" + Nick.GetHost() + " NICK :" + Nick.GetNick()); pClient->SetNick(Nick.GetNick()); } } MCString msParams; msParams["target"] = GetIRCNick().GetNick(); // Send the cached MOTD uSize = m_MotdBuffer.Size(); if (uSize > 0) { for (uIdx = 0; uIdx < uSize; uIdx++) { pClient->PutClient(m_MotdBuffer.GetLine(uIdx, *pClient, msParams)); } } if (GetIRCSock() != nullptr) { CString sUserMode(""); const set& scUserModes = GetIRCSock()->GetUserModes(); for (char cMode : scUserModes) { sUserMode += cMode; } if (!sUserMode.empty()) { pClient->PutClient(":" + GetIRCNick().GetNickMask() + " MODE " + GetIRCNick().GetNick() + " :+" + sUserMode); } } if (m_bIRCAway) { // If they want to know their away reason they'll have to whois // themselves. At least we can tell them their away status... pClient->PutClient(":irc.znc.in 306 " + GetIRCNick().GetNick() + " :You have been marked as being away"); } const vector& vChans = GetChans(); for (CChan* pChan : vChans) { if ((pChan->IsOn()) && (!pChan->IsDetached())) { pChan->AttachUser(pClient); } } bool bClearQuery = m_pUser->AutoClearQueryBuffer(); for (CQuery* pQuery : m_vQueries) { pQuery->SendBuffer(pClient); if (bClearQuery) { delete pQuery; } } if (bClearQuery) { m_vQueries.clear(); } uSize = m_NoticeBuffer.Size(); for (uIdx = 0; uIdx < uSize; uIdx++) { const CBufLine& BufLine = m_NoticeBuffer.GetBufLine(uIdx); CMessage Message(BufLine.GetLine(*pClient, msParams)); Message.SetNetwork(this); Message.SetClient(pClient); Message.SetTime(BufLine.GetTime()); Message.SetTags(BufLine.GetTags()); bool bContinue = false; NETWORKMODULECALL(OnPrivBufferPlayMessage(Message), m_pUser, this, nullptr, &bContinue); if (bContinue) continue; pClient->PutClient(Message); } m_NoticeBuffer.Clear(); pClient->SetPlaybackActive(false); // Tell them why they won't connect if (!GetIRCConnectEnabled()) pClient->PutStatus( t_s("You are currently disconnected from IRC. Use 'connect' to " "reconnect.")); } void CIRCNetwork::ClientDisconnected(CClient* pClient) { auto it = std::find(m_vClients.begin(), m_vClients.end(), pClient); if (it != m_vClients.end()) { m_vClients.erase(it); } } CUser* CIRCNetwork::GetUser() const { return m_pUser; } const CString& CIRCNetwork::GetName() const { return m_sName; } std::vector CIRCNetwork::FindClients( const CString& sIdentifier) const { std::vector vClients; for (CClient* pClient : m_vClients) { if (pClient->GetIdentifier().Equals(sIdentifier)) { vClients.push_back(pClient); } } return vClients; } void CIRCNetwork::SetUser(CUser* pUser) { for (CClient* pClient : m_vClients) { pClient->PutStatus( t_s("This network is being deleted or moved to another user.")); pClient->SetNetwork(nullptr); } m_vClients.clear(); if (m_pUser) { m_pUser->RemoveNetwork(this); } m_pUser = pUser; if (m_pUser) { m_pUser->AddNetwork(this); } } bool CIRCNetwork::SetName(const CString& sName) { if (IsValidNetwork(sName)) { m_sName = sName; return true; } return false; } bool CIRCNetwork::PutUser(const CString& sLine, CClient* pClient, CClient* pSkipClient) { for (CClient* pEachClient : m_vClients) { if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) { pEachClient->PutClient(sLine); if (pClient) { return true; } } } return (pClient == nullptr); } bool CIRCNetwork::PutUser(const CMessage& Message, CClient* pClient, CClient* pSkipClient) { for (CClient* pEachClient : m_vClients) { if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) { pEachClient->PutClient(Message); if (pClient) { return true; } } } return (pClient == nullptr); } bool CIRCNetwork::PutStatus(const CString& sLine, CClient* pClient, CClient* pSkipClient) { for (CClient* pEachClient : m_vClients) { if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) { pEachClient->PutStatus(sLine); if (pClient) { return true; } } } return (pClient == nullptr); } bool CIRCNetwork::PutModule(const CString& sModule, const CString& sLine, CClient* pClient, CClient* pSkipClient) { for (CClient* pEachClient : m_vClients) { if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) { pEachClient->PutModule(sModule, sLine); if (pClient) { return true; } } } return (pClient == nullptr); } // Channels const vector& CIRCNetwork::GetChans() const { return m_vChans; } CChan* CIRCNetwork::FindChan(CString sName) const { if (GetIRCSock()) { // See // https://tools.ietf.org/html/draft-brocklesby-irc-isupport-03#section-3.16 sName.TrimLeft(GetIRCSock()->GetISupport("STATUSMSG", "")); } for (CChan* pChan : m_vChans) { if (sName.Equals(pChan->GetName())) { return pChan; } } return nullptr; } std::vector CIRCNetwork::FindChans(const CString& sWild) const { std::vector vChans; vChans.reserve(m_vChans.size()); const CString sLower = sWild.AsLower(); for (CChan* pChan : m_vChans) { if (pChan->GetName().AsLower().WildCmp(sLower)) vChans.push_back(pChan); } return vChans; } bool CIRCNetwork::AddChan(CChan* pChan) { if (!pChan) { return false; } for (CChan* pEachChan : m_vChans) { if (pEachChan->GetName().Equals(pChan->GetName())) { delete pChan; return false; } } m_vChans.push_back(pChan); return true; } bool CIRCNetwork::AddChan(const CString& sName, bool bInConfig) { if (sName.empty() || FindChan(sName)) { return false; } CChan* pChan = new CChan(sName, this, bInConfig); m_vChans.push_back(pChan); return true; } bool CIRCNetwork::DelChan(const CString& sName) { for (vector::iterator a = m_vChans.begin(); a != m_vChans.end(); ++a) { if (sName.Equals((*a)->GetName())) { delete *a; m_vChans.erase(a); return true; } } return false; } void CIRCNetwork::JoinChans() { // Avoid divsion by zero, it's bad! if (m_vChans.empty()) return; // We start at a random offset into the channel list so that if your // first 3 channels are invite-only and you got MaxJoins == 3, ZNC will // still be able to join the rest of your channels. unsigned int start = rand() % m_vChans.size(); unsigned int uJoins = m_pUser->MaxJoins(); set sChans; for (unsigned int a = 0; a < m_vChans.size(); a++) { unsigned int idx = (start + a) % m_vChans.size(); CChan* pChan = m_vChans[idx]; if (!pChan->IsOn() && !pChan->IsDisabled()) { if (!JoinChan(pChan)) continue; sChans.insert(pChan); // Limit the number of joins if (uJoins != 0 && --uJoins == 0) { // Reset the timer. m_pJoinTimer->Reset(); break; } } } while (!sChans.empty()) JoinChans(sChans); } void CIRCNetwork::JoinChans(set& sChans) { CString sKeys, sJoin; bool bHaveKey = false; size_t uiJoinLength = strlen("JOIN "); while (!sChans.empty()) { set::iterator it = sChans.begin(); const CString& sName = (*it)->GetName(); const CString& sKey = (*it)->GetKey(); size_t len = sName.length() + sKey.length(); len += 2; // two comma if (!sKeys.empty() && uiJoinLength + len >= 512) break; if (!sJoin.empty()) { sJoin += ","; sKeys += ","; } uiJoinLength += len; sJoin += sName; if (!sKey.empty()) { sKeys += sKey; bHaveKey = true; } sChans.erase(it); } if (bHaveKey) PutIRC("JOIN " + sJoin + " " + sKeys); else PutIRC("JOIN " + sJoin); } bool CIRCNetwork::JoinChan(CChan* pChan) { bool bReturn = false; NETWORKMODULECALL(OnJoining(*pChan), m_pUser, this, nullptr, &bReturn); if (bReturn) return false; if (m_pUser->JoinTries() != 0 && pChan->GetJoinTries() >= m_pUser->JoinTries()) { PutStatus(t_f("The channel {1} could not be joined, disabling it.")( pChan->GetName())); pChan->Disable(); } else { pChan->IncJoinTries(); bool bFailed = false; NETWORKMODULECALL(OnTimerAutoJoin(*pChan), m_pUser, this, nullptr, &bFailed); if (bFailed) return false; return true; } return false; } bool CIRCNetwork::IsChan(const CString& sChan) const { if (sChan.empty()) return false; // There is no way this is a chan if (GetChanPrefixes().empty()) return true; // We can't know, so we allow everything // Thanks to the above if (empty), we can do sChan[0] return GetChanPrefixes().find(sChan[0]) != CString::npos; } // Queries const vector& CIRCNetwork::GetQueries() const { return m_vQueries; } CQuery* CIRCNetwork::FindQuery(const CString& sName) const { for (CQuery* pQuery : m_vQueries) { if (sName.Equals(pQuery->GetName())) { return pQuery; } } return nullptr; } std::vector CIRCNetwork::FindQueries(const CString& sWild) const { std::vector vQueries; vQueries.reserve(m_vQueries.size()); const CString sLower = sWild.AsLower(); for (CQuery* pQuery : m_vQueries) { if (pQuery->GetName().AsLower().WildCmp(sLower)) vQueries.push_back(pQuery); } return vQueries; } CQuery* CIRCNetwork::AddQuery(const CString& sName) { if (sName.empty()) { return nullptr; } CQuery* pQuery = FindQuery(sName); if (!pQuery) { pQuery = new CQuery(sName, this); m_vQueries.push_back(pQuery); if (m_pUser->MaxQueryBuffers() > 0) { while (m_vQueries.size() > m_pUser->MaxQueryBuffers()) { delete *m_vQueries.begin(); m_vQueries.erase(m_vQueries.begin()); } } } return pQuery; } bool CIRCNetwork::DelQuery(const CString& sName) { for (vector::iterator a = m_vQueries.begin(); a != m_vQueries.end(); ++a) { if (sName.Equals((*a)->GetName())) { delete *a; m_vQueries.erase(a); return true; } } return false; } // Server list const vector& CIRCNetwork::GetServers() const { return m_vServers; } CServer* CIRCNetwork::FindServer(const CString& sName) const { for (CServer* pServer : m_vServers) { if (sName.Equals(pServer->GetName())) { return pServer; } } return nullptr; } bool CIRCNetwork::DelServer(const CString& sName, unsigned short uPort, const CString& sPass) { if (sName.empty()) { return false; } unsigned int a = 0; bool bSawCurrentServer = false; CServer* pCurServer = GetCurrentServer(); for (vector::iterator it = m_vServers.begin(); it != m_vServers.end(); ++it, a++) { CServer* pServer = *it; if (pServer == pCurServer) bSawCurrentServer = true; if (!pServer->GetName().Equals(sName)) continue; if (uPort != 0 && pServer->GetPort() != uPort) continue; if (!sPass.empty() && pServer->GetPass() != sPass) continue; m_vServers.erase(it); if (pServer == pCurServer) { CIRCSock* pIRCSock = GetIRCSock(); // Make sure we don't skip the next server in the list! if (m_uServerIdx) { m_uServerIdx--; } if (pIRCSock) { pIRCSock->Quit(); PutStatus(t_s("Your current server was removed, jumping...")); } } else if (!bSawCurrentServer) { // Our current server comes after the server which we // are removing. This means that it now got a different // index in m_vServers! m_uServerIdx--; } delete pServer; return true; } return false; } bool CIRCNetwork::AddServer(const CString& sName) { if (sName.empty()) { return false; } bool bSSL = false; CString sLine = sName; sLine.Trim(); CString sHost = sLine.Token(0); CString sPort = sLine.Token(1); if (sPort.TrimPrefix("+")) { bSSL = true; } unsigned short uPort = sPort.ToUShort(); CString sPass = sLine.Token(2, true); return AddServer(sHost, uPort, sPass, bSSL); } bool CIRCNetwork::AddServer(const CString& sName, unsigned short uPort, const CString& sPass, bool bSSL) { #ifndef HAVE_LIBSSL if (bSSL) { return false; } #endif if (sName.empty()) { return false; } if (!uPort) { uPort = 6667; } // Check if server is already added for (CServer* pServer : m_vServers) { if (!sName.Equals(pServer->GetName())) continue; if (uPort != pServer->GetPort()) continue; if (sPass != pServer->GetPass()) continue; if (bSSL != pServer->IsSSL()) continue; // Server is already added return false; } CServer* pServer = new CServer(sName, uPort, sPass, bSSL); m_vServers.push_back(pServer); CheckIRCConnect(); return true; } CServer* CIRCNetwork::GetNextServer(bool bAdvance) { if (m_vServers.empty()) { return nullptr; } if (m_uServerIdx >= m_vServers.size()) { m_uServerIdx = 0; } if (bAdvance) { return m_vServers[m_uServerIdx++]; } else { return m_vServers[m_uServerIdx]; } } CServer* CIRCNetwork::GetCurrentServer() const { size_t uIdx = (m_uServerIdx) ? m_uServerIdx - 1 : 0; if (uIdx >= m_vServers.size()) { return nullptr; } return m_vServers[uIdx]; } void CIRCNetwork::SetIRCServer(const CString& s) { m_sIRCServer = s; } bool CIRCNetwork::SetNextServer(const CServer* pServer) { for (unsigned int a = 0; a < m_vServers.size(); a++) { if (m_vServers[a] == pServer) { m_uServerIdx = a; return true; } } return false; } bool CIRCNetwork::IsLastServer() const { return (m_uServerIdx >= m_vServers.size()); } const CString& CIRCNetwork::GetIRCServer() const { return m_sIRCServer; } const CNick& CIRCNetwork::GetIRCNick() const { return m_IRCNick; } void CIRCNetwork::SetIRCNick(const CNick& n) { m_IRCNick = n; for (CClient* pClient : m_vClients) { pClient->SetNick(n.GetNick()); } } CString CIRCNetwork::GetCurNick() const { const CIRCSock* pIRCSock = GetIRCSock(); if (pIRCSock) { return pIRCSock->GetNick(); } if (!m_vClients.empty()) { return m_vClients[0]->GetNick(); } return ""; } bool CIRCNetwork::Connect() { if (!GetIRCConnectEnabled() || m_pIRCSock || !HasServers()) return false; CServer* pServer = GetNextServer(); if (!pServer) return false; if (CZNC::Get().GetServerThrottle(pServer->GetName())) { // Can't connect right now, schedule retry later CZNC::Get().AddNetworkToQueue(this); return false; } CZNC::Get().AddServerThrottle(pServer->GetName()); bool bSSL = pServer->IsSSL(); #ifndef HAVE_LIBSSL if (bSSL) { PutStatus( t_f("Cannot connect to {1}, because ZNC is not compiled with SSL " "support.")(pServer->GetString(false))); CZNC::Get().AddNetworkToQueue(this); return false; } #endif CIRCSock* pIRCSock = new CIRCSock(this); pIRCSock->SetPass(pServer->GetPass()); pIRCSock->SetSSLTrustedPeerFingerprints(m_ssTrustedFingerprints); pIRCSock->SetTrustAllCerts(GetTrustAllCerts()); pIRCSock->SetTrustPKI(GetTrustPKI()); DEBUG("Connecting user/network [" << m_pUser->GetUserName() << "/" << m_sName << "]"); bool bAbort = false; NETWORKMODULECALL(OnIRCConnecting(pIRCSock), m_pUser, this, nullptr, &bAbort); if (bAbort) { DEBUG("Some module aborted the connection attempt"); PutStatus(t_s("Some module aborted the connection attempt")); delete pIRCSock; CZNC::Get().AddNetworkToQueue(this); return false; } CString sSockName = "IRC::" + m_pUser->GetUserName() + "::" + m_sName; CZNC::Get().GetManager().Connect(pServer->GetName(), pServer->GetPort(), sSockName, 120, bSSL, GetBindHost(), pIRCSock); return true; } bool CIRCNetwork::IsIRCConnected() const { const CIRCSock* pSock = GetIRCSock(); return (pSock && pSock->IsAuthed()); } void CIRCNetwork::SetIRCSocket(CIRCSock* pIRCSock) { m_pIRCSock = pIRCSock; } void CIRCNetwork::IRCConnected() { const SCString& ssCaps = m_pIRCSock->GetAcceptedCaps(); for (CClient* pClient : m_vClients) { pClient->NotifyServerDependentCaps(ssCaps); } if (m_uJoinDelay > 0) { m_pJoinTimer->Delay(m_uJoinDelay); } else { JoinChans(); } } void CIRCNetwork::IRCDisconnected() { for (CClient* pClient : m_vClients) { pClient->ClearServerDependentCaps(); } m_pIRCSock = nullptr; SetIRCServer(""); m_bIRCAway = false; // Get the reconnect going CheckIRCConnect(); } void CIRCNetwork::SetIRCConnectEnabled(bool b) { m_bIRCConnectEnabled = b; if (m_bIRCConnectEnabled) { CheckIRCConnect(); } else if (GetIRCSock()) { if (GetIRCSock()->IsConnected()) { GetIRCSock()->Quit(); } else { GetIRCSock()->Close(); } } } void CIRCNetwork::CheckIRCConnect() { // Do we want to connect? if (GetIRCConnectEnabled() && GetIRCSock() == nullptr) CZNC::Get().AddNetworkToQueue(this); } bool CIRCNetwork::PutIRC(const CString& sLine) { CIRCSock* pIRCSock = GetIRCSock(); if (!pIRCSock) { return false; } pIRCSock->PutIRC(sLine); return true; } bool CIRCNetwork::PutIRC(const CMessage& Message) { CIRCSock* pIRCSock = GetIRCSock(); if (!pIRCSock) { return false; } pIRCSock->PutIRC(Message); return true; } void CIRCNetwork::ClearQueryBuffer() { std::for_each(m_vQueries.begin(), m_vQueries.end(), std::default_delete()); m_vQueries.clear(); } const CString& CIRCNetwork::GetNick(const bool bAllowDefault) const { if (m_sNick.empty()) { return m_pUser->GetNick(bAllowDefault); } return m_sNick; } const CString& CIRCNetwork::GetAltNick(const bool bAllowDefault) const { if (m_sAltNick.empty()) { return m_pUser->GetAltNick(bAllowDefault); } return m_sAltNick; } const CString& CIRCNetwork::GetIdent(const bool bAllowDefault) const { if (m_sIdent.empty()) { return m_pUser->GetIdent(bAllowDefault); } return m_sIdent; } CString CIRCNetwork::GetRealName() const { if (m_sRealName.empty()) { return m_pUser->GetRealName(); } return m_sRealName; } const CString& CIRCNetwork::GetBindHost() const { if (m_sBindHost.empty()) { return m_pUser->GetBindHost(); } return m_sBindHost; } const CString& CIRCNetwork::GetEncoding() const { return m_sEncoding; } CString CIRCNetwork::GetQuitMsg() const { if (m_sQuitMsg.empty()) { return m_pUser->GetQuitMsg(); } return m_sQuitMsg; } void CIRCNetwork::SetNick(const CString& s) { if (m_pUser->GetNick().Equals(s)) { m_sNick = ""; } else { m_sNick = s; } } void CIRCNetwork::SetAltNick(const CString& s) { if (m_pUser->GetAltNick().Equals(s)) { m_sAltNick = ""; } else { m_sAltNick = s; } } void CIRCNetwork::SetIdent(const CString& s) { if (m_pUser->GetIdent().Equals(s)) { m_sIdent = ""; } else { m_sIdent = s; } } void CIRCNetwork::SetRealName(const CString& s) { if (m_pUser->GetRealName().Equals(s)) { m_sRealName = ""; } else { m_sRealName = s; } } void CIRCNetwork::SetBindHost(const CString& s) { if (m_pUser->GetBindHost().Equals(s)) { m_sBindHost = ""; } else { m_sBindHost = s; } } void CIRCNetwork::SetEncoding(const CString& s) { m_sEncoding = CZNC::Get().FixupEncoding(s); if (GetIRCSock()) { GetIRCSock()->SetEncoding(m_sEncoding); } } void CIRCNetwork::SetQuitMsg(const CString& s) { if (m_pUser->GetQuitMsg().Equals(s)) { m_sQuitMsg = ""; } else { m_sQuitMsg = s; } } CString CIRCNetwork::ExpandString(const CString& sStr) const { CString sRet; return ExpandString(sStr, sRet); } CString& CIRCNetwork::ExpandString(const CString& sStr, CString& sRet) const { sRet = sStr; sRet.Replace("%altnick%", GetAltNick()); sRet.Replace("%bindhost%", GetBindHost()); sRet.Replace("%defnick%", GetNick()); sRet.Replace("%ident%", GetIdent()); sRet.Replace("%network%", GetName()); sRet.Replace("%nick%", GetCurNick()); sRet.Replace("%realname%", GetRealName()); return m_pUser->ExpandString(sRet, sRet); } bool CIRCNetwork::LoadModule(const CString& sModName, const CString& sArgs, const CString& sNotice, CString& sError) { CUtils::PrintAction(sNotice); CString sModRet; bool bModRet = GetModules().LoadModule( sModName, sArgs, CModInfo::NetworkModule, GetUser(), this, sModRet); CUtils::PrintStatus(bModRet, sModRet); if (!bModRet) { sError = sModRet; } return bModRet; } znc-1.7.5/src/znc.cpp0000644000175000017500000020132113542151610014624 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include using std::endl; using std::cout; using std::map; using std::set; using std::vector; using std::list; using std::tuple; using std::make_tuple; CZNC::CZNC() : m_TimeStarted(time(nullptr)), m_eConfigState(ECONFIG_NOTHING), m_vpListeners(), m_msUsers(), m_msDelUsers(), m_Manager(), m_sCurPath(""), m_sZNCPath(""), m_sConfigFile(""), m_sSkinName(""), m_sStatusPrefix(""), m_sPidFile(""), m_sSSLCertFile(""), m_sSSLKeyFile(""), m_sSSLDHParamFile(""), m_sSSLCiphers(""), m_sSSLProtocols(""), m_vsBindHosts(), m_vsTrustedProxies(), m_vsMotd(), m_pLockFile(nullptr), m_uiConnectDelay(5), m_uiAnonIPLimit(10), m_uiMaxBufferSize(500), m_uDisabledSSLProtocols(Csock::EDP_SSL), m_pModules(new CModules), m_uBytesRead(0), m_uBytesWritten(0), m_lpConnectQueue(), m_pConnectQueueTimer(nullptr), m_uiConnectPaused(0), m_uiForceEncoding(0), m_sConnectThrottle(), m_bProtectWebSessions(true), m_bHideVersion(false), m_bAuthOnlyViaModule(false), m_Translation("znc"), m_uiConfigWriteDelay(0), m_pConfigTimer(nullptr) { if (!InitCsocket()) { CUtils::PrintError("Could not initialize Csocket!"); exit(-1); } m_sConnectThrottle.SetTTL(30000); } CZNC::~CZNC() { m_pModules->UnloadAll(); for (const auto& it : m_msUsers) { it.second->GetModules().UnloadAll(); const vector& networks = it.second->GetNetworks(); for (CIRCNetwork* pNetwork : networks) { pNetwork->GetModules().UnloadAll(); } } for (CListener* pListener : m_vpListeners) { delete pListener; } for (const auto& it : m_msUsers) { it.second->SetBeingDeleted(true); } m_pConnectQueueTimer = nullptr; // This deletes m_pConnectQueueTimer m_Manager.Cleanup(); DeleteUsers(); delete m_pModules; delete m_pLockFile; ShutdownCsocket(); DeletePidFile(); } CString CZNC::GetVersion() { return CString(VERSION_STR) + CString(ZNC_VERSION_EXTRA); } CString CZNC::GetTag(bool bIncludeVersion, bool bHTML) { if (!Get().m_bHideVersion) { bIncludeVersion = true; } CString sAddress = bHTML ? "https://znc.in" : "https://znc.in"; if (!bIncludeVersion) { return "ZNC - " + sAddress; } CString sVersion = GetVersion(); return "ZNC " + sVersion + " - " + sAddress; } CString CZNC::GetCompileOptionsString() { // Build system doesn't affect ABI return ZNC_COMPILE_OPTIONS_STRING + CString( ", build: " #ifdef BUILD_WITH_CMAKE "cmake" #else "autoconf" #endif ); } CString CZNC::GetUptime() const { time_t now = time(nullptr); return CString::ToTimeStr(now - TimeStarted()); } bool CZNC::OnBoot() { bool bFail = false; ALLMODULECALL(OnBoot(), &bFail); if (bFail) return false; return true; } bool CZNC::HandleUserDeletion() { if (m_msDelUsers.empty()) return false; for (const auto& it : m_msDelUsers) { CUser* pUser = it.second; pUser->SetBeingDeleted(true); if (GetModules().OnDeleteUser(*pUser)) { pUser->SetBeingDeleted(false); continue; } m_msUsers.erase(pUser->GetUserName()); CWebSock::FinishUserSessions(*pUser); delete pUser; } m_msDelUsers.clear(); return true; } class CConfigWriteTimer : public CCron { public: CConfigWriteTimer(int iSecs) : CCron() { SetName("Config write timer"); Start(iSecs); } protected: void RunJob() override { CZNC::Get().SetConfigState(CZNC::ECONFIG_NEED_WRITE); CZNC::Get().DisableConfigTimer(); } }; void CZNC::Loop() { while (true) { CString sError; ConfigState eState = GetConfigState(); switch (eState) { case ECONFIG_NEED_REHASH: SetConfigState(ECONFIG_NOTHING); if (RehashConfig(sError)) { Broadcast("Rehashing succeeded", true); } else { Broadcast("Rehashing failed: " + sError, true); Broadcast("ZNC is in some possibly inconsistent state!", true); } break; case ECONFIG_DELAYED_WRITE: SetConfigState(ECONFIG_NOTHING); if (GetConfigWriteDelay() > 0) { if (m_pConfigTimer == nullptr) { m_pConfigTimer = new CConfigWriteTimer(GetConfigWriteDelay()); GetManager().AddCron(m_pConfigTimer); } break; } /* Fall through */ case ECONFIG_NEED_WRITE: case ECONFIG_NEED_VERBOSE_WRITE: SetConfigState(ECONFIG_NOTHING); // stop pending configuration timer DisableConfigTimer(); if (!WriteConfig()) { Broadcast("Writing the config file failed", true); } else if (eState == ECONFIG_NEED_VERBOSE_WRITE) { Broadcast("Writing the config succeeded", true); } break; case ECONFIG_NOTHING: break; case ECONFIG_NEED_QUIT: return; } // Check for users that need to be deleted if (HandleUserDeletion()) { // Also remove those user(s) from the config file WriteConfig(); } // Csocket wants micro seconds // 100 msec to 5 min m_Manager.DynamicSelectLoop(100 * 1000, 5 * 60 * 1000 * 1000); } } CFile* CZNC::InitPidFile() { if (!m_sPidFile.empty()) { CString sFile; // absolute path or relative to the data dir? if (m_sPidFile[0] != '/') sFile = GetZNCPath() + "/" + m_sPidFile; else sFile = m_sPidFile; return new CFile(sFile); } return nullptr; } bool CZNC::WritePidFile(int iPid) { CFile* File = InitPidFile(); if (File == nullptr) return false; CUtils::PrintAction("Writing pid file [" + File->GetLongName() + "]"); bool bRet = false; if (File->Open(O_WRONLY | O_TRUNC | O_CREAT)) { File->Write(CString(iPid) + "\n"); File->Close(); bRet = true; } delete File; CUtils::PrintStatus(bRet); return bRet; } bool CZNC::DeletePidFile() { CFile* File = InitPidFile(); if (File == nullptr) return false; CUtils::PrintAction("Deleting pid file [" + File->GetLongName() + "]"); bool bRet = File->Delete(); delete File; CUtils::PrintStatus(bRet); return bRet; } bool CZNC::WritePemFile() { #ifndef HAVE_LIBSSL CUtils::PrintError("ZNC was not compiled with ssl support."); return false; #else CString sPemFile = GetPemLocation(); CUtils::PrintAction("Writing Pem file [" + sPemFile + "]"); #ifndef _WIN32 int fd = creat(sPemFile.c_str(), 0600); if (fd == -1) { CUtils::PrintStatus(false, "Unable to open"); return false; } FILE* f = fdopen(fd, "w"); #else FILE* f = fopen(sPemFile.c_str(), "w"); #endif if (!f) { CUtils::PrintStatus(false, "Unable to open"); return false; } CUtils::GenerateCert(f, ""); fclose(f); CUtils::PrintStatus(true); return true; #endif } void CZNC::DeleteUsers() { for (const auto& it : m_msUsers) { it.second->SetBeingDeleted(true); delete it.second; } m_msUsers.clear(); DisableConnectQueue(); } bool CZNC::IsHostAllowed(const CString& sHostMask) const { for (const auto& it : m_msUsers) { if (it.second->IsHostAllowed(sHostMask)) { return true; } } return false; } bool CZNC::AllowConnectionFrom(const CString& sIP) const { if (m_uiAnonIPLimit == 0) return true; return (GetManager().GetAnonConnectionCount(sIP) < m_uiAnonIPLimit); } void CZNC::InitDirs(const CString& sArgvPath, const CString& sDataDir) { // If the bin was not ran from the current directory, we need to add that // dir onto our cwd CString::size_type uPos = sArgvPath.rfind('/'); if (uPos == CString::npos) m_sCurPath = "./"; else m_sCurPath = CDir::ChangeDir("./", sArgvPath.Left(uPos), ""); // Try to set the user's home dir, default to binpath on failure CFile::InitHomePath(m_sCurPath); if (sDataDir.empty()) { m_sZNCPath = CFile::GetHomePath() + "/.znc"; } else { m_sZNCPath = sDataDir; } m_sSSLCertFile = m_sZNCPath + "/znc.pem"; } CString CZNC::GetConfPath(bool bAllowMkDir) const { CString sConfPath = m_sZNCPath + "/configs"; if (bAllowMkDir && !CFile::Exists(sConfPath)) { CDir::MakeDir(sConfPath); } return sConfPath; } CString CZNC::GetUserPath() const { CString sUserPath = m_sZNCPath + "/users"; if (!CFile::Exists(sUserPath)) { CDir::MakeDir(sUserPath); } return sUserPath; } CString CZNC::GetModPath() const { CString sModPath = m_sZNCPath + "/modules"; return sModPath; } const CString& CZNC::GetCurPath() const { if (!CFile::Exists(m_sCurPath)) { CDir::MakeDir(m_sCurPath); } return m_sCurPath; } const CString& CZNC::GetHomePath() const { return CFile::GetHomePath(); } const CString& CZNC::GetZNCPath() const { if (!CFile::Exists(m_sZNCPath)) { CDir::MakeDir(m_sZNCPath); } return m_sZNCPath; } CString CZNC::GetPemLocation() const { return CDir::ChangeDir("", m_sSSLCertFile); } CString CZNC::GetKeyLocation() const { return CDir::ChangeDir( "", m_sSSLKeyFile.empty() ? m_sSSLCertFile : m_sSSLKeyFile); } CString CZNC::GetDHParamLocation() const { return CDir::ChangeDir( "", m_sSSLDHParamFile.empty() ? m_sSSLCertFile : m_sSSLDHParamFile); } CString CZNC::ExpandConfigPath(const CString& sConfigFile, bool bAllowMkDir) { CString sRetPath; if (sConfigFile.empty()) { sRetPath = GetConfPath(bAllowMkDir) + "/znc.conf"; } else { if (sConfigFile.StartsWith("./") || sConfigFile.StartsWith("../")) { sRetPath = GetCurPath() + "/" + sConfigFile; } else if (!sConfigFile.StartsWith("/")) { sRetPath = GetConfPath(bAllowMkDir) + "/" + sConfigFile; } else { sRetPath = sConfigFile; } } return sRetPath; } bool CZNC::WriteConfig() { if (GetConfigFile().empty()) { DEBUG("Config file name is empty?!"); return false; } // We first write to a temporary file and then move it to the right place CFile* pFile = new CFile(GetConfigFile() + "~"); if (!pFile->Open(O_WRONLY | O_CREAT | O_TRUNC, 0600)) { DEBUG("Could not write config to " + GetConfigFile() + "~: " + CString(strerror(errno))); delete pFile; return false; } // We have to "transfer" our lock on the config to the new file. // The old file (= inode) is going away and thus a lock on it would be // useless. These lock should always succeed (races, anyone?). if (!pFile->TryExLock()) { DEBUG("Error while locking the new config file, errno says: " + CString(strerror(errno))); pFile->Delete(); delete pFile; return false; } pFile->Write(MakeConfigHeader() + "\n"); CConfig config; config.AddKeyValuePair("AnonIPLimit", CString(m_uiAnonIPLimit)); config.AddKeyValuePair("MaxBufferSize", CString(m_uiMaxBufferSize)); config.AddKeyValuePair("SSLCertFile", CString(GetPemLocation())); config.AddKeyValuePair("SSLKeyFile", CString(GetKeyLocation())); config.AddKeyValuePair("SSLDHParamFile", CString(GetDHParamLocation())); config.AddKeyValuePair("ProtectWebSessions", CString(m_bProtectWebSessions)); config.AddKeyValuePair("HideVersion", CString(m_bHideVersion)); config.AddKeyValuePair("AuthOnlyViaModule", CString(m_bAuthOnlyViaModule)); config.AddKeyValuePair("Version", CString(VERSION_STR)); config.AddKeyValuePair("ConfigWriteDelay", CString(m_uiConfigWriteDelay)); unsigned int l = 0; for (CListener* pListener : m_vpListeners) { CConfig listenerConfig; listenerConfig.AddKeyValuePair("Host", pListener->GetBindHost()); listenerConfig.AddKeyValuePair("URIPrefix", pListener->GetURIPrefix() + "/"); listenerConfig.AddKeyValuePair("Port", CString(pListener->GetPort())); listenerConfig.AddKeyValuePair( "IPv4", CString(pListener->GetAddrType() != ADDR_IPV6ONLY)); listenerConfig.AddKeyValuePair( "IPv6", CString(pListener->GetAddrType() != ADDR_IPV4ONLY)); listenerConfig.AddKeyValuePair("SSL", CString(pListener->IsSSL())); listenerConfig.AddKeyValuePair( "AllowIRC", CString(pListener->GetAcceptType() != CListener::ACCEPT_HTTP)); listenerConfig.AddKeyValuePair( "AllowWeb", CString(pListener->GetAcceptType() != CListener::ACCEPT_IRC)); config.AddSubConfig("Listener", "listener" + CString(l++), listenerConfig); } config.AddKeyValuePair("ConnectDelay", CString(m_uiConnectDelay)); config.AddKeyValuePair("ServerThrottle", CString(m_sConnectThrottle.GetTTL() / 1000)); if (!m_sPidFile.empty()) { config.AddKeyValuePair("PidFile", m_sPidFile.FirstLine()); } if (!m_sSkinName.empty()) { config.AddKeyValuePair("Skin", m_sSkinName.FirstLine()); } if (!m_sStatusPrefix.empty()) { config.AddKeyValuePair("StatusPrefix", m_sStatusPrefix.FirstLine()); } if (!m_sSSLCiphers.empty()) { config.AddKeyValuePair("SSLCiphers", CString(m_sSSLCiphers)); } if (!m_sSSLProtocols.empty()) { config.AddKeyValuePair("SSLProtocols", m_sSSLProtocols); } for (const CString& sLine : m_vsMotd) { config.AddKeyValuePair("Motd", sLine.FirstLine()); } for (const CString& sProxy : m_vsTrustedProxies) { config.AddKeyValuePair("TrustedProxy", sProxy.FirstLine()); } CModules& Mods = GetModules(); for (const CModule* pMod : Mods) { CString sName = pMod->GetModName(); CString sArgs = pMod->GetArgs(); if (!sArgs.empty()) { sArgs = " " + sArgs.FirstLine(); } config.AddKeyValuePair("LoadModule", sName.FirstLine() + sArgs); } for (const auto& it : m_msUsers) { CString sErr; if (!it.second->IsValid(sErr)) { DEBUG("** Error writing config for user [" << it.first << "] [" << sErr << "]"); continue; } config.AddSubConfig("User", it.second->GetUserName(), it.second->ToConfig()); } config.Write(*pFile); // If Sync() fails... well, let's hope nothing important breaks.. pFile->Sync(); if (pFile->HadError()) { DEBUG("Error while writing the config, errno says: " + CString(strerror(errno))); pFile->Delete(); delete pFile; return false; } // We wrote to a temporary name, move it to the right place if (!pFile->Move(GetConfigFile(), true)) { DEBUG( "Error while replacing the config file with a new version, errno " "says " << strerror(errno)); pFile->Delete(); delete pFile; return false; } // Everything went fine, just need to update the saved path. pFile->SetFileName(GetConfigFile()); // Make sure the lock is kept alive as long as we need it. delete m_pLockFile; m_pLockFile = pFile; return true; } CString CZNC::MakeConfigHeader() { return "// WARNING\n" "//\n" "// Do NOT edit this file while ZNC is running!\n" "// Use webadmin or *controlpanel instead.\n" "//\n" "// Altering this file by hand will forfeit all support.\n" "//\n" "// But if you feel risky, you might want to read help on /znc " "saveconfig and /znc rehash.\n" "// Also check https://wiki.znc.in/Configuration\n"; } bool CZNC::WriteNewConfig(const CString& sConfigFile) { CString sAnswer, sUser, sNetwork; VCString vsLines; vsLines.push_back(MakeConfigHeader()); vsLines.push_back("Version = " + CString(VERSION_STR)); m_sConfigFile = ExpandConfigPath(sConfigFile); if (CFile::Exists(m_sConfigFile)) { CUtils::PrintStatus( false, "WARNING: config [" + m_sConfigFile + "] already exists."); } CUtils::PrintMessage(""); CUtils::PrintMessage("-- Global settings --"); CUtils::PrintMessage(""); // Listen #ifdef HAVE_IPV6 bool b6 = true; #else bool b6 = false; #endif CString sListenHost; CString sURIPrefix; bool bListenSSL = false; unsigned int uListenPort = 0; bool bSuccess; do { bSuccess = true; while (true) { if (!CUtils::GetNumInput("Listen on port", uListenPort, 1025, 65534)) { continue; } if (uListenPort == 6667) { CUtils::PrintStatus(false, "WARNING: Some web browsers reject port " "6667. If you intend to"); CUtils::PrintStatus(false, "use ZNC's web interface, you might want " "to use another port."); if (!CUtils::GetBoolInput("Proceed with port 6667 anyway?", true)) { continue; } } break; } #ifdef HAVE_LIBSSL bListenSSL = CUtils::GetBoolInput("Listen using SSL", bListenSSL); #endif #ifdef HAVE_IPV6 b6 = CUtils::GetBoolInput("Listen using both IPv4 and IPv6", b6); #endif // Don't ask for listen host, it may be configured later if needed. CUtils::PrintAction("Verifying the listener"); CListener* pListener = new CListener( (unsigned short int)uListenPort, sListenHost, sURIPrefix, bListenSSL, b6 ? ADDR_ALL : ADDR_IPV4ONLY, CListener::ACCEPT_ALL); if (!pListener->Listen()) { CUtils::PrintStatus(false, FormatBindError()); bSuccess = false; } else CUtils::PrintStatus(true); delete pListener; } while (!bSuccess); #ifdef HAVE_LIBSSL CString sPemFile = GetPemLocation(); if (!CFile::Exists(sPemFile)) { CUtils::PrintMessage("Unable to locate pem file: [" + sPemFile + "], creating it"); WritePemFile(); } #endif vsLines.push_back(""); vsLines.push_back("\tPort = " + CString(uListenPort)); vsLines.push_back("\tIPv4 = true"); vsLines.push_back("\tIPv6 = " + CString(b6)); vsLines.push_back("\tSSL = " + CString(bListenSSL)); if (!sListenHost.empty()) { vsLines.push_back("\tHost = " + sListenHost); } vsLines.push_back(""); // !Listen set ssGlobalMods; GetModules().GetDefaultMods(ssGlobalMods, CModInfo::GlobalModule); vector vsGlobalModNames; for (const CModInfo& Info : ssGlobalMods) { vsGlobalModNames.push_back(Info.GetName()); vsLines.push_back("LoadModule = " + Info.GetName()); } CUtils::PrintMessage( "Enabled global modules [" + CString(", ").Join(vsGlobalModNames.begin(), vsGlobalModNames.end()) + "]"); // User CUtils::PrintMessage(""); CUtils::PrintMessage("-- Admin user settings --"); CUtils::PrintMessage(""); vsLines.push_back(""); CString sNick; do { CUtils::GetInput("Username", sUser, "", "alphanumeric"); } while (!CUser::IsValidUserName(sUser)); vsLines.push_back(""); CString sSalt; sAnswer = CUtils::GetSaltedHashPass(sSalt); vsLines.push_back("\tPass = " + CUtils::sDefaultHash + "#" + sAnswer + "#" + sSalt + "#"); vsLines.push_back("\tAdmin = true"); CUtils::GetInput("Nick", sNick, CUser::MakeCleanUserName(sUser)); vsLines.push_back("\tNick = " + sNick); CUtils::GetInput("Alternate nick", sAnswer, sNick + "_"); if (!sAnswer.empty()) { vsLines.push_back("\tAltNick = " + sAnswer); } CUtils::GetInput("Ident", sAnswer, sUser); vsLines.push_back("\tIdent = " + sAnswer); CUtils::GetInput("Real name", sAnswer, "", "optional"); if (!sAnswer.empty()) { vsLines.push_back("\tRealName = " + sAnswer); } CUtils::GetInput("Bind host", sAnswer, "", "optional"); if (!sAnswer.empty()) { vsLines.push_back("\tBindHost = " + sAnswer); } set ssUserMods; GetModules().GetDefaultMods(ssUserMods, CModInfo::UserModule); vector vsUserModNames; for (const CModInfo& Info : ssUserMods) { vsUserModNames.push_back(Info.GetName()); vsLines.push_back("\tLoadModule = " + Info.GetName()); } CUtils::PrintMessage( "Enabled user modules [" + CString(", ").Join(vsUserModNames.begin(), vsUserModNames.end()) + "]"); CUtils::PrintMessage(""); if (CUtils::GetBoolInput("Set up a network?", true)) { vsLines.push_back(""); CUtils::PrintMessage(""); CUtils::PrintMessage("-- Network settings --"); CUtils::PrintMessage(""); do { CUtils::GetInput("Name", sNetwork, "freenode"); } while (!CIRCNetwork::IsValidNetwork(sNetwork)); vsLines.push_back("\t"); set ssNetworkMods; GetModules().GetDefaultMods(ssNetworkMods, CModInfo::NetworkModule); vector vsNetworkModNames; for (const CModInfo& Info : ssNetworkMods) { vsNetworkModNames.push_back(Info.GetName()); vsLines.push_back("\t\tLoadModule = " + Info.GetName()); } CString sHost, sPass, sHint; bool bSSL = false; unsigned int uServerPort = 0; if (sNetwork.Equals("freenode")) { sHost = "chat.freenode.net"; #ifdef HAVE_LIBSSL bSSL = true; #endif } else { sHint = "host only"; } while (!CUtils::GetInput("Server host", sHost, sHost, sHint) || !CServer::IsValidHostName(sHost)) ; #ifdef HAVE_LIBSSL bSSL = CUtils::GetBoolInput("Server uses SSL?", bSSL); #endif while (!CUtils::GetNumInput("Server port", uServerPort, 1, 65535, bSSL ? 6697 : 6667)) ; CUtils::GetInput("Server password (probably empty)", sPass); vsLines.push_back("\t\tServer = " + sHost + ((bSSL) ? " +" : " ") + CString(uServerPort) + " " + sPass); CString sChans; if (CUtils::GetInput("Initial channels", sChans)) { vsLines.push_back(""); VCString vsChans; sChans.Replace(",", " "); sChans.Replace(";", " "); sChans.Split(" ", vsChans, false, "", "", true, true); for (const CString& sChan : vsChans) { vsLines.push_back("\t\t"); vsLines.push_back("\t\t"); } } CUtils::PrintMessage("Enabled network modules [" + CString(", ").Join(vsNetworkModNames.begin(), vsNetworkModNames.end()) + "]"); vsLines.push_back("\t"); } vsLines.push_back(""); CUtils::PrintMessage(""); // !User CFile File; bool bFileOK, bFileOpen = false; do { CUtils::PrintAction("Writing config [" + m_sConfigFile + "]"); bFileOK = true; if (CFile::Exists(m_sConfigFile)) { if (!File.TryExLock(m_sConfigFile)) { CUtils::PrintStatus(false, "ZNC is currently running on this config."); bFileOK = false; } else { File.Close(); CUtils::PrintStatus(false, "This config already exists."); if (CUtils::GetBoolInput( "Are you sure you want to overwrite it?", false)) CUtils::PrintAction("Overwriting config [" + m_sConfigFile + "]"); else bFileOK = false; } } if (bFileOK) { File.SetFileName(m_sConfigFile); if (File.Open(O_WRONLY | O_CREAT | O_TRUNC, 0600)) { bFileOpen = true; } else { CUtils::PrintStatus(false, "Unable to open file"); bFileOK = false; } } if (!bFileOK) { while (!CUtils::GetInput("Please specify an alternate location", m_sConfigFile, "", "or \"stdout\" for displaying the config")) ; if (m_sConfigFile.Equals("stdout")) bFileOK = true; else m_sConfigFile = ExpandConfigPath(m_sConfigFile); } } while (!bFileOK); if (!bFileOpen) { CUtils::PrintMessage(""); CUtils::PrintMessage("Printing the new config to stdout:"); CUtils::PrintMessage(""); cout << endl << "------------------------------------------------------" "----------------------" << endl << endl; } for (const CString& sLine : vsLines) { if (bFileOpen) { File.Write(sLine + "\n"); } else { cout << sLine << endl; } } if (bFileOpen) { File.Close(); if (File.HadError()) CUtils::PrintStatus(false, "There was an error while writing the config"); else CUtils::PrintStatus(true); } else { cout << endl << "------------------------------------------------------" "----------------------" << endl << endl; } if (File.HadError()) { bFileOpen = false; CUtils::PrintMessage("Printing the new config to stdout instead:"); cout << endl << "------------------------------------------------------" "----------------------" << endl << endl; for (const CString& sLine : vsLines) { cout << sLine << endl; } cout << endl << "------------------------------------------------------" "----------------------" << endl << endl; } const CString sProtocol(bListenSSL ? "https" : "http"); const CString sSSL(bListenSSL ? "+" : ""); CUtils::PrintMessage(""); CUtils::PrintMessage( "To connect to this ZNC you need to connect to it as your IRC server", true); CUtils::PrintMessage( "using the port that you supplied. You have to supply your login info", true); CUtils::PrintMessage( "as the IRC server password like this: user/network:pass.", true); CUtils::PrintMessage(""); CUtils::PrintMessage("Try something like this in your IRC client...", true); CUtils::PrintMessage("/server " + sSSL + CString(uListenPort) + " " + sUser + ":", true); CUtils::PrintMessage(""); CUtils::PrintMessage( "To manage settings, users and networks, point your web browser to", true); CUtils::PrintMessage( sProtocol + "://:" + CString(uListenPort) + "/", true); CUtils::PrintMessage(""); File.UnLock(); bool bWantLaunch = bFileOpen; if (bWantLaunch) { // "export ZNC_NO_LAUNCH_AFTER_MAKECONF=1" would cause znc --makeconf to // not offer immediate launch. // Useful for distros which want to create config when znc package is // installed. // See https://github.com/znc/znc/pull/257 char* szNoLaunch = getenv("ZNC_NO_LAUNCH_AFTER_MAKECONF"); if (szNoLaunch && *szNoLaunch == '1') { bWantLaunch = false; } } if (bWantLaunch) { bWantLaunch = CUtils::GetBoolInput("Launch ZNC now?", true); } return bWantLaunch; } void CZNC::BackupConfigOnce(const CString& sSuffix) { static bool didBackup = false; if (didBackup) return; didBackup = true; CUtils::PrintAction("Creating a config backup"); CString sBackup = CDir::ChangeDir(m_sConfigFile, "../znc.conf." + sSuffix); if (CFile::Copy(m_sConfigFile, sBackup)) CUtils::PrintStatus(true, sBackup); else CUtils::PrintStatus(false, strerror(errno)); } bool CZNC::ParseConfig(const CString& sConfig, CString& sError) { m_sConfigFile = ExpandConfigPath(sConfig, false); CConfig config; if (!ReadConfig(config, sError)) return false; if (!LoadGlobal(config, sError)) return false; if (!LoadUsers(config, sError)) return false; return true; } bool CZNC::ReadConfig(CConfig& config, CString& sError) { sError.clear(); CUtils::PrintAction("Opening config [" + m_sConfigFile + "]"); if (!CFile::Exists(m_sConfigFile)) { sError = "No such file"; CUtils::PrintStatus(false, sError); CUtils::PrintMessage( "Restart ZNC with the --makeconf option if you wish to create this " "config."); return false; } if (!CFile::IsReg(m_sConfigFile)) { sError = "Not a file"; CUtils::PrintStatus(false, sError); return false; } CFile* pFile = new CFile(m_sConfigFile); // need to open the config file Read/Write for fcntl() // exclusive locking to work properly! if (!pFile->Open(m_sConfigFile, O_RDWR)) { sError = "Can not open config file"; CUtils::PrintStatus(false, sError); delete pFile; return false; } if (!pFile->TryExLock()) { sError = "ZNC is already running on this config."; CUtils::PrintStatus(false, sError); delete pFile; return false; } // (re)open the config file delete m_pLockFile; m_pLockFile = pFile; CFile& File = *pFile; if (!config.Parse(File, sError)) { CUtils::PrintStatus(false, sError); return false; } CUtils::PrintStatus(true); // check if config is from old ZNC version and // create a backup file if necessary CString sSavedVersion; config.FindStringEntry("version", sSavedVersion); if (sSavedVersion.empty()) { CUtils::PrintError( "Config does not contain a version identifier. It may be be too " "old or corrupt."); return false; } tuple tSavedVersion = make_tuple(sSavedVersion.Token(0, false, ".").ToUInt(), sSavedVersion.Token(1, false, ".").ToUInt()); tuple tCurrentVersion = make_tuple(VERSION_MAJOR, VERSION_MINOR); if (tSavedVersion < tCurrentVersion) { CUtils::PrintMessage("Found old config from ZNC " + sSavedVersion + ". Saving a backup of it."); BackupConfigOnce("pre-" + CString(VERSION_STR)); } else if (tSavedVersion > tCurrentVersion) { CUtils::PrintError("Config was saved from ZNC " + sSavedVersion + ". It may or may not work with current ZNC " + GetVersion()); } return true; } bool CZNC::RehashConfig(CString& sError) { ALLMODULECALL(OnPreRehash(), NOTHING); CConfig config; if (!ReadConfig(config, sError)) return false; if (!LoadGlobal(config, sError)) return false; // do not reload users - it's dangerous! ALLMODULECALL(OnPostRehash(), NOTHING); return true; } bool CZNC::LoadGlobal(CConfig& config, CString& sError) { sError.clear(); MCString msModules; // Modules are queued for later loading VCString vsList; config.FindStringVector("loadmodule", vsList); for (const CString& sModLine : vsList) { CString sModName = sModLine.Token(0); CString sArgs = sModLine.Token(1, true); // compatibility for pre-1.0 configs CString sSavedVersion; config.FindStringEntry("version", sSavedVersion); tuple tSavedVersion = make_tuple(sSavedVersion.Token(0, false, ".").ToUInt(), sSavedVersion.Token(1, false, ".").ToUInt()); if (sModName == "saslauth" && tSavedVersion < make_tuple(0, 207)) { CUtils::PrintMessage( "saslauth module was renamed to cyrusauth. Loading cyrusauth " "instead."); sModName = "cyrusauth"; } // end-compatibility for pre-1.0 configs if (msModules.find(sModName) != msModules.end()) { sError = "Module [" + sModName + "] already loaded"; CUtils::PrintError(sError); return false; } CString sModRet; CModule* pOldMod; pOldMod = GetModules().FindModule(sModName); if (!pOldMod) { CUtils::PrintAction("Loading global module [" + sModName + "]"); bool bModRet = GetModules().LoadModule(sModName, sArgs, CModInfo::GlobalModule, nullptr, nullptr, sModRet); CUtils::PrintStatus(bModRet, bModRet ? "" : sModRet); if (!bModRet) { sError = sModRet; return false; } } else if (pOldMod->GetArgs() != sArgs) { CUtils::PrintAction("Reloading global module [" + sModName + "]"); bool bModRet = GetModules().ReloadModule(sModName, sArgs, nullptr, nullptr, sModRet); CUtils::PrintStatus(bModRet, sModRet); if (!bModRet) { sError = sModRet; return false; } } else CUtils::PrintMessage("Module [" + sModName + "] already loaded."); msModules[sModName] = sArgs; } m_vsMotd.clear(); config.FindStringVector("motd", vsList); for (const CString& sMotd : vsList) { AddMotd(sMotd); } if (config.FindStringVector("bindhost", vsList)) { CUtils::PrintStatus(false, "WARNING: the global BindHost list is deprecated. " "Ignoring the following lines:"); for (const CString& sHost : vsList) { CUtils::PrintStatus(false, "BindHost = " + sHost); } } if (config.FindStringVector("vhost", vsList)) { CUtils::PrintStatus(false, "WARNING: the global vHost list is deprecated. " "Ignoring the following lines:"); for (const CString& sHost : vsList) { CUtils::PrintStatus(false, "vHost = " + sHost); } } m_vsTrustedProxies.clear(); config.FindStringVector("trustedproxy", vsList); for (const CString& sProxy : vsList) { AddTrustedProxy(sProxy); } CString sVal; if (config.FindStringEntry("pidfile", sVal)) m_sPidFile = sVal; if (config.FindStringEntry("statusprefix", sVal)) m_sStatusPrefix = sVal; if (config.FindStringEntry("sslcertfile", sVal)) m_sSSLCertFile = sVal; if (config.FindStringEntry("sslkeyfile", sVal)) m_sSSLKeyFile = sVal; if (config.FindStringEntry("ssldhparamfile", sVal)) m_sSSLDHParamFile = sVal; if (config.FindStringEntry("sslciphers", sVal)) m_sSSLCiphers = sVal; if (config.FindStringEntry("skin", sVal)) SetSkinName(sVal); if (config.FindStringEntry("connectdelay", sVal)) SetConnectDelay(sVal.ToUInt()); if (config.FindStringEntry("serverthrottle", sVal)) m_sConnectThrottle.SetTTL(sVal.ToUInt() * 1000); if (config.FindStringEntry("anoniplimit", sVal)) m_uiAnonIPLimit = sVal.ToUInt(); if (config.FindStringEntry("maxbuffersize", sVal)) m_uiMaxBufferSize = sVal.ToUInt(); if (config.FindStringEntry("protectwebsessions", sVal)) m_bProtectWebSessions = sVal.ToBool(); if (config.FindStringEntry("hideversion", sVal)) m_bHideVersion = sVal.ToBool(); if (config.FindStringEntry("authonlyviamodule", sVal)) m_bAuthOnlyViaModule = sVal.ToBool(); if (config.FindStringEntry("sslprotocols", sVal)) { if (!SetSSLProtocols(sVal)) { VCString vsProtocols = GetAvailableSSLProtocols(); CUtils::PrintError("Invalid SSLProtocols value [" + sVal + "]"); CUtils::PrintError( "The syntax is [SSLProtocols = [+|-] ...]"); CUtils::PrintError( "Available protocols are [" + CString(", ").Join(vsProtocols.begin(), vsProtocols.end()) + "]"); return false; } } if (config.FindStringEntry("configwritedelay", sVal)) m_uiConfigWriteDelay = sVal.ToUInt(); UnloadRemovedModules(msModules); if (!LoadListeners(config, sError)) return false; return true; } bool CZNC::LoadUsers(CConfig& config, CString& sError) { sError.clear(); m_msUsers.clear(); CConfig::SubConfig subConf; config.FindSubConfig("user", subConf); for (const auto& subIt : subConf) { const CString& sUserName = subIt.first; CConfig* pSubConf = subIt.second.m_pSubConfig; CUtils::PrintMessage("Loading user [" + sUserName + "]"); std::unique_ptr pUser(new CUser(sUserName)); if (!m_sStatusPrefix.empty()) { if (!pUser->SetStatusPrefix(m_sStatusPrefix)) { sError = "Invalid StatusPrefix [" + m_sStatusPrefix + "] Must be 1-5 chars, no spaces."; CUtils::PrintError(sError); return false; } } if (!pUser->ParseConfig(pSubConf, sError)) { CUtils::PrintError(sError); return false; } if (!pSubConf->empty()) { sError = "Unhandled lines in config for User [" + sUserName + "]!"; CUtils::PrintError(sError); DumpConfig(pSubConf); return false; } CString sErr; if (!AddUser(pUser.release(), sErr, true)) { sError = "Invalid user [" + sUserName + "] " + sErr; } if (!sError.empty()) { CUtils::PrintError(sError); pUser->SetBeingDeleted(true); return false; } } if (m_msUsers.empty()) { sError = "You must define at least one user in your config."; CUtils::PrintError(sError); return false; } return true; } bool CZNC::LoadListeners(CConfig& config, CString& sError) { sError.clear(); // Delete all listeners while (!m_vpListeners.empty()) { delete m_vpListeners[0]; m_vpListeners.erase(m_vpListeners.begin()); } // compatibility for pre-1.0 configs const char* szListenerEntries[] = {"listen", "listen6", "listen4", "listener", "listener6", "listener4"}; VCString vsList; config.FindStringVector("loadmodule", vsList); // This has to be after SSLCertFile is handled since it uses that value for (const char* szEntry : szListenerEntries) { config.FindStringVector(szEntry, vsList); for (const CString& sListener : vsList) { if (!AddListener(szEntry + CString(" ") + sListener, sError)) return false; } } // end-compatibility for pre-1.0 configs CConfig::SubConfig subConf; config.FindSubConfig("listener", subConf); for (const auto& subIt : subConf) { CConfig* pSubConf = subIt.second.m_pSubConfig; if (!AddListener(pSubConf, sError)) return false; if (!pSubConf->empty()) { sError = "Unhandled lines in Listener config!"; CUtils::PrintError(sError); CZNC::DumpConfig(pSubConf); return false; } } if (m_vpListeners.empty()) { sError = "You must supply at least one Listener in your config."; CUtils::PrintError(sError); return false; } return true; } void CZNC::UnloadRemovedModules(const MCString& msModules) { // unload modules which are no longer in the config set ssUnload; for (CModule* pCurMod : GetModules()) { if (msModules.find(pCurMod->GetModName()) == msModules.end()) ssUnload.insert(pCurMod->GetModName()); } for (const CString& sMod : ssUnload) { if (GetModules().UnloadModule(sMod)) CUtils::PrintMessage("Unloaded global module [" + sMod + "]"); else CUtils::PrintMessage("Could not unload [" + sMod + "]"); } } void CZNC::DumpConfig(const CConfig* pConfig) { CConfig::EntryMapIterator eit = pConfig->BeginEntries(); for (; eit != pConfig->EndEntries(); ++eit) { const CString& sKey = eit->first; const VCString& vsList = eit->second; VCString::const_iterator it = vsList.begin(); for (; it != vsList.end(); ++it) { CUtils::PrintError(sKey + " = " + *it); } } CConfig::SubConfigMapIterator sit = pConfig->BeginSubConfigs(); for (; sit != pConfig->EndSubConfigs(); ++sit) { const CString& sKey = sit->first; const CConfig::SubConfig& sSub = sit->second; CConfig::SubConfig::const_iterator it = sSub.begin(); for (; it != sSub.end(); ++it) { CUtils::PrintError("SubConfig [" + sKey + " " + it->first + "]:"); DumpConfig(it->second.m_pSubConfig); } } } void CZNC::ClearTrustedProxies() { m_vsTrustedProxies.clear(); } bool CZNC::AddTrustedProxy(const CString& sHost) { if (sHost.empty()) { return false; } for (const CString& sTrustedProxy : m_vsTrustedProxies) { if (sTrustedProxy.Equals(sHost)) { return false; } } m_vsTrustedProxies.push_back(sHost); return true; } bool CZNC::RemTrustedProxy(const CString& sHost) { VCString::iterator it; for (it = m_vsTrustedProxies.begin(); it != m_vsTrustedProxies.end(); ++it) { if (sHost.Equals(*it)) { m_vsTrustedProxies.erase(it); return true; } } return false; } void CZNC::Broadcast(const CString& sMessage, bool bAdminOnly, CUser* pSkipUser, CClient* pSkipClient) { for (const auto& it : m_msUsers) { if (bAdminOnly && !it.second->IsAdmin()) continue; if (it.second != pSkipUser) { // TODO: translate message to user's language CString sMsg = sMessage; bool bContinue = false; USERMODULECALL(OnBroadcast(sMsg), it.second, nullptr, &bContinue); if (bContinue) continue; it.second->PutStatusNotice("*** " + sMsg, nullptr, pSkipClient); } } } CModule* CZNC::FindModule(const CString& sModName, const CString& sUsername) { if (sUsername.empty()) { return CZNC::Get().GetModules().FindModule(sModName); } CUser* pUser = FindUser(sUsername); return (!pUser) ? nullptr : pUser->GetModules().FindModule(sModName); } CModule* CZNC::FindModule(const CString& sModName, CUser* pUser) { if (pUser) { return pUser->GetModules().FindModule(sModName); } return CZNC::Get().GetModules().FindModule(sModName); } bool CZNC::UpdateModule(const CString& sModule) { CModule* pModule; map musLoaded; map mnsLoaded; // Unload the module for every user and network for (const auto& it : m_msUsers) { CUser* pUser = it.second; pModule = pUser->GetModules().FindModule(sModule); if (pModule) { musLoaded[pUser] = pModule->GetArgs(); pUser->GetModules().UnloadModule(sModule); } // See if the user has this module loaded to a network vector vNetworks = pUser->GetNetworks(); for (CIRCNetwork* pNetwork : vNetworks) { pModule = pNetwork->GetModules().FindModule(sModule); if (pModule) { mnsLoaded[pNetwork] = pModule->GetArgs(); pNetwork->GetModules().UnloadModule(sModule); } } } // Unload the global module bool bGlobal = false; CString sGlobalArgs; pModule = GetModules().FindModule(sModule); if (pModule) { bGlobal = true; sGlobalArgs = pModule->GetArgs(); GetModules().UnloadModule(sModule); } // Lets reload everything bool bError = false; CString sErr; // Reload the global module if (bGlobal) { if (!GetModules().LoadModule(sModule, sGlobalArgs, CModInfo::GlobalModule, nullptr, nullptr, sErr)) { DEBUG("Failed to reload [" << sModule << "] globally [" << sErr << "]"); bError = true; } } // Reload the module for all users for (const auto& it : musLoaded) { CUser* pUser = it.first; const CString& sArgs = it.second; if (!pUser->GetModules().LoadModule( sModule, sArgs, CModInfo::UserModule, pUser, nullptr, sErr)) { DEBUG("Failed to reload [" << sModule << "] for [" << pUser->GetUserName() << "] [" << sErr << "]"); bError = true; } } // Reload the module for all networks for (const auto& it : mnsLoaded) { CIRCNetwork* pNetwork = it.first; const CString& sArgs = it.second; if (!pNetwork->GetModules().LoadModule( sModule, sArgs, CModInfo::NetworkModule, pNetwork->GetUser(), pNetwork, sErr)) { DEBUG("Failed to reload [" << sModule << "] for [" << pNetwork->GetUser()->GetUserName() << "/" << pNetwork->GetName() << "] [" << sErr << "]"); bError = true; } } return !bError; } CUser* CZNC::FindUser(const CString& sUsername) { map::iterator it = m_msUsers.find(sUsername); if (it != m_msUsers.end()) { return it->second; } return nullptr; } bool CZNC::DeleteUser(const CString& sUsername) { CUser* pUser = FindUser(sUsername); if (!pUser) { return false; } m_msDelUsers[pUser->GetUserName()] = pUser; return true; } bool CZNC::AddUser(CUser* pUser, CString& sErrorRet, bool bStartup) { if (FindUser(pUser->GetUserName()) != nullptr) { sErrorRet = t_s("User already exists"); DEBUG("User [" << pUser->GetUserName() << "] - already exists"); return false; } if (!pUser->IsValid(sErrorRet)) { DEBUG("Invalid user [" << pUser->GetUserName() << "] - [" << sErrorRet << "]"); return false; } bool bFailed = false; // do not call OnAddUser hook during ZNC startup if (!bStartup) { GLOBALMODULECALL(OnAddUser(*pUser, sErrorRet), &bFailed); } if (bFailed) { DEBUG("AddUser [" << pUser->GetUserName() << "] aborted by a module [" << sErrorRet << "]"); return false; } m_msUsers[pUser->GetUserName()] = pUser; return true; } CListener* CZNC::FindListener(u_short uPort, const CString& sBindHost, EAddrType eAddr) { for (CListener* pListener : m_vpListeners) { if (pListener->GetPort() != uPort) continue; if (pListener->GetBindHost() != sBindHost) continue; if (pListener->GetAddrType() != eAddr) continue; return pListener; } return nullptr; } bool CZNC::AddListener(const CString& sLine, CString& sError) { CString sName = sLine.Token(0); CString sValue = sLine.Token(1, true); EAddrType eAddr = ADDR_ALL; if (sName.Equals("Listen4") || sName.Equals("Listen") || sName.Equals("Listener4")) { eAddr = ADDR_IPV4ONLY; } if (sName.Equals("Listener6")) { eAddr = ADDR_IPV6ONLY; } CListener::EAcceptType eAccept = CListener::ACCEPT_ALL; if (sValue.TrimPrefix("irc_only ")) eAccept = CListener::ACCEPT_IRC; else if (sValue.TrimPrefix("web_only ")) eAccept = CListener::ACCEPT_HTTP; bool bSSL = false; CString sPort; CString sBindHost; if (ADDR_IPV4ONLY == eAddr) { sValue.Replace(":", " "); } if (sValue.Contains(" ")) { sBindHost = sValue.Token(0, false, " "); sPort = sValue.Token(1, true, " "); } else { sPort = sValue; } if (sPort.TrimPrefix("+")) { bSSL = true; } // No support for URIPrefix for old-style configs. CString sURIPrefix; unsigned short uPort = sPort.ToUShort(); return AddListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept, sError); } bool CZNC::AddListener(unsigned short uPort, const CString& sBindHost, const CString& sURIPrefixRaw, bool bSSL, EAddrType eAddr, CListener::EAcceptType eAccept, CString& sError) { CString sHostComment; if (!sBindHost.empty()) { sHostComment = " on host [" + sBindHost + "]"; } CString sIPV6Comment; switch (eAddr) { case ADDR_ALL: sIPV6Comment = ""; break; case ADDR_IPV4ONLY: sIPV6Comment = " using ipv4"; break; case ADDR_IPV6ONLY: sIPV6Comment = " using ipv6"; } CUtils::PrintAction("Binding to port [" + CString((bSSL) ? "+" : "") + CString(uPort) + "]" + sHostComment + sIPV6Comment); #ifndef HAVE_IPV6 if (ADDR_IPV6ONLY == eAddr) { sError = t_s("IPv6 is not enabled"); CUtils::PrintStatus(false, sError); return false; } #endif #ifndef HAVE_LIBSSL if (bSSL) { sError = t_s("SSL is not enabled"); CUtils::PrintStatus(false, sError); return false; } #else CString sPemFile = GetPemLocation(); if (bSSL && !CFile::Exists(sPemFile)) { sError = t_f("Unable to locate pem file: {1}")(sPemFile); CUtils::PrintStatus(false, sError); // If stdin is e.g. /dev/null and we call GetBoolInput(), // we are stuck in an endless loop! if (isatty(0) && CUtils::GetBoolInput("Would you like to create a new pem file?", true)) { sError.clear(); WritePemFile(); } else { return false; } CUtils::PrintAction("Binding to port [+" + CString(uPort) + "]" + sHostComment + sIPV6Comment); } #endif if (!uPort) { sError = t_s("Invalid port"); CUtils::PrintStatus(false, sError); return false; } // URIPrefix must start with a slash and end without one. CString sURIPrefix = CString(sURIPrefixRaw); if (!sURIPrefix.empty()) { if (!sURIPrefix.StartsWith("/")) { sURIPrefix = "/" + sURIPrefix; } if (sURIPrefix.EndsWith("/")) { sURIPrefix.TrimRight("/"); } } CListener* pListener = new CListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept); if (!pListener->Listen()) { sError = FormatBindError(); CUtils::PrintStatus(false, sError); delete pListener; return false; } m_vpListeners.push_back(pListener); CUtils::PrintStatus(true); return true; } bool CZNC::AddListener(CConfig* pConfig, CString& sError) { CString sBindHost; CString sURIPrefix; bool bSSL; bool b4; #ifdef HAVE_IPV6 bool b6 = true; #else bool b6 = false; #endif bool bIRC; bool bWeb; unsigned short uPort; if (!pConfig->FindUShortEntry("port", uPort)) { sError = "No port given"; CUtils::PrintError(sError); return false; } pConfig->FindStringEntry("host", sBindHost); pConfig->FindBoolEntry("ssl", bSSL, false); pConfig->FindBoolEntry("ipv4", b4, true); pConfig->FindBoolEntry("ipv6", b6, b6); pConfig->FindBoolEntry("allowirc", bIRC, true); pConfig->FindBoolEntry("allowweb", bWeb, true); pConfig->FindStringEntry("uriprefix", sURIPrefix); EAddrType eAddr; if (b4 && b6) { eAddr = ADDR_ALL; } else if (b4 && !b6) { eAddr = ADDR_IPV4ONLY; } else if (!b4 && b6) { eAddr = ADDR_IPV6ONLY; } else { sError = "No address family given"; CUtils::PrintError(sError); return false; } CListener::EAcceptType eAccept; if (bIRC && bWeb) { eAccept = CListener::ACCEPT_ALL; } else if (bIRC && !bWeb) { eAccept = CListener::ACCEPT_IRC; } else if (!bIRC && bWeb) { eAccept = CListener::ACCEPT_HTTP; } else { sError = "Either Web or IRC or both should be selected"; CUtils::PrintError(sError); return false; } return AddListener(uPort, sBindHost, sURIPrefix, bSSL, eAddr, eAccept, sError); } bool CZNC::AddListener(CListener* pListener) { if (!pListener->GetRealListener()) { // Listener doesn't actually listen delete pListener; return false; } // We don't check if there is an identical listener already listening // since one can't listen on e.g. the same port multiple times m_vpListeners.push_back(pListener); return true; } bool CZNC::DelListener(CListener* pListener) { auto it = std::find(m_vpListeners.begin(), m_vpListeners.end(), pListener); if (it != m_vpListeners.end()) { m_vpListeners.erase(it); delete pListener; return true; } return false; } CString CZNC::FormatBindError() { CString sError = (errno == 0 ? t_s(("unknown error, check the host name")) : CString(strerror(errno))); return t_f("Unable to bind: {1}")(sError); } static CZNC* s_pZNC = nullptr; void CZNC::CreateInstance() { if (s_pZNC) abort(); s_pZNC = new CZNC(); } CZNC& CZNC::Get() { return *s_pZNC; } void CZNC::DestroyInstance() { delete s_pZNC; s_pZNC = nullptr; } CZNC::TrafficStatsMap CZNC::GetTrafficStats(TrafficStatsPair& Users, TrafficStatsPair& ZNC, TrafficStatsPair& Total) { TrafficStatsMap ret; unsigned long long uiUsers_in, uiUsers_out, uiZNC_in, uiZNC_out; const map& msUsers = CZNC::Get().GetUserMap(); uiUsers_in = uiUsers_out = 0; uiZNC_in = BytesRead(); uiZNC_out = BytesWritten(); for (const auto& it : msUsers) { ret[it.first] = TrafficStatsPair(it.second->BytesRead(), it.second->BytesWritten()); uiUsers_in += it.second->BytesRead(); uiUsers_out += it.second->BytesWritten(); } for (Csock* pSock : m_Manager) { CUser* pUser = nullptr; if (pSock->GetSockName().StartsWith("IRC::")) { pUser = ((CIRCSock*)pSock)->GetNetwork()->GetUser(); } else if (pSock->GetSockName().StartsWith("USR::")) { pUser = ((CClient*)pSock)->GetUser(); } if (pUser) { ret[pUser->GetUserName()].first += pSock->GetBytesRead(); ret[pUser->GetUserName()].second += pSock->GetBytesWritten(); uiUsers_in += pSock->GetBytesRead(); uiUsers_out += pSock->GetBytesWritten(); } else { uiZNC_in += pSock->GetBytesRead(); uiZNC_out += pSock->GetBytesWritten(); } } Users = TrafficStatsPair(uiUsers_in, uiUsers_out); ZNC = TrafficStatsPair(uiZNC_in, uiZNC_out); Total = TrafficStatsPair(uiUsers_in + uiZNC_in, uiUsers_out + uiZNC_out); return ret; } CZNC::TrafficStatsMap CZNC::GetNetworkTrafficStats(const CString& sUsername, TrafficStatsPair& Total) { TrafficStatsMap Networks; CUser* pUser = FindUser(sUsername); if (pUser) { for (const CIRCNetwork* pNetwork : pUser->GetNetworks()) { Networks[pNetwork->GetName()].first = pNetwork->BytesRead(); Networks[pNetwork->GetName()].second = pNetwork->BytesWritten(); Total.first += pNetwork->BytesRead(); Total.second += pNetwork->BytesWritten(); } for (Csock* pSock : m_Manager) { CIRCNetwork* pNetwork = nullptr; if (pSock->GetSockName().StartsWith("IRC::")) { pNetwork = ((CIRCSock*)pSock)->GetNetwork(); } else if (pSock->GetSockName().StartsWith("USR::")) { pNetwork = ((CClient*)pSock)->GetNetwork(); } if (pNetwork && pNetwork->GetUser() == pUser) { Networks[pNetwork->GetName()].first = pSock->GetBytesRead(); Networks[pNetwork->GetName()].second = pSock->GetBytesWritten(); Total.first += pSock->GetBytesRead(); Total.second += pSock->GetBytesWritten(); } } } return Networks; } void CZNC::AuthUser(std::shared_ptr AuthClass) { // TODO unless the auth module calls it, CUser::IsHostAllowed() is not // honoured bool bReturn = false; GLOBALMODULECALL(OnLoginAttempt(AuthClass), &bReturn); if (bReturn) return; CUser* pUser = FindUser(AuthClass->GetUsername()); if (!pUser || !pUser->CheckPass(AuthClass->GetPassword())) { AuthClass->RefuseLogin("Invalid Password"); return; } CString sHost = AuthClass->GetRemoteIP(); if (!pUser->IsHostAllowed(sHost)) { AuthClass->RefuseLogin("Your host [" + sHost + "] is not allowed"); return; } AuthClass->AcceptLogin(*pUser); } class CConnectQueueTimer : public CCron { public: CConnectQueueTimer(int iSecs) : CCron() { SetName("Connect users"); Start(iSecs); // Don't wait iSecs seconds for first timer run m_bRunOnNextCall = true; } ~CConnectQueueTimer() override { // This is only needed when ZNC shuts down: // CZNC::~CZNC() sets its CConnectQueueTimer pointer to nullptr and // calls the manager's Cleanup() which destroys all sockets and // timers. If something calls CZNC::EnableConnectQueue() here // (e.g. because a CIRCSock is destroyed), the socket manager // deletes that timer almost immediately, but CZNC now got a // dangling pointer to this timer which can crash later on. // // Unlikely but possible ;) CZNC::Get().LeakConnectQueueTimer(this); } protected: void RunJob() override { list ConnectionQueue; list& RealConnectionQueue = CZNC::Get().GetConnectionQueue(); // Problem: If a network can't connect right now because e.g. it // is throttled, it will re-insert itself into the connection // queue. However, we must only give each network a single // chance during this timer run. // // Solution: We move the connection queue to our local list at // the beginning and work from that. ConnectionQueue.swap(RealConnectionQueue); while (!ConnectionQueue.empty()) { CIRCNetwork* pNetwork = ConnectionQueue.front(); ConnectionQueue.pop_front(); if (pNetwork->Connect()) { break; } } /* Now re-insert anything that is left in our local list into * the real connection queue. */ RealConnectionQueue.splice(RealConnectionQueue.begin(), ConnectionQueue); if (RealConnectionQueue.empty()) { DEBUG("ConnectQueueTimer done"); CZNC::Get().DisableConnectQueue(); } } }; void CZNC::SetConnectDelay(unsigned int i) { if (i < 1) { // Don't hammer server with our failed connects i = 1; } if (m_uiConnectDelay != i && m_pConnectQueueTimer != nullptr) { m_pConnectQueueTimer->Start(i); } m_uiConnectDelay = i; } VCString CZNC::GetAvailableSSLProtocols() { // NOTE: keep in sync with SetSSLProtocols() return {"SSLv2", "SSLv3", "TLSv1", "TLSV1.1", "TLSv1.2"}; } bool CZNC::SetSSLProtocols(const CString& sProtocols) { VCString vsProtocols; sProtocols.Split(" ", vsProtocols, false, "", "", true, true); unsigned int uDisabledProtocols = Csock::EDP_SSL; for (CString& sProtocol : vsProtocols) { unsigned int uFlag = 0; bool bEnable = sProtocol.TrimPrefix("+"); bool bDisable = sProtocol.TrimPrefix("-"); // NOTE: keep in sync with GetAvailableSSLProtocols() if (sProtocol.Equals("All")) { uFlag = ~0; } else if (sProtocol.Equals("SSLv2")) { uFlag = Csock::EDP_SSLv2; } else if (sProtocol.Equals("SSLv3")) { uFlag = Csock::EDP_SSLv3; } else if (sProtocol.Equals("TLSv1")) { uFlag = Csock::EDP_TLSv1; } else if (sProtocol.Equals("TLSv1.1")) { uFlag = Csock::EDP_TLSv1_1; } else if (sProtocol.Equals("TLSv1.2")) { uFlag = Csock::EDP_TLSv1_2; } else { return false; } if (bEnable) { uDisabledProtocols &= ~uFlag; } else if (bDisable) { uDisabledProtocols |= uFlag; } else { uDisabledProtocols = ~uFlag; } } m_sSSLProtocols = sProtocols; m_uDisabledSSLProtocols = uDisabledProtocols; return true; } void CZNC::EnableConnectQueue() { if (!m_pConnectQueueTimer && !m_uiConnectPaused && !m_lpConnectQueue.empty()) { m_pConnectQueueTimer = new CConnectQueueTimer(m_uiConnectDelay); GetManager().AddCron(m_pConnectQueueTimer); } } void CZNC::DisableConnectQueue() { if (m_pConnectQueueTimer) { // This will kill the cron m_pConnectQueueTimer->Stop(); m_pConnectQueueTimer = nullptr; } } void CZNC::PauseConnectQueue() { DEBUG("Connection queue paused"); m_uiConnectPaused++; if (m_pConnectQueueTimer) { m_pConnectQueueTimer->Pause(); } } void CZNC::ResumeConnectQueue() { DEBUG("Connection queue resumed"); m_uiConnectPaused--; EnableConnectQueue(); if (m_pConnectQueueTimer) { m_pConnectQueueTimer->UnPause(); } } void CZNC::ForceEncoding() { m_uiForceEncoding++; #ifdef HAVE_ICU for (Csock* pSock : GetManager()) { pSock->SetEncoding(FixupEncoding(pSock->GetEncoding())); } #endif } void CZNC::UnforceEncoding() { m_uiForceEncoding--; } bool CZNC::IsForcingEncoding() const { return m_uiForceEncoding; } CString CZNC::FixupEncoding(const CString& sEncoding) const { if (!m_uiForceEncoding) { return sEncoding; } if (sEncoding.empty()) { return "UTF-8"; } const char* sRealEncoding = sEncoding.c_str(); if (sEncoding[0] == '*' || sEncoding[0] == '^') { sRealEncoding++; } if (!*sRealEncoding) { return "UTF-8"; } #ifdef HAVE_ICU UErrorCode e = U_ZERO_ERROR; UConverter* cnv = ucnv_open(sRealEncoding, &e); if (cnv) { ucnv_close(cnv); } if (U_FAILURE(e)) { return "UTF-8"; } #endif return sEncoding; } void CZNC::AddNetworkToQueue(CIRCNetwork* pNetwork) { // Make sure we are not already in the queue if (std::find(m_lpConnectQueue.begin(), m_lpConnectQueue.end(), pNetwork) != m_lpConnectQueue.end()) { return; } m_lpConnectQueue.push_back(pNetwork); EnableConnectQueue(); } void CZNC::LeakConnectQueueTimer(CConnectQueueTimer* pTimer) { if (m_pConnectQueueTimer == pTimer) m_pConnectQueueTimer = nullptr; } bool CZNC::WaitForChildLock() { return m_pLockFile && m_pLockFile->ExLock(); } void CZNC::DisableConfigTimer() { if (m_pConfigTimer) { m_pConfigTimer->Stop(); m_pConfigTimer = nullptr; } } znc-1.7.5/src/Translation.cpp0000644000175000017500000001236013542151610016333 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #ifdef HAVE_I18N #include #endif namespace { std::map FillTranslations() { std::map mTranslations; CDir Dir; Dir.Fill(_DATADIR_ "/translations"); for (CFile* pFile : Dir) { CString sName = pFile->GetShortName(); CTranslationInfo& translation = mTranslations[sName]; MCString msData; // TODO: make the file format more sensible than this msData.ReadFromDisk(pFile->GetLongName()); translation.sSelfName = msData["SelfName"]; // TODO: right-to-left support } return mTranslations; } } // namespace std::map CTranslationInfo::GetTranslations() { static std::map mTranslations = FillTranslations(); return mTranslations; } CTranslation& CTranslation::Get() { static CTranslation translation; return translation; } CString CTranslation::Singular(const CString& sDomain, const CString& sContext, const CString& sEnglish) { #ifdef HAVE_I18N const std::locale& loc = LoadTranslation(sDomain); return boost::locale::translate(sContext, sEnglish).str(loc); #else return sEnglish; #endif } CString CTranslation::Plural(const CString& sDomain, const CString& sContext, const CString& sEnglish, const CString& sEnglishes, int iNum) { #ifdef HAVE_I18N const std::locale& loc = LoadTranslation(sDomain); return boost::locale::translate(sContext, sEnglish, sEnglishes, iNum) .str(loc); #else if (iNum == 1) { return sEnglish; } else { return sEnglishes; } #endif } const std::locale& CTranslation::LoadTranslation(const CString& sDomain) { CString sLanguage = m_sLanguageStack.empty() ? "" : m_sLanguageStack.back(); sLanguage.Replace("-", "_"); if (sLanguage.empty()) sLanguage = "C"; #ifdef HAVE_I18N // Not using built-in support for multiple domains in single std::locale // via overloaded call to .str() because we need to be able to reload // translations from disk independently when a module gets updated auto& domain = m_Translations[sDomain]; auto lang_it = domain.find(sLanguage); if (lang_it == domain.end()) { boost::locale::generator gen; gen.add_messages_path(LOCALE_DIR); gen.add_messages_domain(sDomain); std::tie(lang_it, std::ignore) = domain.emplace(sLanguage, gen(sLanguage + ".UTF-8")); } return lang_it->second; #else // dummy, it's not used anyway return std::locale::classic(); #endif } void CTranslation::PushLanguage(const CString& sLanguage) { m_sLanguageStack.push_back(sLanguage); } void CTranslation::PopLanguage() { m_sLanguageStack.pop_back(); } void CTranslation::NewReference(const CString& sDomain) { m_miReferences[sDomain]++; } void CTranslation::DelReference(const CString& sDomain) { if (!--m_miReferences[sDomain]) { m_Translations.erase(sDomain); } } CString CCoreTranslationMixin::t_s(const CString& sEnglish, const CString& sContext) { return CTranslation::Get().Singular("znc", sContext, sEnglish); } CInlineFormatMessage CCoreTranslationMixin::t_f(const CString& sEnglish, const CString& sContext) { return CInlineFormatMessage(t_s(sEnglish, sContext)); } CInlineFormatMessage CCoreTranslationMixin::t_p(const CString& sEnglish, const CString& sEnglishes, int iNum, const CString& sContext) { return CInlineFormatMessage(CTranslation::Get().Plural( "znc", sContext, sEnglish, sEnglishes, iNum)); } CDelayedTranslation CCoreTranslationMixin::t_d(const CString& sEnglish, const CString& sContext) { return CDelayedTranslation("znc", sContext, sEnglish); } CLanguageScope::CLanguageScope(const CString& sLanguage) { CTranslation::Get().PushLanguage(sLanguage); } CLanguageScope::~CLanguageScope() { CTranslation::Get().PopLanguage(); } CString CDelayedTranslation::Resolve() const { return CTranslation::Get().Singular(m_sDomain, m_sContext, m_sEnglish); } CTranslationDomainRefHolder::CTranslationDomainRefHolder(const CString& sDomain) : m_sDomain(sDomain) { CTranslation::Get().NewReference(sDomain); } CTranslationDomainRefHolder::~CTranslationDomainRefHolder() { CTranslation::Get().DelReference(m_sDomain); } znc-1.7.5/src/User.cpp0000644000175000017500000013303313542151610014754 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include using std::vector; using std::set; class CUserTimer : public CCron { public: CUserTimer(CUser* pUser) : CCron(), m_pUser(pUser) { SetName("CUserTimer::" + m_pUser->GetUserName()); Start(m_pUser->GetPingSlack()); } ~CUserTimer() override {} CUserTimer(const CUserTimer&) = delete; CUserTimer& operator=(const CUserTimer&) = delete; private: protected: void RunJob() override { const vector& vUserClients = m_pUser->GetUserClients(); for (CClient* pUserClient : vUserClients) { if (pUserClient->GetTimeSinceLastDataTransaction() >= m_pUser->GetPingFrequency()) { pUserClient->PutClient("PING :ZNC"); } } // Restart timer for the case if the period had changed. Usually this is // noop Start(m_pUser->GetPingSlack()); } CUser* m_pUser; }; CUser::CUser(const CString& sUserName) : m_sUserName(sUserName), m_sCleanUserName(MakeCleanUserName(sUserName)), m_sNick(m_sCleanUserName), m_sAltNick(""), m_sIdent(m_sCleanUserName), m_sRealName(""), m_sBindHost(""), m_sDCCBindHost(""), m_sPass(""), m_sPassSalt(""), m_sStatusPrefix("*"), m_sDefaultChanModes(""), m_sClientEncoding(""), m_sQuitMsg(""), m_mssCTCPReplies(), m_sTimestampFormat("[%H:%M:%S]"), m_sTimezone(""), m_eHashType(HASH_NONE), m_sUserPath(CZNC::Get().GetUserPath() + "/" + sUserName), m_bMultiClients(true), m_bDenyLoadMod(false), m_bAdmin(false), m_bDenySetBindHost(false), m_bAutoClearChanBuffer(true), m_bAutoClearQueryBuffer(true), m_bBeingDeleted(false), m_bAppendTimestamp(false), m_bPrependTimestamp(true), m_bAuthOnlyViaModule(false), m_pUserTimer(nullptr), m_vIRCNetworks(), m_vClients(), m_ssAllowedHosts(), m_uChanBufferSize(50), m_uQueryBufferSize(50), m_uBytesRead(0), m_uBytesWritten(0), m_uMaxJoinTries(10), m_uMaxNetworks(1), m_uMaxQueryBuffers(50), m_uMaxJoins(0), m_uNoTrafficTimeout(180), m_sSkinName(""), m_pModules(new CModules) { m_pUserTimer = new CUserTimer(this); CZNC::Get().GetManager().AddCron(m_pUserTimer); } CUser::~CUser() { // Delete networks while (!m_vIRCNetworks.empty()) { delete *m_vIRCNetworks.begin(); } // Delete clients while (!m_vClients.empty()) { CZNC::Get().GetManager().DelSockByAddr(m_vClients[0]); } m_vClients.clear(); // Delete modules (unloads all modules!) delete m_pModules; m_pModules = nullptr; CZNC::Get().GetManager().DelCronByAddr(m_pUserTimer); CZNC::Get().AddBytesRead(m_uBytesRead); CZNC::Get().AddBytesWritten(m_uBytesWritten); } template struct TOption { const char* name; void (CUser::*pSetter)(T); }; bool CUser::ParseConfig(CConfig* pConfig, CString& sError) { TOption StringOptions[] = { {"nick", &CUser::SetNick}, {"quitmsg", &CUser::SetQuitMsg}, {"altnick", &CUser::SetAltNick}, {"ident", &CUser::SetIdent}, {"realname", &CUser::SetRealName}, {"chanmodes", &CUser::SetDefaultChanModes}, {"bindhost", &CUser::SetBindHost}, {"vhost", &CUser::SetBindHost}, {"dccbindhost", &CUser::SetDCCBindHost}, {"dccvhost", &CUser::SetDCCBindHost}, {"timestampformat", &CUser::SetTimestampFormat}, {"skin", &CUser::SetSkinName}, {"clientencoding", &CUser::SetClientEncoding}, }; TOption UIntOptions[] = { {"jointries", &CUser::SetJoinTries}, {"maxnetworks", &CUser::SetMaxNetworks}, {"maxquerybuffers", &CUser::SetMaxQueryBuffers}, {"maxjoins", &CUser::SetMaxJoins}, {"notraffictimeout", &CUser::SetNoTrafficTimeout}, }; TOption BoolOptions[] = { {"keepbuffer", &CUser::SetKeepBuffer}, // XXX compatibility crap from pre-0.207 {"autoclearchanbuffer", &CUser::SetAutoClearChanBuffer}, {"autoclearquerybuffer", &CUser::SetAutoClearQueryBuffer}, {"multiclients", &CUser::SetMultiClients}, {"denyloadmod", &CUser::SetDenyLoadMod}, {"admin", &CUser::SetAdmin}, {"denysetbindhost", &CUser::SetDenySetBindHost}, {"denysetvhost", &CUser::SetDenySetBindHost}, {"appendtimestamp", &CUser::SetTimestampAppend}, {"prependtimestamp", &CUser::SetTimestampPrepend}, {"authonlyviamodule", &CUser::SetAuthOnlyViaModule}, }; for (const auto& Option : StringOptions) { CString sValue; if (pConfig->FindStringEntry(Option.name, sValue)) (this->*Option.pSetter)(sValue); } for (const auto& Option : UIntOptions) { CString sValue; if (pConfig->FindStringEntry(Option.name, sValue)) (this->*Option.pSetter)(sValue.ToUInt()); } for (const auto& Option : BoolOptions) { CString sValue; if (pConfig->FindStringEntry(Option.name, sValue)) (this->*Option.pSetter)(sValue.ToBool()); } VCString vsList; pConfig->FindStringVector("allow", vsList); for (const CString& sHost : vsList) { AddAllowedHost(sHost); } pConfig->FindStringVector("ctcpreply", vsList); for (const CString& sReply : vsList) { AddCTCPReply(sReply.Token(0), sReply.Token(1, true)); } CString sValue; CString sDCCLookupValue; pConfig->FindStringEntry("dcclookupmethod", sDCCLookupValue); if (pConfig->FindStringEntry("bouncedccs", sValue)) { if (sValue.ToBool()) { CUtils::PrintAction("Loading Module [bouncedcc]"); CString sModRet; bool bModRet = GetModules().LoadModule( "bouncedcc", "", CModInfo::UserModule, this, nullptr, sModRet); CUtils::PrintStatus(bModRet, sModRet); if (!bModRet) { sError = sModRet; return false; } if (sDCCLookupValue.Equals("Client")) { GetModules().FindModule("bouncedcc")->SetNV("UseClientIP", "1"); } } } if (pConfig->FindStringEntry("buffer", sValue)) SetBufferCount(sValue.ToUInt(), true); if (pConfig->FindStringEntry("chanbuffersize", sValue)) SetChanBufferSize(sValue.ToUInt(), true); if (pConfig->FindStringEntry("querybuffersize", sValue)) SetQueryBufferSize(sValue.ToUInt(), true); if (pConfig->FindStringEntry("awaysuffix", sValue)) { CUtils::PrintMessage( "WARNING: AwaySuffix has been deprecated, instead try -> " "LoadModule = awaynick %nick%_" + sValue); } if (pConfig->FindStringEntry("autocycle", sValue)) { if (sValue.Equals("true")) CUtils::PrintError( "WARNING: AutoCycle has been removed, instead try -> " "LoadModule = autocycle"); } if (pConfig->FindStringEntry("keepnick", sValue)) { if (sValue.Equals("true")) CUtils::PrintError( "WARNING: KeepNick has been deprecated, instead try -> " "LoadModule = keepnick"); } if (pConfig->FindStringEntry("statusprefix", sValue)) { if (!SetStatusPrefix(sValue)) { sError = "Invalid StatusPrefix [" + sValue + "] Must be 1-5 chars, no spaces."; CUtils::PrintError(sError); return false; } } if (pConfig->FindStringEntry("timezone", sValue)) { SetTimezone(sValue); } if (pConfig->FindStringEntry("timezoneoffset", sValue)) { if (fabs(sValue.ToDouble()) > 0.1) { CUtils::PrintError( "WARNING: TimezoneOffset has been deprecated, now you can set " "your timezone by name"); } } if (pConfig->FindStringEntry("timestamp", sValue)) { if (!sValue.Trim_n().Equals("true")) { if (sValue.Trim_n().Equals("append")) { SetTimestampAppend(true); SetTimestampPrepend(false); } else if (sValue.Trim_n().Equals("prepend")) { SetTimestampAppend(false); SetTimestampPrepend(true); } else if (sValue.Trim_n().Equals("false")) { SetTimestampAppend(false); SetTimestampPrepend(false); } else { SetTimestampFormat(sValue); } } } if (pConfig->FindStringEntry("language", sValue)) { SetLanguage(sValue); } pConfig->FindStringEntry("pass", sValue); // There are different formats for this available: // Pass = // Pass = - // Pass = plain# // Pass = # // Pass = ### // 'Salted hash' means hash of 'password' + 'salt' // Possible hashes are md5 and sha256 if (sValue.TrimSuffix("-")) { SetPass(sValue.Trim_n(), CUser::HASH_MD5); } else { CString sMethod = sValue.Token(0, false, "#"); CString sPass = sValue.Token(1, true, "#"); if (sMethod == "md5" || sMethod == "sha256") { CUser::eHashType type = CUser::HASH_MD5; if (sMethod == "sha256") type = CUser::HASH_SHA256; CString sSalt = sPass.Token(1, false, "#"); sPass = sPass.Token(0, false, "#"); SetPass(sPass, type, sSalt); } else if (sMethod == "plain") { SetPass(sPass, CUser::HASH_NONE); } else { SetPass(sValue, CUser::HASH_NONE); } } CConfig::SubConfig subConf; CConfig::SubConfig::const_iterator subIt; pConfig->FindSubConfig("pass", subConf); if (!sValue.empty() && !subConf.empty()) { sError = "Password defined more than once"; CUtils::PrintError(sError); return false; } subIt = subConf.begin(); if (subIt != subConf.end()) { CConfig* pSubConf = subIt->second.m_pSubConfig; CString sHash; CString sMethod; CString sSalt; CUser::eHashType method; pSubConf->FindStringEntry("hash", sHash); pSubConf->FindStringEntry("method", sMethod); pSubConf->FindStringEntry("salt", sSalt); if (sMethod.empty() || sMethod.Equals("plain")) method = CUser::HASH_NONE; else if (sMethod.Equals("md5")) method = CUser::HASH_MD5; else if (sMethod.Equals("sha256")) method = CUser::HASH_SHA256; else { sError = "Invalid hash method"; CUtils::PrintError(sError); return false; } SetPass(sHash, method, sSalt); if (!pSubConf->empty()) { sError = "Unhandled lines in config!"; CUtils::PrintError(sError); CZNC::DumpConfig(pSubConf); return false; } ++subIt; } if (subIt != subConf.end()) { sError = "Password defined more than once"; CUtils::PrintError(sError); return false; } pConfig->FindSubConfig("network", subConf); for (subIt = subConf.begin(); subIt != subConf.end(); ++subIt) { const CString& sNetworkName = subIt->first; CUtils::PrintMessage("Loading network [" + sNetworkName + "]"); CIRCNetwork* pNetwork = FindNetwork(sNetworkName); if (!pNetwork) { pNetwork = new CIRCNetwork(this, sNetworkName); } if (!pNetwork->ParseConfig(subIt->second.m_pSubConfig, sError)) { return false; } } if (pConfig->FindStringVector("server", vsList, false) || pConfig->FindStringVector("chan", vsList, false) || pConfig->FindSubConfig("chan", subConf, false)) { CIRCNetwork* pNetwork = FindNetwork("default"); if (!pNetwork) { CString sErrorDummy; pNetwork = AddNetwork("default", sErrorDummy); } if (pNetwork) { CUtils::PrintMessage( "NOTICE: Found deprecated config, upgrading to a network"); if (!pNetwork->ParseConfig(pConfig, sError, true)) { return false; } } } pConfig->FindStringVector("loadmodule", vsList); for (const CString& sMod : vsList) { CString sModName = sMod.Token(0); CString sNotice = "Loading user module [" + sModName + "]"; // XXX Legacy crap, added in ZNC 0.089 if (sModName == "discon_kick") { sNotice = "NOTICE: [discon_kick] was renamed, loading [disconkick] " "instead"; sModName = "disconkick"; } // XXX Legacy crap, added in ZNC 0.099 if (sModName == "fixfreenode") { sNotice = "NOTICE: [fixfreenode] doesn't do anything useful anymore, " "ignoring it"; CUtils::PrintMessage(sNotice); continue; } // XXX Legacy crap, added in ZNC 0.207 if (sModName == "admin") { sNotice = "NOTICE: [admin] module was renamed, loading [controlpanel] " "instead"; sModName = "controlpanel"; } // XXX Legacy crap, should have been added ZNC 0.207, but added only in // 1.1 :( if (sModName == "away") { sNotice = "NOTICE: [away] was renamed, loading [awaystore] instead"; sModName = "awaystore"; } // XXX Legacy crap, added in 1.1; fakeonline module was dropped in 1.0 // and returned in 1.1 if (sModName == "fakeonline") { sNotice = "NOTICE: [fakeonline] was renamed, loading [modules_online] " "instead"; sModName = "modules_online"; } // XXX Legacy crap, added in 1.3 if (sModName == "charset") { CUtils::PrintAction( "NOTICE: Charset support was moved to core, importing old " "charset module settings"); size_t uIndex = 1; if (sMod.Token(uIndex).Equals("-force")) { uIndex++; } VCString vsClient, vsServer; sMod.Token(uIndex).Split(",", vsClient); sMod.Token(uIndex + 1).Split(",", vsServer); if (vsClient.empty() || vsServer.empty()) { CUtils::PrintStatus( false, "charset module was loaded with wrong parameters."); continue; } SetClientEncoding(vsClient[0]); for (CIRCNetwork* pNetwork : m_vIRCNetworks) { pNetwork->SetEncoding(vsServer[0]); } CUtils::PrintStatus(true, "Using [" + vsClient[0] + "] for clients, and [" + vsServer[0] + "] for servers"); continue; } CString sModRet; CString sArgs = sMod.Token(1, true); bool bModRet = LoadModule(sModName, sArgs, sNotice, sModRet); CUtils::PrintStatus(bModRet, sModRet); if (!bModRet) { // XXX The awaynick module was retired in 1.6 (still available as // external module) if (sModName == "awaynick") { // load simple_away instead, unless it's already on the list if (std::find(vsList.begin(), vsList.end(), "simple_away") == vsList.end()) { sNotice = "Loading [simple_away] module instead"; sModName = "simple_away"; // not a fatal error if simple_away is not available LoadModule(sModName, sArgs, sNotice, sModRet); } } else { sError = sModRet; return false; } } continue; } // Move ircconnectenabled to the networks if (pConfig->FindStringEntry("ircconnectenabled", sValue)) { for (CIRCNetwork* pNetwork : m_vIRCNetworks) { pNetwork->SetIRCConnectEnabled(sValue.ToBool()); } } return true; } CIRCNetwork* CUser::AddNetwork(const CString& sNetwork, CString& sErrorRet) { if (!CIRCNetwork::IsValidNetwork(sNetwork)) { sErrorRet = t_s("Invalid network name. It should be alphanumeric. Not to be " "confused with server name"); return nullptr; } else if (FindNetwork(sNetwork)) { sErrorRet = t_f("Network {1} already exists")(sNetwork); return nullptr; } CIRCNetwork* pNetwork = new CIRCNetwork(this, sNetwork); bool bCancel = false; USERMODULECALL(OnAddNetwork(*pNetwork, sErrorRet), this, nullptr, &bCancel); if (bCancel) { RemoveNetwork(pNetwork); delete pNetwork; return nullptr; } return pNetwork; } bool CUser::AddNetwork(CIRCNetwork* pNetwork) { if (FindNetwork(pNetwork->GetName())) { return false; } m_vIRCNetworks.push_back(pNetwork); return true; } void CUser::RemoveNetwork(CIRCNetwork* pNetwork) { auto it = std::find(m_vIRCNetworks.begin(), m_vIRCNetworks.end(), pNetwork); if (it != m_vIRCNetworks.end()) { m_vIRCNetworks.erase(it); } } bool CUser::DeleteNetwork(const CString& sNetwork) { CIRCNetwork* pNetwork = FindNetwork(sNetwork); if (pNetwork) { bool bCancel = false; USERMODULECALL(OnDeleteNetwork(*pNetwork), this, nullptr, &bCancel); if (!bCancel) { delete pNetwork; return true; } } return false; } CIRCNetwork* CUser::FindNetwork(const CString& sNetwork) const { for (CIRCNetwork* pNetwork : m_vIRCNetworks) { if (pNetwork->GetName().Equals(sNetwork)) { return pNetwork; } } return nullptr; } const vector& CUser::GetNetworks() const { return m_vIRCNetworks; } CString CUser::ExpandString(const CString& sStr) const { CString sRet; return ExpandString(sStr, sRet); } CString& CUser::ExpandString(const CString& sStr, CString& sRet) const { CString sTime = CUtils::CTime(time(nullptr), m_sTimezone); sRet = sStr; sRet.Replace("%altnick%", GetAltNick()); sRet.Replace("%bindhost%", GetBindHost()); sRet.Replace("%defnick%", GetNick()); sRet.Replace("%ident%", GetIdent()); sRet.Replace("%nick%", GetNick()); sRet.Replace("%realname%", GetRealName()); sRet.Replace("%time%", sTime); sRet.Replace("%uptime%", CZNC::Get().GetUptime()); sRet.Replace("%user%", GetUserName()); sRet.Replace("%version%", CZNC::GetVersion()); sRet.Replace("%vhost%", GetBindHost()); sRet.Replace("%znc%", CZNC::GetTag(false)); // Allows for escaping ExpandString if necessary, or to prevent // defaults from kicking in if you don't want them. sRet.Replace("%empty%", ""); // The following lines do not exist. You must be on DrUgS! sRet.Replace("%irc%", "All your IRC are belong to ZNC"); // Chosen by fair zocchihedron dice roll by SilverLeo sRet.Replace("%rand%", "42"); return sRet; } CString CUser::AddTimestamp(const CString& sStr) const { timeval tv; gettimeofday(&tv, nullptr); return AddTimestamp(tv, sStr); } CString CUser::AddTimestamp(time_t tm, const CString& sStr) const { timeval tv; tv.tv_sec = tm; tv.tv_usec = 0; return AddTimestamp(tv, sStr); } CString CUser::AddTimestamp(timeval tv, const CString& sStr) const { CString sRet = sStr; if (!GetTimestampFormat().empty() && (m_bAppendTimestamp || m_bPrependTimestamp)) { CString sTimestamp = CUtils::FormatTime(tv, GetTimestampFormat(), m_sTimezone); if (sTimestamp.empty()) { return sRet; } if (m_bPrependTimestamp) { sRet = sTimestamp; sRet += " " + sStr; } if (m_bAppendTimestamp) { // From http://www.mirc.com/colors.html // The Control+O key combination in mIRC inserts ascii character 15, // which turns off all previous attributes, including color, bold, // underline, and italics. // // \x02 bold // \x03 mIRC-compatible color // \x04 RRGGBB color // \x0F normal/reset (turn off bold, colors, etc.) // \x12 reverse (weechat) // \x16 reverse (mirc, kvirc) // \x1D italic // \x1F underline // Also see http://www.visualirc.net/tech-attrs.php // // Keep in sync with CIRCSocket::IcuExt__UCallback if (CString::npos != sRet.find_first_of("\x02\x03\x04\x0F\x12\x16\x1D\x1F")) { sRet += "\x0F"; } sRet += " " + sTimestamp; } } return sRet; } void CUser::BounceAllClients() { for (CClient* pClient : m_vClients) { pClient->BouncedOff(); } m_vClients.clear(); } void CUser::UserConnected(CClient* pClient) { if (!MultiClients()) { BounceAllClients(); } pClient->PutClient(":irc.znc.in 001 " + pClient->GetNick() + " :" + t_s("Welcome to ZNC")); m_vClients.push_back(pClient); } void CUser::UserDisconnected(CClient* pClient) { auto it = std::find(m_vClients.begin(), m_vClients.end(), pClient); if (it != m_vClients.end()) { m_vClients.erase(it); } } void CUser::CloneNetworks(const CUser& User) { const vector& vNetworks = User.GetNetworks(); for (CIRCNetwork* pUserNetwork : vNetworks) { CIRCNetwork* pNetwork = FindNetwork(pUserNetwork->GetName()); if (pNetwork) { pNetwork->Clone(*pUserNetwork); } else { new CIRCNetwork(this, *pUserNetwork); } } set ssDeleteNetworks; for (CIRCNetwork* pNetwork : m_vIRCNetworks) { if (!(User.FindNetwork(pNetwork->GetName()))) { ssDeleteNetworks.insert(pNetwork->GetName()); } } for (const CString& sNetwork : ssDeleteNetworks) { // The following will move all the clients to the user. // So the clients are not disconnected. The client could // have requested the rehash. Then when we do // client->PutStatus("Rehashing succeeded!") we would // crash if there was no client anymore. const vector& vClients = FindNetwork(sNetwork)->GetClients(); while (vClients.begin() != vClients.end()) { CClient* pClient = vClients.front(); // This line will remove pClient from vClients, // because it's a reference to the internal Network's vector. pClient->SetNetwork(nullptr); } DeleteNetwork(sNetwork); } } bool CUser::Clone(const CUser& User, CString& sErrorRet, bool bCloneNetworks) { sErrorRet.clear(); if (!User.IsValid(sErrorRet, true)) { return false; } // user names can only specified for the constructor, changing it later // on breaks too much stuff (e.g. lots of paths depend on the user name) if (GetUserName() != User.GetUserName()) { DEBUG("Ignoring username in CUser::Clone(), old username [" << GetUserName() << "]; New username [" << User.GetUserName() << "]"); } if (!User.GetPass().empty()) { SetPass(User.GetPass(), User.GetPassHashType(), User.GetPassSalt()); } SetNick(User.GetNick(false)); SetAltNick(User.GetAltNick(false)); SetIdent(User.GetIdent(false)); SetRealName(User.GetRealName()); SetStatusPrefix(User.GetStatusPrefix()); SetBindHost(User.GetBindHost()); SetDCCBindHost(User.GetDCCBindHost()); SetQuitMsg(User.GetQuitMsg()); SetSkinName(User.GetSkinName()); SetDefaultChanModes(User.GetDefaultChanModes()); SetChanBufferSize(User.GetChanBufferSize(), true); SetQueryBufferSize(User.GetQueryBufferSize(), true); SetJoinTries(User.JoinTries()); SetMaxNetworks(User.MaxNetworks()); SetMaxQueryBuffers(User.MaxQueryBuffers()); SetMaxJoins(User.MaxJoins()); SetNoTrafficTimeout(User.GetNoTrafficTimeout()); SetClientEncoding(User.GetClientEncoding()); SetLanguage(User.GetLanguage()); // Allowed Hosts m_ssAllowedHosts.clear(); const set& ssHosts = User.GetAllowedHosts(); for (const CString& sHost : ssHosts) { AddAllowedHost(sHost); } for (CClient* pSock : m_vClients) { if (!IsHostAllowed(pSock->GetRemoteIP())) { pSock->PutStatusNotice( t_s("You are being disconnected because your IP is no longer " "allowed to connect to this user")); pSock->Close(); } } // !Allowed Hosts // Networks if (bCloneNetworks) { CloneNetworks(User); } // !Networks // CTCP Replies m_mssCTCPReplies.clear(); const MCString& msReplies = User.GetCTCPReplies(); for (const auto& it : msReplies) { AddCTCPReply(it.first, it.second); } // !CTCP Replies // Flags SetAutoClearChanBuffer(User.AutoClearChanBuffer()); SetAutoClearQueryBuffer(User.AutoClearQueryBuffer()); SetMultiClients(User.MultiClients()); SetDenyLoadMod(User.DenyLoadMod()); SetAdmin(User.IsAdmin()); SetDenySetBindHost(User.DenySetBindHost()); SetAuthOnlyViaModule(User.AuthOnlyViaModule()); SetTimestampAppend(User.GetTimestampAppend()); SetTimestampPrepend(User.GetTimestampPrepend()); SetTimestampFormat(User.GetTimestampFormat()); SetTimezone(User.GetTimezone()); // !Flags // Modules set ssUnloadMods; CModules& vCurMods = GetModules(); const CModules& vNewMods = User.GetModules(); for (CModule* pNewMod : vNewMods) { CString sModRet; CModule* pCurMod = vCurMods.FindModule(pNewMod->GetModName()); if (!pCurMod) { vCurMods.LoadModule(pNewMod->GetModName(), pNewMod->GetArgs(), CModInfo::UserModule, this, nullptr, sModRet); } else if (pNewMod->GetArgs() != pCurMod->GetArgs()) { vCurMods.ReloadModule(pNewMod->GetModName(), pNewMod->GetArgs(), this, nullptr, sModRet); } } for (CModule* pCurMod : vCurMods) { CModule* pNewMod = vNewMods.FindModule(pCurMod->GetModName()); if (!pNewMod) { ssUnloadMods.insert(pCurMod->GetModName()); } } for (const CString& sMod : ssUnloadMods) { vCurMods.UnloadModule(sMod); } // !Modules return true; } const set& CUser::GetAllowedHosts() const { return m_ssAllowedHosts; } bool CUser::AddAllowedHost(const CString& sHostMask) { if (sHostMask.empty() || m_ssAllowedHosts.find(sHostMask) != m_ssAllowedHosts.end()) { return false; } m_ssAllowedHosts.insert(sHostMask); return true; } bool CUser::RemAllowedHost(const CString& sHostMask) { return m_ssAllowedHosts.erase(sHostMask) > 0; } void CUser::ClearAllowedHosts() { m_ssAllowedHosts.clear(); } bool CUser::IsHostAllowed(const CString& sHost) const { if (m_ssAllowedHosts.empty()) { return true; } for (const CString& sAllowedHost : m_ssAllowedHosts) { if (CUtils::CheckCIDR(sHost, sAllowedHost)) { return true; } } return false; } const CString& CUser::GetTimestampFormat() const { return m_sTimestampFormat; } bool CUser::GetTimestampAppend() const { return m_bAppendTimestamp; } bool CUser::GetTimestampPrepend() const { return m_bPrependTimestamp; } bool CUser::IsValidUserName(const CString& sUserName) { // /^[a-zA-Z][a-zA-Z@._\-]*$/ const char* p = sUserName.c_str(); if (sUserName.empty()) { return false; } if ((*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z')) { return false; } while (*p) { if (*p != '@' && *p != '.' && *p != '-' && *p != '_' && !isalnum(*p)) { return false; } p++; } return true; } bool CUser::IsValid(CString& sErrMsg, bool bSkipPass) const { sErrMsg.clear(); if (!bSkipPass && m_sPass.empty()) { sErrMsg = t_s("Password is empty"); return false; } if (m_sUserName.empty()) { sErrMsg = t_s("Username is empty"); return false; } if (!CUser::IsValidUserName(m_sUserName)) { sErrMsg = t_s("Username is invalid"); return false; } return true; } CConfig CUser::ToConfig() const { CConfig config; CConfig passConfig; CString sHash; switch (m_eHashType) { case HASH_NONE: sHash = "Plain"; break; case HASH_MD5: sHash = "MD5"; break; case HASH_SHA256: sHash = "SHA256"; break; } passConfig.AddKeyValuePair("Salt", m_sPassSalt); passConfig.AddKeyValuePair("Method", sHash); passConfig.AddKeyValuePair("Hash", GetPass()); config.AddSubConfig("Pass", "password", passConfig); config.AddKeyValuePair("Nick", GetNick()); config.AddKeyValuePair("AltNick", GetAltNick()); config.AddKeyValuePair("Ident", GetIdent()); config.AddKeyValuePair("RealName", GetRealName()); config.AddKeyValuePair("BindHost", GetBindHost()); config.AddKeyValuePair("DCCBindHost", GetDCCBindHost()); config.AddKeyValuePair("QuitMsg", GetQuitMsg()); if (CZNC::Get().GetStatusPrefix() != GetStatusPrefix()) config.AddKeyValuePair("StatusPrefix", GetStatusPrefix()); config.AddKeyValuePair("Skin", GetSkinName()); config.AddKeyValuePair("ChanModes", GetDefaultChanModes()); config.AddKeyValuePair("ChanBufferSize", CString(GetChanBufferSize())); config.AddKeyValuePair("QueryBufferSize", CString(GetQueryBufferSize())); config.AddKeyValuePair("AutoClearChanBuffer", CString(AutoClearChanBuffer())); config.AddKeyValuePair("AutoClearQueryBuffer", CString(AutoClearQueryBuffer())); config.AddKeyValuePair("MultiClients", CString(MultiClients())); config.AddKeyValuePair("DenyLoadMod", CString(DenyLoadMod())); config.AddKeyValuePair("Admin", CString(IsAdmin())); config.AddKeyValuePair("DenySetBindHost", CString(DenySetBindHost())); config.AddKeyValuePair("TimestampFormat", GetTimestampFormat()); config.AddKeyValuePair("AppendTimestamp", CString(GetTimestampAppend())); config.AddKeyValuePair("PrependTimestamp", CString(GetTimestampPrepend())); config.AddKeyValuePair("AuthOnlyViaModule", CString(AuthOnlyViaModule())); config.AddKeyValuePair("Timezone", m_sTimezone); config.AddKeyValuePair("JoinTries", CString(m_uMaxJoinTries)); config.AddKeyValuePair("MaxNetworks", CString(m_uMaxNetworks)); config.AddKeyValuePair("MaxQueryBuffers", CString(m_uMaxQueryBuffers)); config.AddKeyValuePair("MaxJoins", CString(m_uMaxJoins)); config.AddKeyValuePair("ClientEncoding", GetClientEncoding()); config.AddKeyValuePair("Language", GetLanguage()); config.AddKeyValuePair("NoTrafficTimeout", CString(GetNoTrafficTimeout())); // Allow Hosts if (!m_ssAllowedHosts.empty()) { for (const CString& sHost : m_ssAllowedHosts) { config.AddKeyValuePair("Allow", sHost); } } // CTCP Replies if (!m_mssCTCPReplies.empty()) { for (const auto& itb : m_mssCTCPReplies) { config.AddKeyValuePair("CTCPReply", itb.first.AsUpper() + " " + itb.second); } } // Modules const CModules& Mods = GetModules(); if (!Mods.empty()) { for (CModule* pMod : Mods) { CString sArgs = pMod->GetArgs(); if (!sArgs.empty()) { sArgs = " " + sArgs; } config.AddKeyValuePair("LoadModule", pMod->GetModName() + sArgs); } } // Networks for (CIRCNetwork* pNetwork : m_vIRCNetworks) { config.AddSubConfig("Network", pNetwork->GetName(), pNetwork->ToConfig()); } return config; } bool CUser::CheckPass(const CString& sPass) const { if(AuthOnlyViaModule() || CZNC::Get().GetAuthOnlyViaModule()) { return false; } switch (m_eHashType) { case HASH_MD5: return m_sPass.Equals(CUtils::SaltedMD5Hash(sPass, m_sPassSalt)); case HASH_SHA256: return m_sPass.Equals(CUtils::SaltedSHA256Hash(sPass, m_sPassSalt)); case HASH_NONE: default: return (sPass == m_sPass); } } /*CClient* CUser::GetClient() { // Todo: optimize this by saving a pointer to the sock CSockManager& Manager = CZNC::Get().GetManager(); CString sSockName = "USR::" + m_sUserName; for (unsigned int a = 0; a < Manager.size(); a++) { Csock* pSock = Manager[a]; if (pSock->GetSockName().Equals(sSockName)) { if (!pSock->IsClosed()) { return (CClient*) pSock; } } } return (CClient*) CZNC::Get().GetManager().FindSockByName(sSockName); }*/ CString CUser::GetLocalDCCIP() const { if (!GetDCCBindHost().empty()) return GetDCCBindHost(); for (CIRCNetwork* pNetwork : m_vIRCNetworks) { CIRCSock* pIRCSock = pNetwork->GetIRCSock(); if (pIRCSock) { return pIRCSock->GetLocalIP(); } } if (!GetAllClients().empty()) { return GetAllClients()[0]->GetLocalIP(); } return ""; } bool CUser::PutUser(const CString& sLine, CClient* pClient, CClient* pSkipClient) { for (CClient* pEachClient : m_vClients) { if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) { pEachClient->PutClient(sLine); if (pClient) { return true; } } } return (pClient == nullptr); } bool CUser::PutAllUser(const CString& sLine, CClient* pClient, CClient* pSkipClient) { PutUser(sLine, pClient, pSkipClient); for (CIRCNetwork* pNetwork : m_vIRCNetworks) { if (pNetwork->PutUser(sLine, pClient, pSkipClient)) { return true; } } return (pClient == nullptr); } bool CUser::PutStatus(const CString& sLine, CClient* pClient, CClient* pSkipClient) { vector vClients = GetAllClients(); for (CClient* pEachClient : vClients) { if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) { pEachClient->PutStatus(sLine); if (pClient) { return true; } } } return (pClient == nullptr); } bool CUser::PutStatusNotice(const CString& sLine, CClient* pClient, CClient* pSkipClient) { vector vClients = GetAllClients(); for (CClient* pEachClient : vClients) { if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) { pEachClient->PutStatusNotice(sLine); if (pClient) { return true; } } } return (pClient == nullptr); } bool CUser::PutModule(const CString& sModule, const CString& sLine, CClient* pClient, CClient* pSkipClient) { for (CClient* pEachClient : m_vClients) { if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) { pEachClient->PutModule(sModule, sLine); if (pClient) { return true; } } } return (pClient == nullptr); } bool CUser::PutModNotice(const CString& sModule, const CString& sLine, CClient* pClient, CClient* pSkipClient) { for (CClient* pEachClient : m_vClients) { if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) { pEachClient->PutModNotice(sModule, sLine); if (pClient) { return true; } } } return (pClient == nullptr); } CString CUser::MakeCleanUserName(const CString& sUserName) { return sUserName.Token(0, false, "@").Replace_n(".", ""); } bool CUser::IsUserAttached() const { if (!m_vClients.empty()) { return true; } for (const CIRCNetwork* pNetwork : m_vIRCNetworks) { if (pNetwork->IsUserAttached()) { return true; } } return false; } bool CUser::LoadModule(const CString& sModName, const CString& sArgs, const CString& sNotice, CString& sError) { bool bModRet = true; CString sModRet; CModInfo ModInfo; if (!CZNC::Get().GetModules().GetModInfo(ModInfo, sModName, sModRet)) { sError = t_f("Unable to find modinfo {1}: {2}")(sModName, sModRet); return false; } CUtils::PrintAction(sNotice); if (!ModInfo.SupportsType(CModInfo::UserModule) && ModInfo.SupportsType(CModInfo::NetworkModule)) { CUtils::PrintMessage( "NOTICE: Module [" + sModName + "] is a network module, loading module for all networks in user."); // Do they have old NV? CFile fNVFile = CFile(GetUserPath() + "/moddata/" + sModName + "/.registry"); for (CIRCNetwork* pNetwork : m_vIRCNetworks) { // Check whether the network already has this module loaded (#954) if (pNetwork->GetModules().FindModule(sModName)) { continue; } if (fNVFile.Exists()) { CString sNetworkModPath = pNetwork->GetNetworkPath() + "/moddata/" + sModName; if (!CFile::Exists(sNetworkModPath)) { CDir::MakeDir(sNetworkModPath); } fNVFile.Copy(sNetworkModPath + "/.registry"); } bModRet = pNetwork->GetModules().LoadModule( sModName, sArgs, CModInfo::NetworkModule, this, pNetwork, sModRet); if (!bModRet) { break; } } } else { bModRet = GetModules().LoadModule(sModName, sArgs, CModInfo::UserModule, this, nullptr, sModRet); } if (!bModRet) { sError = sModRet; } return bModRet; } // Setters void CUser::SetNick(const CString& s) { m_sNick = s; } void CUser::SetAltNick(const CString& s) { m_sAltNick = s; } void CUser::SetIdent(const CString& s) { m_sIdent = s; } void CUser::SetRealName(const CString& s) { m_sRealName = s; } void CUser::SetBindHost(const CString& s) { m_sBindHost = s; } void CUser::SetDCCBindHost(const CString& s) { m_sDCCBindHost = s; } void CUser::SetPass(const CString& s, eHashType eHash, const CString& sSalt) { m_sPass = s; m_eHashType = eHash; m_sPassSalt = sSalt; } void CUser::SetMultiClients(bool b) { m_bMultiClients = b; } void CUser::SetDenyLoadMod(bool b) { m_bDenyLoadMod = b; } void CUser::SetAdmin(bool b) { m_bAdmin = b; } void CUser::SetDenySetBindHost(bool b) { m_bDenySetBindHost = b; } void CUser::SetDefaultChanModes(const CString& s) { m_sDefaultChanModes = s; } void CUser::SetClientEncoding(const CString& s) { m_sClientEncoding = CZNC::Get().FixupEncoding(s); for (CClient* pClient : GetAllClients()) { pClient->SetEncoding(m_sClientEncoding); } } void CUser::SetQuitMsg(const CString& s) { m_sQuitMsg = s; } void CUser::SetAutoClearChanBuffer(bool b) { for (CIRCNetwork* pNetwork : m_vIRCNetworks) { for (CChan* pChan : pNetwork->GetChans()) { pChan->InheritAutoClearChanBuffer(b); } } m_bAutoClearChanBuffer = b; } void CUser::SetAutoClearQueryBuffer(bool b) { m_bAutoClearQueryBuffer = b; } bool CUser::SetBufferCount(unsigned int u, bool bForce) { return SetChanBufferSize(u, bForce); } bool CUser::SetChanBufferSize(unsigned int u, bool bForce) { if (!bForce && u > CZNC::Get().GetMaxBufferSize()) return false; for (CIRCNetwork* pNetwork : m_vIRCNetworks) { for (CChan* pChan : pNetwork->GetChans()) { pChan->InheritBufferCount(u, bForce); } } m_uChanBufferSize = u; return true; } bool CUser::SetQueryBufferSize(unsigned int u, bool bForce) { if (!bForce && u > CZNC::Get().GetMaxBufferSize()) return false; for (CIRCNetwork* pNetwork : m_vIRCNetworks) { for (CQuery* pQuery : pNetwork->GetQueries()) { pQuery->SetBufferCount(u, bForce); } } m_uQueryBufferSize = u; return true; } bool CUser::AddCTCPReply(const CString& sCTCP, const CString& sReply) { // Reject CTCP requests containing spaces if (sCTCP.find_first_of(' ') != CString::npos) { return false; } // Reject empty CTCP requests if (sCTCP.empty()) { return false; } m_mssCTCPReplies[sCTCP.AsUpper()] = sReply; return true; } bool CUser::DelCTCPReply(const CString& sCTCP) { return m_mssCTCPReplies.erase(sCTCP.AsUpper()) > 0; } bool CUser::SetStatusPrefix(const CString& s) { if ((!s.empty()) && (s.length() < 6) && (!s.Contains(" "))) { m_sStatusPrefix = (s.empty()) ? "*" : s; return true; } return false; } bool CUser::SetLanguage(const CString& s) { // They look like ru-RU for (char c : s) { if (isalpha(c) || c == '-' || c == '_') { } else { return false; } } m_sLanguage = s; // 1.7.0 accidentally used _ instead of -, which made language // non-selectable. But it's possible that someone put _ to znc.conf // manually. // TODO: cleanup _ some time later. m_sLanguage.Replace("_", "-"); return true; } // !Setters // Getters vector CUser::GetAllClients() const { vector vClients; for (CIRCNetwork* pNetwork : m_vIRCNetworks) { for (CClient* pClient : pNetwork->GetClients()) { vClients.push_back(pClient); } } for (CClient* pClient : m_vClients) { vClients.push_back(pClient); } return vClients; } const CString& CUser::GetUserName() const { return m_sUserName; } const CString& CUser::GetCleanUserName() const { return m_sCleanUserName; } const CString& CUser::GetNick(bool bAllowDefault) const { return (bAllowDefault && m_sNick.empty()) ? GetCleanUserName() : m_sNick; } const CString& CUser::GetAltNick(bool bAllowDefault) const { return (bAllowDefault && m_sAltNick.empty()) ? GetCleanUserName() : m_sAltNick; } const CString& CUser::GetIdent(bool bAllowDefault) const { return (bAllowDefault && m_sIdent.empty()) ? GetCleanUserName() : m_sIdent; } CString CUser::GetRealName() const { // Not include version number via GetTag() because of // https://github.com/znc/znc/issues/818#issuecomment-70402820 return (!m_sRealName.Trim_n().empty()) ? m_sRealName : "ZNC - https://znc.in"; } const CString& CUser::GetBindHost() const { return m_sBindHost; } const CString& CUser::GetDCCBindHost() const { return m_sDCCBindHost; } const CString& CUser::GetPass() const { return m_sPass; } CUser::eHashType CUser::GetPassHashType() const { return m_eHashType; } const CString& CUser::GetPassSalt() const { return m_sPassSalt; } bool CUser::DenyLoadMod() const { return m_bDenyLoadMod; } bool CUser::IsAdmin() const { return m_bAdmin; } bool CUser::DenySetBindHost() const { return m_bDenySetBindHost; } bool CUser::MultiClients() const { return m_bMultiClients; } bool CUser::AuthOnlyViaModule() const { return m_bAuthOnlyViaModule; } const CString& CUser::GetStatusPrefix() const { return m_sStatusPrefix; } const CString& CUser::GetDefaultChanModes() const { return m_sDefaultChanModes; } const CString& CUser::GetClientEncoding() const { return m_sClientEncoding; } bool CUser::HasSpaceForNewNetwork() const { return GetNetworks().size() < MaxNetworks(); } CString CUser::GetQuitMsg() const { return (!m_sQuitMsg.Trim_n().empty()) ? m_sQuitMsg : "%znc%"; } const MCString& CUser::GetCTCPReplies() const { return m_mssCTCPReplies; } unsigned int CUser::GetBufferCount() const { return GetChanBufferSize(); } unsigned int CUser::GetChanBufferSize() const { return m_uChanBufferSize; } unsigned int CUser::GetQueryBufferSize() const { return m_uQueryBufferSize; } bool CUser::AutoClearChanBuffer() const { return m_bAutoClearChanBuffer; } bool CUser::AutoClearQueryBuffer() const { return m_bAutoClearQueryBuffer; } // CString CUser::GetSkinName() const { return (!m_sSkinName.empty()) ? // m_sSkinName : CZNC::Get().GetSkinName(); } CString CUser::GetSkinName() const { return m_sSkinName; } CString CUser::GetLanguage() const { return m_sLanguage; } const CString& CUser::GetUserPath() const { if (!CFile::Exists(m_sUserPath)) { CDir::MakeDir(m_sUserPath); } return m_sUserPath; } // !Getters unsigned long long CUser::BytesRead() const { unsigned long long uBytes = m_uBytesRead; for (const CIRCNetwork* pNetwork : m_vIRCNetworks) { uBytes += pNetwork->BytesRead(); } return uBytes; } unsigned long long CUser::BytesWritten() const { unsigned long long uBytes = m_uBytesWritten; for (const CIRCNetwork* pNetwork : m_vIRCNetworks) { uBytes += pNetwork->BytesWritten(); } return uBytes; } znc-1.7.5/znc.service.in0000644000175000017500000000025413542151610015322 0ustar somebodysomebody[Unit] Description=ZNC, an advanced IRC bouncer After=network.target [Service] ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/znc -f User=znc [Install] WantedBy=multi-user.target znc-1.7.5/configure.ac0000644000175000017500000005415413542151610015037 0ustar somebodysomebodydnl This redefines AC_PROG_CC to a version which errors out instead. This is dnl because all our tests should be done with the C++ compiler. This should dnl catch stuff which accidentally uses the C compiler. AC_DEFUN([AC_PROG_CC], [m4_errprint(__file__:__line__[: Something is trying to use the C compiler. Since this is a C++ project, this should not happen! ])m4_exit(1)]) dnl Needed for AC_PATH_PROGS_FEATURE_CHECK which was added in 2.62 AC_PREREQ([2.62]) dnl Keep the version number in sync with version.h! AC_INIT([znc], [1.7.5]) LIBZNC_VERSION=1.7.5 AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/znc.cpp]) AC_LANG([C++]) AC_CONFIG_HEADERS([include/znc/zncconfig.h]) AH_TOP([#ifndef ZNCCONFIG_H #define ZNCCONFIG_H]) AH_BOTTOM([#endif /* ZNCCONFIG_H */]) AC_DEFUN([ZNC_AUTO_FAIL], [ # This looks better in the summary at the end $1="not found" if test "x$old_$1" != "xauto" ; then AC_MSG_ERROR([$2]) else AC_MSG_WARN([$3]) fi ]) # AC_PROG_CXX sets CXXFLAGS to "-O2 -g" if it is unset which we don't want CXXFLAGS="$CXXFLAGS " AC_PROG_CXX # "Optional" because we want custom error message AX_CXX_COMPILE_STDCXX_11([noext], [optional]) if test x"$HAVE_CXX11" != x1; then AC_MSG_ERROR([Upgrade your compiler. GCC 4.8+ and Clang 3.2+ are known to work.]) fi appendLib () { if test "$LIBS" != ""; then LIBS="$LIBS $*" else LIBS=$* fi } appendCXX () { if test "$CXXFLAGS" != ""; then CXXFLAGS="$CXXFLAGS $*" else CXXFLAGS=$* fi } appendMod () { if test "$MODFLAGS" != ""; then MODFLAGS="$MODFLAGS $*" else MODFLAGS=$* fi } appendLD () { if test "$LDFLAGS" != ""; then LDFLAGS="$LDFLAGS $*" else LDFLAGS=$* fi } AC_PROG_INSTALL AC_PROG_GREP AC_PROG_SED AC_CANONICAL_HOST AC_SYS_LARGEFILE ZNC_VISIBILITY AC_PATH_PROG([GIT], [git]) PKG_PROG_PKG_CONFIG() AC_ARG_ENABLE( [debug], AS_HELP_STRING([--enable-debug], [enable debugging]), [DEBUG="$enableval"], [DEBUG="no"]) AC_ARG_ENABLE( [ipv6], AS_HELP_STRING([--disable-ipv6], [disable ipv6 support]), [IPV6="$enableval"], [IPV6="yes"]) AC_ARG_ENABLE( [openssl], AS_HELP_STRING([--disable-openssl], [disable openssl]), [SSL="$enableval"], [SSL="auto"]) AC_ARG_ENABLE( [zlib], AS_HELP_STRING([--disable-zlib], [disable zlib]), [ZLIB="$enableval"], [ZLIB="auto"]) AC_ARG_ENABLE( [perl], AS_HELP_STRING([--enable-perl], [enable perl]), [PERL="$enableval"], [PERL="no"]) AC_ARG_ENABLE( [python], AS_HELP_STRING([--enable-python[[[=python3]]]], [enable python. By default python3.pc of pkg-config is used, but you can use another name, for example python-3.1]), [PYTHON="$enableval"], [PYTHON="no"]) AC_ARG_ENABLE( [swig], AS_HELP_STRING([--enable-swig], [Enable automatic generation of source files needed for modperl/modpython. This value is ignored if perl and python are disabled. Usually no need to enable it. ]), [USESWIG="$enableval"], [USESWIG="auto"]) AC_ARG_ENABLE( [cyrus], AS_HELP_STRING([--enable-cyrus], [enable cyrus]), [if test "$enableval" = "yes" ; then CYRUS=1; fi],) AC_ARG_ENABLE( [optimization], AS_HELP_STRING([--disable-optimization], [Disable some compiler optimizations to decrease memory usage while compiling]), [OPTIMIZE="$enableval"], [OPTIMIZE="yes"]) AC_ARG_ENABLE( [tdns], AS_HELP_STRING([--disable-tdns], [disable threads usage for DNS resolving]), [TDNS="$enableval"], [TDNS="auto"]) AC_ARG_ENABLE( [run-from-source], AS_HELP_STRING([--enable-run-from-source], [ZNC will be runnable without installation]), [if test "x$enableval" = "xyes" ; then AC_DEFINE([RUN_FROM_SOURCE], [1], [Define if ZNC should be runnable without installation]) fi RUNFROMSOURCE="$enableval"], [RUNFROMSOURCE="no"]) AC_ARG_ENABLE( [poll], AS_HELP_STRING([--disable-poll], [use select() instead of poll()]), [POLL="$enableval"], [POLL="yes"]) AC_ARG_WITH( [gtest], AS_HELP_STRING([--with-gtest=DIR], [Path to directory with src/gtest-all.cc file. If not specified, git submodule will be used. If it is not available either, "make test" will fail.])) if test "x$with_gtest" != xno; then AC_SUBST([GTEST_DIR], [$with_gtest]) fi AC_ARG_WITH([gmock], AS_HELP_STRING([--with-gmock=DIR], [Path to directory with src/gmock-all.cc and src/gmock_main.cc files. If not specified, git submodule will be used. If it is not available either, "make test" will fail.])) if test "x$with_gmock" != xno; then AC_SUBST([GMOCK_DIR], [$with_gmock]) fi AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), [ if test x"$with_systemdsystemunitdir" = xyes; then with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) fi ]) if test "x$with_systemdsystemunitdir" != xno; then AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) fi AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ]) case "${host_os}" in freebsd*) # -D__GNU_LIBRARY__ makes this work on fbsd 4.11 appendCXX -I/usr/local/include -D__GNU_LIBRARY__ appendLib -L/usr/local/lib -lcompat appendMod -L/usr/local/lib ;; solaris*) appendLib -lsocket -lnsl -lresolv ISSUN=1 ;; cygwin) # We don't want to use -std=gnu++11 instead of -std=c++11, but among other things, -std=c++11 defines __STRICT_ANSI__ which makes cygwin not to compile: undefined references to strerror_r, to fdopen, to strcasecmp, etc (their declarations in system headers are between ifdef) appendCXX -U__STRICT_ANSI__ ISCYGWIN=1 ;; darwin*) ISDARWIN=1 AC_PATH_PROG([BREW], [brew]) if test -n "$BREW"; then # add default homebrew paths if test "x$HAVE_ICU" != "xno"; then AC_MSG_CHECKING([icu4c via homebrew]) icu4c_prefix=`$BREW --prefix icu4c` if test -n "$icu4c_prefix"; then export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$icu4c_prefix/lib/pkgconfig" AC_MSG_RESULT([$icu4c_prefix]) else AC_MSG_RESULT([no]) fi fi if test "x$PYTHON" != "xno"; then brew_python_pc="$PYTHON" # This is duplication of non-darwin python logic below... if test "x$brew_python_pc" = "xyes"; then brew_python_pc="python3" fi AC_MSG_CHECKING([python3 via homebrew]) python3_prefix=`$BREW --prefix python3` if test -n "$python3_prefix"; then python3_prefix=`find "$python3_prefix/" -name $brew_python_pc.pc | head -n1` if test -n "$python3_prefix"; then python3_prefix=`dirname "$python3_prefix"` export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$python3_prefix" AC_MSG_RESULT([$python3_prefix]) else AC_MSG_RESULT([no $brew_python_pc.pc found]) fi else AC_MSG_RESULT([no]) fi fi if test "x$SSL" != "xno"; then AC_MSG_CHECKING([openssl via homebrew]) openssl_prefix=`$BREW --prefix openssl` if test -n "$openssl_prefix"; then export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$openssl_prefix/lib/pkgconfig" AC_MSG_RESULT([$openssl_prefix]) else AC_MSG_RESULT([no]) fi fi fi ;; esac if test "$DEBUG" != "no"; then appendCXX -ggdb3 AC_DEFINE([_DEBUG], [1], [Define for debugging]) if test "x$ISCYGWIN" != x1; then # These enable some debug options in g++'s STL, e.g. invalid use of iterators # But they cause crashes on cygwin while loading modules AC_DEFINE([_GLIBCXX_DEBUG], [1], [Enable extra debugging checks in libstdc++]) AC_DEFINE([_GLIBCXX_DEBUG_PEDANTIC], [1], [Enable extra debugging checks in libstdc++]) fi else if test "x$OPTIMIZE" = "xyes"; then appendCXX -O2 # In old times needed to define _FORTIFY_SOURCE to 2 ourself. # Then GCC started to define it itself to 2. It was ok. # But then GCC 4.7 started to define it to 0 or 2 depending on optimization level, and it started to conflict with our define. AC_MSG_CHECKING([whether compiler predefines _FORTIFY_SOURCE]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ ]], [[ #ifndef _FORTIFY_SOURCE #error "Just checking, nothing fatal here" #endif ]]) ], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) appendCXX "-D_FORTIFY_SOURCE=2" ]) fi fi if test "$IPV6" != "no"; then AC_DEFINE([HAVE_IPV6], [1], [Define if IPv6 support is enabled]) fi if test "x$GXX" = "xyes"; then appendCXX -Wall -W -Wno-unused-parameter -Woverloaded-virtual -Wshadow fi if test "$POLL" = "yes"; then # poll() is broken on Mac OS, it fails with POLLNVAL for pipe()s. if test -n "$ISDARWIN" then # Did they give us --enable-poll? if test -n "$enable_poll" then # Yes, they asked for this. AC_MSG_WARN([poll() is known to be broken on Mac OS X. You have been warned.]) else # No, our default value of "yes" got applied. AC_MSG_WARN([poll() is known to be broken on Mac OS X. Using select() instead.]) AC_MSG_WARN([Use --enable-poll for forcing poll() to be used.]) POLL=no fi fi if test "$POLL" = "yes"; then AC_DEFINE([CSOCK_USE_POLL], [1], [Use poll() instead of select()]) fi fi AC_CHECK_LIB( gnugetopt, getopt_long,) AC_CHECK_FUNCS([lstat getopt_long getpassphrase clock_gettime tcsetattr]) # ----- Check for dlopen AC_SEARCH_LIBS([dlopen], [dl], [], [AC_MSG_ERROR([Could not find dlopen. ZNC will not work on this box until you upgrade this ancient system or at least install the necessary system libraries.])]) # ----- Check for pthreads AX_PTHREAD([ AC_DEFINE([HAVE_PTHREAD], [1], [Define if you have POSIX threads libraries and header files.]) appendCXX "$PTHREAD_CFLAGS" appendLib "$PTHREAD_LIBS" ], [ AC_MSG_ERROR([This compiler/OS doesn't seem to support pthreads.]) ]) # Note that old broken systems, such as OpenBSD, NetBSD, which don't support AI_ADDRCONFIG, also have thread-unsafe getaddrinfo(). # Gladly, they fixed thread-safety before support of AI_ADDRCONFIG, so this can be abused to detect the thread-safe getaddrinfo(). # # TODO: drop support of blocking DNS at some point. OpenBSD supports AI_ADDRCONFIG since Nov 2014, and their getaddrinfo() is thread-safe since Nov 2013. NetBSD's one is thread-safe since ages ago. DNS_TEXT=blocking if test "x$TDNS" != "xno"; then old_TDNS=$TDNS AC_MSG_CHECKING([whether getaddrinfo() supports AI_ADDRCONFIG]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #include #include #include ]], [[ int x = AI_ADDRCONFIG; (void) x; ]]) ], [ AC_MSG_RESULT([yes]) TDNS=yes ], [ AC_MSG_RESULT([no]) TDNS=no ]) if test "x$TDNS" = "xyes"; then DNS_TEXT=threads AC_DEFINE([HAVE_THREADED_DNS], [1], [Define if threaded DNS is enabled]) else ZNC_AUTO_FAIL([TDNS], [support for threaded DNS not found. Try --disable-tdns. Disabling it may result in a slight performance decrease but will not have any other side-effects], [support for threaded DNS not found, so DNS resolving will be blocking]) fi fi # ----- Check for openssl SSL_TEXT="$SSL" if test "x$SSL" != "xno"; then old_SSL=$SSL PKG_CHECK_MODULES([openssl], [openssl], [ appendLib "$openssl_LIBS" appendCXX "$openssl_CFLAGS" ], [ # Don't reorder this! # On some arches libssl depends on libcrypto without linking to it :( AC_CHECK_LIB( crypto, BIO_new,, SSL=no ; SSL_TEXT="no (libcrypt not found)" ) AC_CHECK_LIB( ssl, SSL_shutdown,, SSL=no ; SSL_TEXT="no (libssl not found)" ) ]) if test "x$SSL" != "xno"; then AC_MSG_CHECKING([whether openssl is usable]) AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #include #include ]], [[ SSL_CTX* ctx = SSL_CTX_new(SSLv23_method()); SSL* ssl = SSL_new(ctx); DH* dh = DH_new(); DH_free(dh); SSL_free(ssl); SSL_CTX_free(ctx); ]]) ], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) SSL=no SSL_TEXT="no (openssl not usable)" ]) fi if test "x$SSL" = "xno" ; then ZNC_AUTO_FAIL([SSL], [OpenSSL not found. Try --disable-openssl.], [OpenSSL was not found and thus disabled]) NOSSL=1 else AC_DEFINE([HAVE_LIBSSL], [1], [Define if openssl is enabled]) SSL=yes SSL_TEXT=yes fi else NOSSL=1 SSL_TEXT="no (explicitly disabled)" fi # ----- Check for zlib old_ZLIB="$ZLIB" ZLIB_TEXT="$ZLIB" if test "x$ZLIB" != "xno"; then AC_MSG_CHECKING([whether zlib is usable]) my_saved_LIBS="$LIBS" appendLib "-lz" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include "zlib.h" ]], [[ z_stream zs; (void) deflateInit2(&zs, 0, 0, 0, 0, 0); (void) deflate(&zs, 0); ]]) ], [ AC_MSG_RESULT([yes]) ZLIB=yes ZLIB_TEXT=yes ], [ AC_MSG_RESULT([no]) ZLIB=no ZLIB_TEXT="no (libz not found)" ]) if test "x$ZLIB" = "xno"; then ZNC_AUTO_FAIL([ZLIB], [zlib was not found. Try --disable-zlib], [zlib was not found and thus disabled]) LIBS="$my_saved_LIBS" else AC_DEFINE([HAVE_ZLIB], [1], [Define if zlib is available]) fi fi AC_ARG_ENABLE( [charset], AS_HELP_STRING([--disable-charset], [disable ICU support]), [HAVE_ICU="$enableval"], [HAVE_ICU="auto"]) if test "x$HAVE_ICU" != "xno" then old_HAVE_ICU="$HAVE_ICU" PKG_CHECK_MODULES([icu], [icu-uc], [ appendLib "$icu_LIBS" appendCXX "$icu_CFLAGS" HAVE_ICU=yes AC_DEFINE([HAVE_ICU], [1], [Enable ICU library for Unicode handling]) AC_DEFINE([U_USING_ICU_NAMESPACE], [0], [Do not clutter global namespace with ICU C++ stuff]) ], [ ZNC_AUTO_FAIL([HAVE_ICU], [support for charset conversion not found. Try --disable-charset.], [support for charset conversion not found and thus disabled]) HAVE_ICU="no (icu-uc not found via pkg-config)" ]) fi # For integration test only PKG_CHECK_MODULES([qt], [Qt5Network >= 5.4], [], [:]) AC_ARG_WITH( [module-prefix], AS_HELP_STRING([--with-module-prefix], [module object code [LIBDIR/znc]]), [MODDIR=$withval], [MODDIR="${libdir}/znc"] ) AC_ARG_WITH( [module-data-prefix], AS_HELP_STRING([--with-module-data-prefix=DIR], [static module data (webadmin skins) [DATADIR/znc]]), [DATADIR=$withval], [DATADIR="${datadir}/znc"] ) appendMod "$CXXFLAGS" appendMod "$CFLAG_VISIBILITY" if test -z "$ISSUN" -a -z "$ISDARWIN" -a -z "$ISCYGWIN"; then # This is an unknown compiler flag on some OS appendLD -Wl,--export-dynamic fi if test -z "$ISCYGWIN" ; then # cygwin doesn't need -fPIC, everything else does (for modules) # warning: -fPIC ignored for target (all code is position independent) appendMod -fPIC else # But cygwin does want most of ZNC in a shared lib # See https://cygwin.com/ml/cygwin-apps/2015-07/msg00108.html for the reasoning behind the name. LIBZNC="cygznc-${LIBZNC_VERSION}.dll" LIBZNCDIR="$bindir" # See above about __STRICT_ANSI__ qt_CFLAGS="$qt_CFLAGS -U__STRICT_ANSI__" fi if test -z "$ISDARWIN"; then MODLINK="-shared" else # Mac OS X differentiates between shared libs (-dynamiclib) # and loadable modules (-bundle). MODLINK="-bundle -flat_namespace -undefined suppress" # TODO test if -twolevel_namespace and/or # -undefined dynamic_lookup work # (dynamic_lookup might only work on 10.4 and later) fi if test "x$PERL" != xno -o "x$PYTHON" != xno; then old_USESWIG="$USESWIG" if test "x$USESWIG" != "xno"; then AC_PROG_SWIG([3.0.0]) test -z "$SWIG" && USESWIG=no if test "x$USESWIG" = xno -a "x$old_USESWIG" = yes; then AC_MSG_ERROR([Could not found appropriate SWIG installation. Check config.log for details.]) fi fi if test -r "$srcdir/modules/modperl/generated.tar.gz" -a -r "$srcdir/modules/modpython/generated.tar.gz"; then AC_MSG_NOTICE([modperl/modpython files are found, disabling SWIG]) USESWIG=no fi if test "x$USESWIG" = xno; then if test ! -r "$srcdir/modules/modperl/generated.tar.gz" -o ! -r "$srcdir/modules/modpython/generated.tar.gz"; then AC_MSG_ERROR([Can not build modperl/modpython. Either install SWIG, or build ZNC from a tarball, or disable modperl/modpython. Check config.log for details.]) else AC_MSG_NOTICE([modperl/modpython files are found, no SWIG needed]) fi USESWIG="not needed" SWIG="" else USESWIG=yes fi else if test "x$USESWIG" = "xyes"; then AC_MSG_WARN([swig is used only for perl and python, but both are disabled. Disabling swig.]) fi USESWIG='not needed' fi PERL_TEXT="$PERL" if test "x$PERL" != "xno"; then old_PERL="$PERL" AC_PATH_PROG([PERL_BINARY], [perl], []) if test -n "$PERL_BINARY" && eval "$PERL_BINARY -e'use 5.010'"; then my_saved_LDFLAGS="$LDFLAGS" appendLD `$PERL_BINARY -MExtUtils::Embed -e ccopts -e ldopts` AC_CHECK_LIB(perl, perl_alloc, [: No, we do not want autoconf to do sth automatically], PERL="no" ; PERL_TEXT="no (libperl not found)") LDFLAGS="$my_saved_LDFLAGS" else PERL="no" PERL_TEXT="no (perl binary not found or too old)" fi if test "x$PERL" = "xno"; then ZNC_AUTO_FAIL([PERL], [perl not found. Try --disable-perl.], [perl was not found and thus disabled]) PERL_BINARY="" else PERL="yes" PERL_TEXT="yes" fi fi PYTHON_TEXT="$PYTHON" if test "x$PYTHON" != "xno"; then # Default value for just --enable-python if test "x$PYTHON" = "xyes"; then PYTHON="python3" fi old_PYTHON="$PYTHON" if test -z "$PKG_CONFIG"; then AC_MSG_ERROR([pkg-config is required for modpython.]) fi PKG_CHECK_MODULES([python], [$PYTHON-embed >= 3.0],, [ PKG_CHECK_MODULES([python], [$PYTHON >= 3.0],, AC_MSG_ERROR([$PYTHON.pc not found or is wrong. Try --disable-python or install python3.])) ]) my_saved_LIBS="$LIBS" my_saved_CXXFLAGS="$CXXFLAGS" appendLib $python_LIBS appendCXX $python_CFLAGS AC_CHECK_FUNC([Py_Initialize], [], [PYTHON="no" ; PYTHON_TEXT="no (libpython not found)"]) if test "x$PYTHON" != "xno"; then # Yes, modpython depends on perl. AC_PATH_PROG([PERL_BINARY], [perl]) if test -z "$PERL_BINARY"; then AC_MSG_ERROR([To compile modpython you need to be able to execute perl scripts. Try --disable-python or install perl.]) fi LIBS="$my_saved_LIBS" CXXFLAGS="$my_saved_CXXFLAGS" fi if test "x$HAVE_ICU" != "xyes"; then AC_MSG_ERROR([Modpython requires ZNC to be compiled with charset support, but ICU library not found. Try --disable-python or install libicu.]) fi if test "x$PYTHON" = "xno"; then ZNC_AUTO_FAIL([PYTHON], [python not found. Try --disable-python.], [python was not found and thus disabled]) PYTHONCFG_BINARY="" else PYTHON="yes" PYTHON_TEXT="yes" fi fi if test -n "$CYRUS"; then AC_CHECK_LIB( sasl2, sasl_server_init, [: Dont let autoconf add -lsasl2, Makefile handles that], AC_MSG_ERROR([could not find libsasl2. Try --disable-cyrus.])) fi # Check if we want modtcl AC_ARG_ENABLE( [tcl], AS_HELP_STRING([--enable-tcl], [enable modtcl]), [TCL="$enableval"], [TCL="no"]) AC_ARG_WITH( [tcl-flags], AS_HELP_STRING([--with-tcl-flags=FLAGS], [The flags needed for compiling and linking modtcl]), [TCL_FLAGS="$withval"],) if test x"$TCL" = "xyes" then AC_ARG_WITH( [tcl], AS_HELP_STRING([--with-tcl=DIR], [directory containing tclConfig.sh]), TCL_DIR="${withval}") # This will need to be extended in the future, but I don't think # it's a good idea to stuff a shitload of random stuff in here right now for path in $TCL_DIR /usr/lib /usr/lib/tcl8.4 /usr/lib/tcl8.5 /usr/lib/tcl8.6 do file="${path}/tclConfig.sh" AC_MSG_CHECKING([for ${file}]) if test -r ${file} then TCL_CONF=${file} AC_MSG_RESULT([yes]) break fi AC_MSG_RESULT([no]) done if test x"${TCL_CONF}" = x then # They --enable-tcl'd, so give them some sane default TCL_FLAGS="-I/usr/include/tcl -ltcl" AC_MSG_WARN([Could not find tclConfig.sh, using some sane defaults.]) else AC_MSG_CHECKING([modtcl flags]) . ${TCL_CONF} # eval because those vars depend on other vars in there eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_INCLUDE_SPEC=\"${TCL_INCLUDE_SPEC}\"" TCL_FLAGS="$TCL_INCLUDE_SPEC $TCL_LIB_SPEC" AC_MSG_RESULT([$TCL_FLAGS]) fi my_saved_LIBS="$LIBS" appendLib "$TCL_FLAGS" AC_CHECK_FUNC([Tcl_CreateInterp], [TCL_TEST=yes], [TCL_TEST=no]) if test x"$TCL_TEST" = "xno"; then AC_MSG_ERROR([tcl not found, try --disable-tcl, or install tcl properly. If tcl is installed to a non-standard path, use --enable-tcl --with-tcl=/path]) fi LIBS="$my_saved_LIBS" fi AC_CACHE_CHECK([for GNU make], [ac_cv_path_GNUMAKE], [ AC_PATH_PROGS_FEATURE_CHECK([GNUMAKE], [make gmake], [[ if $ac_path_GNUMAKE --version | $GREP GNU > /dev/null; then ac_cv_path_GNUMAKE=$ac_path_GNUMAKE ac_path_GNUMAKE_found=: fi ]], [AC_MSG_ERROR([could not find GNU make])] ) ]) GNUMAKE=`echo $ac_cv_path_GNUMAKE | $SED "s%.*/%%"` # this is in the end, for not trying to include it when it doesn't exist yet appendCXX "-include znc/zncconfig.h" appendMod "-include znc/zncconfig.h" AC_SUBST([CXXFLAGS]) AC_SUBST([CPPFLAGS]) AC_SUBST([MODFLAGS]) AC_SUBST([LDFLAGS]) AC_SUBST([LIBS]) AC_SUBST([LIBZNC]) AC_SUBST([LIBZNCDIR]) AC_SUBST([ISCYGWIN]) AC_SUBST([MODLINK]) AC_SUBST([NOSSL]) AC_SUBST([TCL_FLAGS]) AC_SUBST([CYRUS]) AC_SUBST([MODDIR]) AC_SUBST([DATADIR]) AC_SUBST([PERL]) AC_SUBST([PYTHON]) AC_SUBST([SWIG]) AC_SUBST([python_CFLAGS]) AC_SUBST([python_LIBS]) AC_SUBST([qt_CFLAGS]) AC_SUBST([qt_LIBS]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([znc-buildmod]) AC_CONFIG_FILES([man/Makefile]) AC_CONFIG_FILES([znc.pc]) AC_CONFIG_FILES([znc-uninstalled.pc]) AC_CONFIG_FILES([modules/Makefile]) AC_OUTPUT if test "x$ISCYGWIN" = x1; then # Side effect of undefining __STRICT_ANSI__ # http://llvm.org/bugs/show_bug.cgi?id=13530 echo >> include/znc/zncconfig.h echo '#ifndef ZNCCONFIG_H_ADDITIONS' >> include/znc/zncconfig.h echo '#define ZNCCONFIG_H_ADDITIONS' >> include/znc/zncconfig.h echo '#ifdef __clang__' >> include/znc/zncconfig.h echo 'struct __float128;' >> include/znc/zncconfig.h echo '#endif' >> include/znc/zncconfig.h echo '#endif' >> include/znc/zncconfig.h fi echo echo ZNC AC_PACKAGE_VERSION configured echo echo "The configure script is deprecated and will be removed from ZNC" echo "in some future version. Use either CMake or the convenience wrapper" echo "configure.sh which takes the same parameters as configure." echo echo "prefix: $prefix" echo "debug: $DEBUG" echo "ipv6: $IPV6" echo "openssl: $SSL_TEXT" echo "dns: $DNS_TEXT" echo "perl: $PERL_TEXT" echo "python: $PYTHON_TEXT" echo "swig: $USESWIG" if test x"$CYRUS" = "x" ; then echo "cyrus: no" else echo "cyrus: yes" fi if test x"$TCL_FLAGS" = "x" ; then echo "tcl: no" else echo "tcl: yes" fi echo "charset: $HAVE_ICU" echo "zlib: $ZLIB_TEXT" echo "run from src: $RUNFROMSOURCE" echo echo "Now you can run \"$GNUMAKE\" to compile ZNC" znc-1.7.5/NOTICE0000644000175000017500000000575613542151610013461 0ustar somebodysomebodyZNC === ZNC includes code from Csocket (https://github.com/jimloco/Csocket), licensed under the Sleepycat-alike License. ZNC includes code generated by SWIG (http://www.swig.org), not governed by SWIG's license. ZNC includes code of autoconf macro AX_CXX_COMPILE_STDCXX_11, its permissive license is inside the file. ZNC includes modified code of autoconf macro AX_PTHREAD, licensed under the GPLv3+. ZNC includes modified code of autoconf macro AC_PROG_SWIG, licensed under the GPLv2+ with Autoconf Exception. ZNC includes modified code of autoconf macro AM_ICONV, licensed under the FSF Unlimited License. ZNC includes modified code of autoconf macro gl_VISIBILITY, licensed under the FSF Unlimited License. ZNC includes modified code of MD5 implementation by Christophe Devine, licensed under the GPLv2+. ZNC includes resized External Wikipedia icon (https://commons.wikimedia.org/wiki/File:External.svg), which is in the public domain. ZNC includes modified code for SSL verification by Alban Diquet (https://github.com/iSECPartners/ssl-conservatory/) and Daniel Stenberg (https://github.com/bagder/curl/blob/master/lib/), licensed under the MIT License. ZNC includes code from jQuery (http://jquery.com/), licensed under the MIT License. ZNC includes code from jQuery UI (http://jqueryui.com/), licensed under the MIT License. ZNC includes code from Selectize (http://brianreavis.github.io/selectize.js/), licensed under the Apache License 2.0. ZNC includes modified code from CMakeFindFrameworks.cmake by Kitware, Inc., licensed under BSD License. ZNC includes modified code from TestLargeFiles.cmake, licensed under Boost Software License, Version 1.0. ZNC is developed by these people: Prozac Jim Hull Uli Schlachter SilverLeo kroimon flakes Alexey "DarthGandalf" Sokolov Kyle Fuller These people, in no particular order, have helped develop ZNC, for example by sending in patches, writing new modules or finding significant bugs: Kuja - runs and pays for znc.in derblubber toby Zack3000 d4n13L - graphiX webadmin skin Veit "Cru" Wahlich crox Freman (http://fremnet.net/contact) Sebastian Ramacher cnu - master of destruction (security issues) Ingmar "KiNgMaR" Runge Michael "Svedrin" Ziegler Robert Lacroix (http://www.robertlacroix.com) Martin "Nirjen" Martimeo Reed Loden Brian Campbell (bcampbell@splafinga.com) Joshua M. Clulow (http://sysmgr.org) evaryont Michael "adgar" Edgar Jens-Andre "vain" Koch Heiko Hund - cyrusauth module Philippe (http://sourceforge.net/users/cycomate) - kickrejoin module J-P Nurmi Thomas Ward If you did something useful and want to be listed here too, add yourself and submit the patch. znc-1.7.5/config.sub0000755000175000017500000010741513542151642014540 0ustar somebodysomebody#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2017 Free Software Foundation, Inc. timestamp='2017-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx | dvp \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pru \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; leon|leon[3-9]) basic_machine=sparc-$basic_machine ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pru-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; asmjs) basic_machine=asmjs-unknown ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; e500v[12]) basic_machine=powerpc-unknown os=$os"spe" ;; e500v[12]-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` os=$os"spe" ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; leon-*|leon[3-9]-*) basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mipsEE* | ee | ps2) basic_machine=mips64r5900el-scei case $os in -linux*) ;; *) os=-elf ;; esac ;; iop) basic_machine=mipsel-scei os=-irx ;; dvp) basic_machine=dvp-scei os=-elf ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -irx* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -ios) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; pru-*) os=-elf ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: znc-1.7.5/configure.sh0000755000175000017500000001062613542151610015065 0ustar somebodysomebody#!/bin/sh # # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # http://stackoverflow.com/questions/18993438/shebang-env-preferred-python-version # http://stackoverflow.com/questions/12070516/conditional-shebang-line-for-different-versions-of-python """:" which python3 >/dev/null 2>&1 && exec python3 "$0" "$@" which python >/dev/null 2>&1 && exec python "$0" "$@" which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" echo "Error: configure wrapper requires python" exec echo "Either install python, or use cmake directly" ":""" import argparse import os import subprocess import sys import re extra_args = [os.path.dirname(sys.argv[0])] parser = argparse.ArgumentParser() def gnu_install_dir(name, cmake=None): if cmake is None: cmake = name.upper() parser.add_argument('--' + name, action='append', metavar=cmake, dest='cm_args', type=lambda s: '-DCMAKE_INSTALL_{}={}'.format(cmake, s)) gnu_install_dir('prefix') gnu_install_dir('bindir') gnu_install_dir('sbindir') gnu_install_dir('libexecdir') gnu_install_dir('sysconfdir') gnu_install_dir('sharedstatedir') gnu_install_dir('localstatedir') gnu_install_dir('libdir') gnu_install_dir('includedir') gnu_install_dir('oldincludedir') gnu_install_dir('datarootdir') gnu_install_dir('datadir') gnu_install_dir('infodir') gnu_install_dir('localedir') gnu_install_dir('mandir') gnu_install_dir('docdir') group = parser.add_mutually_exclusive_group() group.add_argument('--enable-debug', action='store_const', dest='build_type', const='Debug', default='Release') group.add_argument('--disable-debug', action='store_const', dest='build_type', const='Release', default='Release') def tristate(name, cmake=None): if cmake is None: cmake = name.upper() group = parser.add_mutually_exclusive_group() group.add_argument('--enable-' + name, action='append_const', dest='cm_args', const='-DWANT_{}=YES'.format(cmake)) group.add_argument('--disable-' + name, action='append_const', dest='cm_args', const='-DWANT_{}=NO'.format(cmake)) tristate('ipv6') tristate('openssl') tristate('zlib') tristate('perl') tristate('swig') tristate('cyrus') tristate('charset', 'ICU') tristate('tcl') tristate('i18n') class HandlePython(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): extra_args.append('-DWANT_PYTHON=YES') if values is not None: extra_args.append('-DWANT_PYTHON_VERSION=' + values) group = parser.add_mutually_exclusive_group() group.add_argument('--enable-python', action=HandlePython, nargs='?', metavar='PYTHON_VERSION') group.add_argument('--disable-python', action='append_const', dest='cm_args', const='-DWANT_PYTHON=NO') parser.add_argument('--with-gtest', action='store', dest='gtest') parser.add_argument('--with-gmock', action='store', dest='gmock') class HandleSystemd(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): extra_args.append('-DWANT_SYSTEMD=YES') if values is not None: extra_args.append('-DWANT_SYSTEMD_DIR=' + values) parser.add_argument('--with-systemdsystemunitdir', action=HandleSystemd, nargs='?', metavar='UNITDIR') def env_type(s): name, value = s.split('=', 1) return (name, value) parser.add_argument('env', nargs='*', type=env_type, metavar='ENV_VAR=VALUE') args = parser.parse_args() cm_args = args.cm_args or [] for env_key, env_value in args.env: os.environ[env_key] = env_value if args.gtest: os.environ['GTEST_ROOT'] = args.gtest if args.gmock: os.environ['GMOCK_ROOT'] = args.gmock if os.environ.get('CXX') is not None: extra_args.append('-DCMAKE_CXX_COMPILER=' + os.environ['CXX']) try: os.remove('CMakeCache.txt') except OSError: pass subprocess.check_call(['cmake', '-DCMAKE_BUILD_TYPE=' + args.build_type] + cm_args + extra_args) znc-1.7.5/CONTRIBUTING.md0000644000175000017500000000171413542151610014774 0ustar somebodysomebodyReporting bugs ============== * When reporting a bug: * Please ensure that you are on the latest version in case the bug you are reporting is already fixed. * If you did some custom modification to ZNC, please make sure that the bug isn't caused by that modification. * Please include the following information: * OS/distribution version * `/znc version` * If you are reporting a crash, please see [the debugging page] on wiki.znc.in. * If you are reporting an issue with connectivity, please run ZNC in debug mode and include the relevant part of the output. To enable debug mode, run ZNC with the `-D` flag. [The debugging page]:https://wiki.znc.in/Debugging Code changes ============ * Follow the exact same conventions and style of the file you change. * For deciding which branch to pull request, please see [the branches page] on wiki.znc.in. [The branches page]:https://wiki.znc.in/Branches znc-1.7.5/znc.pc.in0000644000175000017500000000076413542151610014272 0ustar somebodysomebody# You can access these with e.g. pkg-config --variable=moddir znc prefix=@prefix@ exec_prefix=@exec_prefix@ datarootdir=@datarootdir@ bindir=@bindir@ libdir=@libdir@ datadir=@datadir@ includedir=@includedir@ cxx=@CXX@ CPPFLAGS=@CPPFLAGS@ MODFLAGS=@MODFLAGS@ version=@PACKAGE_VERSION@ moddir=@MODDIR@ moddatadir=@DATADIR@ modlink=@MODLINK@ INC_PATH=-I${includedir}/znc Name: ZNC Description: An advanced IRC proxy Version: ${version} URL: https://znc.in Cflags: ${CPPFLAGS} ${MODFLAGS} ${INC_PATH} znc-1.7.5/README.md0000644000175000017500000001564013542151610014025 0ustar somebodysomebody# [![ZNC](https://wiki.znc.in/resources/assets/wiki.png)](https://znc.in) - An advanced IRC bouncer [![Travis Build Status](https://img.shields.io/travis/znc/znc/master.svg?label=linux%2Fmacos)](https://travis-ci.org/znc/znc) [![Jenkins Build Status](https://img.shields.io/jenkins/s/https/jenkins.znc.in/job/znc/job/znc/job/master.svg?label=freebsd)](https://jenkins.znc.in/job/znc/job/znc/job/master/) [![AppVeyor Build status](https://img.shields.io/appveyor/ci/DarthGandalf/znc/master.svg?label=windows)](https://ci.appveyor.com/project/DarthGandalf/znc/branch/master) [![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=1759)](https://www.bountysource.com/trackers/1759-znc?utm_source=1759&utm_medium=shield&utm_campaign=TRACKER_BADGE) [![Coverage Status](https://img.shields.io/codecov/c/github/znc/znc.svg)](https://codecov.io/gh/znc/znc) [![Coverity Scan Build Status](https://img.shields.io/coverity/scan/6778.svg)](https://scan.coverity.com/projects/znc-coverity) ## Table of contents - [Minimal Requirements](#minimal-requirements) - [Optional Requirements](#optional-requirements) - [Installing ZNC](#installing-znc) - [Setting up znc.conf](#setting-up-zncconf) - [Special config options](#special-config-options) - [Using ZNC](#using-znc) - [File Locations](#file-locations) - [ZNC's config file](#zncs-config-file) - [Writing own modules](#writing-own-modules) - [Further information](#further-information) ## Minimal Requirements Core: * GNU make * pkg-config * GCC 4.8 or clang 3.2 * Either of: * autoconf and automake (but only if building from git, not from tarball) * CMake ## Optional Requirements SSL/TLS support: * openssl 0.9.7d or later * try installing openssl-dev, openssl-devel or libssl-dev * macOS: OpenSSL from Homebrew is preferred over system modperl: * perl and its bundled libperl * SWIG if building from git modpython: * python3 and its bundled libpython * perl is a build dependency * macOS: Python from Homebrew is preferred over system version * SWIG if building from git cyrusauth: * This module needs cyrus-sasl2 Character Encodings: * To get proper character encoding and charsets install ICU (`libicu4-dev`) I18N (UI translation) * CMake-based build only * Boost.Locale * gettext is a build dependency ## Installing ZNC Currently there are 2 build systems in place: CMake and `./configure`. `./configure` will eventually be removed. There is also `configure.sh` which should make migration to CMake easier: it accepts the same parameters as `./configure`, but calls CMake with CMake-style parameters. ### Installing with CMake Installation from source code is performed using the CMake toolchain. ```shell mkdir build cd build cmake .. make make install ``` You can use `cmake-gui` or `ccmake` for more interactiveness. Note for FreeBSD users: By default base OpenSSL is selected. If you want the one from ports, use `-DOPENSSL_ROOT_DIR=/usr/local`. For troubleshooting, `cmake --system-information` will show you details. ### Installing with `./configure` Installation from source code is performed using the `automake` toolchain. If you are building from git, you will need to run `./autogen.sh` first to produce the `configure` script. ```shell mkdir build cd build ../configure make make install ``` You can use `./configure --help` if you want to get a list of options, though the defaults should be suiting most needs. ## Setting up znc.conf For setting up a configuration file in `~/.znc` you can simply do `znc --makeconf` or `./znc --makeconf` for in-place execution. If you are using SSL you should do `znc --makepem` ## Special config options When you create your ZNC configuration file via --makeconf, you are asked two questions which might not be easy to understand. > Number of lines to buffer per channel How many messages should be buffered for each channel. When you connect to ZNC you get a buffer replay for each channel which shows what was said last. This option selects the number of lines this replay should consist of. Increasing this can greatly increase ZNC's memory usage if you are hosting many users. The default value should be fine for most setups. > Would you like to keep buffers after replay? If this is disabled, you get the buffer playback only once and then it is deleted. If this is enabled, the buffer is not deleted. This may be useful if you regularly use more than one client to connect to ZNC. ## Using ZNC Once you have started ZNC you can connect with your favorite IRC-client to ZNC. You should use `username:password` as the server password (e.g. `/pass user:pass`). Once you are connected you can do `/msg *status help` for some commands. Every module you have loaded (`/msg *status listmods`) should additionally provide `/msg *modulename help` ## File Locations In its data dir (`~/.znc` is default) ZNC saves most of its data. The only exception are modules and module data, which are saved in `/lib/znc` and `/share/znc`, and the znc binary itself. More modules (e.g. if you install some later) can be saved in `/modules` (-> `~/.znc/modules`). In the datadir is only one file: - `znc.pem` - This is the server certificate ZNC uses for listening and is created with `znc --makepem`. These directories are also in there: - configs - Contains `znc.conf` (ZNC's config file) and backups of older configs. - modules - ZNC also looks in here for a module. - moddata - Global modules save their settings here. (e.g. webadmin saves the current skin name in here) - users - This is per-user data and mainly contains just a moddata directory. ## ZNC's config file This file shouldn't be too hard too understand. An explanation of all the items can be found on the [Configuration](https://wiki.znc.in/Configuration) page. **Warning: it is better not to edit config while ZNC is running.** Use the [webadmin] and [controlpanel] modules instead. [webadmin]:https://wiki.znc.in/Webadmin [controlpanel]:https://wiki.znc.in/Controlpanel If you changed some settings while ZNC is running, a simple `pkill -SIGUSR1 znc` will make ZNC rewrite its config file. Alternatively you can use `/msg *status saveconfig` ## Writing own modules You can write your own modules in either C++, python or perl. C++ modules are compiled by either saving them in the modules source dir and running make or with the `znc-buildmod` shell script. For additional info look in the wiki: - [Writing modules](https://wiki.znc.in/Writing_modules) Perl modules are loaded through the global module [ModPerl](https://wiki.znc.in/Modperl). Python modules are loaded through the global module [ModPython](https://wiki.znc.in/Modpython). ## Further information Please visit https://znc.in/ or #znc on freenode if you still have questions: - [freenode webchat](https://webchat.freenode.net/?nick=znc_....&channels=znc) - [ircs://irc.freenode.net:6697/znc](ircs://irc.freenode.net:6697/znc) You can get the latest development version with git: `git clone https://github.com/znc/znc.git --recursive` znc-1.7.5/znc-uninstalled.pc.in0000644000175000017500000000112013542151610016575 0ustar somebodysomebody# You can access these with e.g. pkg-config --variable=moddir znc prefix=@prefix@ exec_prefix=@exec_prefix@ datarootdir=@datarootdir@ bindir=@bindir@ libdir=@libdir@ datadir=@datadir@ includedir=@includedir@ cxx=@CXX@ CPPFLAGS=@CPPFLAGS@ MODFLAGS=@MODFLAGS@ version=@PACKAGE_VERSION@ moddir=@MODDIR@ moddatadir=@DATADIR@ modlink=@MODLINK@ # This and the following two lines should be the only differences to znc.pc.in srcdir=@abs_srcdir@ INC_PATH=-I${srcdir}/ Name: ZNC Description: An advanced IRC proxy Version: ${version} URL: https://znc.in Cflags: ${CPPFLAGS} ${MODFLAGS} ${INC_PATH} znc-1.7.5/third_party/0000755000175000017500000000000013542151610015071 5ustar somebodysomebodyznc-1.7.5/third_party/googletest/0000755000175000017500000000000013542151610017245 5ustar somebodysomebodyznc-1.7.5/third_party/Csocket/0000755000175000017500000000000013542151610016464 5ustar somebodysomebodyznc-1.7.5/third_party/Csocket/Csocket.cc0000644000175000017500000033101413322046236020373 0ustar somebodysomebody/** * @file Csocket.cc * @author Jim Hull * * Copyright (c) 1999-2012 Jim Hull * All rights reserved * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * Redistributions in any form must be accompanied by information on how to obtain * complete source code for this software and any accompanying software that uses this software. * The source code must either be included in the distribution or be available for no more than * the cost of distribution plus a nominal fee, and must be freely redistributable * under reasonable conditions. For an executable file, complete source code means the source * code for all modules it contains. It does not include source code for modules or files * that typically accompany the major components of the operating system on which the executable file runs. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OF THIS SOFTWARE BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*** * doing this because there seems to be a bug that is losing the "short" on htons when in optimize mode turns into a macro * gcc 4.3.4 */ #if defined(__OPTIMIZE__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 3 #pragma GCC diagnostic warning "-Wconversion" #endif /* defined(__OPTIMIZE__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 3 */ #include "Csocket.h" #ifdef __NetBSD__ #include #endif /* __NetBSD__ */ #ifdef HAVE_LIBSSL #include #include #include #include #ifndef OPENSSL_NO_COMP #include #endif #define HAVE_ERR_REMOVE_STATE #ifdef OPENSSL_VERSION_NUMBER # if OPENSSL_VERSION_NUMBER >= 0x10000000 # undef HAVE_ERR_REMOVE_STATE # define HAVE_ERR_REMOVE_THREAD_STATE # endif # if OPENSSL_VERSION_NUMBER < 0x10001000 # define OPENSSL_NO_TLS1_1 /* 1.0.1-pre~: openssl/openssl@637f374ad49d5f6d4f81d87d7cdd226428aa470c */ # define OPENSSL_NO_TLS1_2 /* 1.0.1-pre~: openssl/openssl@7409d7ad517650db332ae528915a570e4e0ab88b */ # endif # ifndef LIBRESSL_VERSION_NUMBER /* forked from OpenSSL 1.0.1g, sets high version "with the idea of discouraging software from relying on magic numbers for detecting features"(!) */ # if OPENSSL_VERSION_NUMBER >= 0x10100000 # undef HAVE_ERR_REMOVE_THREAD_STATE /* 1.1.0-pre4: openssl/openssl@8509dcc9f319190c565ab6baad7c88d37a951d1c */ # undef OPENSSL_NO_SSL2 /* 1.1.0-pre4: openssl/openssl@e80381e1a3309f5d4a783bcaa508a90187a48882 */ # define OPENSSL_NO_SSL2 /* 1.1.0-pre1: openssl/openssl@45f55f6a5bdcec411ef08a6f8aae41d5d3d234ad */ # define HAVE_FLEXIBLE_TLS_METHOD /* 1.1.0-pre1: openssl/openssl@32ec41539b5b23bc42503589fcc5be65d648d1f5 */ # define HAVE_OPAQUE_SSL # endif # endif /* LIBRESSL_VERSION_NUMBER */ #endif /* OPENSSL_VERSION_NUMBER */ #endif /* HAVE_LIBSSL */ #ifdef HAVE_ICU #include #include #include #endif /* HAVE_ICU */ #include #include #define CS_SRANDBUFFER 128 /* * timeradd/timersub is missing on solaris' sys/time.h, provide * some fallback macros */ #ifndef timeradd #define timeradd(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ if ((result)->tv_usec >= 1000000) { \ ++(result)->tv_sec; \ (result)->tv_usec -= 1000000; \ } \ } while (0) #endif #ifndef timersub #define timersub(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((result)->tv_usec < 0) { \ --(result)->tv_sec; \ (result)->tv_usec += 1000000; \ } \ } while (0) #endif using std::stringstream; using std::ostream; using std::endl; using std::min; using std::vector; #define CREATE_ARES_VER( a, b, c ) ((a<<16)|(b<<8)|c) #ifndef _NO_CSOCKET_NS // some people may not want to use a namespace namespace Csocket { #endif /* _NO_CSOCKET_NS */ static int s_iCsockSSLIdx = 0; //!< this gets setup once in InitSSL int GetCsockSSLIdx() { return( s_iCsockSSLIdx ); } #ifdef _WIN32 #if defined(_WIN32) && (!defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)) //! thanks to KiNgMaR @ #znc for this wrapper static int inet_pton( int af, const char *src, void *dst ) { sockaddr_storage aAddress; int iAddrLen = sizeof( sockaddr_storage ); memset( &aAddress, 0, iAddrLen ); char * pTmp = strdup( src ); aAddress.ss_family = af; // this is important: // The function fails if the sin_family member of the SOCKADDR_IN structure is not set to AF_INET or AF_INET6. int iRet = WSAStringToAddressA( pTmp, af, NULL, ( sockaddr * )&aAddress, &iAddrLen ); free( pTmp ); if( iRet == 0 ) { if( af == AF_INET6 ) memcpy( dst, &( ( sockaddr_in6 * ) &aAddress )->sin6_addr, sizeof( in6_addr ) ); else memcpy( dst, &( ( sockaddr_in * ) &aAddress )->sin_addr, sizeof( in_addr ) ); return( 1 ); } return( -1 ); } #endif static inline void set_non_blocking( cs_sock_t fd ) { u_long iOpts = 1; ioctlsocket( fd, FIONBIO, &iOpts ); } /* * not used by anything anymore static inline void set_blocking(cs_sock_t fd) { u_long iOpts = 0; ioctlsocket( fd, FIONBIO, &iOpts ); } */ static inline void set_close_on_exec( cs_sock_t fd ) { // TODO add this for windows // see http://gcc.gnu.org/ml/java-patches/2002-q1/msg00696.html // for infos on how to do this } #else // _WIN32 static inline void set_non_blocking( cs_sock_t fd ) { int fdflags = fcntl( fd, F_GETFL, 0 ); if( fdflags < 0 ) return; // Ignore errors fcntl( fd, F_SETFL, fdflags|O_NONBLOCK ); } /* * not used by anything anymore static inline void set_blocking(cs_sock_t fd) { int fdflags = fcntl(fd, F_GETFL, 0); if( fdflags < 0 ) return; // Ignore errors fdflags &= ~O_NONBLOCK; fcntl( fd, F_SETFL, fdflags ); } */ static inline void set_close_on_exec( cs_sock_t fd ) { int fdflags = fcntl( fd, F_GETFD, 0 ); if( fdflags < 0 ) return; // Ignore errors fcntl( fd, F_SETFD, fdflags|FD_CLOEXEC ); } #endif /* _WIN32 */ void CSSockAddr::SinFamily() { #ifdef HAVE_IPV6 m_saddr6.sin6_family = PF_INET6; #endif /* HAVE_IPV6 */ m_saddr.sin_family = PF_INET; } void CSSockAddr::SinPort( uint16_t iPort ) { #ifdef HAVE_IPV6 m_saddr6.sin6_port = htons( iPort ); #endif /* HAVE_IPV6 */ m_saddr.sin_port = htons( iPort ); } void CSSockAddr::SetIPv6( bool b ) { #ifndef HAVE_IPV6 if( b ) { CS_DEBUG( "-DHAVE_IPV6 must be set during compile time to enable this feature" ); m_bIsIPv6 = false; return; } #endif /* HAVE_IPV6 */ m_bIsIPv6 = b; SinFamily(); } #ifdef HAVE_LIBSSL static int _PemPassCB( char *pBuff, int iBuffLen, int rwflag, void * pcSocket ) { Csock * pSock = static_cast( pcSocket ); const CS_STRING & sPassword = pSock->GetPemPass(); if( iBuffLen <= 0 ) return( 0 ); memset( pBuff, '\0', iBuffLen ); if( sPassword.empty() ) return( 0 ); int iUseBytes = min( iBuffLen - 1, ( int )sPassword.length() ); memcpy( pBuff, sPassword.data(), iUseBytes ); return( iUseBytes ); } static int _CertVerifyCB( int preverify_ok, X509_STORE_CTX *x509_ctx ) { Csock * pSock = GetCsockFromCTX( x509_ctx ); if( pSock ) return( pSock->VerifyPeerCertificate( preverify_ok, x509_ctx ) ); return( preverify_ok ); } static void _InfoCallback( const SSL * pSSL, int where, int ret ) { if( ( where & SSL_CB_HANDSHAKE_DONE ) && ret != 0 ) { Csock * pSock = static_cast( SSL_get_ex_data( pSSL, GetCsockSSLIdx() ) ); if( pSock ) pSock->SSLHandShakeFinished(); } } Csock * GetCsockFromCTX( X509_STORE_CTX * pCTX ) { Csock * pSock = NULL; SSL * pSSL = ( SSL * ) X509_STORE_CTX_get_ex_data( pCTX, SSL_get_ex_data_X509_STORE_CTX_idx() ); if( pSSL ) pSock = ( Csock * ) SSL_get_ex_data( pSSL, GetCsockSSLIdx() ); return( pSock ); } #endif /* HAVE_LIBSSL */ #ifdef USE_GETHOSTBYNAME // this issue here is getaddrinfo has a significant behavior difference when dealing with round robin dns on an // ipv4 network. This is not desirable IMHO. so when this is compiled without ipv6 support backwards compatibility // is maintained. static int __GetHostByName( const CS_STRING & sHostName, struct in_addr * paddr, u_int iNumRetries ) { int iReturn = HOST_NOT_FOUND; struct hostent * hent = NULL; #ifdef __linux__ char hbuff[2048]; struct hostent hentbuff; int err; for( u_int a = 0; a < iNumRetries; ++a ) { memset( ( char * ) hbuff, '\0', 2048 ); iReturn = gethostbyname_r( sHostName.c_str(), &hentbuff, hbuff, 2048, &hent, &err ); if( iReturn == 0 ) break; if( iReturn != TRY_AGAIN ) { CS_DEBUG( "gethostyname_r: " << hstrerror( h_errno ) ); break; } } if( !hent && iReturn == 0 ) iReturn = HOST_NOT_FOUND; #else for( u_int a = 0; a < iNumRetries; ++a ) { iReturn = HOST_NOT_FOUND; hent = gethostbyname( sHostName.c_str() ); if( hent ) { iReturn = 0; break; } if( h_errno != TRY_AGAIN ) { #ifndef _WIN32 CS_DEBUG( "gethostyname: " << hstrerror( h_errno ) ); #endif /* _WIN32 */ break; } } #endif /* __linux__ */ if( iReturn == 0 ) memcpy( &paddr->s_addr, hent->h_addr_list[0], sizeof( paddr->s_addr ) ); return( iReturn == TRY_AGAIN ? EAGAIN : iReturn ); } #endif /* !USE_GETHOSTBYNAME */ #ifdef HAVE_C_ARES void Csock::FreeAres() { if( m_pARESChannel ) { ares_destroy( m_pARESChannel ); m_pARESChannel = NULL; } } static void AresHostCallback( void * pArg, int status, int timeouts, struct hostent *hent ) { Csock * pSock = ( Csock * )pArg; if( status == ARES_SUCCESS && hent && hent->h_addr_list[0] != NULL ) { CSSockAddr * pSockAddr = pSock->GetCurrentAddr(); if( hent->h_addrtype == AF_INET ) { pSock->SetIPv6( false ); memcpy( pSockAddr->GetAddr(), hent->h_addr_list[0], sizeof( *( pSockAddr->GetAddr() ) ) ); } #ifdef HAVE_IPV6 else if( hent->h_addrtype == AF_INET6 ) { pSock->SetIPv6( true ); memcpy( pSockAddr->GetAddr6(), hent->h_addr_list[0], sizeof( *( pSockAddr->GetAddr6() ) ) ); } #endif /* HAVE_IPV6 */ else { status = ARES_ENOTFOUND; } } else { CS_DEBUG( ares_strerror( status ) ); if( status == ARES_SUCCESS ) { CS_DEBUG( "Received ARES_SUCCESS without any useful reply, using NODATA instead" ); status = ARES_ENODATA; } } pSock->SetAresFinished( status ); } #endif /* HAVE_C_ARES */ CGetAddrInfo::CGetAddrInfo( const CS_STRING & sHostname, Csock * pSock, CSSockAddr & csSockAddr ) : m_pSock( pSock ), m_csSockAddr( csSockAddr ) { m_sHostname = sHostname; m_pAddrRes = NULL; m_iRet = ETIMEDOUT; } CGetAddrInfo::~CGetAddrInfo() { if( m_pAddrRes ) freeaddrinfo( m_pAddrRes ); m_pAddrRes = NULL; } void CGetAddrInfo::Init() { memset( ( struct addrinfo * )&m_cHints, '\0', sizeof( m_cHints ) ); m_cHints.ai_family = m_csSockAddr.GetAFRequire(); m_cHints.ai_socktype = SOCK_STREAM; m_cHints.ai_protocol = IPPROTO_TCP; #ifdef AI_ADDRCONFIG // this is suppose to eliminate host from appearing that this system can not support m_cHints.ai_flags = AI_ADDRCONFIG; #endif /* AI_ADDRCONFIG */ if( m_pSock && ( m_pSock->GetType() == Csock::LISTENER || m_pSock->GetConState() == Csock::CST_BINDVHOST ) ) { // when doing a dns for bind only, set the AI_PASSIVE flag as suggested by the man page m_cHints.ai_flags |= AI_PASSIVE; } } int CGetAddrInfo::Process() { m_iRet = getaddrinfo( m_sHostname.c_str(), NULL, &m_cHints, &m_pAddrRes ); if( m_iRet == EAI_AGAIN ) return( EAGAIN ); else if( m_iRet == 0 ) return( 0 ); return( ETIMEDOUT ); } int CGetAddrInfo::Finish() { if( m_iRet == 0 && m_pAddrRes ) { std::list lpTryAddrs; bool bFound = false; for( struct addrinfo * pRes = m_pAddrRes; pRes; pRes = pRes->ai_next ) { // pass through the list building out a lean list of candidates to try. AI_CONFIGADDR doesn't always seem to work #ifdef __sun if( ( pRes->ai_socktype != SOCK_STREAM ) || ( pRes->ai_protocol != IPPROTO_TCP && pRes->ai_protocol != IPPROTO_IP ) ) #else if( ( pRes->ai_socktype != SOCK_STREAM ) || ( pRes->ai_protocol != IPPROTO_TCP ) ) #endif /* __sun work around broken impl of getaddrinfo */ continue; if( ( m_csSockAddr.GetAFRequire() != CSSockAddr::RAF_ANY ) && ( pRes->ai_family != m_csSockAddr.GetAFRequire() ) ) continue; // they requested a special type, so be certain we woop past anything unwanted lpTryAddrs.push_back( pRes ); } for( std::list::iterator it = lpTryAddrs.begin(); it != lpTryAddrs.end(); ) { // cycle through these, leaving the last iterator for the outside caller to call, so if there is an error it can call the events struct addrinfo * pRes = *it; bool bTryConnect = false; if( pRes->ai_family == AF_INET ) { if( m_pSock ) m_pSock->SetIPv6( false ); m_csSockAddr.SetIPv6( false ); struct sockaddr_in * pTmp = ( struct sockaddr_in * )pRes->ai_addr; memcpy( m_csSockAddr.GetAddr(), &( pTmp->sin_addr ), sizeof( *( m_csSockAddr.GetAddr() ) ) ); if( m_pSock && m_pSock->GetConState() == Csock::CST_DESTDNS && m_pSock->GetType() == Csock::OUTBOUND ) { bTryConnect = true; } else { bFound = true; break; } } #ifdef HAVE_IPV6 else if( pRes->ai_family == AF_INET6 ) { if( m_pSock ) m_pSock->SetIPv6( true ); m_csSockAddr.SetIPv6( true ); struct sockaddr_in6 * pTmp = ( struct sockaddr_in6 * )pRes->ai_addr; memcpy( m_csSockAddr.GetAddr6(), &( pTmp->sin6_addr ), sizeof( *( m_csSockAddr.GetAddr6() ) ) ); if( m_pSock && m_pSock->GetConState() == Csock::CST_DESTDNS && m_pSock->GetType() == Csock::OUTBOUND ) { bTryConnect = true; } else { bFound = true; break; } } #endif /* HAVE_IPV6 */ ++it; // increment the iterator her so we know if its the last element or not if( bTryConnect && it != lpTryAddrs.end() ) { // save the last attempt for the outer loop, the issue then becomes that the error is thrown on the last failure if( m_pSock->CreateSocksFD() && m_pSock->Connect() ) { m_pSock->SetSkipConnect( true ); // this tells the socket that the connection state has been started bFound = true; break; } m_pSock->CloseSocksFD(); } else if( bTryConnect ) { bFound = true; } } if( bFound ) // the data pointed to here is invalid now, but the pointer itself is a good test { return( 0 ); } } return( ETIMEDOUT ); } int CS_GetAddrInfo( const CS_STRING & sHostname, Csock * pSock, CSSockAddr & csSockAddr ) { #ifdef USE_GETHOSTBYNAME if( pSock ) pSock->SetIPv6( false ); csSockAddr.SetIPv6( false ); int iRet = __GetHostByName( sHostname, csSockAddr.GetAddr(), 3 ); return( iRet ); #else CGetAddrInfo cInfo( sHostname, pSock, csSockAddr ); cInfo.Init(); int iRet = cInfo.Process(); if( iRet != 0 ) return( iRet ); return( cInfo.Finish() ); #endif /* USE_GETHOSTBYNAME */ } int Csock::ConvertAddress( const struct sockaddr_storage * pAddr, socklen_t iAddrLen, CS_STRING & sIP, uint16_t * piPort ) const { char szHostname[NI_MAXHOST]; char szServ[NI_MAXSERV]; int iRet = getnameinfo( ( const struct sockaddr * )pAddr, iAddrLen, szHostname, NI_MAXHOST, szServ, NI_MAXSERV, NI_NUMERICHOST|NI_NUMERICSERV ); if( iRet == 0 ) { sIP = szHostname; if( piPort ) *piPort = ( uint16_t )atoi( szServ ); } return( iRet ); } bool InitCsocket() { #ifdef _WIN32 WSADATA wsaData; int iResult = WSAStartup( MAKEWORD( 2, 2 ), &wsaData ); if( iResult != NO_ERROR ) return( false ); #endif /* _WIN32 */ #ifdef HAVE_C_ARES #if ARES_VERSION >= CREATE_ARES_VER( 1, 6, 1 ) if( ares_library_init( ARES_LIB_INIT_ALL ) != 0 ) return( false ); #endif /* ARES_VERSION >= CREATE_ARES_VER( 1, 6, 1 ) */ #endif /* HAVE_C_ARES */ #ifdef HAVE_LIBSSL if( !InitSSL() ) return( false ); #endif /* HAVE_LIBSSL */ return( true ); } void ShutdownCsocket() { #ifdef HAVE_LIBSSL #if defined( HAVE_ERR_REMOVE_THREAD_STATE ) ERR_remove_thread_state( NULL ); #elif defined( HAVE_ERR_REMOVE_STATE ) ERR_remove_state( 0 ); #endif #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); #endif #ifndef OPENSSL_IS_BORINGSSL CONF_modules_unload( 1 ); #endif ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); #endif /* HAVE_LIBSSL */ #ifdef HAVE_C_ARES #if ARES_VERSION >= CREATE_ARES_VER( 1, 6, 1 ) ares_library_cleanup(); #endif /* ARES_VERSION >= CREATE_ARES_VER( 1, 6, 1 ) */ #endif /* HAVE_C_ARES */ #ifdef _WIN32 WSACleanup(); #endif /* _WIN32 */ } #ifdef HAVE_LIBSSL bool InitSSL( ECompType eCompressionType ) { SSL_load_error_strings(); if( SSL_library_init() != 1 ) { CS_DEBUG( "SSL_library_init() failed!" ); return( false ); } #ifndef _WIN32 if( access( "/dev/urandom", R_OK ) == 0 ) { RAND_load_file( "/dev/urandom", 1024 ); } else if( access( "/dev/random", R_OK ) == 0 ) { RAND_load_file( "/dev/random", 1024 ); } else { CS_DEBUG( "Unable to locate entropy location! Tried /dev/urandom and /dev/random" ); return( false ); } #endif /* _WIN32 */ #ifndef OPENSSL_NO_COMP COMP_METHOD *cm = NULL; if( CT_ZLIB & eCompressionType ) { cm = COMP_zlib(); if( cm ) SSL_COMP_add_compression_method( CT_ZLIB, cm ); } #endif // setting this up once in the begining s_iCsockSSLIdx = SSL_get_ex_new_index( 0, NULL, NULL, NULL, NULL ); return( true ); } void SSLErrors( const char *filename, u_int iLineNum ) { unsigned long iSSLError = 0; while( ( iSSLError = ERR_get_error() ) != 0 ) { CS_DEBUG( "at " << filename << ":" << iLineNum ); char szError[512]; memset( ( char * ) szError, '\0', 512 ); ERR_error_string_n( iSSLError, szError, 511 ); if( *szError ) CS_DEBUG( szError ); } } #endif /* HAVE_LIBSSL */ void CSAdjustTVTimeout( struct timeval & tv, long iTimeoutMS ) { if( iTimeoutMS >= 0 ) { long iCurTimeout = tv.tv_usec / 1000; iCurTimeout += tv.tv_sec * 1000; if( iCurTimeout > iTimeoutMS ) { tv.tv_sec = iTimeoutMS / 1000; tv.tv_usec = iTimeoutMS % 1000; } } } #define CS_UNKNOWN_ERROR "Unknown Error" static const char * CS_StrError( int iErrno, char * pszBuff, size_t uBuffLen ) { #if defined( sgi ) || defined(__sun) || (defined(__NetBSD_Version__) && __NetBSD_Version__ < 4000000000) return( strerror( iErrno ) ); #else memset( pszBuff, '\0', uBuffLen ); #if defined( _WIN32 ) if ( strerror_s( pszBuff, uBuffLen, iErrno ) == 0 ) return( pszBuff ); #elif !defined( _GNU_SOURCE ) || !defined(__GLIBC__) || defined( __FreeBSD__ ) if( strerror_r( iErrno, pszBuff, uBuffLen ) == 0 ) return( pszBuff ); #else return( strerror_r( iErrno, pszBuff, uBuffLen ) ); #endif /* (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined( _GNU_SOURCE ) */ #endif /* defined( sgi ) || defined(__sun) || defined(_WIN32) || (defined(__NetBSD_Version__) && __NetBSD_Version__ < 4000000000) */ return( CS_UNKNOWN_ERROR ); } void __Perror( const CS_STRING & s, const char * pszFile, u_int iLineNo ) { char szBuff[0xff]; std::cerr << s << "(" << pszFile << ":" << iLineNo << "): " << CS_StrError( GetSockError(), szBuff, 0xff ) << endl; } uint64_t millitime() { uint64_t iTime = 0; #ifdef _WIN32 struct timeb tm; ftime( &tm ); iTime = tm.time * 1000; iTime += tm.millitm; #else struct timeval tv; gettimeofday( &tv, NULL ); iTime = ( uint64_t )tv.tv_sec * 1000; iTime += ( ( uint64_t )tv.tv_usec / 1000 ); #endif /* _WIN32 */ return( iTime ); } #ifndef _MSC_VER #define CS_GETTIMEOFDAY gettimeofday #else #define CS_GETTIMEOFDAY win32_gettimeofday // timezone-agnostic implementation of gettimeofday static int win32_gettimeofday( struct timeval* now, void* ) { static const ULONGLONG epoch = 116444736000000000ULL; // Jan 1st 1970 ULARGE_INTEGER file_time; SYSTEMTIME system_time; GetSystemTime( &system_time ); if ( !SystemTimeToFileTime( &system_time, ( LPFILETIME )&file_time) ) return( 1 ); now->tv_sec = ( long )( ( file_time.QuadPart - epoch ) / 10000000L ); now->tv_usec = ( long )( system_time.wMilliseconds * 1000 ); return 0; } #endif #ifndef _NO_CSOCKET_NS // some people may not want to use a namespace } using namespace Csocket; #endif /* _NO_CSOCKET_NS */ CCron::CCron() { m_iCycles = 0; m_iMaxCycles = 0; m_bActive = true; timerclear( &m_tTime ); m_tTimeSequence.tv_sec = 60; m_tTimeSequence.tv_usec = 0; m_bPause = false; m_bRunOnNextCall = false; } void CCron::run( timeval & tNow ) { if( m_bPause ) return; if( !timerisset( &tNow ) ) CS_GETTIMEOFDAY( &tNow, NULL ); if( m_bActive && ( !timercmp( &tNow, &m_tTime, < ) || m_bRunOnNextCall ) ) { m_bRunOnNextCall = false; // Setting this here because RunJob() could set it back to true RunJob(); if( m_iMaxCycles > 0 && ++m_iCycles >= m_iMaxCycles ) m_bActive = false; else timeradd( &tNow, &m_tTimeSequence, &m_tTime ); } } void CCron::StartMaxCycles( double dTimeSequence, u_int iMaxCycles ) { timeval tNow; m_tTimeSequence.tv_sec = ( time_t ) dTimeSequence; // this could be done with modf(), but we're avoiding bringing in libm just for the one function. m_tTimeSequence.tv_usec = ( suseconds_t )( ( dTimeSequence - ( double )( ( time_t ) dTimeSequence ) ) * 1000000 ); CS_GETTIMEOFDAY( &tNow, NULL ); timeradd( &tNow, &m_tTimeSequence, &m_tTime ); m_iMaxCycles = iMaxCycles; m_bActive = true; } void CCron::StartMaxCycles( const timeval& tTimeSequence, u_int iMaxCycles ) { timeval tNow; m_tTimeSequence = tTimeSequence; CS_GETTIMEOFDAY( &tNow, NULL ); timeradd( &tNow, &m_tTimeSequence, &m_tTime ); m_iMaxCycles = iMaxCycles; m_bActive = true; } void CCron::Start( double dTimeSequence ) { StartMaxCycles( dTimeSequence, 0 ); } void CCron::Start( const timeval& tTimeSequence ) { StartMaxCycles( tTimeSequence, 0 ); } void CCron::Stop() { m_bActive = false; } void CCron::Pause() { m_bPause = true; } void CCron::UnPause() { m_bPause = false; } void CCron::Reset() { Stop(); Start(m_tTimeSequence); } timeval CCron::GetInterval() const { return( m_tTimeSequence ); } u_int CCron::GetMaxCycles() const { return( m_iMaxCycles ); } u_int CCron::GetCyclesLeft() const { return( ( m_iMaxCycles > m_iCycles ? ( m_iMaxCycles - m_iCycles ) : 0 ) ); } bool CCron::isValid() const { return( m_bActive ); } const CS_STRING & CCron::GetName() const { return( m_sName ); } void CCron::SetName( const CS_STRING & sName ) { m_sName = sName; } void CCron::RunJob() { CS_DEBUG( "This should be overridden" ); } bool CSMonitorFD::GatherFDsForSelect( std::map< cs_sock_t, short > & miiReadyFds, long & iTimeoutMS ) { iTimeoutMS = -1; // don't bother changing anything in the default implementation for( std::map< cs_sock_t, short >::iterator it = m_miiMonitorFDs.begin(); it != m_miiMonitorFDs.end(); ++it ) { miiReadyFds[it->first] = it->second; } return( m_bEnabled ); } bool CSMonitorFD::CheckFDs( const std::map< cs_sock_t, short > & miiReadyFds ) { std::map< cs_sock_t, short > miiTriggerdFds; for( std::map< cs_sock_t, short >::iterator it = m_miiMonitorFDs.begin(); it != m_miiMonitorFDs.end(); ++it ) { std::map< cs_sock_t, short >::const_iterator itFD = miiReadyFds.find( it->first ); if( itFD != miiReadyFds.end() ) miiTriggerdFds[itFD->first] = itFD->second; } if( !miiTriggerdFds.empty() ) return( FDsThatTriggered( miiTriggerdFds ) ); return( m_bEnabled ); } CSockCommon::~CSockCommon() { // delete any left over crons CleanupCrons(); CleanupFDMonitors(); } void CSockCommon::CleanupCrons() { for( size_t a = 0; a < m_vcCrons.size(); ++a ) CS_Delete( m_vcCrons[a] ); m_vcCrons.clear(); } void CSockCommon::CleanupFDMonitors() { for( size_t a = 0; a < m_vcMonitorFD.size(); ++a ) CS_Delete( m_vcMonitorFD[a] ); m_vcMonitorFD.clear(); } void CSockCommon::CheckFDs( const std::map< cs_sock_t, short > & miiReadyFds ) { for( size_t uMon = 0; uMon < m_vcMonitorFD.size(); ++uMon ) { if( !m_vcMonitorFD[uMon]->IsEnabled() || !m_vcMonitorFD[uMon]->CheckFDs( miiReadyFds ) ) m_vcMonitorFD.erase( m_vcMonitorFD.begin() + uMon-- ); } } void CSockCommon::AssignFDs( std::map< cs_sock_t, short > & miiReadyFds, struct timeval * tvtimeout ) { for( size_t uMon = 0; uMon < m_vcMonitorFD.size(); ++uMon ) { long iTimeoutMS = -1; if( m_vcMonitorFD[uMon]->IsEnabled() && m_vcMonitorFD[uMon]->GatherFDsForSelect( miiReadyFds, iTimeoutMS ) ) { CSAdjustTVTimeout( *tvtimeout, iTimeoutMS ); } else { CS_Delete( m_vcMonitorFD[uMon] ); m_vcMonitorFD.erase( m_vcMonitorFD.begin() + uMon-- ); } } } void CSockCommon::Cron() { timeval tNow; timerclear( &tNow ); for( vector::size_type a = 0; a < m_vcCrons.size(); ++a ) { CCron * pcCron = m_vcCrons[a]; if( !pcCron->isValid() ) { CS_Delete( pcCron ); m_vcCrons.erase( m_vcCrons.begin() + a-- ); } else { pcCron->run( tNow ); } } } void CSockCommon::AddCron( CCron * pcCron ) { m_vcCrons.push_back( pcCron ); } void CSockCommon::DelCron( const CS_STRING & sName, bool bDeleteAll, bool bCaseSensitive ) { for( size_t a = 0; a < m_vcCrons.size(); ++a ) { int ( *Cmp )( const char *, const char * ) = ( bCaseSensitive ? strcmp : strcasecmp ); if( Cmp( m_vcCrons[a]->GetName().c_str(), sName.c_str() ) == 0 ) { m_vcCrons[a]->Stop(); CS_Delete( m_vcCrons[a] ); m_vcCrons.erase( m_vcCrons.begin() + a-- ); if( !bDeleteAll ) break; } } } void CSockCommon::DelCron( u_int iPos ) { if( iPos < m_vcCrons.size() ) { m_vcCrons[iPos]->Stop(); CS_Delete( m_vcCrons[iPos] ); m_vcCrons.erase( m_vcCrons.begin() + iPos ); } } void CSockCommon::DelCronByAddr( CCron * pcCron ) { for( size_t a = 0; a < m_vcCrons.size(); ++a ) { if( m_vcCrons[a] == pcCron ) { m_vcCrons[a]->Stop(); CS_Delete( m_vcCrons[a] ); m_vcCrons.erase( m_vcCrons.begin() + a ); return; } } } Csock::Csock( int iTimeout ) : CSockCommon() { #ifdef HAVE_LIBSSL m_pCerVerifyCB = _CertVerifyCB; #endif /* HAVE_LIBSSL */ Init( "", 0, iTimeout ); } Csock::Csock( const CS_STRING & sHostname, uint16_t iport, int iTimeout ) : CSockCommon() { #ifdef HAVE_LIBSSL m_pCerVerifyCB = _CertVerifyCB; #endif /* HAVE_LIBSSL */ Init( sHostname, iport, iTimeout ); } // override this for accept sockets Csock *Csock::GetSockObj( const CS_STRING & sHostname, uint16_t iPort ) { return( NULL ); } #ifdef HAVE_LIBSSL bool Csock::SNIConfigureClient( CS_STRING & sHostname ) { if( m_shostname.empty() ) return( false ); sHostname = m_shostname; return( true ); } #endif #ifdef _WIN32 #define CS_CLOSE closesocket #else #define CS_CLOSE close #endif /* _WIN32 */ Csock::~Csock() { #ifdef _WIN32 // prevent successful closesocket() calls and such from // overwriting any possible previous errors. int iOldError = ::WSAGetLastError(); #endif /* _WIN32 */ #ifdef HAVE_ICU if( m_cnvExt ) ucnv_close( m_cnvExt ); if( m_cnvInt ) ucnv_close( m_cnvInt ); #endif #ifdef HAVE_C_ARES if( m_pARESChannel ) ares_cancel( m_pARESChannel ); FreeAres(); #endif /* HAVE_C_ARES */ #ifdef HAVE_LIBSSL FREE_SSL(); FREE_CTX(); #endif /* HAVE_LIBSSL */ CloseSocksFD(); #ifdef _WIN32 ::WSASetLastError( iOldError ); #endif /* _WIN32 */ } void Csock::CloseSocksFD() { if( m_iReadSock != m_iWriteSock ) { if( m_iReadSock != CS_INVALID_SOCK ) CS_CLOSE( m_iReadSock ); if( m_iWriteSock != CS_INVALID_SOCK ) CS_CLOSE( m_iWriteSock ); } else if( m_iReadSock != CS_INVALID_SOCK ) { CS_CLOSE( m_iReadSock ); } m_iReadSock = CS_INVALID_SOCK; m_iWriteSock = CS_INVALID_SOCK; } void Csock::Dereference() { m_iWriteSock = m_iReadSock = CS_INVALID_SOCK; #ifdef HAVE_LIBSSL m_ssl = NULL; m_ssl_ctx = NULL; #endif /* HAVE_LIBSSL */ // don't delete and erase, just erase since they were moved to the copied sock m_vcCrons.clear(); m_vcMonitorFD.clear(); Close( CLT_DEREFERENCE ); } void Csock::Copy( const Csock & cCopy ) { m_iTcount = cCopy.m_iTcount; m_iLastCheckTimeoutTime = cCopy.m_iLastCheckTimeoutTime; m_uPort = cCopy.m_uPort; m_iRemotePort = cCopy.m_iRemotePort; m_iLocalPort = cCopy.m_iLocalPort; m_iReadSock = cCopy.m_iReadSock; m_iWriteSock = cCopy.m_iWriteSock; m_iTimeout = cCopy.m_iTimeout; m_iMaxConns = cCopy.m_iMaxConns; m_iConnType = cCopy.m_iConnType; m_iMethod = cCopy.m_iMethod; m_bUseSSL = cCopy.m_bUseSSL; m_bIsConnected = cCopy.m_bIsConnected; m_bsslEstablished = cCopy.m_bsslEstablished; m_bEnableReadLine = cCopy.m_bEnableReadLine; m_bPauseRead = cCopy.m_bPauseRead; m_shostname = cCopy.m_shostname; m_sbuffer = cCopy.m_sbuffer; m_sSockName = cCopy.m_sSockName; m_sKeyFile = cCopy.m_sKeyFile; m_sDHParamFile = cCopy.m_sDHParamFile; m_sPemFile = cCopy.m_sPemFile; m_sCipherType = cCopy.m_sCipherType; m_sParentName = cCopy.m_sParentName; m_sSend = cCopy.m_sSend; m_sPemPass = cCopy.m_sPemPass; m_sLocalIP = cCopy.m_sLocalIP; m_sRemoteIP = cCopy.m_sRemoteIP; m_eCloseType = cCopy.m_eCloseType; m_iMaxMilliSeconds = cCopy.m_iMaxMilliSeconds; m_iLastSendTime = cCopy.m_iLastSendTime; m_iBytesRead = cCopy.m_iBytesRead; m_iBytesWritten = cCopy.m_iBytesWritten; m_iStartTime = cCopy.m_iStartTime; m_iMaxBytes = cCopy.m_iMaxBytes; m_iLastSend = cCopy.m_iLastSend; m_uSendBufferPos = cCopy.m_uSendBufferPos; m_iMaxStoredBufferLength = cCopy.m_iMaxStoredBufferLength; m_iTimeoutType = cCopy.m_iTimeoutType; m_address = cCopy.m_address; m_bindhost = cCopy.m_bindhost; m_bIsIPv6 = cCopy.m_bIsIPv6; m_bSkipConnect = cCopy.m_bSkipConnect; #ifdef HAVE_C_ARES FreeAres(); // Not copying this state, but making sure its nulled out m_iARESStatus = -1; // set it to unitialized m_pCurrAddr = NULL; #endif /* HAVE_C_ARES */ #ifdef HAVE_LIBSSL m_bNoSSLCompression = cCopy.m_bNoSSLCompression; m_bSSLCipherServerPreference = cCopy.m_bSSLCipherServerPreference; m_uDisableProtocols = cCopy.m_uDisableProtocols; m_iRequireClientCertFlags = cCopy.m_iRequireClientCertFlags; m_sSSLBuffer = cCopy.m_sSSLBuffer; FREE_SSL(); FREE_CTX(); // be sure to remove anything that was already here m_ssl = cCopy.m_ssl; m_ssl_ctx = cCopy.m_ssl_ctx; m_pCerVerifyCB = cCopy.m_pCerVerifyCB; if( m_ssl ) { SSL_set_ex_data( m_ssl, GetCsockSSLIdx(), this ); #if defined( SSL_CTX_set_tlsext_servername_callback ) SSL_CTX_set_tlsext_servername_arg( m_ssl_ctx, this ); #endif /* SSL_CTX_set_tlsext_servername_callback */ } #endif /* HAVE_LIBSSL */ #ifdef HAVE_ICU SetEncoding(cCopy.m_sEncoding); #endif CleanupCrons(); CleanupFDMonitors(); m_vcCrons = cCopy.m_vcCrons; m_vcMonitorFD = cCopy.m_vcMonitorFD; m_eConState = cCopy.m_eConState; m_sBindHost = cCopy.m_sBindHost; m_iCurBindCount = cCopy.m_iCurBindCount; m_iDNSTryCount = cCopy.m_iDNSTryCount; } Csock & Csock::operator<<( const CS_STRING & s ) { Write( s ); return( *this ); } Csock & Csock::operator<<( ostream & ( *io )( ostream & ) ) { Write( "\r\n" ); return( *this ); } Csock & Csock::operator<<( int32_t i ) { stringstream s; s << i; Write( s.str() ); return( *this ); } Csock & Csock::operator<<( uint32_t i ) { stringstream s; s << i; Write( s.str() ); return( *this ); } Csock & Csock::operator<<( int64_t i ) { stringstream s; s << i; Write( s.str() ); return( *this ); } Csock & Csock::operator<<( uint64_t i ) { stringstream s; s << i; Write( s.str() ); return( *this ); } Csock & Csock::operator<<( float i ) { stringstream s; s << i; Write( s.str() ); return( *this ); } Csock & Csock::operator<<( double i ) { stringstream s; s << i; Write( s.str() ); return( *this ); } bool Csock::Connect() { if( m_bSkipConnect ) { // this was already called, so skipping now. this is to allow easy pass through if( m_eConState != CST_OK ) { m_eConState = ( GetSSL() ? CST_CONNECTSSL : CST_OK ); } return( true ); } #ifndef _WIN32 set_non_blocking( m_iReadSock ); #else if( !GetIPv6() ) set_non_blocking( m_iReadSock ); // non-blocking sockets on Win32 do *not* return ENETUNREACH/EHOSTUNREACH if there's no IPv6 gateway. // we need those error codes for the v4 fallback in GetAddrInfo! #endif /* _WIN32 */ m_iConnType = OUTBOUND; int ret = -1; if( !GetIPv6() ) ret = connect( m_iReadSock, ( struct sockaddr * )m_address.GetSockAddr(), m_address.GetSockAddrLen() ); #ifdef HAVE_IPV6 else ret = connect( m_iReadSock, ( struct sockaddr * )m_address.GetSockAddr6(), m_address.GetSockAddrLen6() ); #endif /* HAVE_IPV6 */ #ifndef _WIN32 if( ret == -1 && GetSockError() != EINPROGRESS ) #else if( ret == -1 && GetSockError() != EINPROGRESS && GetSockError() != WSAEWOULDBLOCK ) #endif /* _WIN32 */ { CS_DEBUG( "Connect Failed. ERRNO [" << GetSockError() << "] FD [" << m_iReadSock << "]" ); return( false ); } #ifdef _WIN32 // do what we didn't do above since connect() is now over! if( GetIPv6() ) set_non_blocking( m_iReadSock ); #endif /* _WIN32 */ if( m_eConState != CST_OK ) { m_eConState = ( GetSSL() ? CST_CONNECTSSL : CST_OK ); } return( true ); } #ifdef HAVE_UNIX_SOCKET static bool prepare_sockaddr(struct sockaddr_un * addr, const CS_STRING & sPath) { memset( addr, 0, sizeof(*addr) ); addr->sun_family = AF_UNIX; if( sizeof(addr->sun_path) <= sPath.length() ) return( false ); memcpy( &addr->sun_path, sPath.c_str(), sPath.length() + 1 ); return true; } bool Csock::ConnectUnix( const CS_STRING & sPath ) { if( m_iReadSock != m_iWriteSock ) return( false ); if( m_iReadSock == CS_INVALID_SOCK ) m_iReadSock = m_iWriteSock = CreateSocket( false, true ); set_non_blocking( m_iReadSock ); m_iConnType = OUTBOUND; struct sockaddr_un addr; if( !prepare_sockaddr( &addr, sPath) ) { CallSockError( EADDRNOTAVAIL ); return( false ); } if( connect( m_iReadSock, ( struct sockaddr * )&addr, sizeof(addr) ) == -1) { CS_DEBUG( "Connect Failed. ERRNO [" << GetSockError() << "] FD [" << m_iReadSock << "]" ); return( false ); } if( m_eConState != CST_OK ) { m_eConState = ( GetSSL() ? CST_CONNECTSSL : CST_OK ); } return( true ); } bool Csock::ListenUnix( const CS_STRING & sBindFile, int iMaxConns, u_int iTimeout ) { m_iConnType = LISTENER; m_iTimeout = iTimeout; m_sBindHost = sBindFile; m_iMaxConns = iMaxConns; SetConState( Csock::CST_OK ); // Should m_address be set up somehow? struct sockaddr_un addr; if( !prepare_sockaddr( &addr, sBindFile) ) { CallSockError( EADDRNOTAVAIL ); return( false ); } m_iReadSock = m_iWriteSock = CreateSocket( true, true ); if( m_iReadSock == CS_INVALID_SOCK ) { CallSockError( EBADF ); return( false ); } if( bind( m_iReadSock, ( struct sockaddr * ) &addr, sizeof(addr) ) == -1 ) { CallSockError( GetSockError() ); return( false ); } if( listen( m_iReadSock, iMaxConns ) == -1 ) { CallSockError( GetSockError() ); return( false ); } // set it none blocking set_non_blocking( m_iReadSock ); // TODO: The following callback makes no sense here; should a // ListeningUnix() be added? We aren't doing anything asynchronous... //Listening( m_sBindHost, m_uPort ); return( true ); } #endif bool Csock::Listen( uint16_t iPort, int iMaxConns, const CS_STRING & sBindHost, u_int iTimeout, bool bDetach ) { m_iConnType = LISTENER; m_iTimeout = iTimeout; m_sBindHost = sBindHost; m_iMaxConns = iMaxConns; SetConState( Csock::CST_OK ); if( !m_sBindHost.empty() ) { if( bDetach ) { int iRet = GetAddrInfo( m_sBindHost, m_address ); if( iRet == ETIMEDOUT ) { CallSockError( EADDRNOTAVAIL ); return( false ); } else if( iRet == EAGAIN ) { SetConState( Csock::CST_BINDVHOST ); return( true ); } } else { // if not detaching, then must block to do DNS resolution, so might as well use internal resolver if( ::CS_GetAddrInfo( m_sBindHost, this, m_address ) != 0 ) { CallSockError( EADDRNOTAVAIL ); return( false ); } } } m_iReadSock = m_iWriteSock = CreateSocket( true ); if( m_iReadSock == CS_INVALID_SOCK ) { CallSockError( EBADF ); return( false ); } #ifdef HAVE_IPV6 # ifdef _WIN32 # ifndef IPPROTO_IPV6 # define IPPROTO_IPV6 41 /* define for apps with _WIN32_WINNT < 0x0501 (XP) */ # endif /* !IPPROTO_IPV6 */ # ifndef IPV6_V6ONLY # define IPV6_V6ONLY 27 # endif /* check for IPV6_V6ONLY support at runtime: only supported on Windows Vista or later */ OSVERSIONINFOEX osvi = { 0 }; DWORDLONG dwlConditionMask = 0; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); osvi.dwMajorVersion = 6; VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); if( VerifyVersionInfo( &osvi, VER_MAJORVERSION, dwlConditionMask ) ) { # endif /* _WIN32 */ # ifdef IPV6_V6ONLY if( GetIPv6() ) { // per RFC3493#5.3 const int on = ( m_address.GetAFRequire() == CSSockAddr::RAF_INET6 ? 1 : 0 ); if( setsockopt( m_iReadSock, IPPROTO_IPV6, IPV6_V6ONLY, ( char * )&on, sizeof( on ) ) != 0 ) PERROR( "IPV6_V6ONLY" ); } # endif /* IPV6_V6ONLY */ # ifdef _WIN32 } # endif /* _WIN32 */ #endif /* HAVE_IPV6 */ m_address.SinFamily(); m_address.SinPort( iPort ); if( !GetIPv6() ) { if( bind( m_iReadSock, ( struct sockaddr * ) m_address.GetSockAddr(), m_address.GetSockAddrLen() ) == -1 ) { CallSockError( GetSockError() ); return( false ); } } #ifdef HAVE_IPV6 else { if( bind( m_iReadSock, ( struct sockaddr * ) m_address.GetSockAddr6(), m_address.GetSockAddrLen6() ) == -1 ) { CallSockError( GetSockError() ); return( false ); } } #endif /* HAVE_IPV6 */ if( listen( m_iReadSock, iMaxConns ) == -1 ) { CallSockError( GetSockError() ); return( false ); } // set it none blocking set_non_blocking( m_iReadSock ); if( m_uPort == 0 || !m_sBindHost.empty() ) { struct sockaddr_storage cAddr; socklen_t iAddrLen = sizeof( cAddr ); if( getsockname( m_iReadSock, ( struct sockaddr * )&cAddr, &iAddrLen ) == 0 ) { ConvertAddress( &cAddr, iAddrLen, m_sBindHost, &m_uPort ); } } Listening( m_sBindHost, m_uPort ); return( true ); } cs_sock_t Csock::Accept( CS_STRING & sHost, uint16_t & iRPort ) { cs_sock_t iSock = CS_INVALID_SOCK; struct sockaddr_storage cAddr; socklen_t iAddrLen = sizeof( cAddr ); iSock = accept( m_iReadSock, ( struct sockaddr * )&cAddr, &iAddrLen ); if( iSock != CS_INVALID_SOCK && getpeername( iSock, ( struct sockaddr * )&cAddr, &iAddrLen ) == 0 ) { ConvertAddress( &cAddr, iAddrLen, sHost, &iRPort ); } if( iSock != CS_INVALID_SOCK ) { // Make it close-on-exec set_close_on_exec( iSock ); // make it none blocking set_non_blocking( iSock ); if( !ConnectionFrom( sHost, iRPort ) ) { CS_CLOSE( iSock ); iSock = CS_INVALID_SOCK; } } return( iSock ); } #ifdef HAVE_LIBSSL #if defined( SSL_CTX_set_tlsext_servername_callback ) static int __SNICallBack( SSL *pSSL, int *piAD, void *pData ) { if( !pSSL || !pData ) return( SSL_TLSEXT_ERR_NOACK ); const char * pServerName = SSL_get_servername( pSSL, TLSEXT_NAMETYPE_host_name ); if( !pServerName ) return( SSL_TLSEXT_ERR_NOACK ); Csock * pSock = static_cast( pData ); CS_STRING sDHParamFile, sKeyFile, sPemFile, sPemPass; if( !pSock->SNIConfigureServer( pServerName, sPemFile, sPemPass ) ) return( SSL_TLSEXT_ERR_NOACK ); pSock->SetDHParamLocation( sDHParamFile ); pSock->SetKeyLocation( sKeyFile ); pSock->SetPemLocation( sPemFile ); pSock->SetPemPass( sPemPass ); SSL_CTX * pCTX = pSock->SetupServerCTX(); SSL_set_SSL_CTX( pSSL, pCTX ); pSock->SetCTXObject( pCTX, true ); return( SSL_TLSEXT_ERR_OK ); } #endif /* SSL_CTX_set_tlsext_servername_callback */ #endif /* HAVE_LIBSSL */ bool Csock::AcceptSSL() { #ifdef HAVE_LIBSSL if( !m_ssl ) if( !SSLServerSetup() ) return( false ); #if defined( SSL_CTX_set_tlsext_servername_callback ) SSL_CTX_set_tlsext_servername_callback( m_ssl_ctx, __SNICallBack ); SSL_CTX_set_tlsext_servername_arg( m_ssl_ctx, this ); #endif /* SSL_CTX_set_tlsext_servername_callback */ int err = SSL_accept( m_ssl ); if( err == 1 ) { return( true ); } int sslErr = SSL_get_error( m_ssl, err ); if( sslErr == SSL_ERROR_WANT_READ || sslErr == SSL_ERROR_WANT_WRITE ) return( true ); SSLErrors( __FILE__, __LINE__ ); #endif /* HAVE_LIBSSL */ return( false ); } #ifdef HAVE_LIBSSL bool Csock::ConfigureCTXOptions( SSL_CTX * pCTX ) { if( pCTX ) { if( SSL_CTX_set_cipher_list( pCTX, m_sCipherType.c_str() ) <= 0 ) { CS_DEBUG( "Could not assign cipher [" << m_sCipherType << "]" ); return( false ); } long uCTXOptions = 0; if( m_uDisableProtocols > 0 ) { #ifdef SSL_OP_NO_SSLv2 if( EDP_SSLv2 & m_uDisableProtocols ) uCTXOptions |= SSL_OP_NO_SSLv2; #endif /* SSL_OP_NO_SSLv2 */ #ifdef SSL_OP_NO_SSLv3 if( EDP_SSLv3 & m_uDisableProtocols ) uCTXOptions |= SSL_OP_NO_SSLv3; #endif /* SSL_OP_NO_SSLv3 */ #ifdef SSL_OP_NO_TLSv1 if( EDP_TLSv1 & m_uDisableProtocols ) uCTXOptions |= SSL_OP_NO_TLSv1; #endif /* SSL_OP_NO_TLSv1 */ #ifdef SSL_OP_NO_TLSv1_1 if( EDP_TLSv1_1 & m_uDisableProtocols ) uCTXOptions |= SSL_OP_NO_TLSv1_1; #endif /* SSL_OP_NO_TLSv1 */ #ifdef SSL_OP_NO_TLSv1_2 if( EDP_TLSv1_2 & m_uDisableProtocols ) uCTXOptions |= SSL_OP_NO_TLSv1_2; #endif /* SSL_OP_NO_TLSv1_2 */ } #ifdef SSL_OP_NO_COMPRESSION if( m_bNoSSLCompression ) uCTXOptions |= SSL_OP_NO_COMPRESSION; #endif /* SSL_OP_NO_COMPRESSION */ #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE if( m_bSSLCipherServerPreference ) uCTXOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE; #endif /* SSL_OP_CIPHER_SERVER_PREFERENCE */ if( uCTXOptions ) SSL_CTX_set_options( pCTX, uCTXOptions ); } return true; } #endif /* HAVE_LIBSSL */ #ifdef HAVE_LIBSSL static SSL_CTX * GetSSLCTX( int iMethod ) { const SSL_METHOD *pMethod = NULL; #ifdef HAVE_FLEXIBLE_TLS_METHOD int iProtoVersion = 0; pMethod = TLS_method(); #else pMethod = SSLv23_method(); #endif // HAVE_FLEXIBLE_TLS_METHOD switch( iMethod ) { case Csock::TLS: break; // defaults already set above, anything else can either match a case or fall through and use defaults anyway #ifdef HAVE_FLEXIBLE_TLS_METHOD #ifndef OPENSSL_NO_TLS1_2 case Csock::TLS12: iProtoVersion = TLS1_2_VERSION; break; #endif /* OPENSSL_NO_TLS1_2 */ #ifndef OPENSSL_NO_TLS1_1 case Csock::TLS11: iProtoVersion = TLS1_1_VERSION; break; #endif /* OPENSSL_NO_TLS1_1 */ #ifndef OPENSSL_NO_TLS1 case Csock::TLS1: iProtoVersion = TLS1_VERSION; break; #endif /* OPENSSL_NO_TLS1 */ #ifndef OPENSSL_NO_SSL3 case Csock::SSL3: iProtoVersion = SSL3_VERSION; break; #endif /* OPENSSL_NO_SSL3 */ #ifndef OPENSSL_NO_SSL2 case Csock::SSL2: pMethod = SSLv2_method(); break; #endif /* OPENSSL_NO_SSL2 */ #else /* HAVE_FLEXIBLE_TLS_METHOD */ #ifndef OPENSSL_NO_TLS1_2 case Csock::TLS12: pMethod = TLSv1_2_method(); break; #endif /* OPENSSL_NO_TLS1_2 */ #ifndef OPENSSL_NO_TLS1_1 case Csock::TLS11: pMethod = TLSv1_1_method(); break; #endif /* OPENSSL_NO_TLS1_1 */ #ifndef OPENSSL_NO_TLS1 case Csock::TLS1: pMethod = TLSv1_method(); break; #endif /* OPENSSL_NO_TLS1 */ #ifndef OPENSSL_NO_SSL3 case Csock::SSL3: pMethod = SSLv3_method(); break; #endif /* OPENSSL_NO_SSL3 */ #ifndef OPENSSL_NO_SSL2 case Csock::SSL2: pMethod = SSLv2_method(); break; #endif /* OPENSSL_NO_SSL2 */ #endif /* HAVE_FLEXIBLE_TLS_METHOD */ default: CS_DEBUG( "WARNING: SSL Client Method other than SSLv23 specified, but has passed through" ); break; } SSL_CTX * pCTX = SSL_CTX_new( pMethod ); if( !pCTX ) { CS_DEBUG( "WARNING: GetSSLCTX failed!" ); return( NULL ); } #ifdef HAVE_FLEXIBLE_TLS_METHOD if( iProtoVersion ) { SSL_CTX_set_min_proto_version( pCTX, iProtoVersion ); SSL_CTX_set_max_proto_version( pCTX, iProtoVersion ); } #endif /* HAVE_FLEXIBLE_TLS_METHOD */ return( pCTX ); } #endif bool Csock::SSLClientSetup() { #ifdef HAVE_LIBSSL m_bUseSSL = true; FREE_SSL(); FREE_CTX(); #ifdef _WIN64 if( m_iReadSock != ( int )m_iReadSock || m_iWriteSock != ( int )m_iWriteSock ) { // sanity check the FD to be sure its compatible with openssl CS_DEBUG( "ERROR: sockfd larger than OpenSSL can handle" ); return( false ); } #endif /* _WIN64 */ m_ssl_ctx = GetSSLCTX( m_iMethod ); if( !m_ssl_ctx ) { CS_DEBUG( "WARNING: Failed to retrieve a valid ctx" ); return( false ); } SSL_CTX_set_default_verify_paths( m_ssl_ctx ); if( !m_sPemFile.empty() ) { // are we sending a client cerificate ? SSL_CTX_set_default_passwd_cb( m_ssl_ctx, _PemPassCB ); SSL_CTX_set_default_passwd_cb_userdata( m_ssl_ctx, ( void * )this ); // // set up the CTX if( SSL_CTX_use_certificate_file( m_ssl_ctx, m_sPemFile.c_str() , SSL_FILETYPE_PEM ) <= 0 ) { CS_DEBUG( "Error with SSLCert file [" << m_sPemFile << "]" ); SSLErrors( __FILE__, __LINE__ ); } CS_STRING privKeyFile = m_sKeyFile.empty() ? m_sPemFile : m_sKeyFile; if( SSL_CTX_use_PrivateKey_file( m_ssl_ctx, privKeyFile.c_str(), SSL_FILETYPE_PEM ) <= 0 ) { CS_DEBUG( "Error with SSLKey file [" << privKeyFile << "]" ); SSLErrors( __FILE__, __LINE__ ); } } if( !ConfigureCTXOptions( m_ssl_ctx ) ) { SSL_CTX_free( m_ssl_ctx ); m_ssl_ctx = NULL; return( false ); } m_ssl = SSL_new( m_ssl_ctx ); if( !m_ssl ) return( false ); SSL_set_rfd( m_ssl, ( int )m_iReadSock ); SSL_set_wfd( m_ssl, ( int )m_iWriteSock ); SSL_set_verify( m_ssl, SSL_VERIFY_PEER, m_pCerVerifyCB ); SSL_set_info_callback( m_ssl, _InfoCallback ); SSL_set_ex_data( m_ssl, GetCsockSSLIdx(), this ); #if defined( SSL_set_tlsext_host_name ) CS_STRING sSNIHostname; if( SNIConfigureClient( sSNIHostname ) ) SSL_set_tlsext_host_name( m_ssl, sSNIHostname.c_str() ); #endif /* SSL_set_tlsext_host_name */ SSLFinishSetup( m_ssl ); return( true ); #else return( false ); #endif /* HAVE_LIBSSL */ } #ifdef HAVE_LIBSSL SSL_CTX * Csock::SetupServerCTX() { SSL_CTX * pCTX = GetSSLCTX( m_iMethod ); if( !pCTX ) { CS_DEBUG( "WARNING: Failed to retrieve a valid ctx" ); return( NULL ); } SSL_CTX_set_default_verify_paths( pCTX ); // set the pemfile password SSL_CTX_set_default_passwd_cb( pCTX, _PemPassCB ); SSL_CTX_set_default_passwd_cb_userdata( pCTX, ( void * )this ); if( m_sPemFile.empty() || access( m_sPemFile.c_str(), R_OK ) != 0 ) { CS_DEBUG( "Empty, missing, or bad pemfile ... [" << m_sPemFile << "]" ); SSL_CTX_free( pCTX ); return( NULL ); } if( ! m_sKeyFile.empty() && access( m_sKeyFile.c_str(), R_OK ) != 0 ) { CS_DEBUG( "Bad keyfile ... [" << m_sKeyFile << "]" ); SSL_CTX_free( pCTX ); return( NULL ); } // // set up the CTX if( SSL_CTX_use_certificate_chain_file( pCTX, m_sPemFile.c_str() ) <= 0 ) { CS_DEBUG( "Error with SSLCert file [" << m_sPemFile << "]" ); SSLErrors( __FILE__, __LINE__ ); SSL_CTX_free( pCTX ); return( NULL ); } CS_STRING privKeyFile = m_sKeyFile.empty() ? m_sPemFile : m_sKeyFile; if( SSL_CTX_use_PrivateKey_file( pCTX, privKeyFile.c_str(), SSL_FILETYPE_PEM ) <= 0 ) { CS_DEBUG( "Error with SSLKey file [" << privKeyFile << "]" ); SSLErrors( __FILE__, __LINE__ ); SSL_CTX_free( pCTX ); return( NULL ); } // check to see if this pem file contains a DH structure for use with DH key exchange // https://github.com/znc/znc/pull/46 CS_STRING DHParamFile = m_sDHParamFile.empty() ? m_sPemFile : m_sDHParamFile; FILE *dhParamsFile = fopen( DHParamFile.c_str(), "r" ); if( !dhParamsFile ) { CS_DEBUG( "Error with DHParam file [" << DHParamFile << "]" ); SSL_CTX_free( pCTX ); return( NULL ); } DH * dhParams = PEM_read_DHparams( dhParamsFile, NULL, NULL, NULL ); fclose( dhParamsFile ); if( dhParams ) { SSL_CTX_set_options( pCTX, SSL_OP_SINGLE_DH_USE ); if( !SSL_CTX_set_tmp_dh( pCTX, dhParams ) ) { CS_DEBUG( "Error setting ephemeral DH parameters from [" << m_sPemFile << "]" ); SSLErrors( __FILE__, __LINE__ ); DH_free( dhParams ); SSL_CTX_free( pCTX ); return( NULL ); } DH_free( dhParams ); } else { // Presumably PEM_read_DHparams failed, as there was no DH structure. Clearing those errors here so they are removed off the stack ERR_clear_error(); } #ifndef OPENSSL_NO_ECDH // Errors for the following block are non-fatal (ECDHE is nice to have // but not a requirement) #ifndef OPENSSL_IS_BORINGSSL // BoringSSL does this thing automatically #if defined( SSL_CTX_set_ecdh_auto ) // Auto-select sensible curve if( !SSL_CTX_set_ecdh_auto( pCTX , 1 ) ) ERR_clear_error(); #elif defined( SSL_CTX_set_tmp_ecdh ) // Use a standard, widely-supported curve EC_KEY * ecdh = EC_KEY_new_by_curve_name( NID_X9_62_prime256v1 ); if( ecdh ) { if( !SSL_CTX_set_tmp_ecdh( pCTX, ecdh ) ) ERR_clear_error(); EC_KEY_free( ecdh ); } else { ERR_clear_error(); } #endif /* SSL_CTX_set_tmp_ecdh */ #endif /* !OPENSSL_IS_BORINGSSL */ #endif /* OPENSSL_NO_ECDH */ if( !ConfigureCTXOptions( pCTX ) ) { SSL_CTX_free( pCTX ); return( NULL ); } return( pCTX ); } #endif /* HAVE_LIBSSL */ bool Csock::SSLServerSetup() { #ifdef HAVE_LIBSSL m_bUseSSL = true; FREE_SSL(); FREE_CTX(); #ifdef _WIN64 if( m_iReadSock != ( int )m_iReadSock || m_iWriteSock != ( int )m_iWriteSock ) { // sanity check the FD to be sure its compatible with openssl CS_DEBUG( "ERROR: sockfd larger than OpenSSL can handle" ); return( false ); } #endif /* _WIN64 */ m_ssl_ctx = SetupServerCTX(); // // setup the SSL m_ssl = SSL_new( m_ssl_ctx ); if( !m_ssl ) return( false ); #if defined( SSL_MODE_SEND_FALLBACK_SCSV ) SSL_set_mode( m_ssl, SSL_MODE_SEND_FALLBACK_SCSV ); #endif /* SSL_MODE_SEND_FALLBACK_SCSV */ // Call for client Verification SSL_set_rfd( m_ssl, ( int )m_iReadSock ); SSL_set_wfd( m_ssl, ( int )m_iWriteSock ); SSL_set_accept_state( m_ssl ); if( m_iRequireClientCertFlags ) { SSL_set_verify( m_ssl, m_iRequireClientCertFlags, m_pCerVerifyCB ); } SSL_set_info_callback( m_ssl, _InfoCallback ); SSL_set_ex_data( m_ssl, GetCsockSSLIdx(), this ); SSLFinishSetup( m_ssl ); return( true ); #else return( false ); #endif /* HAVE_LIBSSL */ } bool Csock::StartTLS() { if( m_iConnType == INBOUND ) return( AcceptSSL() ); if( m_iConnType == OUTBOUND ) return( ConnectSSL() ); CS_DEBUG( "Invalid connection type with StartTLS" ); return( false ); } bool Csock::ConnectSSL() { #ifdef HAVE_LIBSSL if( m_iReadSock == CS_INVALID_SOCK ) return( false ); // this should be long passed at this point if( !m_ssl && !SSLClientSetup() ) return( false ); bool bPass = true; int iErr = SSL_connect( m_ssl ); if( iErr != 1 ) { int sslErr = SSL_get_error( m_ssl, iErr ); bPass = false; if( sslErr == SSL_ERROR_WANT_READ || sslErr == SSL_ERROR_WANT_WRITE ) bPass = true; #ifdef _WIN32 else if( sslErr == SSL_ERROR_SYSCALL && iErr < 0 && GetLastError() == WSAENOTCONN ) { // this seems to be an issue with win32 only. I've seen it happen on slow connections // the issue is calling this before select(), which isn't a problem on unix. Allowing this // to pass in this case is fine because subsequent ssl transactions will occur and the handshake // will finish. At this point, its just instantiating the handshake. bPass = true; } #endif /* _WIN32 */ } else { bPass = true; } if( m_eConState != CST_OK ) m_eConState = CST_OK; return( bPass ); #else return( false ); #endif /* HAVE_LIBSSL */ } #ifdef HAVE_ICU inline bool icuConv( const CS_STRING& src, CS_STRING& tgt, UConverter* cnv_in, UConverter* cnv_out ) { const char* indata = src.c_str(); const char* indataend = indata + src.length(); tgt.clear(); char buf[100]; UChar pivotStart[100]; UChar* pivotSource = pivotStart; UChar* pivotTarget = pivotStart; UChar* pivotLimit = pivotStart + sizeof pivotStart / sizeof pivotStart[0]; const char* outdataend = buf + sizeof buf; bool reset = true; while( true ) { char* outdata = buf; UErrorCode e = U_ZERO_ERROR; ucnv_convertEx( cnv_out, cnv_in, &outdata, outdataend, &indata, indataend, pivotStart, &pivotSource, &pivotTarget, pivotLimit, reset, true, &e ); reset = false; if( U_SUCCESS( e ) ) { if( e != U_ZERO_ERROR ) { CS_DEBUG( "Warning during converting string encoding: " << u_errorName( e ) ); } tgt.append( buf, outdata - buf ); break; } if( e == U_BUFFER_OVERFLOW_ERROR ) { tgt.append( buf, outdata - buf ); continue; } CS_DEBUG( "Error during converting string encoding: " << u_errorName( e ) ); return false; } return true; } static bool isUTF8( const CS_STRING& src, CS_STRING& target) { UErrorCode e = U_ZERO_ERROR; // Convert to UTF-16 without actually converting. This will still count // the number of output characters, so we either get // U_BUFFER_OVERFLOW_ERROR or U_INVALID_CHAR_FOUND. u_strFromUTF8( NULL, 0, NULL, src.c_str(), (int32_t) src.length(), &e ); if( e != U_BUFFER_OVERFLOW_ERROR) return false; target = src; return true; } #endif /* HAVE_ICU */ bool Csock::AllowWrite( uint64_t & iNOW ) const { if( m_iMaxBytes > 0 && m_iMaxMilliSeconds > 0 ) { if( iNOW == 0 ) iNOW = millitime(); if( m_iLastSend < m_iMaxBytes ) return( true ); // allow sending if our out buffer was less than what we can send if( ( iNOW - m_iLastSendTime ) < m_iMaxMilliSeconds ) return( false ); } return( true ); } void Csock::ShrinkSendBuff() { if( m_uSendBufferPos > 0 ) { // just doing this to keep m_sSend from growing out of control m_sSend.erase( 0, m_uSendBufferPos ); m_uSendBufferPos = 0; } } void Csock::IncBuffPos( size_t uBytes ) { m_uSendBufferPos += uBytes; if( m_uSendBufferPos >= m_sSend.size() ) { m_uSendBufferPos = 0; m_sSend.clear(); } } bool Csock::Write( const char *data, size_t len ) { if( len > 0 ) { ShrinkSendBuff(); m_sSend.append( data, len ); } if( m_sSend.empty() ) return( true ); if( m_eConState != CST_OK ) return( true ); // rate shaping size_t iBytesToSend = 0; size_t uBytesInSend = m_sSend.size() - m_uSendBufferPos; #ifdef HAVE_LIBSSL if( m_bUseSSL && m_sSSLBuffer.empty() && !m_bsslEstablished ) { // to keep openssl from spinning, just initiate the connection with 1 byte so the connection establishes faster iBytesToSend = 1; } else #endif /* HAVE_LIBSSL */ if( m_iMaxBytes > 0 && m_iMaxMilliSeconds > 0 ) { uint64_t iNOW = millitime(); // figure out the shaping here // if NOW - m_iLastSendTime > m_iMaxMilliSeconds then send a full length of ( iBytesToSend ) if( ( iNOW - m_iLastSendTime ) > m_iMaxMilliSeconds ) { m_iLastSendTime = iNOW; iBytesToSend = m_iMaxBytes; m_iLastSend = 0; } else // otherwise send m_iMaxBytes - m_iLastSend iBytesToSend = m_iMaxBytes - m_iLastSend; // take which ever is lesser if( uBytesInSend < iBytesToSend ) iBytesToSend = uBytesInSend; // add up the bytes sent m_iLastSend += iBytesToSend; // so, are we ready to send anything ? if( iBytesToSend == 0 ) return( true ); } else { iBytesToSend = uBytesInSend; } #ifdef HAVE_LIBSSL if( m_bUseSSL ) { if( !m_ssl ) { CS_DEBUG( "SSL object is NULL but m_bUseSSL is true" ); return( false ); } if( m_sSSLBuffer.empty() ) // on retrying to write data, ssl wants the data in the SAME spot and the SAME size m_sSSLBuffer.append( m_sSend.data() + m_uSendBufferPos, iBytesToSend ); int iErr = SSL_write( m_ssl, m_sSSLBuffer.data(), ( int )m_sSSLBuffer.length() ); if( iErr < 0 && GetSockError() == ECONNREFUSED ) { // If ret == -1, the underlying BIO reported an I/O error (man SSL_get_error) ConnectionRefused(); return( false ); } switch( SSL_get_error( m_ssl, iErr ) ) { case SSL_ERROR_NONE: m_bsslEstablished = true; // all ok break; case SSL_ERROR_ZERO_RETURN: { // weird closer alert return( false ); } case SSL_ERROR_WANT_READ: // retry break; case SSL_ERROR_WANT_WRITE: // retry break; case SSL_ERROR_SSL: { SSLErrors( __FILE__, __LINE__ ); return( false ); } } if( iErr > 0 ) { m_sSSLBuffer.clear(); IncBuffPos( ( size_t )iErr ); // reset the timer on successful write (we have to set it here because the write // bit might not always be set, so need to trigger) if( TMO_WRITE & GetTimeoutType() ) ResetTimer(); m_iBytesWritten += ( uint64_t )iErr; } return( true ); } #endif /* HAVE_LIBSSL */ #ifdef _WIN32 cs_ssize_t bytes = send( m_iWriteSock, m_sSend.data() + m_uSendBufferPos, iBytesToSend, 0 ); #else cs_ssize_t bytes = write( m_iWriteSock, m_sSend.data() + m_uSendBufferPos, iBytesToSend ); #endif /* _WIN32 */ if( bytes == -1 && GetSockError() == ECONNREFUSED ) { ConnectionRefused(); return( false ); } #ifdef _WIN32 if( bytes <= 0 && GetSockError() != WSAEWOULDBLOCK ) return( false ); #else if( bytes <= 0 && GetSockError() != EAGAIN ) return( false ); #endif /* _WIN32 */ // delete the bytes we sent if( bytes > 0 ) { IncBuffPos( ( size_t )bytes ); if( TMO_WRITE & GetTimeoutType() ) ResetTimer(); // reset the timer on successful write m_iBytesWritten += ( uint64_t )bytes; } return( true ); } bool Csock::Write( const CS_STRING & sData ) { #ifdef HAVE_ICU if( m_cnvExt && !m_cnvSendUTF8 ) { CS_STRING sBinary; if( icuConv( sData, sBinary, m_cnvInt, m_cnvExt ) ) { return( Write( sBinary.c_str(), sBinary.length() ) ); } } // can't convert our UTF-8 string to that encoding, just put it as is... #endif /* HAVE_ICU */ return( Write( sData.c_str(), sData.length() ) ); } cs_ssize_t Csock::Read( char *data, size_t len ) { cs_ssize_t bytes = 0; if( IsReadPaused() && SslIsEstablished() ) return( READ_EAGAIN ); // allow the handshake to complete first #ifdef HAVE_LIBSSL if( m_bUseSSL ) { if( !m_ssl ) { CS_DEBUG( "SSL object is NULL but m_bUseSSL is true" ); return( READ_ERR ); } bytes = SSL_read( m_ssl, data, ( int )len ); if( bytes >= 0 ) m_bsslEstablished = true; // this means all is good in the realm of ssl } else #endif /* HAVE_LIBSSL */ #ifdef _WIN32 bytes = recv( m_iReadSock, data, len, 0 ); #else bytes = read( m_iReadSock, data, len ); #endif /* _WIN32 */ if( bytes == -1 ) { if( GetSockError() == ECONNREFUSED ) return( READ_CONNREFUSED ); if( GetSockError() == ETIMEDOUT ) return( READ_TIMEDOUT ); if( GetSockError() == EINTR || GetSockError() == EAGAIN ) return( READ_EAGAIN ); #ifdef _WIN32 if( GetSockError() == WSAEWOULDBLOCK ) return( READ_EAGAIN ); #endif /* _WIN32 */ #ifdef HAVE_LIBSSL if( m_ssl ) { int iErr = SSL_get_error( m_ssl, ( int )bytes ); if( iErr != SSL_ERROR_WANT_READ && iErr != SSL_ERROR_WANT_WRITE ) return( READ_ERR ); else return( READ_EAGAIN ); } #else return( READ_ERR ); #endif /* HAVE_LIBSSL */ } if( bytes > 0 ) // becareful not to add negative bytes :P m_iBytesRead += ( uint64_t )bytes; return( bytes ); } CS_STRING Csock::GetLocalIP() const { if( !m_sLocalIP.empty() ) return( m_sLocalIP ); cs_sock_t iSock = GetSock(); if( iSock == CS_INVALID_SOCK ) return( "" ); struct sockaddr_storage cAddr; socklen_t iAddrLen = sizeof( cAddr ); if( getsockname( iSock, ( struct sockaddr * )&cAddr, &iAddrLen ) == 0 ) { ConvertAddress( &cAddr, iAddrLen, m_sLocalIP, &m_iLocalPort ); } return( m_sLocalIP ); } CS_STRING Csock::GetRemoteIP() const { if( !m_sRemoteIP.empty() ) return( m_sRemoteIP ); cs_sock_t iSock = GetSock(); if( iSock == CS_INVALID_SOCK ) return( "" ); struct sockaddr_storage cAddr; socklen_t iAddrLen = sizeof( cAddr ); if( getpeername( iSock, ( struct sockaddr * )&cAddr, &iAddrLen ) == 0 ) { ConvertAddress( &cAddr, iAddrLen, m_sRemoteIP, &m_iRemotePort ); } return( m_sRemoteIP ); } bool Csock::IsConnected() const { return( m_bIsConnected ); } void Csock::SetIsConnected( bool b ) { m_bIsConnected = b; } cs_sock_t & Csock::GetRSock() { return( m_iReadSock ); } const cs_sock_t & Csock::GetRSock() const { return( m_iReadSock ); } void Csock::SetRSock( cs_sock_t iSock ) { m_iReadSock = iSock; } cs_sock_t & Csock::GetWSock() { return( m_iWriteSock ); } const cs_sock_t & Csock::GetWSock() const { return( m_iWriteSock ); } void Csock::SetWSock( cs_sock_t iSock ) { m_iWriteSock = iSock; } void Csock::SetSock( cs_sock_t iSock ) { m_iWriteSock = iSock; m_iReadSock = iSock; } cs_sock_t & Csock::GetSock() { return( m_iReadSock ); } const cs_sock_t & Csock::GetSock() const { return( m_iReadSock ); } void Csock::ResetTimer() { m_iLastCheckTimeoutTime = 0; m_iTcount = 0; } void Csock::PauseRead() { m_bPauseRead = true; } bool Csock::IsReadPaused() const { return( m_bPauseRead ); } void Csock::UnPauseRead() { m_bPauseRead = false; ResetTimer(); PushBuff( "", 0, true ); } void Csock::SetTimeout( int iTimeout, u_int iTimeoutType ) { m_iTimeoutType = iTimeoutType; m_iTimeout = iTimeout; } void Csock::CallSockError( int iErrno, const CS_STRING & sDescription ) { if( !sDescription.empty() ) { SockError( iErrno, sDescription ); } else { char szBuff[0xff]; SockError( iErrno, CS_StrError( iErrno, szBuff, 0xff ) ); } } void Csock::SetTimeoutType( u_int iTimeoutType ) { m_iTimeoutType = iTimeoutType; } int Csock::GetTimeout() const { return m_iTimeout; } u_int Csock::GetTimeoutType() const { return( m_iTimeoutType ); } bool Csock::CheckTimeout( time_t iNow ) { if( m_iLastCheckTimeoutTime == 0 ) { m_iLastCheckTimeoutTime = iNow; return( false ); } if( IsReadPaused() ) return( false ); time_t iDiff = 0; if( iNow > m_iLastCheckTimeoutTime ) { iDiff = iNow - m_iLastCheckTimeoutTime; } else { // this is weird, but its possible if someone changes a clock and it went back in time, this essentially has to reset the last check // the worst case scenario is the timeout is about to it and the clock changes, it would then cause // this to pass over the last half the time m_iLastCheckTimeoutTime = iNow; } if( m_iTimeout > 0 ) { // this is basically to help stop a clock adjust ahead, stuff could reset immediatly on a clock jump // otherwise time_t iRealTimeout = m_iTimeout; if( iRealTimeout <= 1 ) m_iTcount++; else if( m_iTcount == 0 ) iRealTimeout /= 2; if( iDiff >= iRealTimeout ) { if( m_iTcount == 0 ) m_iLastCheckTimeoutTime = iNow - iRealTimeout; if( m_iTcount++ >= 1 ) { Timeout(); return( true ); } } } return( false ); } void Csock::PushBuff( const char *data, size_t len, bool bStartAtZero ) { if( !m_bEnableReadLine ) return; // If the ReadLine event is disabled, just ditch here size_t iStartPos = ( m_sbuffer.empty() || bStartAtZero ? 0 : m_sbuffer.length() - 1 ); if( data ) m_sbuffer.append( data, len ); while( !m_bPauseRead && GetCloseType() == CLT_DONT ) { CS_STRING::size_type iFind = m_sbuffer.find( "\n", iStartPos ); if( iFind != CS_STRING::npos ) { CS_STRING sBuff = m_sbuffer.substr( 0, iFind + 1 ); // read up to(including) the newline m_sbuffer.erase( 0, iFind + 1 ); // erase past the newline #ifdef HAVE_ICU if( m_cnvExt ) { CS_STRING sUTF8; if( ( m_cnvTryUTF8 && isUTF8( sBuff, sUTF8 ) ) // maybe it's already UTF-8? || icuConv( sBuff, sUTF8, m_cnvExt, m_cnvInt ) ) { ReadLine( sUTF8 ); } else { CS_DEBUG( "Can't convert received line to UTF-8" ); } } else #endif /* HAVE_ICU */ { ReadLine( sBuff ); } iStartPos = 0; // reset this back to 0, since we need to look for the next newline here. } else { break; } } if( m_iMaxStoredBufferLength > 0 && m_sbuffer.length() > m_iMaxStoredBufferLength ) ReachedMaxBuffer(); // call the max read buffer event } #ifdef HAVE_ICU void Csock::IcuExtToUCallback( UConverterToUnicodeArgs* toArgs, const char* codeUnits, int32_t length, UConverterCallbackReason reason, UErrorCode* err) { if( reason <= UCNV_IRREGULAR ) { *err = U_ZERO_ERROR; ucnv_cbToUWriteSub( toArgs, 0, err ); } } void Csock::IcuExtFromUCallback( UConverterFromUnicodeArgs* fromArgs, const UChar* codeUnits, int32_t length, UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err) { if( reason <= UCNV_IRREGULAR ) { *err = U_ZERO_ERROR; ucnv_cbFromUWriteSub( fromArgs, 0, err ); } } static void icuExtToUCallback( const void* context, UConverterToUnicodeArgs* toArgs, const char* codeUnits, int32_t length, UConverterCallbackReason reason, UErrorCode* err) { Csock* pcSock = (Csock*)context; pcSock->IcuExtToUCallback(toArgs, codeUnits, length, reason, err); } static void icuExtFromUCallback( const void* context, UConverterFromUnicodeArgs* fromArgs, const UChar* codeUnits, int32_t length, UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err) { Csock* pcSock = (Csock*)context; pcSock->IcuExtFromUCallback(fromArgs, codeUnits, length, codePoint, reason, err); } void Csock::SetEncoding( const CS_STRING& sEncoding ) { if( m_cnvExt ) ucnv_close( m_cnvExt ); m_cnvExt = NULL; m_sEncoding = sEncoding; if( !sEncoding.empty() ) { m_cnvTryUTF8 = sEncoding[0] == '*' || sEncoding[0] == '^'; m_cnvSendUTF8 = sEncoding[0] == '^'; const char* sEncodingName = sEncoding.c_str(); if( m_cnvTryUTF8 ) sEncodingName++; UErrorCode e = U_ZERO_ERROR; m_cnvExt = ucnv_open( sEncodingName, &e ); if( U_FAILURE( e ) ) { CS_DEBUG( "Can't set encoding to " << sEncoding << ": " << u_errorName( e ) ); } if( m_cnvExt ) { ucnv_setToUCallBack( m_cnvExt, icuExtToUCallback, this, NULL, NULL, &e ); ucnv_setFromUCallBack( m_cnvExt, icuExtFromUCallback, this, NULL, NULL, &e ); } } } #endif /* HAVE_ICU */ CS_STRING & Csock::GetInternalReadBuffer() { return( m_sbuffer ); } CS_STRING & Csock::GetInternalWriteBuffer() { // in the event that some is grabbing this for some reason, we need to // clean it up so it's what they are expecting. ShrinkSendBuff(); return( m_sSend ); } void Csock::SetMaxBufferThreshold( u_int iThreshold ) { m_iMaxStoredBufferLength = iThreshold; } u_int Csock::GetMaxBufferThreshold() const { return( m_iMaxStoredBufferLength ); } int Csock::GetType() const { return( m_iConnType ); } void Csock::SetType( int iType ) { m_iConnType = iType; } const CS_STRING & Csock::GetSockName() const { return( m_sSockName ); } void Csock::SetSockName( const CS_STRING & sName ) { m_sSockName = sName; } const CS_STRING & Csock::GetHostName() const { return( m_shostname ); } void Csock::SetHostName( const CS_STRING & sHostname ) { m_shostname = sHostname; } uint64_t Csock::GetStartTime() const { return( m_iStartTime ); } void Csock::ResetStartTime() { m_iStartTime = 0; } uint64_t Csock::GetBytesRead() const { return( m_iBytesRead ); } void Csock::ResetBytesRead() { m_iBytesRead = 0; } uint64_t Csock::GetBytesWritten() const { return( m_iBytesWritten ); } void Csock::ResetBytesWritten() { m_iBytesWritten = 0; } double Csock::GetAvgRead( uint64_t iSample ) const { uint64_t iDifference = ( millitime() - m_iStartTime ); if( m_iBytesRead == 0 || iSample > iDifference ) return( ( double )m_iBytesRead ); return( ( ( double )m_iBytesRead / ( ( double )iDifference / ( double )iSample ) ) ); } double Csock::GetAvgWrite( uint64_t iSample ) const { uint64_t iDifference = ( millitime() - m_iStartTime ); if( m_iBytesWritten == 0 || iSample > iDifference ) return( ( double )m_iBytesWritten ); return( ( ( double )m_iBytesWritten / ( ( double )iDifference / ( double )iSample ) ) ); } uint16_t Csock::GetRemotePort() const { if( m_iRemotePort > 0 ) return( m_iRemotePort ); GetRemoteIP(); return( m_iRemotePort ); } uint16_t Csock::GetLocalPort() const { if( m_iLocalPort > 0 ) return( m_iLocalPort ); GetLocalIP(); return( m_iLocalPort ); } uint16_t Csock::GetPort() const { return( m_uPort ); } void Csock::SetPort( uint16_t iPort ) { m_uPort = iPort; } void Csock::Close( ECloseType eCloseType ) { m_eCloseType = eCloseType; } void Csock::NonBlockingIO() { set_non_blocking( m_iReadSock ); if( m_iReadSock != m_iWriteSock ) { set_non_blocking( m_iWriteSock ); } } bool Csock::GetSSL() const { return( m_bUseSSL ); } void Csock::SetSSL( bool b ) { m_bUseSSL = b; } #ifdef HAVE_LIBSSL void Csock::SetCipher( const CS_STRING & sCipher ) { m_sCipherType = sCipher; } const CS_STRING & Csock::GetCipher() const { return( m_sCipherType ); } void Csock::SetDHParamLocation( const CS_STRING & sDHParamFile ) { m_sDHParamFile = sDHParamFile; } const CS_STRING & Csock::GetDHParamLocation() const { return( m_sDHParamFile ); } void Csock::SetKeyLocation( const CS_STRING & sKeyFile ) { m_sKeyFile = sKeyFile; } const CS_STRING & Csock::GetKeyLocation() const { return( m_sKeyFile ); } void Csock::SetPemLocation( const CS_STRING & sPemFile ) { m_sPemFile = sPemFile; } const CS_STRING & Csock::GetPemLocation() const { return( m_sPemFile ); } void Csock::SetPemPass( const CS_STRING & sPassword ) { m_sPemPass = sPassword; } const CS_STRING & Csock::GetPemPass() const { return( m_sPemPass ); } void Csock::SetSSLMethod( int iMethod ) { m_iMethod = iMethod; } int Csock::GetSSLMethod() const { return( m_iMethod ); } void Csock::SetSSLObject( SSL *ssl, bool bDeleteExisting ) { if( bDeleteExisting ) FREE_SSL(); m_ssl = ssl; } SSL * Csock::GetSSLObject() const { if( m_ssl ) return( m_ssl ); return( NULL ); } void Csock::SetCTXObject( SSL_CTX *sslCtx, bool bDeleteExisting ) { if( bDeleteExisting ) FREE_CTX(); m_ssl_ctx = sslCtx; } SSL_SESSION * Csock::GetSSLSession() const { if( m_ssl ) return( SSL_get_session( m_ssl ) ); return( NULL ); } #endif /* HAVE_LIBSSL */ bool Csock::HasWriteBuffer() const { // the fact that this has data in it is good enough. Checking m_uSendBufferPos is a moot point // since once m_uSendBufferPos is at the same position as m_sSend it's cleared (in Write) return( !m_sSend.empty() ); } void Csock::ClearWriteBuffer() { m_sSend.clear(); m_uSendBufferPos = 0; } bool Csock::SslIsEstablished() const { return ( m_bsslEstablished ); } bool Csock::ConnectInetd( bool bIsSSL, const CS_STRING & sHostname ) { if( !sHostname.empty() ) m_sSockName = sHostname; // set our hostname if( m_sSockName.empty() ) { struct sockaddr_in client; socklen_t clen = sizeof( client ); if( getpeername( 0, ( struct sockaddr * )&client, &clen ) < 0 ) { m_sSockName = "0.0.0.0:0"; } else { stringstream s; s << inet_ntoa( client.sin_addr ) << ":" << ntohs( client.sin_port ); m_sSockName = s.str(); } } return( ConnectFD( 0, 1, m_sSockName, bIsSSL, INBOUND ) ); } bool Csock::ConnectFD( int iReadFD, int iWriteFD, const CS_STRING & sName, bool bIsSSL, ETConn eDirection ) { if( eDirection == LISTENER ) { CS_DEBUG( "You can not use a LISTENER type here!" ); return( false ); } // set our socket type SetType( eDirection ); // set the hostname m_sSockName = sName; // set the file descriptors SetRSock( iReadFD ); SetWSock( iWriteFD ); // set it up as non-blocking io NonBlockingIO(); if( bIsSSL ) { if( eDirection == INBOUND && !AcceptSSL() ) return( false ); else if( eDirection == OUTBOUND && !ConnectSSL() ) return( false ); } return( true ); } #ifdef HAVE_LIBSSL X509 *Csock::GetX509() const { if( m_ssl ) return( SSL_get_peer_certificate( m_ssl ) ); return( NULL ); } CS_STRING Csock::GetPeerPubKey() const { CS_STRING sKey; X509 * pCert = GetX509(); if( pCert ) { EVP_PKEY * pKey = X509_get_pubkey( pCert ); if( pKey ) { const BIGNUM * pPubKey = NULL; #ifdef HAVE_OPAQUE_SSL int iType = EVP_PKEY_base_id( pKey ); #else int iType = pKey->type; #endif /* HAVE_OPAQUE_SSL */ switch( iType ) { #ifndef OPENSSL_NO_RSA case EVP_PKEY_RSA: # ifdef HAVE_OPAQUE_SSL RSA_get0_key( EVP_PKEY_get0_RSA( pKey ), &pPubKey, NULL, NULL ); # else pPubKey = pKey->pkey.rsa->n; # endif /* HAVE_OPAQUE_SSL */ break; #endif /* OPENSSL_NO_RSA */ #ifndef OPENSSL_NO_DSA case EVP_PKEY_DSA: # ifdef HAVE_OPAQUE_SSL DSA_get0_key( EVP_PKEY_get0_DSA( pKey ), &pPubKey, NULL ); # else pPubKey = pKey->pkey.dsa->pub_key; # endif /* HAVE_OPAQUE_SSL */ break; #endif /* OPENSSL_NO_DSA */ default: CS_DEBUG( "Not Prepared for Public Key Type [" << iType << "]" ); break; } if( pPubKey ) { char *hxKey = BN_bn2hex( pPubKey ); sKey = hxKey; OPENSSL_free( hxKey ); } EVP_PKEY_free( pKey ); } X509_free( pCert ); } return( sKey ); } long Csock::GetPeerFingerprint( CS_STRING & sFP ) const { sFP.clear(); if( !m_ssl ) return( 0 ); X509 * pCert = GetX509(); #ifdef HAVE_OPAQUE_SSL unsigned char sha1_hash[SHA_DIGEST_LENGTH]; if( pCert && X509_digest( pCert, EVP_sha1(), sha1_hash, NULL ) ) #else unsigned char * sha1_hash = NULL; // Inspired by charybdis if( pCert && (sha1_hash = pCert->sha1_hash) ) #endif /* HAVE_OPAQUE_SSL */ { for( int i = 0; i < SHA_DIGEST_LENGTH; i++ ) { char buf[3]; snprintf( buf, 3, "%02x", sha1_hash[i] ); sFP += buf; } } X509_free( pCert ); return( SSL_get_verify_result( m_ssl ) ); } u_int Csock::GetRequireClientCertFlags() const { return( m_iRequireClientCertFlags ); } void Csock::SetRequiresClientCert( bool bRequiresCert ) { m_iRequireClientCertFlags = ( bRequiresCert ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT|SSL_VERIFY_PEER : 0 ); } #endif /* HAVE_LIBSSL */ void Csock::SetParentSockName( const CS_STRING & sParentName ) { m_sParentName = sParentName; } const CS_STRING & Csock::GetParentSockName() const { return( m_sParentName ); } void Csock::SetRate( u_int iBytes, uint64_t iMilliseconds ) { m_iMaxBytes = iBytes; m_iMaxMilliSeconds = iMilliseconds; } u_int Csock::GetRateBytes() const { return( m_iMaxBytes ); } uint64_t Csock::GetRateTime() const { return( m_iMaxMilliSeconds ); } void Csock::EnableReadLine() { m_bEnableReadLine = true; } void Csock::DisableReadLine() { m_bEnableReadLine = false; m_sbuffer.clear(); } void Csock::ReachedMaxBuffer() { std::cerr << "Warning, Max Buffer length Warning Threshold has been hit" << endl; std::cerr << "If you don't care, then set SetMaxBufferThreshold to 0" << endl; } time_t Csock::GetTimeSinceLastDataTransaction( time_t iNow ) const { if( m_iLastCheckTimeoutTime == 0 ) return( 0 ); return( ( iNow > 0 ? iNow : time( NULL ) ) - m_iLastCheckTimeoutTime ); } time_t Csock::GetNextCheckTimeout( time_t iNow ) const { if( iNow == 0 ) iNow = time( NULL ); time_t iTimeout = m_iTimeout; time_t iDiff = iNow - m_iLastCheckTimeoutTime; /* CheckTimeout() wants to be called after half the timeout */ if( m_iTcount == 0 ) iTimeout /= 2; if( iDiff > iTimeout ) iTimeout = 0; else iTimeout -= iDiff; return( iNow + iTimeout ); } int Csock::GetPending() const { #ifdef HAVE_LIBSSL if( m_ssl ) { // in v23 method, the pending function is initialized to ssl_undefined_const_function // which throws SSL_UNDEFINED_CONST_FUNCTION on to the error stack // this is one of the more stupid things in openssl, it seems bizarre that even though SSL_pending // returns an int, they don't bother returning in error to notify us, so basically // we have to always clear errors here generated by SSL_pending, otherwise the stack could // have a lame error on it causing SSL_write to fail in certain instances. #if defined( OPENSSL_VERSION_NUMBER ) && OPENSSL_VERSION_NUMBER >= 0x00908000 ERR_set_mark(); int iBytes = SSL_pending( m_ssl ); ERR_pop_to_mark(); return( iBytes ); #else int iBytes = SSL_pending( m_ssl ); ERR_clear_error(); // to get safer handling, upgrade your openssl version! return( iBytes ); #endif /* OPENSSL_VERSION_NUMBER */ } else return( 0 ); #else return( 0 ); #endif /* HAVE_LIBSSL */ } bool Csock::CreateSocksFD() { if( m_iReadSock != CS_INVALID_SOCK ) return( true ); m_iReadSock = m_iWriteSock = CreateSocket(); if( m_iReadSock == CS_INVALID_SOCK ) return( false ); m_address.SinFamily(); m_address.SinPort( m_uPort ); return( true ); } int Csock::GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr ) { #ifdef HAVE_IPV6 if( csSockAddr.GetAFRequire() != AF_INET && inet_pton( AF_INET6, sHostname.c_str(), csSockAddr.GetAddr6() ) > 0 ) { SetIPv6( true ); return( 0 ); } #endif /* HAVE_IPV6 */ if( inet_pton( AF_INET, sHostname.c_str(), csSockAddr.GetAddr() ) > 0 ) { #ifdef HAVE_IPV6 SetIPv6( false ); #endif /* HAVE_IPV6 */ return( 0 ); } #ifdef HAVE_C_ARES // need to compute this up here if( !m_pARESChannel ) { if( ares_init( &m_pARESChannel ) != ARES_SUCCESS ) { // TODO throw some debug? FreeAres(); return( ETIMEDOUT ); } m_pCurrAddr = &csSockAddr; // flag its starting int iFamily = AF_INET; #ifdef HAVE_IPV6 #if ARES_VERSION >= CREATE_ARES_VER( 1, 7, 5 ) // as of ares 1.7.5, it falls back to af_inet only when AF_UNSPEC is specified // so this can finally let the code flow through as anticipated :) iFamily = csSockAddr.GetAFRequire(); #else // as of ares 1.6.0 if it fails on af_inet6, it falls back to af_inet, // this code was here in the previous Csocket version, just adding the comment as a reminder iFamily = csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY ? AF_INET6 : csSockAddr.GetAFRequire(); #endif /* CREATE_ARES_VER( 1, 7, 5 ) */ #endif /* HAVE_IPV6 */ ares_gethostbyname( m_pARESChannel, sHostname.c_str(), iFamily, AresHostCallback, this ); } if( !m_pCurrAddr ) { // this means its finished FreeAres(); #ifdef HAVE_IPV6 if( GetType() != LISTENER && m_iARESStatus == ARES_SUCCESS && csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY && GetIPv6() ) { // this means that ares_host returned an ipv6 host, so try a connect right away if( CreateSocksFD() && Connect() ) { SetSkipConnect( true ); } #ifndef _WIN32 else if( GetSockError() == ENETUNREACH ) #else else if( GetSockError() == WSAENETUNREACH || GetSockError() == WSAEHOSTUNREACH ) #endif /* !_WIN32 */ { // the Connect() failed, so throw a retry back in with ipv4, and let it process normally CS_DEBUG( "Failed ipv6 connection with PF_UNSPEC, falling back to ipv4" ); m_iARESStatus = -1; CloseSocksFD(); SetAFRequire( CSSockAddr::RAF_INET ); return( GetAddrInfo( sHostname, csSockAddr ) ); } } #if ARES_VERSION < CREATE_ARES_VER( 1, 5, 3 ) if( m_iARESStatus != ARES_SUCCESS && csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY ) { // this is a workaround for ares < 1.5.3 where the builtin retry on failed AF_INET6 isn't there yet CS_DEBUG( "Retry for older version of c-ares with AF_INET only" ); // this means we tried previously with AF_INET6 and failed, so force AF_INET and retry SetAFRequire( CSSockAddr::RAF_INET ); return( GetAddrInfo( sHostname, csSockAddr ) ); } #endif /* ARES_VERSION < CREATE_ARES_VER( 1, 5, 3 ) */ #endif /* HAVE_IPV6 */ return( m_iARESStatus == ARES_SUCCESS ? 0 : ETIMEDOUT ); } return( EAGAIN ); #else /* HAVE_C_ARES */ return( ::CS_GetAddrInfo( sHostname, this, csSockAddr ) ); #endif /* HAVE_C_ARES */ } int Csock::DNSLookup( EDNSLType eDNSLType ) { if( eDNSLType == DNS_VHOST ) { if( m_sBindHost.empty() ) { if( m_eConState != CST_OK ) m_eConState = CST_DESTDNS; // skip binding, there is no vhost return( 0 ); } m_bindhost.SinFamily(); m_bindhost.SinPort( 0 ); } int iRet = ETIMEDOUT; if( eDNSLType == DNS_VHOST ) { iRet = GetAddrInfo( m_sBindHost, m_bindhost ); #ifdef HAVE_IPV6 if( m_bindhost.GetIPv6() ) { SetAFRequire( CSSockAddr::RAF_INET6 ); } else { SetAFRequire( CSSockAddr::RAF_INET ); } #endif /* HAVE_IPV6 */ } else { iRet = GetAddrInfo( m_shostname, m_address ); } if( iRet == 0 ) { if( !CreateSocksFD() ) { m_iDNSTryCount = 0; return( ETIMEDOUT ); } if( m_eConState != CST_OK ) m_eConState = ( ( eDNSLType == DNS_VHOST ) ? CST_BINDVHOST : CST_CONNECT ); m_iDNSTryCount = 0; return( 0 ); } else if( iRet == EAGAIN ) { #ifndef HAVE_C_ARES m_iDNSTryCount++; if( m_iDNSTryCount > 20 ) { m_iDNSTryCount = 0; return( ETIMEDOUT ); } #endif /* HAVE_C_ARES */ return( EAGAIN ); } m_iDNSTryCount = 0; return( ETIMEDOUT ); } bool Csock::SetupVHost() { if( m_sBindHost.empty() ) { if( m_eConState != CST_OK ) m_eConState = CST_DESTDNS; return( true ); } int iRet = -1; if( !GetIPv6() ) iRet = bind( m_iReadSock, ( struct sockaddr * ) m_bindhost.GetSockAddr(), m_bindhost.GetSockAddrLen() ); #ifdef HAVE_IPV6 else iRet = bind( m_iReadSock, ( struct sockaddr * ) m_bindhost.GetSockAddr6(), m_bindhost.GetSockAddrLen6() ); #endif /* HAVE_IPV6 */ if( iRet == 0 ) { if( m_eConState != CST_OK ) m_eConState = CST_DESTDNS; return( true ); } m_iCurBindCount++; if( m_iCurBindCount > 3 ) { CS_DEBUG( "Failure to bind to " << m_sBindHost ); return( false ); } return( true ); } #ifdef HAVE_LIBSSL void Csock::FREE_SSL() { if( m_ssl ) { SSL_shutdown( m_ssl ); SSL_free( m_ssl ); } m_ssl = NULL; } void Csock::FREE_CTX() { if( m_ssl_ctx ) SSL_CTX_free( m_ssl_ctx ); m_ssl_ctx = NULL; } #endif /* HAVE_LIBSSL */ cs_sock_t Csock::CreateSocket( bool bListen, bool bUnix ) { int domain, protocol; if ( !bUnix ) { #ifdef HAVE_IPV6 domain = ( GetIPv6() ? PF_INET6 : PF_INET ); #else domain = PF_INET; #endif /* HAVE_IPV6 */ protocol = IPPROTO_TCP; } else { #ifdef HAVE_UNIX_SOCKET domain = AF_UNIX; protocol = 0; #else return CS_INVALID_SOCK; #endif } cs_sock_t iRet = socket( domain, SOCK_STREAM, protocol ); if( iRet != CS_INVALID_SOCK ) { set_close_on_exec( iRet ); if( bListen ) { const int on = 1; if( setsockopt( iRet, SOL_SOCKET, SO_REUSEADDR, ( char * ) &on, sizeof( on ) ) != 0 ) PERROR( "SO_REUSEADDR" ); } } else { PERROR( "socket" ); } return( iRet ); } void Csock::Init( const CS_STRING & sHostname, uint16_t uPort, int iTimeout ) { #ifdef HAVE_LIBSSL m_ssl = NULL; m_ssl_ctx = NULL; m_iRequireClientCertFlags = 0; m_uDisableProtocols = 0; m_bNoSSLCompression = false; m_bSSLCipherServerPreference = false; #endif /* HAVE_LIBSSL */ m_iTcount = 0; m_iReadSock = CS_INVALID_SOCK; m_iWriteSock = CS_INVALID_SOCK; m_iTimeout = iTimeout; m_iMaxConns = SOMAXCONN; m_bUseSSL = false; m_bIsConnected = false; m_uPort = uPort; m_shostname = sHostname; m_sbuffer.clear(); m_eCloseType = CLT_DONT; /* * While I appreciate the line ... * "It's 2014, no idea how this made it as a default for the past 16 years..." * TLS 1.2 was introduced in 2008. That being said, it's still not widely supported so I'm not * ready to make it the default. SSL 3.0 is still the most widely supported standard and that's * what a sane default is supposed to be. Additionally, OpenSSL is smart with SSLv23_client_method * as it will check for TLS in addition to SSL (per the manual) which is the reason for its choice. * * https://www.openssl.org/docs/ssl/SSL_CTX_new.html */ m_iMethod = SSL23; m_sCipherType = "ALL"; m_iMaxBytes = 0; m_iMaxMilliSeconds = 0; m_iLastSendTime = 0; m_iLastSend = 0; m_uSendBufferPos = 0; m_bsslEstablished = false; m_bEnableReadLine = false; m_iMaxStoredBufferLength = 1024; m_iConnType = INBOUND; m_iRemotePort = 0; m_iLocalPort = 0; m_iBytesRead = 0; m_iBytesWritten = 0; m_iStartTime = millitime(); m_bPauseRead = false; m_iTimeoutType = TMO_ALL; m_eConState = CST_OK; // default should be ok m_iDNSTryCount = 0; m_iCurBindCount = 0; m_bIsIPv6 = false; m_bSkipConnect = false; m_iLastCheckTimeoutTime = 0; #ifdef HAVE_C_ARES m_pARESChannel = NULL; m_pCurrAddr = NULL; m_iARESStatus = -1; #endif /* HAVE_C_ARES */ #ifdef HAVE_ICU m_cnvTryUTF8 = false; m_cnvSendUTF8 = false; UErrorCode e = U_ZERO_ERROR; m_cnvExt = NULL; m_cnvInt = ucnv_open( "UTF-8", &e ); #endif /* HAVE_ICU */ } ////////////////////////// CSocketManager ////////////////////////// CSocketManager::CSocketManager() : std::vector(), CSockCommon() { m_errno = SUCCESS; m_iCallTimeouts = millitime(); m_iSelectWait = 100000; // Default of 100 milliseconds m_iBytesRead = 0; m_iBytesWritten = 0; } CSocketManager::~CSocketManager() { clear(); } void CSocketManager::clear() { while( !this->empty() ) DelSock( 0 ); } void CSocketManager::Cleanup() { CleanupCrons(); CleanupFDMonitors(); clear(); } Csock * CSocketManager::GetSockObj( const CS_STRING & sHostname, uint16_t uPort, int iTimeout ) { return( new Csock( sHostname, uPort, iTimeout ) ); } void CSocketManager::Connect( const CSConnection & cCon, Csock * pcSock ) { // create the new object if( !pcSock ) pcSock = GetSockObj( cCon.GetHostname(), cCon.GetPort(), cCon.GetTimeout() ); else { pcSock->SetHostName( cCon.GetHostname() ); pcSock->SetPort( cCon.GetPort() ); pcSock->SetTimeout( cCon.GetTimeout() ); } if( cCon.GetAFRequire() != CSSockAddr::RAF_ANY ) pcSock->SetAFRequire( cCon.GetAFRequire() ); // bind the vhost pcSock->SetBindHost( cCon.GetBindHost() ); #ifdef HAVE_LIBSSL pcSock->SetSSL( cCon.GetIsSSL() ); if( cCon.GetIsSSL() ) { if( !cCon.GetPemLocation().empty() ) { pcSock->SetDHParamLocation( cCon.GetDHParamLocation() ); pcSock->SetKeyLocation( cCon.GetKeyLocation() ); pcSock->SetPemLocation( cCon.GetPemLocation() ); pcSock->SetPemPass( cCon.GetPemPass() ); } if( !cCon.GetCipher().empty() ) pcSock->SetCipher( cCon.GetCipher() ); } #endif /* HAVE_LIBSSL */ pcSock->SetType( Csock::OUTBOUND ); pcSock->SetConState( Csock::CST_START ); AddSock( pcSock, cCon.GetSockName() ); } bool CSocketManager::Listen( const CSListener & cListen, Csock * pcSock, uint16_t * piRandPort ) { if( !pcSock ) pcSock = GetSockObj( "", 0 ); if( cListen.GetAFRequire() != CSSockAddr::RAF_ANY ) { pcSock->SetAFRequire( cListen.GetAFRequire() ); #ifdef HAVE_IPV6 if( cListen.GetAFRequire() == CSSockAddr::RAF_INET6 ) pcSock->SetIPv6( true ); #endif /* HAVE_IPV6 */ } #ifdef HAVE_IPV6 else { pcSock->SetIPv6( true ); } #endif /* HAVE_IPV6 */ #ifdef HAVE_LIBSSL pcSock->SetSSL( cListen.GetIsSSL() ); if( cListen.GetIsSSL() && !cListen.GetPemLocation().empty() ) { pcSock->SetDHParamLocation( cListen.GetDHParamLocation() ); pcSock->SetKeyLocation( cListen.GetKeyLocation() ); pcSock->SetPemLocation( cListen.GetPemLocation() ); pcSock->SetPemPass( cListen.GetPemPass() ); pcSock->SetCipher( cListen.GetCipher() ); pcSock->SetRequireClientCertFlags( cListen.GetRequireClientCertFlags() ); } #endif /* HAVE_LIBSSL */ if( piRandPort ) *piRandPort = 0; bool bDetach = ( cListen.GetDetach() && !piRandPort ); // can't detach if we're waiting for the port to come up right now if( pcSock->Listen( cListen.GetPort(), cListen.GetMaxConns(), cListen.GetBindHost(), cListen.GetTimeout(), bDetach ) ) { AddSock( pcSock, cListen.GetSockName() ); if( piRandPort && cListen.GetPort() == 0 ) { cs_sock_t iSock = pcSock->GetSock(); if( iSock == CS_INVALID_SOCK ) { CS_DEBUG( "Failed to attain a valid file descriptor" ); pcSock->Close(); return( false ); } struct sockaddr_in mLocalAddr; socklen_t mLocalLen = sizeof( mLocalAddr ); getsockname( iSock, ( struct sockaddr * ) &mLocalAddr, &mLocalLen ); *piRandPort = ntohs( mLocalAddr.sin_port ); } return( true ); } CS_Delete( pcSock ); return( false ); } bool CSocketManager::HasFDs() const { return( !this->empty() || !m_vcMonitorFD.empty() ); } void CSocketManager::Loop() { for( size_t a = 0; a < this->size(); ++a ) { Csock * pcSock = this->at( a ); if( pcSock->GetType() != Csock::OUTBOUND || pcSock->GetConState() == Csock::CST_OK ) continue; if( pcSock->GetConState() == Csock::CST_DNS ) { if( pcSock->DNSLookup( Csock::DNS_VHOST ) == ETIMEDOUT ) { pcSock->CallSockError( EDOM, "DNS Lookup for bind host failed" ); DelSock( a-- ); continue; } } if( pcSock->GetConState() == Csock::CST_BINDVHOST ) { if( !pcSock->SetupVHost() ) { pcSock->CallSockError( GetSockError(), "Failed to setup bind host" ); DelSock( a-- ); continue; } } if( pcSock->GetConState() == Csock::CST_DESTDNS ) { if( pcSock->DNSLookup( Csock::DNS_DEST ) == ETIMEDOUT ) { pcSock->CallSockError( EADDRNOTAVAIL, "Unable to resolve requested address" ); DelSock( a-- ); continue; } } if( pcSock->GetConState() == Csock::CST_CONNECT ) { if( !pcSock->Connect() ) { if( GetSockError() == ECONNREFUSED ) pcSock->ConnectionRefused(); else pcSock->CallSockError( GetSockError() ); DelSock( a-- ); continue; } } #ifdef HAVE_LIBSSL if( pcSock->GetConState() == Csock::CST_CONNECTSSL ) { if( pcSock->GetSSL() ) { if( !pcSock->ConnectSSL() ) { if( GetSockError() == ECONNREFUSED ) pcSock->ConnectionRefused(); else pcSock->CallSockError( GetSockError() == 0 ? ECONNABORTED : GetSockError() ); DelSock( a-- ); continue; } } } #endif /* HAVE_LIBSSL */ } std::map mpeSocks; Select( mpeSocks ); switch( m_errno ) { case SUCCESS: { for( std::map::iterator itSock = mpeSocks.begin(); itSock != mpeSocks.end(); itSock++ ) { Csock * pcSock = itSock->first; EMessages iErrno = itSock->second; if( iErrno == SUCCESS ) { // read in data // if this is a int iLen = 0; if( pcSock->GetSSL() ) iLen = pcSock->GetPending(); if( iLen <= 0 ) iLen = CS_BLOCKSIZE; CSCharBuffer cBuff( iLen ); cs_ssize_t bytes = pcSock->Read( cBuff(), iLen ); if( bytes != Csock::READ_TIMEDOUT && bytes != Csock::READ_CONNREFUSED && bytes != Csock::READ_ERR && !pcSock->IsConnected() ) { pcSock->SetIsConnected( true ); pcSock->Connected(); } switch( bytes ) { case Csock::READ_EOF: { DelSockByAddr( pcSock ); break; } case Csock::READ_ERR: { bool bHandled = false; #ifdef HAVE_LIBSSL if( pcSock->GetSSL() ) { unsigned long iSSLError = ERR_peek_error(); if( iSSLError ) { char szError[512]; memset( ( char * ) szError, '\0', 512 ); ERR_error_string_n( iSSLError, szError, 511 ); SSLErrors( __FILE__, __LINE__ ); pcSock->CallSockError( GetSockError(), szError ); bHandled = true; } } #endif if( !bHandled ) pcSock->CallSockError( GetSockError() ); DelSockByAddr( pcSock ); break; } case Csock::READ_EAGAIN: break; case Csock::READ_CONNREFUSED: pcSock->ConnectionRefused(); DelSockByAddr( pcSock ); break; case Csock::READ_TIMEDOUT: pcSock->Timeout(); DelSockByAddr( pcSock ); break; default: { if( Csock::TMO_READ & pcSock->GetTimeoutType() ) pcSock->ResetTimer(); // reset the timeout timer pcSock->ReadData( cBuff(), bytes ); // Call ReadData() before PushBuff() so that it is called before the ReadLine() event - LD 07/18/05 pcSock->PushBuff( cBuff(), bytes ); break; } } } else if( iErrno == SELECT_ERROR ) { // a socket came back with an error // usually means it was closed DelSockByAddr( pcSock ); } } break; } case SELECT_TIMEOUT: case SELECT_TRYAGAIN: case SELECT_ERROR: default : break; } uint64_t iMilliNow = millitime(); if( ( iMilliNow - m_iCallTimeouts ) >= 1000 ) { m_iCallTimeouts = iMilliNow; // call timeout on all the sockets that recieved no data for( size_t i = 0; i < this->size(); ++i ) { if( this->at( i )->GetConState() != Csock::CST_OK ) continue; if( this->at( i )->CheckTimeout( ( time_t )( iMilliNow / 1000 ) ) ) DelSock( i-- ); } } // run any Manager Crons we may have Cron(); } void CSocketManager::DynamicSelectLoop( uint64_t iLowerBounds, uint64_t iUpperBounds, time_t iMaxResolution ) { SetSelectTimeout( iLowerBounds ); if( m_errno == SELECT_TIMEOUT ) { // only do this if the previous call to select was a timeout timeval tMaxResolution; timeval tNow; tMaxResolution.tv_sec = iMaxResolution; tMaxResolution.tv_usec = 0; CS_GETTIMEOFDAY( &tNow, NULL ); timeval tSelectTimeout = GetDynamicSleepTime( tNow, tMaxResolution ); uint64_t iSelectTimeout = tSelectTimeout.tv_sec * 1000000 + tSelectTimeout.tv_usec; iSelectTimeout = std::max( iLowerBounds, iSelectTimeout ); iSelectTimeout = std::min( iSelectTimeout, iUpperBounds ); if( iLowerBounds != iSelectTimeout ) SetSelectTimeout( iSelectTimeout ); } Loop(); } void CSocketManager::AddSock( Csock * pcSock, const CS_STRING & sSockName ) { pcSock->SetSockName( sSockName ); this->push_back( pcSock ); } Csock * CSocketManager::FindSockByRemotePort( uint16_t iPort ) { for( size_t i = 0; i < this->size(); ++i ) { if( this->at( i )->GetRemotePort() == iPort ) return( this->at( i ) ); } return( NULL ); } Csock * CSocketManager::FindSockByLocalPort( uint16_t iPort ) { for( size_t i = 0; i < this->size(); ++i ) { if( this->at( i )->GetLocalPort() == iPort ) return( this->at( i ) ); } return( NULL ); } Csock * CSocketManager::FindSockByName( const CS_STRING & sName ) { std::vector::iterator it; std::vector::iterator it_end = this->end(); for( it = this->begin(); it != it_end; it++ ) { if( ( *it )->GetSockName() == sName ) return( *it ); } return( NULL ); } Csock * CSocketManager::FindSockByFD( cs_sock_t iFD ) { for( size_t i = 0; i < this->size(); ++i ) { if( this->at( i )->GetRSock() == iFD || this->at( i )->GetWSock() == iFD ) return( this->at( i ) ); } return( NULL ); } std::vector CSocketManager::FindSocksByName( const CS_STRING & sName ) { std::vector vpSocks; for( size_t i = 0; i < this->size(); ++i ) { if( this->at( i )->GetSockName() == sName ) vpSocks.push_back( this->at( i ) ); } return( vpSocks ); } std::vector CSocketManager::FindSocksByRemoteHost( const CS_STRING & sHostname ) { std::vector vpSocks; for( size_t i = 0; i < this->size(); ++i ) { if( this->at( i )->GetHostName() == sHostname ) vpSocks.push_back( this->at( i ) ); } return( vpSocks ); } void CSocketManager::DelSockByAddr( Csock * pcSock ) { for( size_t a = 0; a < this->size(); ++a ) { if( pcSock == this->at( a ) ) { DelSock( a ); return; } } } void CSocketManager::DelSock( size_t iPos ) { if( iPos >= this->size() ) { CS_DEBUG( "Invalid Sock Position Requested! [" << iPos << "]" ); return; } Csock * pSock = this->at( iPos ); if( pSock->GetCloseType() != Csock::CLT_DEREFERENCE ) { if( pSock->IsConnected() ) { pSock->SetIsConnected( false ); pSock->Disconnected(); // only call disconnected event if connected event was called (IE IsConnected was set) } m_iBytesRead += pSock->GetBytesRead(); m_iBytesWritten += pSock->GetBytesWritten(); } CS_Delete( pSock ); this->erase( this->begin() + iPos ); } bool CSocketManager::SwapSockByIdx( Csock * pNewSock, size_t iOrginalSockIdx ) { if( iOrginalSockIdx >= this->size() ) { CS_DEBUG( "Invalid Sock Position Requested! [" << iOrginalSockIdx << "]" ); return( false ); } Csock * pSock = this->at( iOrginalSockIdx ); pNewSock->Copy( *pSock ); pSock->Dereference(); this->at( iOrginalSockIdx ) = ( Csock * )pNewSock; this->push_back( ( Csock * )pSock ); // this allows it to get cleaned up return( true ); } bool CSocketManager::SwapSockByAddr( Csock * pNewSock, Csock * pOrigSock ) { for( size_t a = 0; a < this->size(); ++a ) { if( this->at( a ) == pOrigSock ) return( SwapSockByIdx( pNewSock, a ) ); } return( false ); } uint64_t CSocketManager::GetBytesRead() const { // Start with the total bytes read from destroyed sockets uint64_t iRet = m_iBytesRead; // Add in the outstanding bytes read from active sockets for( size_t a = 0; a < this->size(); ++a ) iRet += this->at( a )->GetBytesRead(); return( iRet ); } uint64_t CSocketManager::GetBytesWritten() const { // Start with the total bytes written to destroyed sockets uint64_t iRet = m_iBytesWritten; // Add in the outstanding bytes written to active sockets for( size_t a = 0; a < this->size(); ++a ) iRet += this->at( a )->GetBytesWritten(); return( iRet ); } void CSocketManager::FDSetCheck( cs_sock_t iFd, std::map< cs_sock_t, short > & miiReadyFds, ECheckType eType ) { std::map< cs_sock_t, short >::iterator it = miiReadyFds.find( iFd ); if( it != miiReadyFds.end() ) it->second = ( short )( it->second | eType ); // TODO need to figure out why |= throws 'short int' from 'int' may alter its value else miiReadyFds[iFd] = eType; } bool CSocketManager::FDHasCheck( cs_sock_t iFd, std::map< cs_sock_t, short > & miiReadyFds, ECheckType eType ) { std::map< cs_sock_t, short >::iterator it = miiReadyFds.find( iFd ); if( it != miiReadyFds.end() ) return( ( it->second & eType ) != 0 ); return( false ); } int CSocketManager::Select( std::map< cs_sock_t, short > & miiReadyFds, struct timeval *tvtimeout ) { AssignFDs( miiReadyFds, tvtimeout ); #ifdef CSOCK_USE_POLL if( miiReadyFds.empty() ) return( select( 0, NULL, NULL, NULL, tvtimeout ) ); struct pollfd * pFDs = ( struct pollfd * )malloc( sizeof( struct pollfd ) * miiReadyFds.size() ); size_t uCurrPoll = 0; for( std::map< cs_sock_t, short >::iterator it = miiReadyFds.begin(); it != miiReadyFds.end(); ++it, ++uCurrPoll ) { short iEvents = 0; if( it->second & ECT_Read ) iEvents |= POLLIN; if( it->second & ECT_Write ) iEvents |= POLLOUT; pFDs[uCurrPoll].fd = it->first; pFDs[uCurrPoll].events = iEvents; pFDs[uCurrPoll].revents = 0; } int iTimeout = ( int )( tvtimeout->tv_usec / 1000 ); iTimeout += ( int )( tvtimeout->tv_sec * 1000 ); size_t uMaxFD = miiReadyFds.size(); int iRet = poll( pFDs, uMaxFD, iTimeout ); miiReadyFds.clear(); for( uCurrPoll = 0; uCurrPoll < uMaxFD; ++uCurrPoll ) { short iEvents = 0; if( pFDs[uCurrPoll].revents & ( POLLIN|POLLERR|POLLHUP|POLLNVAL ) ) iEvents |= ECT_Read; if( pFDs[uCurrPoll].revents & POLLOUT ) iEvents |= ECT_Write; std::map< cs_sock_t, short >::iterator it = miiReadyFds.find( pFDs[uCurrPoll].fd ); if( it != miiReadyFds.end() ) it->second = ( short )( it->second | iEvents ); // TODO need to figure out why |= throws 'short int' from 'int' may alter its value else miiReadyFds[pFDs[uCurrPoll].fd] = iEvents; } free( pFDs ); #else fd_set rfds, wfds; TFD_ZERO( &rfds ); TFD_ZERO( &wfds ); bool bHasWrite = false; int iHighestFD = 0; for( std::map< cs_sock_t, short >::iterator it = miiReadyFds.begin(); it != miiReadyFds.end(); ++it ) { #ifndef _WIN32 // the first argument to select() is not used on Win32. iHighestFD = std::max( it->first, iHighestFD ); #endif /* _WIN32 */ if( it->second & ECT_Read ) { TFD_SET( it->first, &rfds ); } if( it->second & ECT_Write ) { bHasWrite = true; TFD_SET( it->first, &wfds ); } } int iRet = select( iHighestFD + 1, &rfds, ( bHasWrite ? &wfds : NULL ), NULL, tvtimeout ); if( iRet <= 0 ) { miiReadyFds.clear(); } else { for( std::map< cs_sock_t, short >::iterator it = miiReadyFds.begin(); it != miiReadyFds.end(); ++it ) { if( ( it->second & ECT_Read ) && !TFD_ISSET( it->first, &rfds ) ) it->second &= ~ECT_Read; if( ( it->second & ECT_Write ) && !TFD_ISSET( it->first, &wfds ) ) it->second &= ~ECT_Write; } } #endif /* CSOCK_USE_POLL */ return( iRet ); } void CSocketManager::Select( std::map & mpeSocks ) { mpeSocks.clear(); struct timeval tv; std::map< cs_sock_t, short > miiReadyFds; tv.tv_sec = ( time_t )( m_iSelectWait / 1000000 ); tv.tv_usec = ( time_t )( m_iSelectWait % 1000000 ); u_int iQuickReset = 1000; if( m_iSelectWait == 0 ) iQuickReset = 0; bool bHasAvailSocks = false; uint64_t iNOW = 0; for( size_t i = 0; i < this->size(); ++i ) { Csock * pcSock = this->at( i ); Csock::ECloseType eCloseType = pcSock->GetCloseType(); if( eCloseType == Csock::CLT_NOW || eCloseType == Csock::CLT_DEREFERENCE || ( eCloseType == Csock::CLT_AFTERWRITE && !pcSock->HasWriteBuffer() ) ) { DelSock( i-- ); // close any socks that have requested it continue; } else { pcSock->Cron(); // call the Cron handler here } cs_sock_t & iRSock = pcSock->GetRSock(); cs_sock_t & iWSock = pcSock->GetWSock(); #if !defined(CSOCK_USE_POLL) && !defined(_WIN32) if( iRSock > ( cs_sock_t )FD_SETSIZE || iWSock > ( cs_sock_t )FD_SETSIZE ) { CS_DEBUG( "FD is larger than select() can handle" ); DelSock( i-- ); continue; } #endif /* CSOCK_USE_POLL */ #ifdef HAVE_C_ARES ares_channel pChannel = pcSock->GetAresChannel(); if( pChannel ) { ares_socket_t aiAresSocks[1]; aiAresSocks[0] = ARES_SOCKET_BAD; int iSockMask = ares_getsock( pChannel, aiAresSocks, 1 ); if( ARES_GETSOCK_READABLE( iSockMask, 0 ) ) FDSetCheck( aiAresSocks[0], miiReadyFds, ECT_Read ); if( ARES_GETSOCK_WRITABLE( iSockMask, 0 ) ) FDSetCheck( aiAresSocks[0], miiReadyFds, ECT_Write ); // let ares drop the timeout if it has something timing out sooner then whats in tv currently ares_timeout( pChannel, &tv, &tv ); } #endif /* HAVE_C_ARES */ if( pcSock->GetType() == Csock::LISTENER && pcSock->GetConState() == Csock::CST_BINDVHOST ) { if( !pcSock->Listen( pcSock->GetPort(), pcSock->GetMaxConns(), pcSock->GetBindHost(), pcSock->GetTimeout(), true ) ) { pcSock->Close(); DelSock( i-- ); } continue; } pcSock->AssignFDs( miiReadyFds, &tv ); if( pcSock->GetConState() != Csock::CST_OK ) continue; bHasAvailSocks = true; bool bIsReadPaused = pcSock->IsReadPaused(); if( bIsReadPaused ) { pcSock->ReadPaused(); bIsReadPaused = pcSock->IsReadPaused(); // re-read it again, incase it changed status) } if( iRSock == CS_INVALID_SOCK || iWSock == CS_INVALID_SOCK ) { SelectSock( mpeSocks, SUCCESS, pcSock ); continue; // invalid sock fd } if( pcSock->GetType() != Csock::LISTENER ) { bool bHasWriteBuffer = pcSock->HasWriteBuffer(); if( !bIsReadPaused ) FDSetCheck( iRSock, miiReadyFds, ECT_Read ); if( pcSock->AllowWrite( iNOW ) && ( !pcSock->IsConnected() || bHasWriteBuffer ) ) { if( !pcSock->IsConnected() ) { // set the write bit if not connected yet FDSetCheck( iWSock, miiReadyFds, ECT_Write ); } else if( bHasWriteBuffer && !pcSock->GetSSL() ) { // always set the write bit if there is data to send when NOT ssl FDSetCheck( iWSock, miiReadyFds, ECT_Write ); } else if( bHasWriteBuffer && pcSock->GetSSL() && pcSock->SslIsEstablished() ) { // ONLY set the write bit if there is data to send and the SSL handshake is finished FDSetCheck( iWSock, miiReadyFds, ECT_Write ); } } if( pcSock->GetSSL() && !pcSock->SslIsEstablished() && bHasWriteBuffer ) { // if this is an unestabled SSL session with data to send ... try sending it // do this here, cause otherwise ssl will cause a small // cpu spike waiting for the handshake to finish // resend this data if( !pcSock->Write( "" ) ) { pcSock->Close(); } // warning ... setting write bit in here causes massive CPU spinning on invalid SSL servers // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=631590 // however, we can set the select WAY down and it will retry quickly, but keep it from spinning at 100% tv.tv_usec = iQuickReset; tv.tv_sec = 0; } } else { FDSetCheck( iRSock, miiReadyFds, ECT_Read ); } if( pcSock->GetSSL() && pcSock->GetType() != Csock::LISTENER ) { if( pcSock->GetPending() > 0 && !pcSock->IsReadPaused() ) SelectSock( mpeSocks, SUCCESS, pcSock ); } } // old fashion select, go fer it int iSel; if( !mpeSocks.empty() ) // .1 ms pause to see if anything else is ready (IE if there is SSL data pending, don't wait too long) { tv.tv_usec = iQuickReset; tv.tv_sec = 0; } else if( !this->empty() && !bHasAvailSocks ) { tv.tv_usec = iQuickReset; tv.tv_sec = 0; } iSel = Select( miiReadyFds, &tv ); if( iSel == 0 ) { if( mpeSocks.empty() ) m_errno = SELECT_TIMEOUT; else m_errno = SUCCESS; #ifdef HAVE_C_ARES // run through ares channels and process timeouts for( size_t uSock = 0; uSock < this->size(); ++uSock ) { Csock * pcSock = this->at( uSock ); ares_channel pChannel = pcSock->GetAresChannel(); if( pChannel ) ares_process_fd( pChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD ); } #endif /* HAVE_C_ARES */ return; } if( iSel == -1 && errno == EINTR ) { if( mpeSocks.empty() ) m_errno = SELECT_TRYAGAIN; else m_errno = SUCCESS; return; } else if( iSel == -1 ) { if( mpeSocks.empty() ) m_errno = SELECT_ERROR; else m_errno = SUCCESS; return; } else { m_errno = SUCCESS; } CheckFDs( miiReadyFds ); // find out wich one is ready for( size_t i = 0; i < this->size(); ++i ) { Csock * pcSock = this->at( i ); #ifdef HAVE_C_ARES ares_channel pChannel = pcSock->GetAresChannel(); if( pChannel ) { ares_socket_t aiAresSocks[1]; aiAresSocks[0] = ARES_SOCKET_BAD; ares_getsock( pChannel, aiAresSocks, 1 ); if( FDHasCheck( aiAresSocks[0], miiReadyFds, ECT_Read ) || FDHasCheck( aiAresSocks[0], miiReadyFds, ECT_Write ) ) ares_process_fd( pChannel, aiAresSocks[0], aiAresSocks[0] ); } #endif /* HAVE_C_ARES */ pcSock->CheckFDs( miiReadyFds ); if( pcSock->GetConState() != Csock::CST_OK ) continue; cs_sock_t & iRSock = pcSock->GetRSock(); cs_sock_t & iWSock = pcSock->GetWSock(); EMessages iErrno = SUCCESS; if( iRSock == CS_INVALID_SOCK || iWSock == CS_INVALID_SOCK ) { // trigger a success so it goes through the normal motions // and an error is produced SelectSock( mpeSocks, SUCCESS, pcSock ); continue; // watch for invalid socks } if( FDHasCheck( iWSock, miiReadyFds, ECT_Write ) ) { if( iSel > 0 ) { iErrno = SUCCESS; if( pcSock->HasWriteBuffer() && pcSock->IsConnected() ) { // write whats in the socks send buffer if( !pcSock->Write( "" ) ) { // write failed, sock died :( iErrno = SELECT_ERROR; } } } else { iErrno = SELECT_ERROR; } SelectSock( mpeSocks, iErrno, pcSock ); } else if( FDHasCheck( iRSock, miiReadyFds, ECT_Read ) ) { if( iSel > 0 ) iErrno = SUCCESS; else iErrno = SELECT_ERROR; if( pcSock->GetType() != Csock::LISTENER ) { SelectSock( mpeSocks, iErrno, pcSock ); } else // someone is coming in! { CS_STRING sHost; uint16_t port; cs_sock_t inSock = pcSock->Accept( sHost, port ); if( inSock != CS_INVALID_SOCK ) { if( Csock::TMO_ACCEPT & pcSock->GetTimeoutType() ) pcSock->ResetTimer(); // let them now it got dinged // if we have a new sock, then add it Csock * NewpcSock = ( Csock * )pcSock->GetSockObj( sHost, port ); if( !NewpcSock ) NewpcSock = GetSockObj( sHost, port ); NewpcSock->SetType( Csock::INBOUND ); NewpcSock->SetRSock( inSock ); NewpcSock->SetWSock( inSock ); NewpcSock->SetIPv6( pcSock->GetIPv6() ); bool bAddSock = true; #ifdef HAVE_LIBSSL // // is this ssl ? if( pcSock->GetSSL() ) { NewpcSock->SetCipher( pcSock->GetCipher() ); NewpcSock->SetDHParamLocation( pcSock->GetDHParamLocation() ); NewpcSock->SetKeyLocation( pcSock->GetKeyLocation() ); NewpcSock->SetPemLocation( pcSock->GetPemLocation() ); NewpcSock->SetPemPass( pcSock->GetPemPass() ); NewpcSock->SetRequireClientCertFlags( pcSock->GetRequireClientCertFlags() ); bAddSock = NewpcSock->AcceptSSL(); } #endif /* HAVE_LIBSSL */ if( bAddSock ) { // set the name of the listener NewpcSock->SetParentSockName( pcSock->GetSockName() ); NewpcSock->SetRate( pcSock->GetRateBytes(), pcSock->GetRateTime() ); #ifdef HAVE_ICU NewpcSock->SetEncoding( pcSock->GetEncoding() ); #endif if( NewpcSock->GetSockName().empty() ) { std::stringstream s; s << sHost << ":" << port; AddSock( NewpcSock, s.str() ); } else { AddSock( NewpcSock, NewpcSock->GetSockName() ); } } else { CS_Delete( NewpcSock ); } } #ifdef _WIN32 else if( GetSockError() != WSAEWOULDBLOCK ) #else /* _WIN32 */ else if( GetSockError() != EAGAIN ) #endif /* _WIN32 */ { pcSock->CallSockError( GetSockError() ); } } } } } inline void MinimizeTime( timeval& min, const timeval& another ) { if( timercmp( &min, &another, > ) ) { min = another; } } timeval CSocketManager::GetDynamicSleepTime( const timeval& tNow, const timeval& tMaxResolution ) const { timeval tNextRunTime; timeradd( &tNow, &tMaxResolution, &tNextRunTime ); std::vector::const_iterator it; // This is safe, because we don't modify the vector. std::vector::const_iterator it_end = this->end(); for( it = this->begin(); it != it_end; ++it ) { Csock* pSock = *it; if( pSock->GetConState() != Csock::CST_OK ) tNextRunTime = tNow; // this is in a nebulous state, need to let it proceed like normal time_t iTimeoutInSeconds = pSock->GetTimeout(); if( iTimeoutInSeconds > 0 ) { timeval tNextTimeout; tNextTimeout.tv_sec = pSock->GetNextCheckTimeout( 0 ); // TODO convert socket timeouts to timeval too? tNextTimeout.tv_usec = 0; MinimizeTime( tNextRunTime, tNextTimeout ); } const std::vector & vCrons = pSock->GetCrons(); std::vector::const_iterator cit; std::vector::const_iterator cit_end = vCrons.end(); for( cit = vCrons.begin(); cit != cit_end; ++cit ) MinimizeTime( tNextRunTime, ( *cit )->GetNextRun() ); } std::vector::const_iterator cit; std::vector::const_iterator cit_end = m_vcCrons.end(); for( cit = m_vcCrons.begin(); cit != cit_end; ++cit ) MinimizeTime( tNextRunTime, ( *cit )->GetNextRun() ); timeval tReturnValue; if( timercmp( &tNextRunTime, &tNow, < ) ) { timerclear( &tReturnValue ); return( tReturnValue ); // smallest unit possible } timersub( &tNextRunTime, &tNow, &tReturnValue ); MinimizeTime( tReturnValue, tMaxResolution ); return( tReturnValue ); } void CSocketManager::SelectSock( std::map & mpeSocks, EMessages eErrno, Csock * pcSock ) { if( mpeSocks.find( pcSock ) != mpeSocks.end() ) return; mpeSocks[pcSock] = eErrno; } znc-1.7.5/third_party/Csocket/Csocket.h0000644000175000017500000015715713424164367020264 0ustar somebodysomebody/** * @file Csocket.h * @author Jim Hull * * Copyright (c) 1999-2012 Jim Hull * All rights reserved * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * Redistributions in any form must be accompanied by information on how to obtain * complete source code for this software and any accompanying software that uses this software. * The source code must either be included in the distribution or be available for no more than * the cost of distribution plus a nominal fee, and must be freely redistributable * under reasonable conditions. For an executable file, complete source code means the source * code for all modules it contains. It does not include source code for modules or files * that typically accompany the major components of the operating system on which the executable file runs. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OF THIS SOFTWARE BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * NOTES ... * - You should always compile with -Woverloaded-virtual to detect callbacks that may have been redefined since your last update * - If you want to use gethostbyname instead of getaddrinfo, the use -DUSE_GETHOSTBYNAME when compiling * - To compile with win32 need to link to winsock2, using gcc its -lws2_32 * - Code is formated with 'astyle --style=ansi -t4 --unpad-paren --pad-paren-in --keep-one-line-blocks' */ #ifndef _HAS_CSOCKET_ #define _HAS_CSOCKET_ #include "defines.h" // require this as a general rule, most projects have a defines.h or the like #include #include #ifndef _WIN32 #include #include #include #include #include #include #include #include #include #else #include #include #include #include #include #ifdef _MSC_VER #define strcasecmp _stricmp #define suseconds_t long #endif #ifndef ECONNREFUSED // these aliases might or might not be defined in errno.h // already, depending on the WinSDK version. #define ECONNREFUSED WSAECONNREFUSED #define EINPROGRESS WSAEINPROGRESS #define ETIMEDOUT WSAETIMEDOUT #define EADDRNOTAVAIL WSAEADDRNOTAVAIL #define ECONNABORTED WSAECONNABORTED #define ENETUNREACH WSAENETUNREACH #endif /* ECONNREFUSED */ #endif /* _WIN32 */ #ifdef HAVE_C_ARES #include #endif /* HAVE_C_ARES */ #ifdef HAVE_ICU # include #endif #include #include #include #include #include #ifdef HAVE_LIBSSL #include #include #include #endif /* HAVE_LIBSSL */ #ifdef __sun #include #include #endif /* __sun */ #include #include #include #include #include #include #include #ifndef CS_STRING # ifdef _HAS_CSTRING_ # define CS_STRING Cstring # else # define CS_STRING std::string # endif /* _HAS_CSTRING_ */ #endif /* CS_STRING */ #ifndef CS_DEBUG #ifdef __DEBUG__ # define CS_DEBUG( f ) std::cerr << __FILE__ << ":" << __LINE__ << " " << f << std::endl #else # define CS_DEBUG(f) (void)0 #endif /* __DEBUG__ */ #endif /* CS_DEBUG */ #ifndef CS_EXPORT #define CS_EXPORT #endif /* CS_EXPORT */ #ifndef PERROR #ifdef __DEBUG__ # define PERROR( f ) __Perror( f, __FILE__, __LINE__ ) #else # define PERROR( f ) (void)0 #endif /* __DEBUG__ */ #endif /* PERROR */ #ifdef _WIN32 typedef SOCKET cs_sock_t; #ifdef _WIN64 typedef signed __int64 cs_ssize_t; #else typedef signed int cs_ssize_t; #endif /* _WIN64 */ #define CS_INVALID_SOCK INVALID_SOCKET #else typedef int cs_sock_t; typedef ssize_t cs_ssize_t; #define CS_INVALID_SOCK -1 #endif /* _WIN32 */ /* Assume that everything but windows has Unix sockets */ #ifndef _WIN32 #define HAVE_UNIX_SOCKET #endif #ifdef CSOCK_USE_POLL #include #endif /* CSOCK_USE_POLL */ #ifdef HAVE_UNIX_SOCKET #include #endif #ifndef _NO_CSOCKET_NS // some people may not want to use a namespace namespace Csocket { #endif /* _NO_CSOCKET_NS */ /** * @class CSCharBuffer * @brief Ease of use self deleting char * class. */ class CS_EXPORT CSCharBuffer { public: CSCharBuffer( size_t iSize ) { m_pBuffer = ( char * )malloc( iSize ); } ~CSCharBuffer() { free( m_pBuffer ); } char * operator()() { return( m_pBuffer ); } private: char * m_pBuffer; }; /** * @class CSSockAddr * @brief sockaddr wrapper. */ class CS_EXPORT CSSockAddr { public: CSSockAddr() { m_bIsIPv6 = false; memset( ( struct sockaddr_in * ) &m_saddr, '\0', sizeof( m_saddr ) ); #ifdef HAVE_IPV6 memset( ( struct sockaddr_in6 * ) &m_saddr6, '\0', sizeof( m_saddr6 ) ); #endif /* HAVE_IPV6 */ m_iAFRequire = RAF_ANY; } virtual ~CSSockAddr() {} enum EAFRequire { RAF_ANY = PF_UNSPEC, #ifdef HAVE_IPV6 RAF_INET6 = AF_INET6, #endif /* HAVE_IPV6 */ RAF_INET = AF_INET }; void SinFamily(); void SinPort( uint16_t iPort ); void SetIPv6( bool b ); bool GetIPv6() const { return( m_bIsIPv6 ); } socklen_t GetSockAddrLen() { return( sizeof( m_saddr ) ); } sockaddr_in * GetSockAddr() { return( &m_saddr ); } in_addr * GetAddr() { return( &( m_saddr.sin_addr ) ); } #ifdef HAVE_IPV6 socklen_t GetSockAddrLen6() { return( sizeof( m_saddr6 ) ); } sockaddr_in6 * GetSockAddr6() { return( &m_saddr6 ); } in6_addr * GetAddr6() { return( &( m_saddr6.sin6_addr ) ); } #endif /* HAVE_IPV6 */ void SetAFRequire( EAFRequire iWhich ) { m_iAFRequire = iWhich; } EAFRequire GetAFRequire() const { return( m_iAFRequire ); } private: bool m_bIsIPv6; sockaddr_in m_saddr; #ifdef HAVE_IPV6 sockaddr_in6 m_saddr6; #endif /* HAVE_IPV6 */ EAFRequire m_iAFRequire; }; class Csock; /** * @class CGetAddrInfo * @brief this function is a wrapper around getaddrinfo (for ipv6) * * in the event this code is using ipv6, it calls getaddrinfo, and it tries to start the connection on each iteration * in the linked list returned by getaddrinfo. if pSock is not NULL the following behavior happens. * - if pSock is a listener, or if the connect state is in a bind vhost state (to be used with bind) AI_PASSIVE is sent to getaddrinfo * - if pSock is an outbound connection, AI_ADDRCONFIG and the connection is started from within this function. * getaddrinfo might return multiple (possibly invalid depending on system configuration) ip addresses, so connect needs to try them all. * A classic example of this is a hostname that resolves to both ipv4 and ipv6 ip's. You still need to call Connect (and ConnectSSL) to finish * up the connection state * * Process can be called in a thread, but Init and Finish must only be called from the parent once the thread is complete */ class CS_EXPORT CGetAddrInfo { public: /** * @brief ctor * @param sHostname the host to resolve * @param pSock the sock being setup, this option can be NULL, if it is null csSockAddr is only setup * @param csSockAddr the struct that sockaddr data is being copied to */ CGetAddrInfo( const CS_STRING & sHostname, Csock * pSock, CSSockAddr & csSockAddr ); ~CGetAddrInfo(); //! simply sets up m_cHints for use in process void Init(); //! the simplest part of the function, only calls getaddrinfo and uses only m_sHostname, m_pAddrRes, and m_cHints. int Process(); //! finalizes and sets up csSockAddr (and pSock if not NULL), only needs to be called if Process returns 0, but can be called anyways if flow demands it int Finish(); private: CS_STRING m_sHostname; Csock * m_pSock; CSSockAddr & m_csSockAddr; struct addrinfo * m_pAddrRes; struct addrinfo m_cHints; int m_iRet; }; //! backwards compatible wrapper around CGetAddrInfo and gethostbyname int CS_GetAddrInfo( const CS_STRING & sHostname, Csock * pSock, CSSockAddr & csSockAddr ); /** * This returns the [ex_]data index position for SSL objects only. If you want to tie more data * to the SSL object, you should generate your own at application start so as to avoid collision * with Csocket SSL_set_ex_data() */ int GetCsockSSLIdx(); #ifdef HAVE_LIBSSL //! returns the sock object associated to the particular context. returns NULL on failure or if not available Csock * GetCsockFromCTX( X509_STORE_CTX * pCTX ); #endif /* HAVE_LIBSSL */ const uint32_t CS_BLOCKSIZE = 4096; template inline void CS_Delete( T * & p ) { if( p ) { delete p; p = NULL; } } #ifdef HAVE_LIBSSL enum ECompType { CT_NONE = 0, CT_ZLIB = 1 }; //! adjusts tv with a new timeout if iTimeoutMS is smaller void CSAdjustTVTimeout( struct timeval & tv, long iTimeoutMS ); void SSLErrors( const char *filename, uint32_t iLineNum ); /** * @brief You HAVE to call this in order to use the SSL library, calling InitCsocket() also calls this * so unless you need to call InitSSL for a specific reason call InitCsocket() * @return true on success */ bool InitSSL( ECompType eCompressionType = CT_NONE ); #endif /* HAVE_LIBSSL */ /** * This does all the csocket initialized inclusing InitSSL() and win32 specific initializations, only needs to be called once */ bool InitCsocket(); /** * Shutdown and release global allocated memory */ void ShutdownCsocket(); //! @todo need to make this sock specific via getsockopt inline int GetSockError() { #ifdef _WIN32 return( WSAGetLastError() ); #else return( errno ); #endif /* _WIN32 */ } //! wrappers for FD_SET and such to work in templates. inline void TFD_ZERO( fd_set *set ) { FD_ZERO( set ); } inline void TFD_SET( cs_sock_t iSock, fd_set *set ) { FD_SET( iSock, set ); } inline bool TFD_ISSET( cs_sock_t iSock, fd_set *set ) { return( FD_ISSET( iSock, set ) != 0 ); } inline void TFD_CLR( cs_sock_t iSock, fd_set *set ) { FD_CLR( iSock, set ); } void __Perror( const CS_STRING & s, const char * pszFile, uint32_t iLineNo ); uint64_t millitime(); /** * @class CCron * @brief this is the main cron job class * * You should derive from this class, and override RunJob() with your code * @author Jim Hull */ class CS_EXPORT CCron { public: CCron(); virtual ~CCron() {} //! This is used by the Job Manager, and not you directly void run( timeval & tNow ); /** * @param TimeSequence how often to run in seconds * @param iMaxCycles how many times to run, 0 makes it run forever */ void StartMaxCycles( double dTimeSequence, uint32_t iMaxCycles ); void StartMaxCycles( const timeval& tTimeSequence, uint32_t iMaxCycles ); //! starts and runs infinity amount of times void Start( double dTimeSequence ); void Start( const timeval& TimeSequence ); //! call this to turn off your cron, it will be removed void Stop(); //! pauses excution of your code in RunJob void Pause(); //! removes the pause on RunJon void UnPause(); //! reset the timer void Reset(); timeval GetInterval() const; uint32_t GetMaxCycles() const; uint32_t GetCyclesLeft() const; //! returns true if cron is active bool isValid() const; const CS_STRING & GetName() const; void SetName( const CS_STRING & sName ); //! returns the timestamp of the next estimated run time. Note that it may not run at this EXACT time, but it will run at least at this time or after timeval GetNextRun() const { return( m_tTime ); } public: //! this is the method you should override virtual void RunJob(); protected: bool m_bRunOnNextCall; //!< if set to true, RunJob() gets called on next invocation of run() despite the timeout private: timeval m_tTime; bool m_bActive, m_bPause; timeval m_tTimeSequence; uint32_t m_iMaxCycles, m_iCycles; CS_STRING m_sName; }; /** * @class CSMonitorFD * @brief Class to tie sockets to for monitoring by Csocket at either the Csock or TSockManager. */ class CS_EXPORT CSMonitorFD { public: CSMonitorFD() { m_bEnabled = true; } virtual ~CSMonitorFD() {} /** * @brief called before select, typically you don't need to reimplement this just add sockets via Add and let the default implementation have its way * @param miiReadyFds fill with fd's to monitor and the associated bit to check them for (@see CSockManager::ECheckType) * @param iTimeoutMS the timeout to change to, setting this to -1 (the default) * @return returning false will remove this from monitoring. The same effect can be had by setting m_bEnabled to false as it is returned from this */ virtual bool GatherFDsForSelect( std::map< cs_sock_t, short > & miiReadyFds, long & iTimeoutMS ); /** * @brief called when there are fd's belonging to this class that have triggered * @param miiReadyFds the map of fd's with the bits that triggered them (@see CSockManager::ECheckType) * @return returning false will remove this from monitoring */ virtual bool FDsThatTriggered( const std::map< cs_sock_t, short > & miiReadyFds ) { return( true ); } /** * @brief gets called to diff miiReadyFds with m_miiMonitorFDs, and calls FDsThatTriggered when appropriate. Typically you don't need to reimplement this. * @param miiReadyFds the map of all triggered fd's, not just the fd's from this class * @return returning false will remove this from monitoring */ virtual bool CheckFDs( const std::map< cs_sock_t, short > & miiReadyFds ); /** * @brief adds a file descriptor to be monitored * @param iFD the file descriptor * @param iMonitorEvents bitset of events to monitor for (@see CSockManager::ECheckType) */ void Add( cs_sock_t iFD, short iMonitorEvents ) { m_miiMonitorFDs[iFD] = iMonitorEvents; } //! removes this fd from monitoring void Remove( cs_sock_t iFD ) { m_miiMonitorFDs.erase( iFD ); } //! causes this monitor to be removed void DisableMonitor() { m_bEnabled = false; } bool IsEnabled() const { return( m_bEnabled ); } protected: std::map< cs_sock_t, short > m_miiMonitorFDs; bool m_bEnabled; }; /** * @class CSockCommon * @brief simple class to share common code to both TSockManager and Csock */ class CS_EXPORT CSockCommon { public: CSockCommon() {} virtual ~CSockCommon(); void CleanupCrons(); void CleanupFDMonitors(); //! returns a const reference to the crons associated to this socket const std::vector & GetCrons() const { return( m_vcCrons ); } //! This has a garbage collecter, and is used internall to call the jobs virtual void Cron(); //! insert a newly created cron virtual void AddCron( CCron * pcCron ); /** * @brief deletes a cron by name * @param sName the name of the cron * @param bDeleteAll delete all crons that match sName * @param bCaseSensitive use strcmp or strcasecmp */ virtual void DelCron( const CS_STRING & sName, bool bDeleteAll = true, bool bCaseSensitive = true ); //! delete cron by idx virtual void DelCron( uint32_t iPos ); //! delete cron by address virtual void DelCronByAddr( CCron * pcCron ); void CheckFDs( const std::map< cs_sock_t, short > & miiReadyFds ); void AssignFDs( std::map< cs_sock_t, short > & miiReadyFds, struct timeval * tvtimeout ); //! add an FD set to monitor void MonitorFD( CSMonitorFD * pMonitorFD ) { m_vcMonitorFD.push_back( pMonitorFD ); } protected: std::vector m_vcCrons; std::vector m_vcMonitorFD; }; #ifdef HAVE_LIBSSL typedef int ( *FPCertVerifyCB )( int, X509_STORE_CTX * ); #endif /* HAVE_LIBSSL */ /** * @class Csock * @brief Basic socket class. * * The most basic level socket class. * You can use this class directly for quick things * or use the socket manager. * @see TSocketManager * @author Jim Hull */ class CS_EXPORT Csock : public CSockCommon { public: //! default constructor, sets a timeout of 60 seconds Csock( int iTimeout = 60 ); /** * @brief Advanced constructor, for creating a simple connection * @param sHostname the hostname your are connecting to * @param uPort the port you are connecting to * @param itimeout how long to wait before ditching the connection, default is 60 seconds */ Csock( const CS_STRING & sHostname, uint16_t uPort, int itimeout = 60 ); //! override this for accept sockets virtual Csock *GetSockObj( const CS_STRING & sHostname, uint16_t iPort ); virtual ~Csock(); /** * @brief in the event you pass this class to Copy(), you MUST call this function or * on the original Csock other wise bad side effects will happen (double deletes, weird sock closures, etc) * if you call this function and have not handled the internal pointers, other bad things can happend (memory leaks, fd leaks, etc) * the whole point of this function is to allow this class to go away without shutting down */ virtual void Dereference(); //! use this to copy a sock from one to the other, override it if you have special needs in the event of a copy virtual void Copy( const Csock & cCopy ); enum ETConn { OUTBOUND = 0, //!< outbound connection LISTENER = 1, //!< a socket accepting connections INBOUND = 2 //!< an inbound connection, passed from LISTENER }; enum EFRead { READ_EOF = 0, //!< End Of File, done reading READ_ERR = -1, //!< Error on the socket, socket closed, done reading READ_EAGAIN = -2, //!< Try to get data again READ_CONNREFUSED = -3, //!< Connection Refused READ_TIMEDOUT = -4 //!< Connection timed out }; enum EFSelect { SEL_OK = 0, //!< Select passed ok SEL_TIMEOUT = -1, //!< Select timed out SEL_EAGAIN = -2, //!< Select wants you to try again SEL_ERR = -3 //!< Select recieved an error }; enum ESSLMethod { TLS = 0, SSL23 = TLS, SSL2 = 2, SSL3 = 3, TLS1 = 4, TLS11 = 5, TLS12 = 6 }; enum EDisableProtocol { EDP_None = 0, //!< disable nothing EDP_SSLv2 = 1, //!< disable SSL version 2 EDP_SSLv3 = 2, //!< disable SSL version 3 EDP_TLSv1 = 4, //!< disable TLS version 1 EDP_TLSv1_1 = 8, //!< disable TLS version 1.1 EDP_TLSv1_2 = 16, //!< disable TLS version 1.2 EDP_SSL = (EDP_SSLv2|EDP_SSLv3) }; enum ECONState { CST_START = 0, CST_DNS = CST_START, CST_BINDVHOST = 1, CST_DESTDNS = 2, CST_CONNECT = 3, CST_CONNECTSSL = 4, CST_OK = 5 }; enum ECloseType { CLT_DONT = 0, //!< don't close DER CLT_NOW = 1, //!< close immediatly CLT_AFTERWRITE = 2, //!< close after finishing writing the buffer CLT_DEREFERENCE = 3 //!< used after copy in Csock::Dereference() to cleanup a sock thats being shutdown }; Csock & operator<<( const CS_STRING & s ); Csock & operator<<( std::ostream & ( *io )( std::ostream & ) ); Csock & operator<<( int32_t i ); Csock & operator<<( uint32_t i ); Csock & operator<<( int64_t i ); Csock & operator<<( uint64_t i ); Csock & operator<<( float i ); Csock & operator<<( double i ); /** * @brief Create the connection, this is used by the socket manager, and shouldn't be called directly by the user * @return true on success */ virtual bool Connect(); #ifdef HAVE_UNIX_SOCKET /** * @brief Connect to a UNIX socket. * @param sPath the path to the UNIX socket. */ virtual bool ConnectUnix( const CS_STRING & sPath ); /** * @brief Listens for connections on an UNIX socket * @param sBindFile the socket on which to listen * @param iMaxConns the maximum amount of pending connections to allow * @param iTimeout if no connections come in by this timeout, the listener is closed */ virtual bool ListenUnix( const CS_STRING & sBindFile, int iMaxConns = SOMAXCONN, uint32_t iTimeout = 0 ); #endif /** * @brief Listens for connections * @param iPort the port to listen on * @param iMaxConns the maximum amount of pending connections to allow * @param sBindHost the vhost on which to listen * @param iTimeout if no connections come in by this timeout, the listener is closed * @param bDetach don't block waiting for port to come up, instead detach and return immediately */ virtual bool Listen( uint16_t iPort, int iMaxConns = SOMAXCONN, const CS_STRING & sBindHost = "", uint32_t iTimeout = 0, bool bDetach = false ); //! Accept an inbound connection, this is used internally virtual cs_sock_t Accept( CS_STRING & sHost, uint16_t & iRPort ); //! Accept an inbound SSL connection, this is used internally and called after Accept virtual bool AcceptSSL(); //! This sets up the SSL Client, this is used internally virtual bool SSLClientSetup(); //! This sets up the SSL Server, this is used internally virtual bool SSLServerSetup(); /** * @brief Create the SSL connection * @return true on success * * This is used by the socket manager, and shouldn't be called directly by the user. */ virtual bool ConnectSSL(); //! start a TLS connection on an existing plain connection bool StartTLS(); /** * @brief Write data to the socket * * If not all of the data is sent, it will be stored on * an internal buffer, and tried again with next call to Write * if the socket is blocking, it will send everything, its ok to check ernno after this (nothing else is processed) * * @param data the data to send * @param len the length of data */ virtual bool Write( const char *data, size_t len ); /** * @brief Write a text string to the socket * * Encoding is used, if set * * @param sData the string to send; if encoding is provided, sData should be UTF-8 and will be encoded * @see Write( const char *, int ) */ virtual bool Write( const CS_STRING & sData ); /** * Read from the socket * Just pass in a pointer, big enough to hold len bytes * * @param data the buffer to read into * @param len the size of the buffer * * @return * Returns READ_EOF for EOF * Returns READ_ERR for ERROR * Returns READ_EAGAIN for Try Again ( EAGAIN ) * Returns READ_CONNREFUSED for connection refused * Returns READ_TIMEDOUT for a connection that timed out at the TCP level * Otherwise returns the bytes read into data */ virtual cs_ssize_t Read( char *data, size_t len ); CS_STRING GetLocalIP() const; CS_STRING GetRemoteIP() const; //! Tells you if the socket is connected virtual bool IsConnected() const; //! Sets the sock, telling it its connected (internal use only) virtual void SetIsConnected( bool b ); //! returns a reference to the sock cs_sock_t & GetRSock(); const cs_sock_t & GetRSock() const; void SetRSock( cs_sock_t iSock ); cs_sock_t & GetWSock(); const cs_sock_t & GetWSock() const; void SetWSock( cs_sock_t iSock ); void SetSock( cs_sock_t iSock ); cs_sock_t & GetSock(); const cs_sock_t & GetSock() const; /** * @brief calls SockError, if sDescription is not set, then strerror is used to pull out a default description * @param iErrno the errno to send * @param sDescription the description of the error that occurred */ void CallSockError( int iErrno, const CS_STRING & sDescription = "" ); //! resets the time counter, this is virtual in the event you need an event on the timer being Reset virtual void ResetTimer(); //! will pause/unpause reading on this socket void PauseRead(); void UnPauseRead(); bool IsReadPaused() const; /** * this timeout isn't just connection timeout, but also timeout on * NOT recieving data, to disable this set it to 0 * then the normal TCP timeout will apply (basically TCP will kill a dead connection) * Set the timeout, set to 0 to never timeout */ enum { TMO_READ = 1, TMO_WRITE = 2, TMO_ACCEPT = 4, TMO_ALL = TMO_READ|TMO_WRITE|TMO_ACCEPT }; //! Currently this uses the same value for all timeouts, and iTimeoutType merely states which event will be checked //! for timeouts void SetTimeout( int iTimeout, uint32_t iTimeoutType = TMO_ALL ); void SetTimeoutType( uint32_t iTimeoutType ); int GetTimeout() const; uint32_t GetTimeoutType() const; //! returns true if the socket has timed out virtual bool CheckTimeout( time_t iNow ); /** * pushes data up on the buffer, if a line is ready * it calls the ReadLine event */ virtual void PushBuff( const char *data, size_t len, bool bStartAtZero = false ); //! This gives access to the internal read buffer, if your //! not going to use ReadLine(), then you may want to clear this out //! (if its binary data and not many '\\n') CS_STRING & GetInternalReadBuffer(); //! This gives access to the internal write buffer. //! If you want to check if the send queue fills up, check here. CS_STRING & GetInternalWriteBuffer(); //! sets the max buffered threshold when EnableReadLine() is enabled void SetMaxBufferThreshold( uint32_t iThreshold ); uint32_t GetMaxBufferThreshold() const; //! Returns the connection type from enum eConnType int GetType() const; void SetType( int iType ); //! Returns a reference to the socket name const CS_STRING & GetSockName() const; void SetSockName( const CS_STRING & sName ); //! Returns a reference to the host name const CS_STRING & GetHostName() const; void SetHostName( const CS_STRING & sHostname ); //! Gets the starting time of this socket uint64_t GetStartTime() const; //! Resets the start time void ResetStartTime(); //! Gets the amount of data read during the existence of the socket uint64_t GetBytesRead() const; void ResetBytesRead(); //! Gets the amount of data written during the existence of the socket uint64_t GetBytesWritten() const; void ResetBytesWritten(); //! Get Avg Read Speed in sample milliseconds (default is 1000 milliseconds or 1 second) double GetAvgRead( uint64_t iSample = 1000 ) const; //! Get Avg Write Speed in sample milliseconds (default is 1000 milliseconds or 1 second) double GetAvgWrite( uint64_t iSample = 1000 ) const; //! Returns the remote port uint16_t GetRemotePort() const; //! Returns the local port uint16_t GetLocalPort() const; //! Returns the port uint16_t GetPort() const; void SetPort( uint16_t iPort ); //! just mark us as closed, the parent can pick it up void Close( ECloseType eCloseType = CLT_NOW ); //! returns int of type to close @see ECloseType ECloseType GetCloseType() const { return( m_eCloseType ); } bool IsClosed() const { return( GetCloseType() != CLT_DONT ); } //! Use this to change your fd's to blocking or none blocking void NonBlockingIO(); //! Return true if this socket is using ssl. Note this does not mean the SSL state is finished, but simply that its configured to use ssl bool GetSSL() const; void SetSSL( bool b ); #ifdef HAVE_LIBSSL //! bitwise setter, @see EDisableProtocol void DisableSSLProtocols( u_int uDisableOpts ) { m_uDisableProtocols = uDisableOpts; } //! allow disabling compression void DisableSSLCompression() { m_bNoSSLCompression = true; } //! select the ciphers in server-preferred order void FollowSSLCipherServerPreference() { m_bSSLCipherServerPreference = true; } //! Set the cipher type ( openssl cipher [to see ciphers available] ) void SetCipher( const CS_STRING & sCipher ); const CS_STRING & GetCipher() const; //! Set the pem file location void SetDHParamLocation( const CS_STRING & sDHParamFile ); const CS_STRING & GetDHParamLocation() const; void SetKeyLocation( const CS_STRING & sKeyFile ); const CS_STRING & GetKeyLocation() const; void SetPemLocation( const CS_STRING & sPemFile ); const CS_STRING & GetPemLocation() const; void SetPemPass( const CS_STRING & sPassword ); const CS_STRING & GetPemPass() const; //! Set the SSL method type void SetSSLMethod( int iMethod ); int GetSSLMethod() const; void SetSSLObject( SSL *ssl, bool bDeleteExisting = false ); SSL * GetSSLObject() const; void SetCTXObject( SSL_CTX *sslCtx, bool bDeleteExisting = false ); SSL_SESSION * GetSSLSession() const; //! setting this to NULL will allow the default openssl verification process kick in void SetCertVerifyCB( FPCertVerifyCB pFP ) { m_pCerVerifyCB = pFP; } #endif /* HAVE_LIBSSL */ //! Get the send buffer bool HasWriteBuffer() const; void ClearWriteBuffer(); //! is SSL_accept finished ? //! is the ssl properly finished (from write no error) bool SslIsEstablished() const; //! Use this to bind this socket to inetd bool ConnectInetd( bool bIsSSL = false, const CS_STRING & sHostname = "" ); //! Tie this guy to an existing real file descriptor bool ConnectFD( int iReadFD, int iWriteFD, const CS_STRING & sName, bool bIsSSL = false, ETConn eDirection = INBOUND ); //! Get the peer's X509 cert #ifdef HAVE_LIBSSL //! it is up to you, the caller to call X509_free() on this object X509 *GetX509() const; //! Returns the peer's public key CS_STRING GetPeerPubKey() const; //! Returns the peer's certificate finger print long GetPeerFingerprint( CS_STRING & sFP ) const; uint32_t GetRequireClientCertFlags() const; //! legacy, deprecated @see SetRequireClientCertFlags void SetRequiresClientCert( bool bRequiresCert ); //! bitwise flags, 0 means don't require cert, SSL_VERIFY_PEER verifies peers, SSL_VERIFY_FAIL_IF_NO_PEER_CERT will cause the connection to fail if no cert void SetRequireClientCertFlags( uint32_t iRequireClientCertFlags ) { m_iRequireClientCertFlags = iRequireClientCertFlags; } #endif /* HAVE_LIBSSL */ //! Set The INBOUND Parent sockname virtual void SetParentSockName( const CS_STRING & sParentName ); const CS_STRING & GetParentSockName() const; /** * sets the rate at which we can send data * @param iBytes the amount of bytes we can write * @param iMilliseconds the amount of time we have to rate to iBytes */ virtual void SetRate( uint32_t iBytes, uint64_t iMilliseconds ); uint32_t GetRateBytes() const; uint64_t GetRateTime() const; /** * Connected event */ virtual void Connected() {} /** * Disconnected event */ virtual void Disconnected() {} /** * Sock Timed out event */ virtual void Timeout() {} /** * Ready to read data event */ virtual void ReadData( const char *data, size_t len ) {} /** * * Ready to Read a full line event. If encoding is provided, this is guaranteed to be UTF-8 */ virtual void ReadLine( const CS_STRING & sLine ) {} //! set the value of m_bEnableReadLine to true, we don't want to store a buffer for ReadLine, unless we want it void EnableReadLine(); void DisableReadLine(); //! returns the value of m_bEnableReadLine, if ReadLine is enabled bool HasReadLine() const { return( m_bEnableReadLine ); } /** * This WARNING event is called when your buffer for readline exceeds the warning threshold * and triggers this event. Either Override it and do nothing, or SetMaxBufferThreshold() * This event will only get called if m_bEnableReadLine is enabled */ virtual void ReachedMaxBuffer(); /** * @brief A sock error occured event */ virtual void SockError( int iErrno, const CS_STRING & sDescription ) {} /** * Incoming Connection Event * return false and the connection will fail * default returns true */ virtual bool ConnectionFrom( const CS_STRING & sHost, uint16_t iPort ) { return( true ); } /** * @brief called when type is LISTENER and the listening port is up and running * @param sBindIP the IP that is being bound to. Empty if no bind restriction * @param uPort the listening port */ virtual void Listening( const CS_STRING & sBindIP, uint16_t uPort ) {} /** * Connection Refused Event * */ virtual void ConnectionRefused() {} /** * This gets called every iteration of CSocketManager::Select() if the socket is ReadPaused */ virtual void ReadPaused() {} #ifdef HAVE_LIBSSL /** * Gets called immediatly after the m_ssl member is setup and initialized, useful if you need to assign anything * to this ssl session via SSL_set_ex_data */ virtual void SSLFinishSetup( SSL * pSSL ) {} /** * @brief gets called when a SNI request is sent, and used to configure a SNI session * @param sHostname the hostname sent from the client * @param sPemFile fill this with the location to the pemfile * @param sPemPass fill this with the pemfile password if there is one * @return return true to proceed with the SNI server configuration */ virtual bool SNIConfigureServer( const CS_STRING & sHostname, CS_STRING & sPemFile, CS_STRING & sPemPass ) { return( false ); } /** * @brief called to configure the SNI client * @param sHostname, the hostname to configure SNI with, you can fill this with GetHostname() if its a valid hostname and not an OP * @return returning true causes a call to configure SNI with the hostname returned */ virtual bool SNIConfigureClient( CS_STRING & sHostname ); //! creates a new SSL_CTX based on the setup of this sock SSL_CTX * SetupServerCTX(); /** * @brief called once the SSL handshake is complete, this is triggered via SSL_CB_HANDSHAKE_DONE in SSL_set_info_callback() * * This is a spot where you can look at the finished peer certifificate ... IE *
	 * X509 * pCert = GetX509();
	 * char szName[256];
	 * memset( szName, '\0', 256 );
	 * X509_NAME_get_text_by_NID ( X509_get_subject_name( pCert ), NID_commonName, szName, 255 );
	 * cerr << "Name! " << szName << endl;
	 * X509_free( pCert );
	 * 
*/ virtual void SSLHandShakeFinished() {} /** * @brief this is hooked in via SSL_set_verify, and be default it just returns 1 meaning success * @param iPreVerify the pre-verification status as determined by openssl internally * @param pStoreCTX the X509_STORE_CTX containing the certificate * @return 1 to continue, 0 to abort * * This may get called multiple times, for example with a chain certificate which is fairly typical with * certificates from godaddy, freessl, etc. Additionally, openssl does not do any host verification, they * leave that up to the you. One easy way to deal with this is to wait for SSLHandShakeFinished() and examine * the peer certificate @see SSLHandShakeFinished */ virtual int VerifyPeerCertificate( int iPreVerify, X509_STORE_CTX * pStoreCTX ) { return( 1 ); } #endif /* HAVE_LIBSSL */ //! return how long it has been (in seconds) since the last read or successful write time_t GetTimeSinceLastDataTransaction( time_t iNow = 0 ) const; time_t GetLastCheckTimeout() const { return( m_iLastCheckTimeoutTime ); } //! Returns the time when CheckTimeout() should be called next time_t GetNextCheckTimeout( time_t iNow = 0 ) const; //! return the data imediatly ready for read virtual int GetPending() const; ////////////////////////// // Connection State Stuff //! returns the current connection state ECONState GetConState() const { return( m_eConState ); } //! sets the connection state to eState void SetConState( ECONState eState ) { m_eConState = eState; } //! grabs fd's for the sockets bool CreateSocksFD(); //! puts the socks back to the state they were prior to calling CreateSocksFD void CloseSocksFD(); const CS_STRING & GetBindHost() const { return( m_sBindHost ); } void SetBindHost( const CS_STRING & sBindHost ) { m_sBindHost = sBindHost; } enum EDNSLType { DNS_VHOST, //!< this lookup is for the vhost bind DNS_DEST //!< this lookup is for the destination address }; /** * dns lookup @see EDNSLType * @return 0 for success, EAGAIN to check back again (same arguments as before), ETIMEDOUT on failure */ int DNSLookup( EDNSLType eDNSLType ); //! this is only used on outbound connections, listeners bind in a different spot bool SetupVHost(); bool GetIPv6() const { return( m_bIsIPv6 ); } void SetIPv6( bool b ) { m_bIsIPv6 = b; m_address.SetIPv6( b ); m_bindhost.SetIPv6( b ); } void SetAFRequire( CSSockAddr::EAFRequire iAFRequire ) { m_address.SetAFRequire( iAFRequire ); m_bindhost.SetAFRequire( iAFRequire ); } //! returns true if this socket can write its data, primarily used with rate shaping, initialize iNOW to 0 and it sets it on the first call bool AllowWrite( uint64_t & iNOW ) const; void SetSkipConnect( bool b ) { m_bSkipConnect = b; } /** * @brief override this call with your own DNS lookup method if you have one. By default this function is blocking * @param sHostname the hostname to resolve * @param csSockAddr the destination sock address info @see CSSockAddr * @return 0 on success, ETIMEDOUT if no lookup was found, EAGAIN if you should check again later for an answer */ virtual int GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr ); /** * @brief retrieve name info (numeric only) for a given sockaddr_storage * @param pAddr the sockaddr_storage * @param iAddrLen the length * @param sIP filled with the IP from getnameinfo * @param piPort if not null, filled with the port * @return 0 on success. * * In the event you want to do additional work before or after getnameinfo is called, you can override this and do just that. * One example is in the event that an ipv6 ip is a mapped ipv4 mapped, you can check like so. * - if( pAddr->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED( &(((const struct sockaddr_in6 *)pAddr)->sin6_addr ) ) */ virtual int ConvertAddress( const struct sockaddr_storage * pAddr, socklen_t iAddrLen, CS_STRING & sIP, uint16_t * piPort ) const; #ifdef HAVE_C_ARES CSSockAddr * GetCurrentAddr() const { return( m_pCurrAddr ); } void SetAresFinished( int status ) { m_pCurrAddr = NULL; m_iARESStatus = status; } ares_channel GetAresChannel() const { return( m_pARESChannel ); } #endif /* HAVE_C_ARES */ //! returns the number of max pending connections when type is LISTENER int GetMaxConns() const { return( m_iMaxConns ); } #ifdef HAVE_ICU void SetEncoding( const CS_STRING & sEncoding ); CS_STRING GetEncoding() const { return m_sEncoding; } virtual void IcuExtToUCallback( UConverterToUnicodeArgs* toArgs, const char* codeUnits, int32_t length, UConverterCallbackReason reason, UErrorCode* err ); virtual void IcuExtFromUCallback( UConverterFromUnicodeArgs* fromArgs, const UChar* codeUnits, int32_t length, UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err ); #endif /* HAVE_ICU */ private: //! making private for safety Csock( const Csock & cCopy ) : CSockCommon() {} //! shrink sendbuff by removing m_uSendBufferPos bytes from m_sSend void ShrinkSendBuff(); void IncBuffPos( size_t uBytes ); //! checks for configured protocol disabling // NOTE! if you add any new members, be sure to add them to Copy() uint16_t m_uPort; cs_sock_t m_iReadSock, m_iWriteSock; int m_iTimeout, m_iConnType, m_iMethod, m_iTcount, m_iMaxConns; bool m_bUseSSL, m_bIsConnected; bool m_bsslEstablished, m_bEnableReadLine, m_bPauseRead; CS_STRING m_shostname, m_sbuffer, m_sSockName, m_sDHParamFile, m_sKeyFile, m_sPemFile, m_sCipherType, m_sParentName; CS_STRING m_sSend, m_sPemPass; ECloseType m_eCloseType; // initialized lazily mutable uint16_t m_iRemotePort, m_iLocalPort; mutable CS_STRING m_sLocalIP, m_sRemoteIP; uint64_t m_iMaxMilliSeconds, m_iLastSendTime, m_iBytesRead, m_iBytesWritten, m_iStartTime; uint32_t m_iMaxBytes, m_iMaxStoredBufferLength, m_iTimeoutType; size_t m_iLastSend, m_uSendBufferPos; CSSockAddr m_address, m_bindhost; bool m_bIsIPv6, m_bSkipConnect; time_t m_iLastCheckTimeoutTime; #ifdef HAVE_LIBSSL CS_STRING m_sSSLBuffer; SSL * m_ssl; SSL_CTX * m_ssl_ctx; uint32_t m_iRequireClientCertFlags; u_int m_uDisableProtocols; bool m_bNoSSLCompression; bool m_bSSLCipherServerPreference; FPCertVerifyCB m_pCerVerifyCB; void FREE_SSL(); void FREE_CTX(); bool ConfigureCTXOptions( SSL_CTX * pCTX ); #endif /* HAVE_LIBSSL */ //! Create the socket cs_sock_t CreateSocket( bool bListen = false, bool bUnix = false ); void Init( const CS_STRING & sHostname, uint16_t uPort, int iTimeout = 60 ); // Connection State Info ECONState m_eConState; CS_STRING m_sBindHost; uint32_t m_iCurBindCount, m_iDNSTryCount; #ifdef HAVE_C_ARES void FreeAres(); ares_channel m_pARESChannel; CSSockAddr * m_pCurrAddr; int m_iARESStatus; #endif /* HAVE_C_ARES */ #ifdef HAVE_ICU UConverter* m_cnvInt; UConverter* m_cnvExt; bool m_cnvTryUTF8; bool m_cnvSendUTF8; CS_STRING m_sEncoding; #endif }; /** * @class CSConnection * @brief options for creating a connection */ class CS_EXPORT CSConnection { public: /** * @param sHostname hostname to connect to * @param iPort port to connect to * @param iTimeout connection timeout */ CSConnection( const CS_STRING & sHostname, uint16_t iPort, int iTimeout = 60 ) { m_sHostname = sHostname; m_iPort = iPort; m_iTimeout = iTimeout; m_bIsSSL = false; #ifdef HAVE_LIBSSL m_sCipher = "HIGH"; #endif /* HAVE_LIBSSL */ m_iAFrequire = CSSockAddr::RAF_ANY; } virtual ~CSConnection() {} const CS_STRING & GetHostname() const { return( m_sHostname ); } const CS_STRING & GetSockName() const { return( m_sSockName ); } const CS_STRING & GetBindHost() const { return( m_sBindHost ); } uint16_t GetPort() const { return( m_iPort ); } int GetTimeout() const { return( m_iTimeout ); } bool GetIsSSL() const { return( m_bIsSSL ); } CSSockAddr::EAFRequire GetAFRequire() const { return( m_iAFrequire ); } #ifdef HAVE_LIBSSL const CS_STRING & GetCipher() const { return( m_sCipher ); } const CS_STRING & GetPemLocation() const { return( m_sPemLocation ); } const CS_STRING & GetKeyLocation() const { return( m_sKeyLocation ); } const CS_STRING & GetDHParamLocation() const { return( m_sDHParamLocation ); } const CS_STRING & GetPemPass() const { return( m_sPemPass ); } #endif /* HAVE_LIBSSL */ //! sets the hostname to connect to void SetHostname( const CS_STRING & s ) { m_sHostname = s; } //! sets the name of the socket, used for reference, ie in FindSockByName() void SetSockName( const CS_STRING & s ) { m_sSockName = s; } //! sets the hostname to bind to (vhost support) void SetBindHost( const CS_STRING & s ) { m_sBindHost = s; } //! sets the port to connect to void SetPort( uint16_t i ) { m_iPort = i; } //! sets the connection timeout void SetTimeout( int i ) { m_iTimeout = i; } //! set to true to enable SSL void SetIsSSL( bool b ) { m_bIsSSL = b; } //! sets the AF family type required void SetAFRequire( CSSockAddr::EAFRequire iAFRequire ) { m_iAFrequire = iAFRequire; } #ifdef HAVE_LIBSSL //! set the cipher strength to use, default is HIGH void SetCipher( const CS_STRING & s ) { m_sCipher = s; } //! set the location of the pemfile void SetPemLocation( const CS_STRING & s ) { m_sPemLocation = s; } //! set the pemfile pass void SetPemPass( const CS_STRING & s ) { m_sPemPass = s; } #endif /* HAVE_LIBSSL */ protected: CS_STRING m_sHostname, m_sSockName, m_sBindHost; uint16_t m_iPort; int m_iTimeout; bool m_bIsSSL; CSSockAddr::EAFRequire m_iAFrequire; #ifdef HAVE_LIBSSL CS_STRING m_sDHParamLocation, m_sKeyLocation, m_sPemLocation, m_sPemPass, m_sCipher; #endif /* HAVE_LIBSSL */ }; class CS_EXPORT CSSSLConnection : public CSConnection { public: CSSSLConnection( const CS_STRING & sHostname, uint16_t iPort, int iTimeout = 60 ) : CSConnection( sHostname, iPort, iTimeout ) { SetIsSSL( true ); } }; /** * @class CSListener * @brief options container to create a listener */ class CS_EXPORT CSListener { public: /** * @param iPort port to listen on. Set to 0 to listen on a random port * @param sBindHost host to bind to * @param bDetach don't block while waiting for the port to come up, instead detach and return immediately */ CSListener( uint16_t iPort, const CS_STRING & sBindHost = "", bool bDetach = false ) { m_iPort = iPort; m_sBindHost = sBindHost; m_bIsSSL = false; m_iMaxConns = SOMAXCONN; m_iTimeout = 0; m_iAFrequire = CSSockAddr::RAF_ANY; m_bDetach = bDetach; #ifdef HAVE_LIBSSL m_sCipher = "HIGH"; m_iRequireCertFlags = 0; #endif /* HAVE_LIBSSL */ } virtual ~CSListener() {} void SetDetach( bool b ) { m_bDetach = b; } bool GetDetach() const { return( m_bDetach ); } uint16_t GetPort() const { return( m_iPort ); } const CS_STRING & GetSockName() const { return( m_sSockName ); } const CS_STRING & GetBindHost() const { return( m_sBindHost ); } bool GetIsSSL() const { return( m_bIsSSL ); } int GetMaxConns() const { return( m_iMaxConns ); } uint32_t GetTimeout() const { return( m_iTimeout ); } CSSockAddr::EAFRequire GetAFRequire() const { return( m_iAFrequire ); } #ifdef HAVE_LIBSSL const CS_STRING & GetCipher() const { return( m_sCipher ); } const CS_STRING & GetDHParamLocation() const { return( m_sDHParamLocation ); } const CS_STRING & GetKeyLocation() const { return( m_sKeyLocation ); } const CS_STRING & GetPemLocation() const { return( m_sPemLocation ); } const CS_STRING & GetPemPass() const { return( m_sPemPass ); } uint32_t GetRequireClientCertFlags() const { return( m_iRequireCertFlags ); } #endif /* HAVE_LIBSSL */ //! sets the port to listen on. Set to 0 to listen on a random port void SetPort( uint16_t iPort ) { m_iPort = iPort; } //! sets the sock name for later reference (ie FindSockByName) void SetSockName( const CS_STRING & sSockName ) { m_sSockName = sSockName; } //! sets the host to bind to void SetBindHost( const CS_STRING & sBindHost ) { m_sBindHost = sBindHost; } //! set to true to enable SSL void SetIsSSL( bool b ) { m_bIsSSL = b; } //! set max connections as called by accept() void SetMaxConns( int i ) { m_iMaxConns = i; } //! sets the listen timeout. The listener class will close after timeout has been reached if not 0 void SetTimeout( uint32_t i ) { m_iTimeout = i; } //! sets the AF family type required void SetAFRequire( CSSockAddr::EAFRequire iAFRequire ) { m_iAFrequire = iAFRequire; } #ifdef HAVE_LIBSSL //! set the cipher strength to use, default is HIGH void SetCipher( const CS_STRING & s ) { m_sCipher = s; } //! set the location of the pemfile void SetPemLocation( const CS_STRING & s ) { m_sPemLocation = s; } //! set the location of the keyfile void SetKeyLocation( const CS_STRING & s ) { m_sKeyLocation = s; } //! set the location of the dhparamfile void SetDHParamLocation( const CS_STRING & s ) { m_sDHParamLocation = s; } //! set the pemfile pass void SetPemPass( const CS_STRING & s ) { m_sPemPass = s; } //! set to true if require a client certificate (deprecated @see SetRequireClientCertFlags) void SetRequiresClientCert( bool b ) { m_iRequireCertFlags = ( b ? SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0 ); } //! bitwise flags, 0 means don't require cert, SSL_VERIFY_PEER verifies peers, SSL_VERIFY_FAIL_IF_NO_PEER_CERT will cause the connection to fail if no cert void SetRequireClientCertFlags( unsigned int iRequireCertFlags ) { m_iRequireCertFlags = iRequireCertFlags; } #endif /* HAVE_LIBSSL */ private: uint16_t m_iPort; CS_STRING m_sSockName, m_sBindHost; bool m_bIsSSL; bool m_bDetach; int m_iMaxConns; uint32_t m_iTimeout; CSSockAddr::EAFRequire m_iAFrequire; #ifdef HAVE_LIBSSL CS_STRING m_sDHParamLocation, m_sKeyLocation, m_sPemLocation, m_sPemPass, m_sCipher; uint32_t m_iRequireCertFlags; #endif /* HAVE_LIBSSL */ }; #ifdef HAVE_LIBSSL class CSSSListener : public CSListener { public: CSSSListener( uint16_t iPort, const CS_STRING & sBindHost = "" ) : CSListener( iPort, sBindHost ) { SetIsSSL( true ); } }; #endif /* HAVE_LIBSSL */ /** * @class CSocketManager * @brief Best class to use to interact with the sockets * * Handles SSL and NON Blocking IO. * Rather then use it directly, you'll probably get more use deriving from it. * Override GetSockObj since Csock derivatives need to be new'd correctly. * Makes it easier to use overall. * Another thing to note, is that all sockets are deleted implicitly, so obviously you * can't pass in Csock classes created on the stack. For those of you who don't * know STL very well, the reason I did this is because whenever you add to certain stl containers * (e.g. vector, or map), it is completely rebuilt using the copy constructor on each element. * That then means the constructor and destructor are called on every item in the container. * Not only is this more overhead then just moving pointers around, its dangerous as if you have * an object that is newed and deleted in the destructor the value of its pointer is copied in the * default copy constructor. This means everyone has to know better and create a copy constructor, * or I just make everyone new their object :). * * @see TSocketManager * @author Jim Hull */ class CS_EXPORT CSocketManager : public std::vector, public CSockCommon { public: CSocketManager(); virtual ~CSocketManager(); virtual void clear(); virtual void Cleanup(); virtual Csock * GetSockObj( const CS_STRING & sHostname, uint16_t uPort, int iTimeout = 60 ); enum EMessages { SUCCESS = 0, //!< Select returned at least 1 fd ready for action SELECT_ERROR = -1, //!< An Error Happened, Probably dead socket. That socket is returned if available SELECT_TIMEOUT = -2, //!< Select Timeout SELECT_TRYAGAIN = -3 //!< Select calls for you to try again }; /** * @brief Create a connection * @param cCon the connection which should be established * @param pcSock the socket used for the connection, can be NULL */ void Connect( const CSConnection & cCon, Csock * pcSock = NULL ); /** * @brief Sets up a listening socket * @param cListen the listener configuration * @param pcSock preconfigured sock to use * @param piRandPort if listener is set to port 0, then a random port is used and this is assigned. * * IF you provide piRandPort to be assigned, AND you set bDetach to true, then Listen() still blocks. If you don't want this * behavior, then look for the port assignment to be called in Csock::Listening */ virtual bool Listen( const CSListener & cListen, Csock * pcSock = NULL, uint16_t * piRandPort = NULL ); //! simple method to see if there are file descriptors being processed, useful to know if all the work is done in the manager bool HasFDs() const; /** * Best place to call this class for running, all the call backs are called. * You should through this in your main while loop (long as its not blocking) * all the events are called as needed. */ virtual void Loop(); /** * @brief this is similar to loop, except that it dynamically adjusts the select time based on jobs and timeouts in sockets * * - This type of behavior only works well in a scenario where there is low traffic. If you use this then its because you * - are trying to spare yourself some of those idle loops where nothing is done. If you try to use this code where you have lots of * - connections and/or lots of traffic you might end up causing more CPU usage than just a plain Loop() with a static sleep of 500ms * - its a trade off at some point, and you'll probably find out that the vast majority of the time and in most cases Loop() works fine * - by itself. I've tried to mitigate that as much as possible by not having it change the select if the previous call to select * - was not a timeout. Anyways .... Caveat Emptor. * - Sample useage is cFoo.DynamicSelectLoop( 500000, 5000000 ); which basically says min of 500ms and max of 5s * * @param iLowerBounds the lower bounds to use in MICROSECONDS * @param iUpperBounds the upper bounds to use in MICROSECONDS * @param iMaxResolution the maximum time to calculate overall in seconds */ void DynamicSelectLoop( uint64_t iLowerBounds, uint64_t iUpperBounds, time_t iMaxResolution = 3600 ); /** * Make this method virtual, so you can override it when a socket is added. * Assuming you might want to do some extra stuff */ virtual void AddSock( Csock * pcSock, const CS_STRING & sSockName ); //! returns a pointer to the FIRST sock found by port or NULL on no match virtual Csock * FindSockByRemotePort( uint16_t iPort ); //! returns a pointer to the FIRST sock found by port or NULL on no match virtual Csock * FindSockByLocalPort( uint16_t iPort ); //! returns a pointer to the FIRST sock found by name or NULL on no match virtual Csock * FindSockByName( const CS_STRING & sName ); //! returns a pointer to the FIRST sock found by filedescriptor or NULL on no match virtual Csock * FindSockByFD( cs_sock_t iFD ); virtual std::vector FindSocksByName( const CS_STRING & sName ); //! returns a vector of pointers to socks with sHostname as being connected virtual std::vector FindSocksByRemoteHost( const CS_STRING & sHostname ); //! return the last known error as set by this class int GetErrno() const { return( m_errno ); } //! Get the Select Timeout in MICROSECONDS ( 1000 == 1 millisecond ) uint64_t GetSelectTimeout() const { return( m_iSelectWait ); } //! Set the Select Timeout in MICROSECONDS ( 1000 == 1 millisecond ) //! Setting this to 0 will cause no timeout to happen, Select() will return instantly void SetSelectTimeout( uint64_t iTimeout ) { m_iSelectWait = iTimeout; } //! Delete a sock by addr //! its position is looked up //! the socket is deleted, the appropriate call backs are peformed //! and its instance is removed from the manager virtual void DelSockByAddr( Csock * pcSock ); //! Delete a sock by position in the vector //! the socket is deleted, the appropriate call backs are peformed //! and its instance is removed from the manager //! deleting in a loop can be tricky, be sure you watch your position. //! ie for( uint32_t a = 0; a < size(); a++ ) DelSock( a-- ); virtual void DelSock( size_t iPos ); /** * @brief swaps out a sock with a copy of the original sock * @param pNewSock the new sock to change out with. (this should be constructed by you with the default ctor) * @param iOrginalSockIdx the position in this sockmanager of the original sock * @return true on success */ virtual bool SwapSockByIdx( Csock * pNewSock, size_t iOrginalSockIdx ); /** * @brief swaps out a sock with a copy of the original sock * @param pNewSock the new sock to change out with. (this should be constructed by you with the default ctor) * @param pOrigSock the address of the original socket * @return true on success */ virtual bool SwapSockByAddr( Csock * pNewSock, Csock * pOrigSock ); //! Get the bytes read from all sockets current and past uint64_t GetBytesRead() const; //! Get the bytes written to all sockets current and past uint64_t GetBytesWritten() const; //! this is a strict wrapper around C-api select(). Added in the event you need to do special work here enum ECheckType { ECT_Read = 1, ECT_Write = 2 }; void FDSetCheck( cs_sock_t iFd, std::map< cs_sock_t, short > & miiReadyFds, ECheckType eType ); bool FDHasCheck( cs_sock_t iFd, std::map< cs_sock_t, short > & miiReadyFds, ECheckType eType ); protected: virtual int Select( std::map< cs_sock_t, short > & miiReadyFds, struct timeval *tvtimeout ); private: /** * @brief fills a map of socks to a message for check * map is empty if none are ready, check GetErrno() for the error, if not SUCCESS Select() failed * each struct contains the socks error * @see GetErrno() */ void Select( std::map & mpeSocks ); timeval GetDynamicSleepTime( const timeval& tNow, const timeval& tMaxResolution ) const; //! internal use only virtual void SelectSock( std::map & mpeSocks, EMessages eErrno, Csock * pcSock ); //////// // Connection State Functions /////////// // members EMessages m_errno; uint64_t m_iCallTimeouts; uint64_t m_iBytesRead; uint64_t m_iBytesWritten; uint64_t m_iSelectWait; }; /** * @class TSocketManager * @brief Ease of use templated socket manager * * class CBlahSock : public TSocketManager */ template class TSocketManager : public CSocketManager { public: TSocketManager() : CSocketManager() {} virtual ~TSocketManager() {} virtual T * GetSockObj( const CS_STRING & sHostname, uint16_t uPort, int iTimeout = 60 ) { return( new T( sHostname, uPort, iTimeout ) ); } }; #ifndef _NO_CSOCKET_NS } #endif /* _NO_CSOCKET_NS */ #endif /* _HAS_CSOCKET_ */ znc-1.7.5/.gitmodules0000644000175000017500000000043513542151610014717 0ustar somebodysomebody[submodule "Csocket"] path = third_party/Csocket url = https://github.com/jimloco/Csocket.git [submodule "third_party/googletest"] path = third_party/googletest url = https://github.com/google/googletest [submodule "docker"] path = docker url = https://github.com/znc/znc-docker znc-1.7.5/CMakeLists.txt0000644000175000017500000003055513542151610015310 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # cmake_minimum_required(VERSION 3.1) project(ZNC VERSION 1.7.5) set(ZNC_VERSION 1.7.5) set(append_git_version false) set(alpha_version "") # e.g. "-rc1" set(VERSION_EXTRA "" CACHE STRING "Additional string appended to version, e.g. to mark distribution") set(PROJECT_VERSION "${ZNC_VERSION}") # https://cmake.org/pipermail/cmake/2010-September/039388.html set(_all_targets "" CACHE INTERNAL "") function(znc_add_library name) add_library("${name}" ${ARGN}) set(_all_targets "${_all_targets};${name}" CACHE INTERNAL "") endfunction() function(znc_add_executable name) add_executable("${name}" ${ARGN}) set(_all_targets "${_all_targets};${name}" CACHE INTERNAL "") endfunction() function(znc_add_custom_target name) add_custom_target("${name}" ${ARGN}) set(_all_targets "${_all_targets};${name}" CACHE INTERNAL "") endfunction() list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") include(TestCXX11) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED true) if(NOT CYGWIN) # We don't want to use -std=gnu++11 instead of -std=c++11, but among other # things, -std=c++11 on cygwin defines __STRICT_ANSI__ which makes cygwin # not to compile: undefined references to strerror_r, to fdopen, to # strcasecmp, etc (their declarations in system headers are between ifdef) set(CMAKE_CXX_EXTENSIONS false) endif() include(CMakeFindFrameworks_fixed) include(use_homebrew) include(GNUInstallDirs) include(CheckCXXSymbolExists) include(copy_csocket) set(CMAKE_THREAD_PREFER_PTHREAD true) set(THREADS_PREFER_PTHREAD_FLAG true) find_package(Threads REQUIRED) if(NOT CMAKE_USE_PTHREADS_INIT) message(FATAL_ERROR "This compiler/OS doesn't seem to support pthreads.") endif() include(TestLargeFiles) test_large_files(HAVE_LARGE_FILES_UNUSED_VAR) find_package(PkgConfig) macro(tristate_option opt help) set(WANT_${opt} AUTO CACHE STRING ${help}) set_property(CACHE WANT_${opt} PROPERTY STRINGS AUTO YES NO) if(WANT_${opt} STREQUAL "AUTO") set(TRISTATE_${opt}_REQUIRED) else() set(TRISTATE_${opt}_REQUIRED REQUIRED) endif() endmacro() tristate_option(OPENSSL "Support SSL") if(WANT_OPENSSL) find_package(OpenSSL ${TRISTATE_OPENSSL_REQUIRED}) endif() set(HAVE_LIBSSL "${OPENSSL_FOUND}") set(WANT_IPV6 true CACHE BOOL "Support IPv6") set(HAVE_IPV6 "${WANT_IPV6}") tristate_option(ZLIB "Compress HTTP traffic with Zlib") if(WANT_ZLIB) find_package(ZLIB ${TRISTATE_ZLIB_REQUIRED}) endif() set(HAVE_ZLIB "${ZLIB_FOUND}") tristate_option(CYRUS "Support authentication with Cyrus") if(WANT_CYRUS) pkg_check_modules(CYRUS libsasl2) if(NOT CYRUS_FOUND) # libsasl2.pc is missing on 2.1.25 which is on ubuntu 14.04 # next ubuntu version has 2.1.26 which has libsasl2.pc # # osx (as of El Capitan) doesn't have it either... set(_old_cmake_required_libraries "${CMAKE_REQUIRED_LIBRARIES}") set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} -lsasl2) # sys/types.h here is workaround for sasl 2.1.26: # https://github.com/znc/znc/issues/1243 # https://lists.andrew.cmu.edu/pipermail/cyrus-sasl/2012-December/002572.html # https://cgit.cyrus.foundation/cyrus-sasl/commit/include/sasl.h?id=2f740223fa1820dd71e6ab0e50d4964760789209 check_cxx_symbol_exists(sasl_server_init "sys/types.h;sasl/sasl.h" CYRUS_HARDCODED) set(CMAKE_REQUIRED_LIBRARIES "${_old_cmake_required_libraries}") if(CYRUS_HARDCODED) set(CYRUS_LDFLAGS -lsasl2) set(CYRUS_FOUND true) endif() endif() if(TRISTATE_CYRUS_REQUIRED AND NOT CYRUS_FOUND) message(FATAL_ERROR "Can't find Cyrus SASL 2") endif() endif() tristate_option(ICU "Support character encodings") if(WANT_ICU) pkg_check_modules(ICU ${TRISTATE_ICU_REQUIRED} icu-uc) endif() set(HAVE_ICU "${ICU_FOUND}") set(WANT_PERL false CACHE BOOL "Support Perl modules") set(WANT_PYTHON false CACHE BOOL "Support Python modules") set(WANT_PYTHON_VERSION "python3" CACHE STRING "Python version to use, e.g. python-3.5, this name is passed to pkg-config") if(WANT_PYTHON AND NOT ICU_FOUND) message(FATAL_ERROR "Modpython requires ZNC to be compiled with charset " "support, but ICU library not found") endif() tristate_option(SWIG "Use SWIG to generate modperl and modpython") set(search_swig false) if(WANT_SWIG AND TRISTATE_SWIG_REQUIRED) set(search_swig true) endif() if(WANT_PERL AND NOT EXISTS "${PROJECT_SOURCE_DIR}/modules/modperl/generated.tar.gz") if(WANT_SWIG) set(search_swig true) else() message(FATAL_ERROR "Pregenerated modperl files are not available. " "SWIG is required. Alternatively, build ZNC from tarball.") endif() endif() if(WANT_PYTHON AND NOT EXISTS "${PROJECT_SOURCE_DIR}/modules/modpython/generated.tar.gz") if(WANT_SWIG) set(search_swig true) else() message(FATAL_ERROR "Pregenerated modpython files are not available. " "SWIG is required. Alternatively, build ZNC from tarball.") endif() endif() if(search_swig) find_package(SWIG 3.0.0) if(NOT SWIG_FOUND) message(FATAL_ERROR "Can't find SWIG, therefore Perl and Python aren't supported. " "Alternatively, build ZNC from tarball.") endif() endif() if(WANT_PERL) find_package(PerlLibs 5.10 REQUIRED) endif() if (WANT_PYTHON) find_package(Perl 5.10 REQUIRED) pkg_check_modules(PYTHON "${WANT_PYTHON_VERSION}-embed") if (NOT PYTHON_FOUND) pkg_check_modules(PYTHON "${WANT_PYTHON_VERSION}" REQUIRED) endif() endif() set(WANT_TCL false CACHE BOOL "Support Tcl modules") if(WANT_TCL) find_package(TCL QUIET) if(NOT TCL_FOUND) message(FATAL_ERROR "Can't find Tcl") endif() endif() tristate_option(I18N "Native language support (i18n)") if(WANT_I18N) find_package(Boost ${TRISTATE_I18N_REQUIRED} COMPONENTS locale) find_package(Gettext ${TRISTATE_I18N_REQUIRED}) endif() if(Boost_LOCALE_FOUND AND GETTEXT_MSGFMT_EXECUTABLE) set(HAVE_I18N true) else() set(HAVE_I18N false) message(STATUS "Boost.Locale or gettext (msgfmt) is not found, disabling i18n support") endif() if(HAVE_I18N AND GETTEXT_MSGMERGE_EXECUTABLE) find_program(XGETTEXT_EXECUTABLE xgettext) if(XGETTEXT_EXECUTABLE) add_custom_target(translation) endif() endif() # poll() is broken on Mac OS, it fails with POLLNVAL for pipe()s. if(APPLE) set(CSOCK_USE_POLL false) else() set(CSOCK_USE_POLL true) endif() check_cxx_symbol_exists(getopt_long "getopt.h" HAVE_GETOPT_LONG) check_cxx_symbol_exists(lstat "sys/types.h;sys/stat.h;unistd.h" HAVE_LSTAT) check_cxx_symbol_exists(getpassphrase "stdlib.h" HAVE_GETPASSPHRASE) check_cxx_symbol_exists(tcsetattr "termios.h;unistd.h" HAVE_TCSETATTR) check_cxx_symbol_exists(clock_gettime "time.h" HAVE_CLOCK_GETTIME) # Note that old broken systems, such as OpenBSD, NetBSD, which don't support # AI_ADDRCONFIG, also have thread-unsafe getaddrinfo(). Gladly, they fixed # thread-safety before support of AI_ADDRCONFIG, so this can be abused to # detect the thread-safe getaddrinfo(). # # TODO: drop support of blocking DNS at some point. OpenBSD supports # AI_ADDRCONFIG since Nov 2014, and their getaddrinfo() is thread-safe since # Nov 2013. NetBSD's one is thread-safe since ages ago. check_cxx_symbol_exists(AI_ADDRCONFIG "sys/types.h;sys/socket.h;netdb.h" HAVE_THREADED_DNS) if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT CYGWIN) # These enable some debug options in g++'s STL, e.g. invalid use of # iterators, but they cause crashes on cygwin while loading modules set(_GLIBCXX_DEBUG true) set(_GLIBCXX_DEBUG_PEDANTIC true) endif() if(append_git_version) find_package(Git) endif() file(GLOB csocket_files LIST_DIRECTORIES FALSE "${PROJECT_SOURCE_DIR}/third_party/Csocket/Csocket.*") if(csocket_files STREQUAL "") execute_process(COMMAND git status WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} RESULT_VARIABLE git_status_var OUTPUT_QUIET ERROR_QUIET) if(git_status_var) message(FATAL_ERROR " It looks like git submodules are not initialized.\n" " Either this is not a git clone, or you don't have git installed.\n" " Fetch the tarball from the website: https://znc.in/releases/ ") else() message(FATAL_ERROR " It looks like git submodules are not initialized.\n" " Run: git submodule update --init --recursive") endif() endif() install(DIRECTORY webskins DESTINATION "${CMAKE_INSTALL_DATADIR}/znc") install(DIRECTORY translations DESTINATION "${CMAKE_INSTALL_DATADIR}/znc") install(DIRECTORY man/ DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" FILES_MATCHING PATTERN "znc*") set(WANT_SYSTEMD false CACHE BOOL "Install znc.service to systemd") if(WANT_SYSTEMD) configure_file("znc.service.in" "znc.service") set(SYSTEMD_DIR "" CACHE PATH "Path to systemd units") if(SYSTEMD_DIR STREQUAL "" AND PKG_CONFIG_EXECUTABLE) execute_process(COMMAND "${PKG_CONFIG_EXECUTABLE}" --variable=systemdsystemunitdir systemd OUTPUT_VARIABLE SYSTEMD_DIR) endif() if(SYSTEMD_DIR STREQUAL "") message(FATAL_ERROR "Systemd is enabled, " "but the unit dir can't be found.") endif() install(FILES "${PROJECT_BINARY_DIR}/znc.service" DESTINATION "${SYSTEMD_DIR}") endif() # On cygwin, if to link modules against znc.exe directly, modperl can't call # ZNC's functions very well. They do get called, but global variables have # different addresses. That address actually is in modperl/ZNC.dll if to look # at /proc/123/maps # Example of such global variable is one returned by CZNC::Get() # Modpython seems to work though with STATIC on cygwin... (I didn't test it # too much though) # # Non-cygwin should link modules to /usr/bin/znc directly to prevent this: # error while loading shared libraries: libznc.so: cannot open shared object file: No such file or directory # Without need to touch LD_LIBRARY_PATH if(CYGWIN) set(znc_link "znclib") set(lib_type "SHARED") set(install_lib "znclib") set(znclib_pc "-L${CMAKE_INSTALL_FULL_LIBDIR} -lznc") else() set(znc_link "znc") set(lib_type "STATIC") set(install_lib) set(znclib_pc) endif() configure_file("include/znc/zncconfig.h.cmake.in" "include/znc/zncconfig.h") add_subdirectory(include) add_subdirectory(src) add_subdirectory(modules) add_subdirectory(test) add_subdirectory(zz_msg) add_custom_target(msg_after_all ALL COMMAND "${CMAKE_COMMAND}" -E echo COMMAND "${CMAKE_COMMAND}" -E echo " ZNC was successfully compiled." COMMAND "${CMAKE_COMMAND}" -E echo " Use 'make install' to install ZNC to '${CMAKE_INSTALL_PREFIX}'." COMMAND "${CMAKE_COMMAND}" -E echo VERBATIM) add_dependencies(msg_after_all ${_all_targets}) # @echo "" # @echo " ZNC was successfully compiled." # @echo " Use '$(MAKE) install' to install ZNC to '$(prefix)'." configure_file("ZNCConfig.cmake.in" "ZNCConfig.cmake" @ONLY) include(CMakePackageConfigHelpers) write_basic_package_version_file("ZNCConfigVersion.cmake" COMPATIBILITY AnyNewerVersion) install(FILES "${PROJECT_BINARY_DIR}/ZNCConfig.cmake" "${PROJECT_BINARY_DIR}/ZNCConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_DATADIR}/znc/cmake") configure_file("znc-buildmod.cmake.in" "znc-buildmod" @ONLY) install(PROGRAMS "${PROJECT_BINARY_DIR}/znc-buildmod" DESTINATION "${CMAKE_INSTALL_BINDIR}") configure_file("znc.pc.cmake.in" "znc.pc" @ONLY) install(FILES "${PROJECT_BINARY_DIR}/znc.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") macro(summary_line text var) if(${var}) list(APPEND summary_lines "${text} : yes") else() list(APPEND summary_lines "${text} : no") endif() endmacro() set(summary_lines "ZNC ${ZNC_VERSION}${VERSION_EXTRA}${alpha_version} configured" " " "Prefix : ${CMAKE_INSTALL_PREFIX}") summary_line("SSL " "${OPENSSL_FOUND}") summary_line("IPv6 " "${WANT_IPV6}") summary_line("Async DNS" "${HAVE_THREADED_DNS}") summary_line("Perl " "${PERLLIBS_FOUND}") summary_line("Python " "${PYTHON_FOUND}") summary_line("Tcl " "${TCL_FOUND}") summary_line("Cyrus " "${CYRUS_FOUND}") summary_line("Charset " "${ICU_FOUND}") summary_line("Zlib " "${ZLIB_FOUND}") summary_line("i18n " "${HAVE_I18N}") include(render_framed_multiline) render_framed_multiline("${summary_lines}") message("") message("Now you can run 'make' to compile ZNC") message("") # TODO # ==== # # remove old configure.ac and Makefile.in znc-1.7.5/cmake/0000755000175000017500000000000013542151610013620 5ustar somebodysomebodyznc-1.7.5/cmake/cxx11check/0000755000175000017500000000000013542151610015562 5ustar somebodysomebodyznc-1.7.5/cmake/cxx11check/CMakeLists.txt0000644000175000017500000000144013542151610020321 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # cmake_minimum_required(VERSION 3.0) project(cxx11check) set(CMAKE_VERBOSE_MAKEFILE true) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED true) add_executable(main main.cpp) znc-1.7.5/cmake/cxx11check/main.cpp0000644000175000017500000000300613542151610017211 0ustar somebodysomebody// This file uses code from http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html (serial 5) // Copyright (c) 2008 Benjamin Kosnik // Copyright (c) 2012 Zack Weinberg // Copyright (c) 2013 Roy Stogner // Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov // // Copying and distribution of this file, with or without modification, are // permitted in any medium without royalty provided the copyright notice // and this notice are preserved. This file is offered as-is, without any // warranty. #include template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; struct Base { virtual void f() {} }; struct Child : public Base { virtual void f() override {} }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; auto l = []() {}; // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this namespace test_template_alias_sfinae { struct foo {}; template using member = typename T::member_type; template void func(...) {} template void func(member*) {} void test(); void test() { func(0); } } int main() { std::map m; m.emplace(2, 4); return 0; } znc-1.7.5/cmake/use_homebrew.cmake0000644000175000017500000000471213542151610017312 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if(NOT APPLE) return() endif() include(FindPackageMessage) find_program(brew brew) if(brew) find_package_message(brew "Homebrew found: ${brew}" "1;${brew}") else() find_package_message(brew "Homebrew not found" "0") return() endif() execute_process(COMMAND "${brew}" --prefix icu4c RESULT_VARIABLE brew_icu_f OUTPUT_VARIABLE brew_icu OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) if(brew_icu_f EQUAL 0) find_package_message(brew_icu "ICU via Homebrew: ${brew_icu}" "${brew_icu}") set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${brew_icu}/lib/pkgconfig") endif() execute_process(COMMAND "${brew}" --prefix openssl RESULT_VARIABLE brew_ssl_f OUTPUT_VARIABLE brew_ssl OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) if(brew_ssl_f EQUAL 0) find_package_message(brew_ssl "OpenSSL via Homebrew: ${brew_ssl}" "${brew_ssl}") set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${brew_ssl}/lib/pkgconfig") endif() execute_process(COMMAND "${brew}" --prefix python3 RESULT_VARIABLE brew_python_f OUTPUT_VARIABLE brew_python OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) if(brew_python_f EQUAL 0) find_package_message(brew_python "Python via Homebrew: ${brew_python}" "${brew_python}") list(APPEND Python_FRAMEWORKS_ADDITIONAL "${brew_python}/Frameworks/Python.framework") endif() execute_process(COMMAND "${brew}" --prefix qt5 RESULT_VARIABLE brew_qt5_f OUTPUT_VARIABLE brew_qt5 OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) if(brew_qt5_f EQUAL 0) find_package_message(brew_qt5 "Qt5 via Homebrew: ${brew_qt5}" "${brew_qt5}") endif() execute_process(COMMAND "${brew}" --prefix gettext RESULT_VARIABLE brew_gettext_f OUTPUT_VARIABLE brew_gettext OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) if(brew_gettext_f EQUAL 0) find_package_message(brew_gettext "Gettext via homebrew: ${brew_gettext}" "${brew_gettext}") set(ENV{PATH} "$ENV{PATH}:${brew_gettext}/bin") endif() znc-1.7.5/cmake/TestWindowsFSeek.cpp0000644000175000017500000000025113542151610017532 0ustar somebodysomebody// See TestLargeFiles.cmake for the origin of this file #include int main() { __int64 off=0; _fseeki64(NULL, off, SEEK_SET); return 0; } znc-1.7.5/cmake/TestCXX11.cmake0000644000175000017500000000277413542151610016300 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if(NOT DEFINED cxx11check) message(STATUS "Checking for C++11 support") get_filename_component(_CXX11Check_dir "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) try_compile(cxx11_supported "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cxx11check" "${_CXX11Check_dir}/cxx11check" cxx11check OUTPUT_VARIABLE _CXX11Check_tryout) if(cxx11_supported) message(STATUS "Checking for C++11 support - supported") SET(cxx11check 1 CACHE INTERNAL "C++11 support") file(APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log" "Output of C++11 check:\n${_CXX11Check_tryout}\n") else() file(APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log" "Error in C++11 check:\n${_CXX11Check_tryout}\n") message(STATUS "Checking for C++11 support - not supported") message(FATAL_ERROR " Upgrade your compiler.\n" " GCC 4.8+ and Clang 3.2+ are known to work.") endif() endif() znc-1.7.5/cmake/TestFileOffsetBits.cpp0000644000175000017500000000055513542151610020041 0ustar somebodysomebody// See TestLargeFiles.cmake for the origin of this file #include int main(int argc, char **argv) { /* Cause a compile-time error if off_t is smaller than 64 bits */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[ (LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1 ]; return 0; } znc-1.7.5/cmake/TestLargeFiles.cmake0000644000175000017500000001141613542151610017502 0ustar somebodysomebody# Downloaded from https://panthema.net/2012/1119-eSAIS-Inducing-Suffix-and-LCP-Arrays-in-External-Memory/eSAIS-DC3-LCP-0.5.4/stxxl/misc/cmake/TestLargeFiles.cmake.html # That project's license is Boost Software License, Version 1.0. # - Define macro to check large file support # # TEST_LARGE_FILES(VARIABLE) # # VARIABLE will be set to true if off_t is 64 bits, and fseeko/ftello present. # This macro will also set defines necessary enable large file support, for instance # _LARGE_FILES # _LARGEFILE_SOURCE # _FILE_OFFSET_BITS 64 # HAVE_FSEEKO # # However, it is YOUR job to make sure these defines are set in a cmakedefine so they # end up in a config.h file that is included in your source if necessary! set(_test_large_files_dir "${CMAKE_CURRENT_LIST_DIR}") MACRO(TEST_LARGE_FILES VARIABLE) IF(NOT DEFINED ${VARIABLE}) # On most platforms it is probably overkill to first test the flags for 64-bit off_t, # and then separately fseeko. However, in the future we might have 128-bit filesystems # (ZFS), so it might be dangerous to indiscriminately set e.g. _FILE_OFFSET_BITS=64. MESSAGE(STATUS "Checking for 64-bit off_t") # First check without any special flags TRY_COMPILE(FILE64_OK "${PROJECT_BINARY_DIR}" "${_test_large_files_dir}/TestFileOffsetBits.cpp") if(FILE64_OK) MESSAGE(STATUS "Checking for 64-bit off_t - present") endif(FILE64_OK) if(NOT FILE64_OK) # Test with _FILE_OFFSET_BITS=64 TRY_COMPILE(FILE64_OK "${PROJECT_BINARY_DIR}" "${_test_large_files_dir}/TestFileOffsetBits.cpp" COMPILE_DEFINITIONS "-D_FILE_OFFSET_BITS=64" ) if(FILE64_OK) MESSAGE(STATUS "Checking for 64-bit off_t - present with _FILE_OFFSET_BITS=64") set(_FILE_OFFSET_BITS 64) endif(FILE64_OK) endif(NOT FILE64_OK) if(NOT FILE64_OK) # Test with _LARGE_FILES TRY_COMPILE(FILE64_OK "${PROJECT_BINARY_DIR}" "${_test_large_files_dir}/TestFileOffsetBits.cpp" COMPILE_DEFINITIONS "-D_LARGE_FILES" ) if(FILE64_OK) MESSAGE(STATUS "Checking for 64-bit off_t - present with _LARGE_FILES") set(_LARGE_FILES 1) endif(FILE64_OK) endif(NOT FILE64_OK) if(NOT FILE64_OK) # Test with _LARGEFILE_SOURCE TRY_COMPILE(FILE64_OK "${PROJECT_BINARY_DIR}" "${_test_large_files_dir}/TestFileOffsetBits.cpp" COMPILE_DEFINITIONS "-D_LARGEFILE_SOURCE" ) if(FILE64_OK) MESSAGE(STATUS "Checking for 64-bit off_t - present with _LARGEFILE_SOURCE") set(_LARGEFILE_SOURCE 1) endif(FILE64_OK) endif(NOT FILE64_OK) if(NOT FILE64_OK) # now check for Windows stuff TRY_COMPILE(FILE64_OK "${PROJECT_BINARY_DIR}" "${_test_large_files_dir}/TestWindowsFSeek.cpp") if(FILE64_OK) MESSAGE(STATUS "Checking for 64-bit off_t - present with _fseeki64") set(HAVE__FSEEKI64 1) endif(FILE64_OK) endif(NOT FILE64_OK) if(NOT FILE64_OK) MESSAGE(STATUS "Checking for 64-bit off_t - not present") else(NOT FILE64_OK) # Set the flags we might have determined to be required above configure_file("${_test_large_files_dir}/TestLargeFiles.cpp.cmakein" "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestLargeFiles.cpp") MESSAGE(STATUS "Checking for fseeko/ftello") # Test if ftello/fseeko are available TRY_COMPILE(FSEEKO_COMPILE_OK "${PROJECT_BINARY_DIR}" "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestLargeFiles.cpp") if(FSEEKO_COMPILE_OK) MESSAGE(STATUS "Checking for fseeko/ftello - present") endif(FSEEKO_COMPILE_OK) if(NOT FSEEKO_COMPILE_OK) # glibc 2.2 neds _LARGEFILE_SOURCE for fseeko (but not 64-bit off_t...) TRY_COMPILE(FSEEKO_COMPILE_OK "${PROJECT_BINARY_DIR}" "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestLargeFiles.cpp" COMPILE_DEFINITIONS "-D_LARGEFILE_SOURCE" ) if(FSEEKO_COMPILE_OK) MESSAGE(STATUS "Checking for fseeko/ftello - present with _LARGEFILE_SOURCE") set(_LARGEFILE_SOURCE 1) endif(FSEEKO_COMPILE_OK) endif(NOT FSEEKO_COMPILE_OK) endif(NOT FILE64_OK) if(FSEEKO_COMPILE_OK) SET(${VARIABLE} 1 CACHE INTERNAL "Result of test for large file support" FORCE) set(HAVE_FSEEKO 1) else(FSEEKO_COMPILE_OK) if (HAVE__FSEEKI64) SET(${VARIABLE} 1 CACHE INTERNAL "Result of test for large file support" FORCE) SET(HAVE__FSEEKI64 1 CACHE INTERNAL "Windows 64-bit fseek" FORCE) else (HAVE__FSEEKI64) MESSAGE(STATUS "Checking for fseeko/ftello - not found") SET(${VARIABLE} 0 CACHE INTERNAL "Result of test for large file support" FORCE) endif (HAVE__FSEEKI64) endif(FSEEKO_COMPILE_OK) ENDIF(NOT DEFINED ${VARIABLE}) ENDMACRO(TEST_LARGE_FILES VARIABLE) znc-1.7.5/cmake/gen_version.cmake0000644000175000017500000000450113542151610017140 0ustar somebodysomebody# # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if(nightly) set(git_info "${nightly}") elseif(append_git_version) set(git ${gitcmd} "--git-dir=${srcdir}/.git") execute_process(COMMAND ${git} describe --abbrev=0 HEAD RESULT_VARIABLE git_result ERROR_QUIET OUTPUT_VARIABLE latest_tag) string(STRIP "${latest_tag}" latest_tag) if(git_result EQUAL 0) execute_process(COMMAND ${git} rev-parse --short HEAD OUTPUT_VARIABLE short_id) string(STRIP "${short_id}" short_id) if(latest_tag STREQUAL "") # shallow clone set(git_info "-git-${short_id}") else() # One character "x" per commit, remove newlines from output execute_process(COMMAND ${git} log --format=tformat:x "${latest_tag}..HEAD" OUTPUT_VARIABLE commits_since) string(REGEX REPLACE "[^x]" "" commits_since "${commits_since}") string(LENGTH "${commits_since}" commits_since) if(commits_since EQUAL 0) # If this commit is tagged, don't print anything # (the assumption here is: this is a release) set(git_info "") # However, this shouldn't happen, as for releases # append_git_version should be set to false else() set(git_info "-git-${commits_since}-${short_id}") endif() endif() execute_process(COMMAND ${gitcmd} status --ignore-submodules=dirty --porcelain -- third_party/Csocket WORKING_DIRECTORY "${srcdir}" OUTPUT_VARIABLE franken) string(STRIP "${franken}" franken) if(NOT franken STREQUAL "") message(WARNING " Csocket submodule looks outdated.\n" " Run: git submodule update --init --recursive") set(git_info "${git_info}-frankenznc") endif() else() # Probably .git/ or git isn't found, or something set(git_info "-git-unknown") endif() else() set(git_info "") endif() configure_file("${srcfile}" "${destfile}") znc-1.7.5/cmake/translation_tmpl.py0000755000175000017500000000364113542151610017573 0ustar somebodysomebody#!/usr/bin/env python3 # # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import argparse import glob import os import re parser = argparse.ArgumentParser( description='Extract translateable strings from .tmpl files') parser.add_argument('--directory', action='store') parser.add_argument('--output', action='store') args = parser.parse_args() pattern = re.compile(r'<\?\s*(?:FORMAT|(PLURAL))\s+(?:CTX="([^"]+?)"\s+)?"([^"]+?)"(?(1)\s+"([^"]+?)"|).*?\?>') result = [] for fname in glob.iglob(args.directory + '/*.tmpl'): fbase = os.path.basename(fname) with open(fname) as f: for linenum, line in enumerate(f): for x in pattern.finditer(line): text, plural, context = x.group(3), x.group(4), x.group(2) result.append('#: {}:{}'.format(fbase, linenum + 1)) if context: result.append('msgctxt "{}"'.format(context)) result.append('msgid "{}"'.format(text)) if plural: result.append('msgid_plural "{}"'.format(plural)) result.append('msgstr[0] ""') result.append('msgstr[1] ""') else: result.append('msgstr ""') result.append('') if result: with open(args.output, 'w') as f: for line in result: print(line, file=f) znc-1.7.5/cmake/copy_csocket.cmake0000644000175000017500000000175513542151610017317 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # function(copy_csocket tgt source destination) add_custom_command(OUTPUT "${destination}" COMMAND "${CMAKE_COMMAND}" -D "source=${source}" -D "destination=${destination}" -P "${PROJECT_SOURCE_DIR}/cmake/copy_csocket_cmd.cmake" DEPENDS "${source}" "${PROJECT_SOURCE_DIR}/cmake/copy_csocket_cmd.cmake" VERBATIM) add_custom_target("${tgt}" DEPENDS "${destination}") endfunction() znc-1.7.5/cmake/render_framed_multiline.cmake0000644000175000017500000000221013542151610021474 0ustar somebodysomebody# # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # function(render_framed_multiline lines) set(max_len 0) foreach(l ${lines}) string(LENGTH "${l}" l_len) if(l_len GREATER max_len) set(max_len "${l_len}") endif() endforeach() set(i 0) set(header) while(i LESS max_len) set(header "${header}-") math(EXPR i "${i} + 1") endwhile() message("+-${header}-+") foreach(l ${lines}) string(LENGTH "${l}" l_len) while(l_len LESS max_len) set(l "${l} ") math(EXPR l_len "${l_len} + 1") endwhile() message("| ${l} |") endforeach() message("+-${header}-+") endfunction() znc-1.7.5/cmake/copy_csocket_cmd.cmake0000644000175000017500000000154213542151610020134 0ustar somebodysomebody# # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # file(READ "${source}" content) string(REPLACE "#include \"defines.h\"" "#include " content "${content}") string(REPLACE "#include \"Csocket.h\"" "#include " content "${content}") file(WRITE "${destination}" "${content}") znc-1.7.5/cmake/translation.cmake0000644000175000017500000000504513542151610017164 0ustar somebodysomebody# # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(CMakeParseArguments) function(translation) cmake_parse_arguments(arg "" "FULL;SHORT" "SOURCES;TMPLDIRS" ${ARGN}) set(short "${arg_SHORT}") file(GLOB all_po "${short}.*.po") if(XGETTEXT_EXECUTABLE) set(params) foreach(i ${arg_SOURCES}) list(APPEND params "--explicit_sources=${i}") endforeach() foreach(i ${arg_TMPLDIRS}) list(APPEND params "--tmpl_dirs=${i}") endforeach() add_custom_target("translation_${short}" COMMAND "${PROJECT_SOURCE_DIR}/translation_pot.py" "--include_dir=${CMAKE_CURRENT_SOURCE_DIR}/.." "--strip_prefix=${PROJECT_SOURCE_DIR}/" "--tmp_prefix=${CMAKE_CURRENT_BINARY_DIR}/${short}" "--output=${CMAKE_CURRENT_SOURCE_DIR}/${short}.pot" ${params} VERBATIM) foreach(one_po ${all_po}) add_custom_command(TARGET "translation_${short}" POST_BUILD COMMAND "${GETTEXT_MSGMERGE_EXECUTABLE}" --update --quiet --backup=none "${one_po}" "${short}.pot" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM) endforeach() add_dependencies(translation "translation_${short}") endif() if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${short}.pot") return() endif() znc_add_custom_target("po_${short}") foreach(one_po ${all_po}) get_filename_component(longext "${one_po}" EXT) if(NOT longext MATCHES "^\\.([a-zA-Z_]+)\\.po$") message(WARNING "Unrecognized translation file ${one_po}") continue() endif() set(lang "${CMAKE_MATCH_1}") add_custom_command(OUTPUT "${short}.${lang}.gmo" COMMAND "${GETTEXT_MSGFMT_EXECUTABLE}" -D "${CMAKE_CURRENT_SOURCE_DIR}" -o "${short}.${lang}.gmo" "${short}.${lang}.po" DEPENDS "${short}.${lang}.po" VERBATIM) add_custom_target("po_${short}_${lang}" DEPENDS "${short}.${lang}.gmo") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${short}.${lang}.gmo" DESTINATION "${CMAKE_INSTALL_LOCALEDIR}/${lang}/LC_MESSAGES" RENAME "${arg_FULL}.mo") add_dependencies("po_${short}" "po_${short}_${lang}") endforeach() endfunction() znc-1.7.5/cmake/CMakeFindFrameworks_fixed.cmake0000644000175000017500000000260713542151610021630 0ustar somebodysomebody# Modification from upstream CMakeFindFrameworks.cmake from version 3.3.1: # - add support of ${fwk}_FRAMEWORKS_ADDITIONAL input variable #.rst: # CMakeFindFrameworks # ------------------- # # helper module to find OSX frameworks #============================================================================= # Copyright 2003-2009 Kitware, Inc. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) if(NOT CMAKE_FIND_FRAMEWORKS_INCLUDED) set(CMAKE_FIND_FRAMEWORKS_INCLUDED 1) macro(CMAKE_FIND_FRAMEWORKS fwk) set(${fwk}_FRAMEWORKS) if(APPLE) foreach(dir ${${fwk}_FRAMEWORKS_ADDITIONAL} ~/Library/Frameworks/${fwk}.framework /Library/Frameworks/${fwk}.framework /System/Library/Frameworks/${fwk}.framework /Network/Library/Frameworks/${fwk}.framework) if(EXISTS ${dir}) set(${fwk}_FRAMEWORKS ${${fwk}_FRAMEWORKS} ${dir}) endif() endforeach() endif() endmacro() endif() znc-1.7.5/cmake/perl_check/0000755000175000017500000000000013542151610015717 5ustar somebodysomebodyznc-1.7.5/cmake/perl_check/CMakeLists.txt0000644000175000017500000000212513542151610020457 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # cmake_minimum_required(VERSION 3.0) project(perl_check) set(CMAKE_VERBOSE_MAKEFILE true) if(APPLE) set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS "${CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS} -undefined dynamic_lookup") endif() add_library(main MODULE main.cpp) target_include_directories(main PRIVATE ${PERL_INCLUDE_DIRS}) target_compile_options(main PRIVATE "${PERL_CFLAGS}") target_link_libraries(main PRIVATE ${PERL_LIBRARIES}) set_target_properties(main PROPERTIES LINK_FLAGS "${PERL_LDFLAGS}") znc-1.7.5/cmake/perl_check/main.cpp0000644000175000017500000000160113542151610017345 0ustar somebodysomebody/* * Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include int perlcheck(int argc, char** argv, char** env) { PERL_SYS_INIT3(&argc, &argv, &env); PerlInterpreter* p = perl_alloc(); perl_construct(p); perl_destruct(p); perl_free(p); PERL_SYS_TERM(); return 0; } znc-1.7.5/cmake/TestLargeFiles.cpp.cmakein0000644000175000017500000000130413542151610020605 0ustar somebodysomebody// See TestLargeFiles.cmake for the origin of this file #cmakedefine _LARGEFILE_SOURCE #cmakedefine _LARGEFILE64_SOURCE #cmakedefine _LARGE_FILES #cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS} #include #include #include int main(int argc, char **argv) { /* Cause a compile-time error if off_t is smaller than 64 bits, * and make sure we have ftello / fseeko. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[ (LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1 ]; FILE *fp = fopen(argv[0],"r"); off_t offset = ftello( fp ); fseeko( fp, offset, SEEK_CUR ); fclose(fp); return 0; } znc-1.7.5/cmake/FindPerlLibs.cmake0000644000175000017500000000614513542151610017145 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # perl 5.20 will fix this warning: # https://rt.perl.org/Public/Bug/Display.html?id=120670 set(PERL_CFLAGS -Wno-reserved-user-defined-literal -Wno-literal-suffix CACHE STRING "Perl compiler flags") if(PerlLibs_FIND_VERSION_EXACT) set(_PerlLibs_exact EXACT) else() set(_PerlLibs_exact) endif() find_package(Perl ${PerlLibs_FIND_VERSION} ${PerlLibs_exact} QUIET) if(PERL_FOUND) if(PERL_INCLUDE_DIR AND PERL_LIBRARIES) else() execute_process( COMMAND "${PERL_EXECUTABLE}" -MExtUtils::Embed -e perl_inc OUTPUT_VARIABLE _PerlLibs_inc_output OUTPUT_STRIP_TRAILING_WHITESPACE) string(REGEX REPLACE "^ *-I" "" _PerlLibs_include "${_PerlLibs_inc_output}") execute_process( COMMAND "${PERL_EXECUTABLE}" -MExtUtils::Embed -e ldopts OUTPUT_VARIABLE _PerlLibs_ld_output OUTPUT_STRIP_TRAILING_WHITESPACE) separate_arguments(_PerlLibs_ld_output) set(_PerlLibs_ldflags) set(_PerlLibs_libraries) foreach(_PerlLibs_i ${_PerlLibs_ld_output}) if("${_PerlLibs_i}" MATCHES "^-l") list(APPEND _PerlLibs_libraries "${_PerlLibs_i}") else() set(_PerlLibs_ldflags "${_PerlLibs_ldflags} ${_PerlLibs_i}") endif() endforeach() get_filename_component(_PerlLibs_dir "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) try_compile(_PerlLibs_try "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/perl_check" "${_PerlLibs_dir}/perl_check" perl_check CMAKE_FLAGS "-DPERL_INCLUDE_DIRS=${_PerlLibs_include}" "-DPERL_LDFLAGS=${_PerlLibs_ldflags}" "-DPERL_LIBRARIES=${_PerlLibs_libraries}" "-DPERL_CFLAGS=${PERL_CFLAGS}" OUTPUT_VARIABLE _PerlLibs_tryout) if(_PerlLibs_try) set(PERL_INCLUDE_DIR "${_PerlLibs_include}" CACHE PATH "Perl include dir") set(PERL_LDFLAGS "${_PerlLibs_ldflags}" CACHE STRING "Perl linker flags") set(PERL_LIBRARIES "${_PerlLibs_libraries}" CACHE STRING "Perl libraries") file(APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log" "Output using Perl:\n${_PerlLibs_tryout}\n") else() set(_PerlLibs_failmsg FAIL_MESSAGE "Attempt to use Perl failed") file(APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log" "Error using Perl:\n${_PerlLibs_tryout}\n") endif() endif() else() set(_PerlLibs_failmsg FAIL_MESSAGE "Perl not found") endif() find_package_handle_standard_args(PerlLibs REQUIRED_VARS PERL_INCLUDE_DIR PERL_LIBRARIES VERSION_VAR PERL_VERSION_STRING ${_PerlLibs_failmsg}) set(PERL_INCLUDE_DIRS "${PERL_INCLUDE_DIR}") mark_as_advanced(PERL_INCLUDE_DIR PERL_LDFLAGS PERL_LIBRARIES PERL_CFLAGS) znc-1.7.5/Jenkinsfile0000644000175000017500000000171113542151610014724 0ustar somebodysomebody#!groovy timestamps { node('freebsd') { // freebsd 10.3 + pkg install git openjdk cmake icu pkgconf swig30 python3 boost-libs gettext-tools qt5-buildtools qt5-network qt5-qmake timeout(time: 30, unit: 'MINUTES') { def wsdir = pwd() stage('Checkout') { step([$class: 'WsCleanup']) checkout scm sh 'git submodule update --init --recursive' } dir("$wsdir/build") { stage('Build') { sh "cmake $wsdir -DWANT_PERL=ON -DWANT_PYTHON=ON -DCMAKE_INSTALL_PREFIX=$wsdir/build/install-prefix" sh 'make VERBOSE=1 all' } stage('Unit test') { withEnv(['GTEST_OUTPUT=xml:unit-test.xml']) { sh 'make unittest' } } stage('Integration test') { withEnv(['GTEST_OUTPUT=xml:integration-test.xml']) { sh 'make install' sh 'make inttest' } } junit '**/*test.xml' } } } } znc-1.7.5/.dockerignore0000644000175000017500000000001413542151610015207 0ustar somebodysomebody.git build* znc-1.7.5/bootstrap.sh0000777000175000017500000000000013542151610017104 2autogen.shustar somebodysomebodyznc-1.7.5/docker/0000755000175000017500000000000013542151610014007 5ustar somebodysomebodyznc-1.7.5/.clang-format0000644000175000017500000000044213542151610015113 0ustar somebodysomebody--- BasedOnStyle: Google Standard: Cpp11 IndentWidth: 4 TabWidth: 4 AccessModifierOffset: -2 DerivePointerAlignment: false PointerAlignment: Left # Prevent breaking doxygen, as clang-format doesn't support reflowing of doxygen comments yet (as of 3.5.0). CommentPragmas: '^\*|^/|^!' ... znc-1.7.5/Dockerfile0000644000175000017500000000266613542151610014544 0ustar somebodysomebodyFROM alpine:3.8 ARG VERSION_EXTRA="" # musl silently doesn't support AI_ADDRCONFIG yet, and ZNC doesn't support Happy Eyeballs yet. # Together they cause very slow connection. So for now IPv6 is disabled here. ARG CMAKEFLAGS="-DVERSION_EXTRA=${VERSION_EXTRA} -DCMAKE_INSTALL_PREFIX=/opt/znc -DWANT_CYRUS=YES -DWANT_PERL=YES -DWANT_PYTHON=YES -DWANT_IPV6=NO" ARG MAKEFLAGS="" ARG BUILD_DATE ARG VCS_REF LABEL org.label-schema.schema-version="1.0" LABEL org.label-schema.vcs-ref=$VCS_REF LABEL org.label-schema.vcs-url="https://github.com/znc/znc" LABEL org.label-schema.build-date=$BUILD_DATE LABEL org.label-schema.url="https://znc.in" COPY . /znc-src RUN set -x \ && adduser -S znc \ && addgroup -S znc RUN apk add --no-cache \ boost \ build-base \ ca-certificates \ cmake \ cyrus-sasl \ gettext \ icu-dev \ libressl-dev \ perl \ python3 \ su-exec \ tini \ tzdata RUN apk add --no-cache --virtual build-dependencies \ boost-dev \ cyrus-sasl-dev \ perl-dev \ python3-dev \ swig \ && cd /znc-src \ && mkdir build && cd build \ && cmake .. ${CMAKEFLAGS} \ && make $MAKEFLAGS \ && make install \ && apk del build-dependencies \ && cd / && rm -rf /znc-src COPY docker/slim/entrypoint.sh / COPY docker/*/??-*.sh /startup-sequence/ VOLUME /znc-data ENTRYPOINT ["/entrypoint.sh"] znc-1.7.5/man/0000755000175000017500000000000013542151610013313 5ustar somebodysomebodyznc-1.7.5/man/znc-buildmod.10000644000175000017500000000100713542151610015762 0ustar somebodysomebody.TH ZNC\-BUILDMOD 1 2013\-06\-12 ZNC .SH NAME znc\-buildmod \- compile ZNC modules .SH SYNOPSIS .B znc\-buildmod FILE... .SH DESCRIPTION .BR znc\-buildmod compiles a ZNC module for you. You just give it a list of source files and every single file is compiled into a module. .SH EXIT STATUS Normally, exit status is 0 if everything went fine. In case the compiler errors when compiling some module, the exit status is 1. .SH ENVIRONMENT Variables .SS CXXFLAGS .SS LDFLAGS .SS MODLINK .SS INCLUDES .SS LIBS may be used. znc-1.7.5/man/Makefile.in0000644000175000017500000000136213542151610015362 0ustar somebodysomebodySHELL := @SHELL@ # Support out-of-tree builds VPATH := @srcdir@ prefix := @prefix@ exec_prefix := @exec_prefix@ datarootdir := @datarootdir@ mandir := @mandir@ INSTALL := @INSTALL@ INSTALL_DATA := @INSTALL_DATA@ MAN1 := znc.1.gz znc-buildmod.1.gz ifneq "$(V)" "" VERBOSE=1 endif ifeq "$(VERBOSE)" "" Q=@ E=@echo else Q= E=@\# endif all: $(MAN1) %.1.gz: %.1 Makefile $(E) Packing man page $@... $(Q)gzip -9 <$< >$@ clean: -rm -f $(MAN1) install: $(MAN1) test -d $(DESTDIR)$(mandir)/man1 || $(INSTALL) -d $(DESTDIR)$(mandir)/man1 $(INSTALL_DATA) $(MAN1) $(DESTDIR)$(mandir)/man1 uninstall: for file in $(MAN1) ; do \ rm $(DESTDIR)$(mandir)/man1/$$file || exit 1 ; \ done rmdir $(DESTDIR)$(mandir)/man1 znc-1.7.5/man/znc.10000644000175000017500000000617113542151610014174 0ustar somebodysomebody.TH ZNC 1 2010\-05\-10 ZNC .SH NAME znc \- An advanced IRC bouncer .SH SYNOPSIS .B znc \-\-help .br .B znc \-\-version .br .B znc \-\-makepass .br .B znc .RB [ \-n ] .RB [ \-d .IR datadir ] .RB [ \-D ] .RB [ \-f ] .br .B znc .RB [ \-n ] .RB [ \-d .IR datadir ] .RB [ \-D ] .RB [ \-f ] .B \-\-makeconf .br .B znc .RB [ \-n ] .RB [ \-d .IR datadir ] .RB [ \-D ] .RB [ \-f ] .B \-\-makepem .SH DESCRIPTION .B znc is an IRC proxy. It runs as a daemon and connects to IRC server, then allows you to connect from a workstation and work as the user that is logged in to the IRC server. After you disconnect, it maintains the connection to the server. It acts like any normal IRC server, so you can use any IRC client to connect to it. .SH OPTIONS .TP .BR \-h ", " \-\-help Output a brief help message. .TP .BR \-v ", " \-\-version Show the full version number. .TP .BR \-n ", " \-\-no-color Don't use any color escape sequences. .TP .BR \-f ", " \-\-foreground Don't fork the ZNC process into the background. .TP .BR \-D ", " \-\-debug Print debug output to the console. Implies .BR --foreground . .TP .BI \-d " DATADIR" "\fR,\fP \-\-datadir=" DATADIR Specify another datadir. This is where .B znc saves everything. .TP .BR \-c ", " \-\-makeconf Interactively create a new configuration. .TP .BR \-s ", " \-\-makepass Hash a password for use in .IR znc.conf . .TP .BR \-p ", " \-\-makepem Generate .IR znc.pem . This is the server certificate .B znc uses. You need this for SSL. .TP .BR \-r ", " \-\-allow-root Don't complain if ZNC is run with root privileges. .SH SIGNALS This section explains how .B znc reacts to different signals: .TP .B SIGINT Exit ZNC. This is equivalent to .I /znc shutdown .TP .B SIGHUP Reload znc.conf. This is equivalent to .I /znc rehash. .B DO NOT do this very often, things can break badly! .TP .B SIGUSR1 Rewrite znc.conf. This is equivalent to .I /znc saveconfig .SH FILES .TP .I /usr/local/share/znc/ Static module data like webadmin skins .TP .I /usr/local/lib/znc/ .B znc installs its modules to this directory. .TP .I /usr/local/include/znc/ These are the headers needed for compiling own modules. .TP .I ~/.znc This is the default datadir. The following paths assume that you use this. If you change this via .I \-\-datadir then the following lines are relative to that dir. .TP .I ~/.znc/znc.pem This is the server certificate .B znc uses for listening on SSL ports. You can generate this via .I --makepem and you may replace this with your own certificate, if you want to. .TP .I ~/.znc/modules/ If you compile your own modules, you can save them here. .TP .I ~/.znc/configs/znc.conf This is the path to .IR znc.conf . Use .I \-\-makeconf for an easy way to generate it. .TP .IB ~/.znc/users/ USERNAME / The data for every user is saved in this dir. .B USERNAME refers to the user name of that user. .TP .IB ~/.znc/users/ USERNAME /moddata/ MODULENAME / This is where each module can save some stuff. This is mainly used for remembering module settings that are not part of .IR znc.conf . .TP .IB ~/.znc/moddata/ MODULENAME / This is where global modules may save their settings. .SH SEE ALSO .BR znc-buildmod (1) .PP Full documentation at: .I https://znc.in/ znc-1.7.5/autogen.sh0000755000175000017500000000243713542151610014547 0ustar somebodysomebody#!/bin/sh # Run this to generate all the initial makefiles, etc. # This is based on various examples which can be found everywhere. set -e FLAGS=${FLAGS--Wall} ACLOCAL=${ACLOCAL-aclocal} AUTOHEADER=${AUTOHEADER-autoheader} AUTOCONF=${AUTOCONF-autoconf} AUTOMAKE=${AUTOMAKE-automake} ACLOCAL_FLAGS="${ACLOCAL_FLAGS--I m4} ${FLAGS}" AUTOHEADER_FLAGS="${AUTOHEADER_FLAGS} ${FLAGS}" AUTOCONF_FLAGS="${AUTOCONF_FLAGS} ${FLAGS}" AUTOMAKE_FLAGS="${AUTOMAKE_FLAGS---add-missing} ${FLAGS}" die() { echo "$@" exit 1 } do_cmd() { echo "Running '$@'" $@ } test -f configure.ac || die "No configure.ac found." which pkg-config > /dev/null || die "ERROR: pkg-config not found. Install pkg-config and run $0 again" # Generate aclocal.m4 for use by autoconf do_cmd $ACLOCAL $ACLOCAL_FLAGS # Generate zncconfig.h.in for configure do_cmd $AUTOHEADER $AUTOHEADER_FLAGS # Generate configure do_cmd $AUTOCONF $AUTOCONF_FLAGS # Copy config.sub, config.guess, install.sh, ... # This will complain that we don't use automake, let's just ignore that do_cmd $AUTOMAKE $AUTOMAKE_FLAGS || true test -f config.guess -a -f config.sub -a -f install-sh || die "Automake didn't install config.guess, config.sub and install-sh!" echo "(Yes, automake is supposed to fail, ignore that)" echo echo "You may now run ./configure." znc-1.7.5/zz_msg/0000755000175000017500000000000013542151610014051 5ustar somebodysomebodyznc-1.7.5/zz_msg/CMakeLists.txt0000644000175000017500000000204113542151610016606 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This is implementation detail of CMake, but this install() runs last. # Details are at https://cmake.org/pipermail/cmake/2011-July/045615.html install(CODE "message(\" ****************************************************************** ZNC was successfully installed. You can use '${CMAKE_INSTALL_FULL_BINDIR}/znc --makeconf' to generate a config file. If you need help with using ZNC, please visit our wiki at: http://znc.in\")") znc-1.7.5/znc-buildmod.cmake.in0000755000175000017500000000716613542151610016553 0ustar somebodysomebody#!/bin/sh # # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # http://stackoverflow.com/questions/18993438/shebang-env-preferred-python-version # http://stackoverflow.com/questions/12070516/conditional-shebang-line-for-different-versions-of-python """:" which python3 >/dev/null 2>&1 && exec python3 "$0" "$@" which python >/dev/null 2>&1 && exec python "$0" "$@" which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" echo "Error: znc-buildmod requires python" exec echo "Either install python, or use cmake directly" ":""" from __future__ import print_function import argparse import glob import os import shutil import subprocess import sys import tempfile if sys.version_info < (3, 0): class TemporaryDirectory(object): def __enter__(self): self.name = tempfile.mkdtemp() return self.name def __exit__(self, *a, **k): shutil.rmtree(self.name) tempfile.TemporaryDirectory = TemporaryDirectory parser = argparse.ArgumentParser( description='Build external ZNC modules and place the results to ' 'current directory. Several modules can be built at once.', epilog='Adjustable environment variables: CXXFLAGS, LDFLAGS, LIBS') parser.add_argument('-v', '--verbose', action='count', default=0, help='use -vvv for more verbosity') parser.add_argument('files', nargs='+', metavar='file.cpp', help="path to the module's source file") args = parser.parse_args() with tempfile.TemporaryDirectory() as cmdir: with open(os.path.join(cmdir, 'CMakeLists.txt'), 'w') as cm: print('cmake_minimum_required(VERSION 3.1)', file=cm) print('project(ExternalModules)', file=cm) print('find_package(ZNC @ZNC_VERSION_MAJOR@.@ZNC_VERSION_MINOR@ HINTS ' '@CMAKE_INSTALL_FULL_DATADIR@/znc REQUIRED)', file=cm) if args.verbose > 0: print('set(CMAKE_VERBOSE_MAKEFILE true)', file=cm) for mod_cpp in args.files: mod, _ = os.path.splitext(os.path.basename(mod_cpp)) print(file=cm) print('add_library(module_{} MODULE {})'.format( mod, os.path.abspath(mod_cpp)), file=cm) print('znc_setup_module(TARGET module_{} NAME {})'.format(mod, mod), file=cm) print('target_link_libraries(module_{} PRIVATE {})'.format( mod, os.environ.get('LIBS', '')), file=cm) if args.verbose > 0: with open(os.path.join(cmdir, 'CMakeLists.txt')) as cm: print(cm.read()) with tempfile.TemporaryDirectory() as build: command = ['cmake', cmdir] if args.verbose > 1: cmd.append('--debug-output') if args.verbose > 2: cmd.append('--trace') if args.verbose > 0: print(command) subprocess.check_call(command, cwd=build) subprocess.check_call(['cmake', '--build', '.'], cwd=build) for so in glob.iglob(os.path.join(build, '*.so')): try: os.remove(os.path.basename(so)) except OSError: pass shutil.copy(so, os.getcwd()) znc-1.7.5/translation_pot.py0000755000175000017500000000671013542151610016341 0ustar somebodysomebody#!/usr/bin/env python3 # # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import argparse import glob import os import re import subprocess parser = argparse.ArgumentParser() parser.add_argument('--include_dir', action='store') parser.add_argument('--explicit_sources', action='append') parser.add_argument('--tmpl_dirs', action='append') parser.add_argument('--strip_prefix', action='store') parser.add_argument('--tmp_prefix', action='store') parser.add_argument('--output', action='store') args = parser.parse_args() pot_list = [] # .tmpl tmpl_pot = args.tmp_prefix + '_tmpl.pot' tmpl_uniq_pot = args.tmp_prefix + '_tmpl_uniq.pot' tmpl = [] pattern = re.compile(r'<\?\s*(?:FORMAT|(PLURAL))\s+(?:CTX="([^"]+?)"\s+)?"([^"]+?)"(?(1)\s+"([^"]+?)"|).*?(?:"TRANSLATORS:\s*([^"]+?)")?\s*\?>') for tmpl_dir in args.tmpl_dirs: for fname in glob.iglob(tmpl_dir + '/*.tmpl'): fbase = fname[len(args.strip_prefix):] with open(fname, 'rt', encoding='utf8') as f: for linenum, line in enumerate(f): for x in pattern.finditer(line): text, plural, context, comment = x.group(3), x.group(4), x.group(2), x.group(5) if comment: tmpl.append('# {}'.format(comment)) tmpl.append('#: {}:{}'.format(fbase, linenum + 1)) if context: tmpl.append('msgctxt "{}"'.format(context)) tmpl.append('msgid "{}"'.format(text)) if plural: tmpl.append('msgid_plural "{}"'.format(plural)) tmpl.append('msgstr[0] ""') tmpl.append('msgstr[1] ""') else: tmpl.append('msgstr ""') tmpl.append('') # Bundle header to .tmpl, even if there were no .tmpl files. # Some .tmpl files contain non-ASCII characters, and the header is needed # anyway, because it's omitted from xgettext call below. with open(tmpl_pot, 'wt', encoding='utf8') as f: print('msgid ""', file=f) print('msgstr ""', file=f) print(r'"Content-Type: text/plain; charset=UTF-8\n"', file=f) print(r'"Content-Transfer-Encoding: 8bit\n"', file=f) print(file=f) for line in tmpl: print(line, file=f) subprocess.check_call(['msguniq', '--force-po', '-o', tmpl_uniq_pot, tmpl_pot]) pot_list.append(tmpl_uniq_pot) # .cpp main_pot = args.tmp_prefix + '_main.pot' subprocess.check_call(['xgettext', '--omit-header', '-D', args.include_dir, '-o', main_pot, '--keyword=t_s:1,1t', '--keyword=t_s:1,2c,2t', '--keyword=t_f:1,1t', '--keyword=t_f:1,2c,2t', '--keyword=t_p:1,2,3t', '--keyword=t_p:1,2,4c,4t', '--keyword=t_d:1,1t', '--keyword=t_d:1,2c,2t', ] + args.explicit_sources) if os.path.isfile(main_pot): pot_list.append(main_pot) # combine if pot_list: subprocess.check_call(['msgcat', '-o', args.output] + pot_list) znc-1.7.5/.codecov.yml0000644000175000017500000000102113542151610014755 0ustar somebodysomebodyignore: - /cmake/ - /test/ - /modules/modp*/*.cpp - /modules/modp*/swig* - /modules/modpython/znc_core.py - /modules/modperl/ZNC.pm fixes: - "usr/local/lib/znc/::modules/" # C++ and Python seem to work without this, but Perl needs this. codecov: ci: # Cygwin fails integration test with --coverage enabled, I don't know why - !appveyor # FreeBSD doesn't support C++ coverage yet (can't find libprofile_rt.a) - !jenkins.znc.in coverage: status: project: default: threshold: 1% znc-1.7.5/ZNCConfig.cmake.in0000644000175000017500000000300413542151610015724 0ustar somebodysomebody# # Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include("${CMAKE_CURRENT_LIST_DIR}/znc_internal.cmake") include("${CMAKE_CURRENT_LIST_DIR}/znc_public.cmake") include(CMakeParseArguments) # For some reason cygwin fails to build modules if Threads::Threads # is not found. if(NOT CYGWIN) set(ZNC_NO_INCLUDE_THREADS true) endif() if(NOT ZNC_NO_INCLUDE_THREADS) set(CMAKE_THREAD_PREFER_PTHREAD true) set(THREADS_PREFER_PTHREAD_FLAG true) find_package(Threads REQUIRED) if(NOT CMAKE_USE_PTHREADS_INIT) message(FATAL_ERROR "This compiler/OS doesn't seem " "to support pthreads.") endif() endif() function(znc_setup_module) cmake_parse_arguments(znc_mod "" "TARGET;NAME" "" ${ARGN}) set_target_properties("${znc_mod_TARGET}" PROPERTIES OUTPUT_NAME "${znc_mod_NAME}" PREFIX "" SUFFIX ".so" NO_SONAME true CXX_VISIBILITY_PRESET "hidden") target_link_libraries("${znc_mod_TARGET}" PRIVATE ZNC::ZNC) endfunction() message(STATUS "Found ZNC @ZNC_VERSION@") znc-1.7.5/config.guess0000755000175000017500000012640313542151642015073 0ustar somebodysomebody#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2017 Free Software Foundation, Inc. timestamp='2017-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || \ echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "${UNAME_MACHINE_ARCH}" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; *:Sortix:*:*) echo ${UNAME_MACHINE}-unknown-sortix exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; e2k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; k1om:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; mips64el:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) eval $set_cc_for_build X86_64_ABI= # If there is a compiler, see if it is configured for 32-bit objects. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_X32 >/dev/null then X86_64_ABI=x32 fi fi echo ${UNAME_MACHINE}-pc-linux-${LIBC}${X86_64_ABI} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; SX-ACE:SUPER-UX:*:*) echo sxace-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; esac cat >&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: znc-1.7.5/LICENSE0000644000175000017500000002613613542151610013555 0ustar somebodysomebody Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. znc-1.7.5/modules/0000755000175000017500000000000013542151610014210 5ustar somebodysomebodyznc-1.7.5/modules/data/0000755000175000017500000000000013542151610015121 5ustar somebodysomebodyznc-1.7.5/modules/data/listsockets/0000755000175000017500000000000013542151610017470 5ustar somebodysomebodyznc-1.7.5/modules/data/listsockets/tmpl/0000755000175000017500000000000013542151610020444 5ustar somebodysomebodyznc-1.7.5/modules/data/listsockets/tmpl/index.tmpl0000644000175000017500000000137013542151610022452 0ustar somebodysomebody
znc-1.7.5/modules/data/send_raw/0000755000175000017500000000000013542151610016723 5ustar somebodysomebodyznc-1.7.5/modules/data/send_raw/tmpl/0000755000175000017500000000000013542151610017677 5ustar somebodysomebodyznc-1.7.5/modules/data/send_raw/tmpl/index.tmpl0000644000175000017500000000341613542151610021710 0ustar somebodysomebody

"/>
znc-1.7.5/modules/data/send_raw/files/0000755000175000017500000000000013542151610020025 5ustar somebodysomebodyznc-1.7.5/modules/data/send_raw/files/select.js0000644000175000017500000000060213542151610021640 0ustar somebodysomebodyfunction updateUser() { var select = document.getElementById('selectnetwork'); var opt = select.options[select.selectedIndex]; document.getElementById('user').value = opt.parentNode.getAttribute('label'); } function init() { updateUser(); document.getElementById('networklabel').firstChild.nodeValue = 'Network:'; document.getElementById('userblock').removeAttribute('style'); } znc-1.7.5/modules/data/blockuser/0000755000175000017500000000000013542151610017112 5ustar somebodysomebodyznc-1.7.5/modules/data/blockuser/tmpl/0000755000175000017500000000000013542151610020066 5ustar somebodysomebodyznc-1.7.5/modules/data/blockuser/tmpl/blockuser_WebadminUser.tmpl0000644000175000017500000000115313542151610025422 0ustar somebodysomebody
checked="checked" disabled="disabled" />
znc-1.7.5/modules/data/sasl/0000755000175000017500000000000013542151610016063 5ustar somebodysomebodyznc-1.7.5/modules/data/sasl/tmpl/0000755000175000017500000000000013542151610017037 5ustar somebodysomebodyznc-1.7.5/modules/data/sasl/tmpl/index.tmpl0000644000175000017500000000476613542151610021061 0ustar somebodysomebody

" />
" autocomplete="off" />

"> checked="checked" />

" />
znc-1.7.5/modules/data/samplewebapi/0000755000175000017500000000000013542151610017572 5ustar somebodysomebodyznc-1.7.5/modules/data/samplewebapi/tmpl/0000755000175000017500000000000013542151610020546 5ustar somebodysomebodyznc-1.7.5/modules/data/samplewebapi/tmpl/index.tmpl0000644000175000017500000000116313542151610022554 0ustar somebodysomebody

Sample Web API

Text:

Sample text that will be returned plain on submit/API request.
znc-1.7.5/modules/data/perform/0000755000175000017500000000000013542151610016573 5ustar somebodysomebodyznc-1.7.5/modules/data/perform/tmpl/0000755000175000017500000000000013542151610017547 5ustar somebodysomebodyznc-1.7.5/modules/data/perform/tmpl/index.tmpl0000644000175000017500000000142713542151610021560 0ustar somebodysomebody


" />
znc-1.7.5/modules/data/stickychan/0000755000175000017500000000000013542151610017261 5ustar somebodysomebodyznc-1.7.5/modules/data/stickychan/tmpl/0000755000175000017500000000000013542151610020235 5ustar somebodysomebodyznc-1.7.5/modules/data/stickychan/tmpl/index.tmpl0000644000175000017500000000136413542151610022246 0ustar somebodysomebody
checked="checked" />
" />
znc-1.7.5/modules/data/stickychan/tmpl/stickychan_WebadminChan.tmpl0000644000175000017500000000103113542151610025666 0ustar somebodysomebody
checked="checked" />
znc-1.7.5/modules/data/cert/0000755000175000017500000000000013542151610016056 5ustar somebodysomebodyznc-1.7.5/modules/data/cert/tmpl/0000755000175000017500000000000013542151610017032 5ustar somebodysomebodyznc-1.7.5/modules/data/cert/tmpl/index.tmpl0000644000175000017500000000217113542151610021040 0ustar somebodysomebody

" />
znc-1.7.5/modules/data/lastseen/0000755000175000017500000000000013542151610016737 5ustar somebodysomebodyznc-1.7.5/modules/data/lastseen/tmpl/0000755000175000017500000000000013542151610017713 5ustar somebodysomebodyznc-1.7.5/modules/data/lastseen/tmpl/index.tmpl0000644000175000017500000000167713542151610021733 0ustar somebodysomebody
[] []
znc-1.7.5/modules/data/lastseen/tmpl/lastseen_WebadminUser.tmpl0000644000175000017500000000041013542151610025067 0ustar somebodysomebody
znc-1.7.5/modules/data/certauth/0000755000175000017500000000000013542151610016740 5ustar somebodysomebodyznc-1.7.5/modules/data/certauth/tmpl/0000755000175000017500000000000013542151610017714 5ustar somebodysomebodyznc-1.7.5/modules/data/certauth/tmpl/index.tmpl0000644000175000017500000000203313542151610021717 0ustar somebodysomebody

" />

[]
znc-1.7.5/modules/data/notes/0000755000175000017500000000000013542151610016251 5ustar somebodysomebodyznc-1.7.5/modules/data/notes/tmpl/0000755000175000017500000000000013542151610017225 5ustar somebodysomebodyznc-1.7.5/modules/data/notes/tmpl/index.tmpl0000644000175000017500000000256513542151610021242 0ustar somebodysomebody

" />

<? FORMAT " />
znc-1.7.5/modules/data/notes/files/0000755000175000017500000000000013542151610017353 5ustar somebodysomebodyznc-1.7.5/modules/data/notes/files/trash.gif0000644000175000017500000000014213542151610021160 0ustar somebodysomebodyGIF89a€fff!ù,@9Œ©Ðï"C²¾i€vyã …ÜG–f²¥êÈXÖç†äêömÖ%»ðŠ¢D2LL#"Ê ³…‹ž ;znc-1.7.5/modules/data/q/0000755000175000017500000000000013542151610015361 5ustar somebodysomebodyznc-1.7.5/modules/data/q/tmpl/0000755000175000017500000000000013542151610016335 5ustar somebodysomebodyznc-1.7.5/modules/data/q/tmpl/index.tmpl0000644000175000017500000000275613542151610020354 0ustar somebodysomebody

Q

" />
" autocomplete="off" />

checked="checked" disabled="disabled" />
" />
znc-1.7.5/modules/data/webadmin/0000755000175000017500000000000013542151610016707 5ustar somebodysomebodyznc-1.7.5/modules/data/webadmin/tmpl/0000755000175000017500000000000013542151610017663 5ustar somebodysomebodyznc-1.7.5/modules/data/webadmin/tmpl/listusers.tmpl0000644000175000017500000000313713542151610022622 0ustar somebodysomebody
There are no users defined. Click here if you would like to add one.
[]
[] [] []
znc-1.7.5/modules/data/webadmin/tmpl/index.tmpl0000644000175000017500000000040213542151610021664 0ustar somebodysomebody


znc-1.7.5/modules/data/webadmin/tmpl/traffic.tmpl0000644000175000017500000000641313542151610022203 0ustar somebodysomebody

ZNC

znc-1.7.5/modules/data/webadmin/tmpl/add_edit_chan.tmpl0000644000175000017500000000617013542151610023313 0ustar somebodysomebody

"/>
"/>
"/>
"/>

checked="checked" /> checked="checked" disabled="disabled" />

"/> "/> "/> "/>
znc-1.7.5/modules/data/webadmin/tmpl/del_network.tmpl0000644000175000017500000000162613542151610023103 0ustar somebodysomebody

"/>
"/>
znc-1.7.5/modules/data/webadmin/tmpl/del_user.tmpl0000644000175000017500000000152613542151610022367 0ustar somebodysomebody

"/>
"/>
znc-1.7.5/modules/data/webadmin/tmpl/settings.tmpl0000644000175000017500000002366313542151610022433 0ustar somebodysomebody

checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
checked="checked"/>
"/>
" value=""/>
"/>

"/>
"/>
"/>
"/>
"/>
checked="checked" />
checked="checked" />
checked="checked" />

checked="checked" disabled="disabled" /> disabled="disabled" title="" /> checked="checked" disabled="disabled"/> checked="checked" disabled="disabled"/>
"/>
znc-1.7.5/modules/data/webadmin/tmpl/add_edit_user.tmpl0000644000175000017500000004664013542151610023366 0ustar somebodysomebody

"/>
" autocomplete="off" />
"/>
" checked="checked" disabled="disabled" />

Otherwise, one entry per line, wildcards * and ? are available." ?>

"/>
"/>
"/>
"/>
"/>
"/>

[]
[] []


checked="checked" disabled="disabled" /> disabled="disabled" title="" /> checked="checked" disabled="disabled"/> checked="checked" disabled="disabled"/>

"/>
"/>

"/>
"/>

checked="checked" disabled="disabled" />

"/>

Europe/Berlin
, or GMT-6" ?>
">
"/>
"/>
"/>
" disabled="disabled" />

TIME Buy a watch!
" ?>
1 ?>
ZNC is compiled without i18n support

"/> "/> "/> "/> "/> "/> "/> "/> "/>
znc-1.7.5/modules/data/webadmin/tmpl/add_edit_network.tmpl0000644000175000017500000003244613542151610024100 0ustar somebodysomebody
/: / /: /

{1} or username field as {2}" "ClientConnectHint_Password ESC=" "ClientConnectHint_Username ESC=" ?>

"/>
"/>
"/>
"/>
"/>
"/>
checked="checked" />
checked="checked" />
checked="checked" />


" onchange="floodprotection_change();" checked="checked" />
" value="" value="2.00" disabled="disabled" />
" value="" value="9" disabled="disabled" />
" value="" />
">


[]
[] [] checked="checked" />

checked="checked" disabled="disabled" /> disabled="disabled" title="" /> checked="checked" disabled="disabled"/> checked="checked" disabled="disabled"/>

"/> "/> "/> "/>
znc-1.7.5/modules/data/webadmin/tmpl/encoding_settings.tmpl0000644000175000017500000000633313542151610024274 0ustar somebodysomebody
ICU
    
checked="checked" disabled="disabled" />
checked="checked" disabled="disabled" />
checked="checked" disabled="disabled" />
checked="checked" disabled="disabled" />
disabled="disabled" />
UTF-8, or ISO-8859-15" ?>
znc-1.7.5/modules/data/webadmin/files/0000755000175000017500000000000013542151610020011 5ustar somebodysomebodyznc-1.7.5/modules/data/webadmin/files/webadmin.css0000644000175000017500000000045513542151610022315 0ustar somebodysomebody.encoding-placeholder-big { text-decoration:underline; font-style:italic; } .encoding-settings { width: 500px; } table .sorted::after { content:" â–¾"; } table .reverse-sorted::after { content:" â–´"; } .ctcpreplies_row_request { width: 100px; } .ctcpreplies_row_response { width: 400px; } znc-1.7.5/modules/data/webadmin/files/webadmin.js0000644000175000017500000001471213542151610022142 0ustar somebodysomebodyfunction floodprotection_change() { var protection = document.getElementById('floodprotection_checkbox'); var rate = document.getElementById('floodrate'); var burst = document.getElementById('floodburst'); if (protection.checked) { rate.removeAttribute('disabled'); burst.removeAttribute('disabled'); } else { rate.disabled = 'disabled'; burst.disabled = 'disabled'; } } function make_sortable_table(table) { if (table.rows.length >= 1) { // Ensure that the table at least contains a row for the headings var headings = table.rows[0].getElementsByTagName("th"); for (var i = 0; i < headings.length; i++) { // This function acts to scope the i variable, so we can pass it off // as the column_index, otherwise column_index would just be the max // value of i, every single time. (function (i) { var heading = headings[i]; if (!heading.classList.contains("ignore-sort")) { heading.addEventListener("click", function () { // Bind a click event to the heading sort_table(this, i, table, headings); }); } })(i); } } } function sort_table(clicked_column, column_index, table, headings) { for (var i = 0; i < headings.length; i++) { if (headings[i] != clicked_column) { headings[i].classList.remove("sorted"); headings[i].classList.remove("reverse-sorted"); } } var reverse = false; clicked_column.classList.toggle("reverse"); if (clicked_column.classList.contains("sorted")) { reverse = true; clicked_column.classList.remove("sorted"); clicked_column.classList.add("reverse-sorted"); } else { clicked_column.classList.remove("reverse-sorted"); clicked_column.classList.add("sorted"); } // This array will contain tuples in the form [(value, row)] where value // is extracted from the column to be sorted by var rows_and_sortable_value = []; for (var i = 1, row; row = table.rows[i]; i++) { for (var j = 0, col; col = row.cells[j]; j++) { // If we're at the column index we want to sort by if (j === column_index) { var cell = row.getElementsByTagName("td")[j]; var value = cell.innerHTML; rows_and_sortable_value.push([value, row]); } } } rows_and_sortable_value.sort(function (a, b) { // If both values are integers, sort by that else as strings if (isInt(a[0]) && isInt(b[0])) { return a[0] - b[0]; } else { return b[0].localeCompare(a[0]); } }); if (reverse) { rows_and_sortable_value.reverse(); } var parent = table.rows[1].parentNode; for (var i = 0; i < rows_and_sortable_value.length; i++) { // Remove the existing entry for the row from the table parent.removeChild(rows_and_sortable_value[i][1]); // Insert at the first position, before the first child parent.insertBefore(rows_and_sortable_value[i][1], parent.firstChild); } } function isInt(value) { return !isNaN(value) && (function (x) { return (x | 0) === x; })(parseFloat(value)) } function make_sortable() { var tables = document.querySelectorAll("table.sortable"); for (var i = 0; i < tables.length; i++) { make_sortable_table(tables[i]); } } function serverlist_init($) { function serialize() { var text = ""; $("#servers_tbody > tr").each(function() { var host = $(".servers_row_host", $(this)).val(); var port = $(".servers_row_port", $(this)).val(); var ssl = $(".servers_row_ssl", $(this)).is(":checked"); var pass = $(".servers_row_pass", $(this)).val(); if (host.length == 0) return; text += host; text += " "; if (ssl) text += "+"; text += port; text += " "; text += pass; text += "\n"; }); $("#servers_text").val(text); } function add_row(host, port, ssl, pass) { var row = $(""); function delete_row() { row.remove(); serialize(); } row.append( $("").append($("").attr({"type":"text"}) .addClass("servers_row_host").val(host)), $("").append($("").attr({"type":"number"}) .addClass("servers_row_port").val(port)), $("").append($("").attr({"type":"checkbox"}) .addClass("servers_row_ssl").prop("checked", ssl)), $("").append($("").attr({"type":"text"}) .addClass("servers_row_pass").val(pass)), $("").append($("").attr({"type":"button"}) .val("X").click(delete_row)) ); $("input", row).change(serialize); $("#servers_tbody").append(row); } (function() { var servers_text = $("#servers_text").val(); // Parse it $.each(servers_text.split("\n"), function(i, line) { if (line.length == 0) return; line = line.split(" "); var host = line[0]; var port = line[1] || "6667"; var pass = line[2] || ""; var ssl; if (port.match(/^\+/)) { ssl = true; port = port.substr(1); } else { ssl = false; } add_row(host, port, ssl, pass); }); $("#servers_add").click(function() { add_row("", 6697, true, ""); // Not serializing, because empty host doesn't emit anything anyway }); $("#servers_plain").hide(); $("#servers_js").show(); })(); } function ctcpreplies_init($) { function serialize() { var text = ""; $("#ctcpreplies_tbody > tr").each(function() { var request = $(".ctcpreplies_row_request", $(this)).val(); var response = $(".ctcpreplies_row_response", $(this)).val(); if (request.length == 0) return; text += request; text += " "; text += response; text += "\n"; }); $("#ctcpreplies_text").val(text); } function add_row(request, response) { var row = $(""); function delete_row() { row.remove(); serialize(); } row.append( $("").append($("").val(request) .addClass("ctcpreplies_row_request") .attr({"type":"text","list":"ctcpreplies_list"})), $("").append($("").val(response) .addClass("ctcpreplies_row_response") .attr({"type":"text","placeholder":$("#ctcpreplies_js").data("placeholder")})), $("").append($("").val("X") .attr({"type":"button"}).click(delete_row)) ); $("input", row).change(serialize); $("#ctcpreplies_tbody").append(row); } (function() { var replies_text = $("#ctcpreplies_text").val(); $.each(replies_text.split("\n"), function(i, line) { if (line.length == 0) return; var space = line.indexOf(" "); var request; var response; if (space == -1) { request = line; response = ""; } else { request = line.substr(0, space); response = line.substr(space + 1); } add_row(request, response); }); $("#ctcpreplies_add").click(function() { add_row("", ""); }); $("#ctcpreplies_plain").hide(); $("#ctcpreplies_js").show(); })(); } znc-1.7.5/modules/alias.cpp0000644000175000017500000003477613542151610016026 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include using std::vector; using std::stringstream; class CAlias { private: CModule* parent; CString name; VCString alias_cmds; public: // getters/setters const CString& GetName() const { return name; } // name should be a single, all uppercase word void SetName(const CString& newname) { name = newname.Token(0, false, " "); name.MakeUpper(); } // combined getter/setter for command list VCString& AliasCmds() { return alias_cmds; } // check registry if alias exists static bool AliasExists(CModule* module, CString alias_name) { alias_name = alias_name.Token(0, false, " ").MakeUpper(); return (module->FindNV(alias_name) != module->EndNV()); } // populate alias from stored settings in registry, or return false if none // exists static bool AliasGet(CAlias& alias, CModule* module, CString line) { line = line.Token(0, false, " ").MakeUpper(); MCString::iterator i = module->FindNV(line); if (i == module->EndNV()) return false; alias.parent = module; alias.name = line; i->second.Split("\n", alias.alias_cmds, false); return true; } // constructors CAlias() : parent(nullptr) {} CAlias(CModule* new_parent, const CString& new_name) : parent(new_parent) { SetName(new_name); } // produce a command string from this alias' command list CString GetCommands() const { return CString("\n").Join(alias_cmds.begin(), alias_cmds.end()); } // write this alias to registry void Commit() const { if (!parent) return; parent->SetNV(name, GetCommands()); } // delete this alias from regisrty void Delete() const { if (!parent) return; parent->DelNV(name); } private: // this function helps imprint out. it checks if there is a substitution // token at 'caret' in 'alias_data' // and if it finds one, pulls the appropriate token out of 'line' and // appends it to 'output', and updates 'caret'. // 'skip' is updated based on the logic that we should skip the % at the // caret if we fail to parse the token. void ParseToken(const CString& alias_data, const CString& line, CString& output, size_t& caret, size_t& skip) const { bool optional = false; bool subsequent = false; size_t index = caret + 1; int token = -1; skip = 1; // try to read optional flag if (alias_data.length() > index && alias_data[index] == '?') { optional = true; ++index; } // try to read integer if (alias_data.length() > index && CString(alias_data.substr(index)).Convert(&token)) { // skip any numeric digits in string (supposed to fail if // whitespace precedes integer) while (alias_data.length() > index && alias_data[index] >= '0' && alias_data[index] <= '9') ++index; } else { // token was malformed. leave caret unchanged, and flag first // character for skipping return; } // try to read subsequent flag if (alias_data.length() > index && alias_data[index] == '+') { subsequent = true; ++index; } // try to read end-of-substitution marker if (alias_data.length() > index && alias_data[index] == '%') { ++index; } else return; // if we get here, we're definitely dealing with a token, so get the // token's value CString stok = line.Token(token, subsequent, " "); if (stok.empty() && !optional) // blow up if token is required and also empty throw std::invalid_argument( parent->t_f("missing required parameter: {1}")(CString(token))); // write token value to output output.append(stok); // since we're moving the cursor after the end of the token, skip no // characters skip = 0; // advance the cursor forward by the size of the token caret = index; } public: // read an IRC line and do token substitution // throws an exception if a required parameter is missing, and might also // throw if you manage to make it bork CString Imprint(CString line) const { CString output; CString alias_data = GetCommands(); alias_data = parent->ExpandString(alias_data); size_t lastfound = 0, skip = 0; // it would be very inefficient to attempt to blindly replace every // possible token // so let's just parse the line and replace when we find them // token syntax: // %[?]n[+]% // adding ? makes the substitution optional (you'll get "" if there are // insufficient tokens, otherwise the alias will fail) // adding + makes the substitution contain all tokens from the nth to // the end of the line while (true) { // if (found >= (int) alias_data.length()) break; // ^ shouldn't be possible. size_t found = alias_data.find("%", lastfound + skip); // if we found nothing, break if (found == CString::npos) break; // capture everything between the last stopping point and here output.append(alias_data.substr(lastfound, found - lastfound)); // attempt to read a token, updates indices based on // success/failure ParseToken(alias_data, line, output, found, skip); lastfound = found; } // append from the final output += alias_data.substr(lastfound); return output; } }; class CAliasMod : public CModule { private: bool sending_lines; public: void CreateCommand(const CString& sLine) { CString name = sLine.Token(1, false, " "); if (!CAlias::AliasExists(this, name)) { CAlias na(this, name); na.Commit(); PutModule(t_f("Created alias: {1}")(na.GetName())); } else PutModule(t_s("Alias already exists.")); } void DeleteCommand(const CString& sLine) { CString name = sLine.Token(1, false, " "); CAlias delete_alias; if (CAlias::AliasGet(delete_alias, this, name)) { PutModule(t_f("Deleted alias: {1}")(delete_alias.GetName())); delete_alias.Delete(); } else PutModule(t_s("Alias does not exist.")); } void AddCmd(const CString& sLine) { CString name = sLine.Token(1, false, " "); CAlias add_alias; if (CAlias::AliasGet(add_alias, this, name)) { add_alias.AliasCmds().push_back(sLine.Token(2, true, " ")); add_alias.Commit(); PutModule(t_s("Modified alias.")); } else PutModule(t_s("Alias does not exist.")); } void InsertCommand(const CString& sLine) { CString name = sLine.Token(1, false, " "); CAlias insert_alias; int index; if (CAlias::AliasGet(insert_alias, this, name)) { // if Convert succeeds, then i has been successfully read from user // input if (!sLine.Token(2, false, " ").Convert(&index) || index < 0 || index > (int)insert_alias.AliasCmds().size()) { PutModule(t_s("Invalid index.")); return; } insert_alias.AliasCmds().insert( insert_alias.AliasCmds().begin() + index, sLine.Token(3, true, " ")); insert_alias.Commit(); PutModule(t_s("Modified alias.")); } else PutModule(t_s("Alias does not exist.")); } void RemoveCommand(const CString& sLine) { CString name = sLine.Token(1, false, " "); CAlias remove_alias; int index; if (CAlias::AliasGet(remove_alias, this, name)) { if (!sLine.Token(2, false, " ").Convert(&index) || index < 0 || index > (int)remove_alias.AliasCmds().size() - 1) { PutModule(t_s("Invalid index.")); return; } remove_alias.AliasCmds().erase(remove_alias.AliasCmds().begin() + index); remove_alias.Commit(); PutModule(t_s("Modified alias.")); } else PutModule(t_s("Alias does not exist.")); } void ClearCommand(const CString& sLine) { CString name = sLine.Token(1, false, " "); CAlias clear_alias; if (CAlias::AliasGet(clear_alias, this, name)) { clear_alias.AliasCmds().clear(); clear_alias.Commit(); PutModule(t_s("Modified alias.")); } else PutModule(t_s("Alias does not exist.")); } void ListCommand(const CString& sLine) { MCString::iterator i = BeginNV(); if (i == EndNV()) { PutModule(t_s("There are no aliases.")); return; } VCString vsAliases; for (; i != EndNV(); ++i) { vsAliases.push_back(i->first); } PutModule(t_f("The following aliases exist: {1}")( CString(t_s(", ", "list|separator")) .Join(vsAliases.begin(), vsAliases.end()))); } void DumpCommand(const CString& sLine) { MCString::iterator i = BeginNV(); if (i == EndNV()) { PutModule(t_s("There are no aliases.")); return; } PutModule("-----------------------"); PutModule("/ZNC-CLEAR-ALL-ALIASES!"); for (; i != EndNV(); ++i) { PutModule("/msg " + GetModNick() + " Create " + i->first); if (!i->second.empty()) { VCString it; uint idx; i->second.Split("\n", it); for (idx = 0; idx < it.size(); ++idx) { PutModule("/msg " + GetModNick() + " Add " + i->first + " " + it[idx]); } } } PutModule("-----------------------"); } void InfoCommand(const CString& sLine) { CString name = sLine.Token(1, false, " "); CAlias info_alias; if (CAlias::AliasGet(info_alias, this, name)) { PutModule(t_f("Actions for alias {1}:")(info_alias.GetName())); for (size_t i = 0; i < info_alias.AliasCmds().size(); ++i) { CString num(i); CString padding(4 - (num.length() > 3 ? 3 : num.length()), ' '); PutModule(num + padding + info_alias.AliasCmds()[i]); } PutModule( t_f("End of actions for alias {1}.")(info_alias.GetName())); } else PutModule(t_s("Alias does not exist.")); } MODCONSTRUCTOR(CAliasMod), sending_lines(false) { AddHelpCommand(); AddCommand("Create", t_d(""), t_d("Creates a new, blank alias called name."), [=](const CString& sLine) { CreateCommand(sLine); }); AddCommand("Delete", t_d(""), t_d("Deletes an existing alias."), [=](const CString& sLine) { DeleteCommand(sLine); }); AddCommand("Add", t_d(" "), t_d("Adds a line to an existing alias."), [=](const CString& sLine) { AddCmd(sLine); }); AddCommand("Insert", t_d(" "), t_d("Inserts a line into an existing alias."), [=](const CString& sLine) { InsertCommand(sLine); }); AddCommand("Remove", t_d(" "), t_d("Removes a line from an existing alias."), [=](const CString& sLine) { RemoveCommand(sLine); }); AddCommand("Clear", t_d(""), t_d("Removes all lines from an existing alias."), [=](const CString& sLine) { ClearCommand(sLine); }); AddCommand("List", "", t_d("Lists all aliases by name."), [=](const CString& sLine) { ListCommand(sLine); }); AddCommand("Info", t_d(""), t_d("Reports the actions performed by an alias."), [=](const CString& sLine) { InfoCommand(sLine); }); AddCommand( "Dump", "", t_d("Generate a list of commands to copy your alias config."), [=](const CString& sLine) { DumpCommand(sLine); }); } EModRet OnUserRaw(CString& sLine) override { CAlias current_alias; if (sending_lines) return CONTINUE; try { if (sLine.Equals("ZNC-CLEAR-ALL-ALIASES!")) { ListCommand(""); PutModule(t_s("Clearing all of them!")); ClearNV(); return HALT; } else if (CAlias::AliasGet(current_alias, this, sLine)) { VCString rawLines; current_alias.Imprint(sLine).Split("\n", rawLines, false); sending_lines = true; for (size_t i = 0; i < rawLines.size(); ++i) { m_pClient->ReadLine(rawLines[i]); } sending_lines = false; return HALT; } } catch (std::exception& e) { CString my_nick = (GetNetwork() == nullptr ? "" : GetNetwork()->GetCurNick()); if (my_nick.empty()) my_nick = "*"; PutUser(CString(":znc.in 461 " + my_nick + " " + current_alias.GetName() + " :ZNC alias error: ") + e.what()); return HALTCORE; } return CONTINUE; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("alias"); Info.AddType(CModInfo::NetworkModule); } USERMODULEDEFS(CAliasMod, t_s("Provides bouncer-side command alias support.")) znc-1.7.5/modules/blockuser.cpp0000644000175000017500000001671013542151610016712 0ustar somebodysomebody/* * Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::vector; #define MESSAGE \ t_s("Your account has been disabled. Contact your administrator.") class CBlockUser : public CModule { public: MODCONSTRUCTOR(CBlockUser) { AddHelpCommand(); AddCommand("List", "", t_d("List blocked users"), [this](const CString& sLine) { OnListCommand(sLine); }); AddCommand("Block", t_d(""), t_d("Block a user"), [this](const CString& sLine) { OnBlockCommand(sLine); }); AddCommand("Unblock", t_d(""), t_d("Unblock a user"), [this](const CString& sLine) { OnUnblockCommand(sLine); }); } ~CBlockUser() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { VCString vArgs; VCString::iterator it; MCString::iterator it2; // Load saved settings for (it2 = BeginNV(); it2 != EndNV(); ++it2) { // Ignore errors Block(it2->first); } // Parse arguments, each argument is a user name to block sArgs.Split(" ", vArgs, false); for (it = vArgs.begin(); it != vArgs.end(); ++it) { if (!Block(*it)) { sMessage = t_f("Could not block {1}")(*it); return false; } } return true; } /* If a user is on the blocked list and tries to log in, displays - MESSAGE and stops their log in attempt.*/ EModRet OnLoginAttempt(std::shared_ptr Auth) override { if (IsBlocked(Auth->GetUsername())) { Auth->RefuseLogin(MESSAGE); return HALT; } return CONTINUE; } void OnModCommand(const CString& sCommand) override { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied")); } else { HandleCommand(sCommand); } } // Displays all blocked users as a list. void OnListCommand(const CString& sCommand) { if (BeginNV() == EndNV()) { PutModule(t_s("No users are blocked")); return; } PutModule(t_s("Blocked users:")); for (auto it = BeginNV(); it != EndNV(); ++it) { PutModule(it->first); } } /* Blocks a user if possible(ie not self, not already blocked). Displays an error message if not possible. */ void OnBlockCommand(const CString& sCommand) { CString sUser = sCommand.Token(1, true); if (sUser.empty()) { PutModule(t_s("Usage: Block ")); return; } if (GetUser()->GetUserName().Equals(sUser)) { PutModule(t_s("You can't block yourself")); return; } if (Block(sUser)) PutModule(t_f("Blocked {1}")(sUser)); else PutModule(t_f("Could not block {1} (misspelled?)")(sUser)); } // Unblocks a user from the blocked list. void OnUnblockCommand(const CString& sCommand) { CString sUser = sCommand.Token(1, true); if (sUser.empty()) { PutModule(t_s("Usage: Unblock ")); return; } if (DelNV(sUser)) PutModule(t_f("Unblocked {1}")(sUser)); else PutModule(t_s("This user is not blocked")); } // Provides GUI to configure this module by adding a widget to user page in webadmin. bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "webadmin/user" && WebSock.GetSession()->IsAdmin()) { CString sAction = Tmpl["WebadminAction"]; if (sAction == "display") { Tmpl["Blocked"] = CString(IsBlocked(Tmpl["Username"])); Tmpl["Self"] = CString(Tmpl["Username"].Equals( WebSock.GetSession()->GetUser()->GetUserName())); return true; } if (sAction == "change" && WebSock.GetParam("embed_blockuser_presented").ToBool()) { if (Tmpl["Username"].Equals( WebSock.GetSession()->GetUser()->GetUserName()) && WebSock.GetParam("embed_blockuser_block").ToBool()) { WebSock.GetSession()->AddError( t_s("You can't block yourself")); } else if (WebSock.GetParam("embed_blockuser_block").ToBool()) { if (!WebSock.GetParam("embed_blockuser_old").ToBool()) { if (Block(Tmpl["Username"])) { WebSock.GetSession()->AddSuccess( t_f("Blocked {1}")(Tmpl["Username"])); } else { WebSock.GetSession()->AddError( t_f("Couldn't block {1}")(Tmpl["Username"])); } } } else if (WebSock.GetParam("embed_blockuser_old").ToBool()) { if (DelNV(Tmpl["Username"])) { WebSock.GetSession()->AddSuccess( t_f("Unblocked {1}")(Tmpl["Username"])); } else { WebSock.GetSession()->AddError( t_f("User {1} is not blocked")(Tmpl["Username"])); } } return true; } } return false; } private: /* Iterates through all blocked users and returns true if the specified user (sUser) is blocked, else returns false.*/ bool IsBlocked(const CString& sUser) { MCString::iterator it; for (it = BeginNV(); it != EndNV(); ++it) { if (sUser == it->first) { return true; } } return false; } bool Block(const CString& sUser) { CUser* pUser = CZNC::Get().FindUser(sUser); if (!pUser) return false; // Disconnect all clients vector vpClients = pUser->GetAllClients(); vector::iterator it; for (it = vpClients.begin(); it != vpClients.end(); ++it) { (*it)->PutStatusNotice(MESSAGE); (*it)->Close(Csock::CLT_AFTERWRITE); } // Disconnect all networks from irc vector vNetworks = pUser->GetNetworks(); for (vector::iterator it2 = vNetworks.begin(); it2 != vNetworks.end(); ++it2) { (*it2)->SetIRCConnectEnabled(false); } SetNV(pUser->GetUserName(), ""); return true; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("blockuser"); Info.SetHasArgs(true); Info.SetArgsHelpText( Info.t_s("Enter one or more user names. Separate them by spaces.")); } GLOBALMODULEDEFS(CBlockUser, t_s("Block certain users from logging in.")) znc-1.7.5/modules/nickserv.cpp0000644000175000017500000001313413542151610016542 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include class CNickServ : public CModule { void DoNickCommand(const CString& sCmd, const CString& sNick) { MCString msValues; msValues["nickname"] = sNick; msValues["password"] = GetNV("Password"); PutIRC(CString::NamedFormat(GetNV(sCmd), msValues)); } public: void SetCommand(const CString& sLine) { SetNV("Password", sLine.Token(1, true)); PutModule(t_s("Password set")); } void ClearCommand(const CString& sLine) { DelNV("Password"); PutModule(t_s("Done")); } void SetNSNameCommand(const CString& sLine) { SetNV("NickServName", sLine.Token(1, true)); PutModule(t_s("NickServ name set")); } void ClearNSNameCommand(const CString& sLine) { DelNV("NickServName"); PutModule(t_s("Done")); } void ViewCommandsCommand(const CString& sLine) { PutModule("IDENTIFY " + GetNV("IdentifyCmd")); } void SetCommandCommand(const CString& sLine) { CString sCmd = sLine.Token(1); CString sNewCmd = sLine.Token(2, true); if (sCmd.Equals("IDENTIFY")) { SetNV("IdentifyCmd", sNewCmd); } else { PutModule( t_s("No such editable command. See ViewCommands for list.")); return; } PutModule(t_s("Ok")); } MODCONSTRUCTOR(CNickServ) { AddHelpCommand(); AddCommand("Set", t_d("password"), t_d("Set your nickserv password"), [=](const CString& sLine) { SetCommand(sLine); }); AddCommand("Clear", "", t_d("Clear your nickserv password"), [=](const CString& sLine) { ClearCommand(sLine); }); AddCommand("SetNSName", t_d("nickname"), t_d("Set NickServ name (Useful on networks like EpiKnet, " "where NickServ is named Themis"), [=](const CString& sLine) { SetNSNameCommand(sLine); }); AddCommand("ClearNSName", "", t_d("Reset NickServ name to default (NickServ)"), [=](const CString& sLine) { ClearNSNameCommand(sLine); }); AddCommand( "ViewCommands", "", t_d("Show patterns for lines, which are being sent to NickServ"), [=](const CString& sLine) { ViewCommandsCommand(sLine); }); AddCommand("SetCommand", t_d("cmd new-pattern"), t_d("Set pattern for commands"), [=](const CString& sLine) { SetCommandCommand(sLine); }); } ~CNickServ() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { if (!sArgs.empty() && sArgs != "") { SetNV("Password", sArgs); SetArgs(""); } if (GetNV("IdentifyCmd").empty()) { SetNV("IdentifyCmd", "NICKSERV IDENTIFY {password}"); } return true; } void HandleMessage(CNick& Nick, const CString& sMessage) { CString sNickServName = (!GetNV("NickServName").empty()) ? GetNV("NickServName") : "NickServ"; if (!GetNV("Password").empty() && Nick.NickEquals(sNickServName) && (sMessage.find("msg") != CString::npos || sMessage.find("authenticate") != CString::npos || sMessage.find("choose a different nickname") != CString::npos || sMessage.find("please choose a different nick") != CString::npos || sMessage.find("If this is your nick, identify yourself with") != CString::npos || sMessage.find("If this is your nick, type") != CString::npos || sMessage.find("This is a registered nickname, please identify") != CString::npos || sMessage.find("is a registered nick - you must auth to account") != CString::npos || sMessage.StripControls_n().find( "type /NickServ IDENTIFY password") != CString::npos || sMessage.StripControls_n().find( "type /msg NickServ IDENTIFY password") != CString::npos) && sMessage.AsUpper().find("IDENTIFY") != CString::npos && sMessage.find("help") == CString::npos) { MCString msValues; msValues["password"] = GetNV("Password"); PutIRC(CString::NamedFormat(GetNV("IdentifyCmd"), msValues)); } } EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override { HandleMessage(Nick, sMessage); return CONTINUE; } EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override { HandleMessage(Nick, sMessage); return CONTINUE; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("nickserv"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s("Please enter your nickserv password.")); } NETWORKMODULEDEFS(CNickServ, t_s("Auths you with NickServ (prefer SASL module instead)")) znc-1.7.5/modules/q.cpp0000644000175000017500000006317513542151610015170 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include using std::set; #ifndef Q_DEBUG_COMMUNICATION #define Q_DEBUG_COMMUNICATION 0 #endif class CQModule : public CModule { public: MODCONSTRUCTOR(CQModule) {} ~CQModule() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { if (!sArgs.empty()) { SetUsername(sArgs.Token(0)); SetPassword(sArgs.Token(1)); } else { m_sUsername = GetNV("Username"); m_sPassword = GetNV("Password"); } CString sTmp; m_bUseCloakedHost = (sTmp = GetNV("UseCloakedHost")).empty() ? true : sTmp.ToBool(); m_bUseChallenge = (sTmp = GetNV("UseChallenge")).empty() ? true : sTmp.ToBool(); m_bRequestPerms = GetNV("RequestPerms").ToBool(); m_bJoinOnInvite = (sTmp = GetNV("JoinOnInvite")).empty() ? true : sTmp.ToBool(); m_bJoinAfterCloaked = (sTmp = GetNV("JoinAfterCloaked")).empty() ? true : sTmp.ToBool(); // Make sure NVs are stored in config. Note: SetUseCloakedHost() is // called further down. SetUseChallenge(m_bUseChallenge); SetRequestPerms(m_bRequestPerms); SetJoinOnInvite(m_bJoinOnInvite); SetJoinAfterCloaked(m_bJoinAfterCloaked); OnIRCDisconnected(); // reset module's state if (IsIRCConnected()) { // check for usermode +x if we are already connected set scUserModes = GetNetwork()->GetIRCSock()->GetUserModes(); if (scUserModes.find('x') != scUserModes.end()) m_bCloaked = true; // This will only happen once, and only if the user loads the module // after connecting to IRC. // Also don't notify the user in case he already had mode +x set. if (GetNV("UseCloakedHost").empty()) { if (!m_bCloaked) PutModule(t_s( "Notice: Your host will be cloaked the next time you " "reconnect to IRC. " "If you want to cloak your host now, /msg *q Cloak. " "You can set your preference " "with /msg *q Set UseCloakedHost true/false.")); m_bUseCloakedHost = true; SetUseCloakedHost(m_bUseCloakedHost); m_bJoinAfterCloaked = true; SetJoinAfterCloaked(m_bJoinAfterCloaked); } else if (m_bUseChallenge) { Cloak(); } WhoAmI(); } else { SetUseCloakedHost(m_bUseCloakedHost); } return true; } void OnIRCDisconnected() override { m_bCloaked = false; m_bAuthed = false; m_bRequestedWhoami = false; m_bRequestedChallenge = false; m_bCatchResponse = false; } void OnIRCConnected() override { if (m_bUseCloakedHost) Cloak(); WhoAmI(); } void OnModCommand(const CString& sLine) override { CString sCommand = sLine.Token(0).AsLower(); if (sCommand == "help") { PutModule(t_s("The following commands are available:")); CTable Table; Table.AddColumn(t_s("Command")); Table.AddColumn(t_s("Description")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Auth [ ]")); Table.SetCell(t_s("Description"), t_s("Tries to authenticate you with Q. Both " "parameters are optional.")); Table.AddRow(); Table.SetCell(t_s("Command"), "Cloak"); Table.SetCell( t_s("Description"), t_s("Tries to set usermode +x to hide your real hostname.")); Table.AddRow(); Table.SetCell(t_s("Command"), "Status"); Table.SetCell(t_s("Description"), t_s("Prints the current status of the module.")); Table.AddRow(); Table.SetCell(t_s("Command"), "Update"); Table.SetCell( t_s("Description"), t_s("Re-requests the current user information from Q.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Set ")); Table.SetCell(t_s("Description"), t_s("Changes the value of the given setting. See the " "list of settings below.")); Table.AddRow(); Table.SetCell(t_s("Command"), "Get"); Table.SetCell(t_s("Description"), t_s("Prints out the current configuration. See the " "list of settings below.")); PutModule(Table); PutModule(t_s("The following settings are available:")); CTable Table2; Table2.AddColumn(t_s("Setting")); Table2.AddColumn(t_s("Type")); Table2.AddColumn(t_s("Description")); Table2.AddRow(); Table2.SetCell(t_s("Setting"),"Username"); Table2.SetCell(t_s("Type"), t_s("String")); Table2.SetCell(t_s("Description"), t_s("Your Q username.")); Table2.AddRow(); Table2.SetCell(t_s("Setting"), "Password"); Table2.SetCell(t_s("Type"), t_s("String")); Table2.SetCell(t_s("Description"), t_s("Your Q password.")); Table2.AddRow(); Table2.SetCell(t_s("Setting"), "UseCloakedHost"); Table2.SetCell(t_s("Type"), t_s("Boolean")); Table2.SetCell(t_s("Description"), t_s("Whether to cloak your hostname (+x) " "automatically on connect.")); Table2.AddRow(); Table2.SetCell(t_s("Setting"), "UseChallenge"); Table2.SetCell(t_s("Type"), t_s("Boolean")); Table2.SetCell(t_s("Description"), t_s("Whether to use the CHALLENGEAUTH mechanism to " "avoid sending passwords in cleartext.")); Table2.AddRow(); Table2.SetCell(t_s("Setting"), "RequestPerms"); Table2.SetCell(t_s("Type"), t_s("Boolean")); Table2.SetCell(t_s("Description"), t_s("Whether to request voice/op from Q on " "join/devoice/deop.")); Table2.AddRow(); Table2.SetCell(t_s("Setting"), "JoinOnInvite"); Table2.SetCell(t_s("Type"), t_s("Boolean")); Table2.SetCell(t_s("Description"), t_s("Whether to join channels when Q invites you.")); Table2.AddRow(); Table2.SetCell(t_s("Setting"), "JoinAfterCloaked"); Table2.SetCell(t_s("Type"), t_s("Boolean")); Table2.SetCell( t_s("Description"), t_s("Whether to delay joining channels until after you " "are cloaked.")); PutModule(Table2); PutModule( t_s("This module takes 2 optional parameters: " "")); PutModule(t_s("Module settings are stored between restarts.")); } else if (sCommand == "set") { CString sSetting = sLine.Token(1).AsLower(); CString sValue = sLine.Token(2); if (sSetting.empty() || sValue.empty()) { PutModule(t_s("Syntax: Set ")); } else if (sSetting == "username") { SetUsername(sValue); PutModule(t_s("Username set")); } else if (sSetting == "password") { SetPassword(sValue); PutModule(t_s("Password set")); } else if (sSetting == "usecloakedhost") { SetUseCloakedHost(sValue.ToBool()); PutModule(t_s("UseCloakedHost set")); } else if (sSetting == "usechallenge") { SetUseChallenge(sValue.ToBool()); PutModule(t_s("UseChallenge set")); } else if (sSetting == "requestperms") { SetRequestPerms(sValue.ToBool()); PutModule(t_s("RequestPerms set")); } else if (sSetting == "joinoninvite") { SetJoinOnInvite(sValue.ToBool()); PutModule(t_s("JoinOnInvite set")); } else if (sSetting == "joinaftercloaked") { SetJoinAfterCloaked(sValue.ToBool()); PutModule(t_s("JoinAfterCloaked set")); } else PutModule(t_f("Unknown setting: {1}")(sSetting)); } else if (sCommand == "get" || sCommand == "list") { CTable Table; Table.AddColumn(t_s("Setting")); Table.AddColumn(t_s("Value")); Table.AddRow(); Table.SetCell(t_s("Setting"), "Username"); Table.SetCell(t_s("Value"), m_sUsername); Table.AddRow(); Table.SetCell(t_s("Setting"), "Password"); Table.SetCell(t_s("Value"), "*****"); // m_sPassword Table.AddRow(); Table.SetCell(t_s("Setting"), "UseCloakedHost"); Table.SetCell(t_s("Value"), CString(m_bUseCloakedHost)); Table.AddRow(); Table.SetCell(t_s("Setting"), "UseChallenge"); Table.SetCell(t_s("Value"), CString(m_bUseChallenge)); Table.AddRow(); Table.SetCell(t_s("Setting"), "RequestPerms"); Table.SetCell(t_s("Value"), CString(m_bRequestPerms)); Table.AddRow(); Table.SetCell(t_s("Setting"), "JoinOnInvite"); Table.SetCell(t_s("Value"), CString(m_bJoinOnInvite)); Table.AddRow(); Table.SetCell(t_s("Setting"), "JoinAfterCloaked"); Table.SetCell(t_s("Value"), CString(m_bJoinAfterCloaked)); PutModule(Table); } else if (sCommand == "status") { PutModule(IsIRCConnected() ? t_s("Connected: yes") : t_s("Connected: no")); PutModule(m_bCloaked ? t_s("Cloacked: yes") : t_s("Cloacked: no")); PutModule(m_bAuthed ? t_s("Authenticated: yes") : t_s("Authenticated: no")); } else { // The following commands require an IRC connection. if (!IsIRCConnected()) { PutModule(t_s("Error: You are not connected to IRC.")); return; } if (sCommand == "cloak") { if (!m_bCloaked) Cloak(); else PutModule(t_s("Error: You are already cloaked!")); } else if (sCommand == "auth") { if (!m_bAuthed) Auth(sLine.Token(1), sLine.Token(2)); else PutModule(t_s("Error: You are already authed!")); } else if (sCommand == "update") { WhoAmI(); PutModule(t_s("Update requested.")); } else { PutModule(t_s("Unknown command. Try 'help'.")); } } } EModRet OnRaw(CString& sLine) override { // use OnRaw because OnUserMode is not defined (yet?) if (sLine.Token(1) == "396" && sLine.Token(3).find("users.quakenet.org") != CString::npos) { m_bCloaked = true; PutModule(t_s("Cloak successful: Your hostname is now cloaked.")); // Join channels immediately after our spoof is set, but only if // both UseCloakedHost and JoinAfterCloaked is enabled. See #602. if (m_bJoinAfterCloaked) { GetNetwork()->JoinChans(); } } return CONTINUE; } EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override { return HandleMessage(Nick, sMessage); } EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override { return HandleMessage(Nick, sMessage); } EModRet OnJoining(CChan& Channel) override { // Halt if are not already cloaked, but the user requres that we delay // channel join till after we are cloaked. if (!m_bCloaked && m_bUseCloakedHost && m_bJoinAfterCloaked) return HALT; return CONTINUE; } void OnJoin(const CNick& Nick, CChan& Channel) override { if (m_bRequestPerms && IsSelf(Nick)) HandleNeed(Channel, "ov"); } void OnDeop2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override { if (m_bRequestPerms && IsSelf(Nick) && (!pOpNick || !IsSelf(*pOpNick))) HandleNeed(Channel, "o"); } void OnDevoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override { if (m_bRequestPerms && IsSelf(Nick) && (!pOpNick || !IsSelf(*pOpNick))) HandleNeed(Channel, "v"); } EModRet OnInvite(const CNick& Nick, const CString& sChan) override { if (!Nick.NickEquals("Q") || !Nick.GetHost().Equals("CServe.quakenet.org")) return CONTINUE; if (m_bJoinOnInvite) GetNetwork()->AddChan(sChan, false); return CONTINUE; } CString GetWebMenuTitle() override { return "Q"; } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "index") { bool bSubmitted = (WebSock.GetParam("submitted").ToInt() != 0); if (bSubmitted) { CString FormUsername = WebSock.GetParam("user"); if (!FormUsername.empty()) SetUsername(FormUsername); CString FormPassword = WebSock.GetParam("password"); if (!FormPassword.empty()) SetPassword(FormPassword); SetUseCloakedHost(WebSock.GetParam("usecloakedhost").ToBool()); SetUseChallenge(WebSock.GetParam("usechallenge").ToBool()); SetRequestPerms(WebSock.GetParam("requestperms").ToBool()); SetJoinOnInvite(WebSock.GetParam("joinoninvite").ToBool()); SetJoinAfterCloaked( WebSock.GetParam("joinaftercloaked").ToBool()); } Tmpl["Username"] = m_sUsername; CTemplate& o1 = Tmpl.AddRow("OptionLoop"); o1["Name"] = "usecloakedhost"; o1["DisplayName"] = "UseCloakedHost"; o1["Tooltip"] = t_s("Whether to cloak your hostname (+x) automatically on " "connect."); o1["Checked"] = CString(m_bUseCloakedHost); CTemplate& o2 = Tmpl.AddRow("OptionLoop"); o2["Name"] = "usechallenge"; o2["DisplayName"] = "UseChallenge"; o2["Tooltip"] = t_s("Whether to use the CHALLENGEAUTH mechanism to avoid " "sending passwords in cleartext."); o2["Checked"] = CString(m_bUseChallenge); CTemplate& o3 = Tmpl.AddRow("OptionLoop"); o3["Name"] = "requestperms"; o3["DisplayName"] = "RequestPerms"; o3["Tooltip"] = t_s("Whether to request voice/op from Q on join/devoice/deop."); o3["Checked"] = CString(m_bRequestPerms); CTemplate& o4 = Tmpl.AddRow("OptionLoop"); o4["Name"] = "joinoninvite"; o4["DisplayName"] = "JoinOnInvite"; o4["Tooltip"] = t_s("Whether to join channels when Q invites you."); o4["Checked"] = CString(m_bJoinOnInvite); CTemplate& o5 = Tmpl.AddRow("OptionLoop"); o5["Name"] = "joinaftercloaked"; o5["DisplayName"] = "JoinAfterCloaked"; o5["Tooltip"] = t_s("Whether to delay joining channels until after you are " "cloaked."); o5["Checked"] = CString(m_bJoinAfterCloaked); if (bSubmitted) { WebSock.GetSession()->AddSuccess( t_s("Changes have been saved!")); } return true; } return false; } private: bool m_bCloaked{}; bool m_bAuthed{}; bool m_bRequestedWhoami{}; bool m_bRequestedChallenge{}; bool m_bCatchResponse{}; MCString m_msChanModes; void PutQ(const CString& sMessage) { PutIRC("PRIVMSG Q@CServe.quakenet.org :" + sMessage); #if Q_DEBUG_COMMUNICATION PutModule("[ZNC --> Q] " + sMessage); #endif } void Cloak() { if (m_bCloaked) return; PutModule(t_s("Cloak: Trying to cloak your hostname, setting +x...")); PutIRC("MODE " + GetNetwork()->GetIRCSock()->GetNick() + " +x"); } void WhoAmI() { m_bRequestedWhoami = true; PutQ("WHOAMI"); } void Auth(const CString& sUsername = "", const CString& sPassword = "") { if (m_bAuthed) return; if (!sUsername.empty()) SetUsername(sUsername); if (!sPassword.empty()) SetPassword(sPassword); if (m_sUsername.empty() || m_sPassword.empty()) { PutModule( t_s("You have to set a username and password to use this " "module! See 'help' for details.")); return; } if (m_bUseChallenge) { PutModule(t_s("Auth: Requesting CHALLENGE...")); m_bRequestedChallenge = true; PutQ("CHALLENGE"); } else { PutModule(t_s("Auth: Sending AUTH request...")); PutQ("AUTH " + m_sUsername + " " + m_sPassword); } } void ChallengeAuth(CString sChallenge) { if (m_bAuthed) return; CString sUsername = m_sUsername.AsLower() .Replace_n("[", "{") .Replace_n("]", "}") .Replace_n("\\", "|"); CString sPasswordHash = m_sPassword.Left(10).SHA256(); CString sKey = CString(sUsername + ":" + sPasswordHash).SHA256(); CString sResponse = HMAC_SHA256(sKey, sChallenge); PutModule( t_s("Auth: Received challenge, sending CHALLENGEAUTH request...")); PutQ("CHALLENGEAUTH " + m_sUsername + " " + sResponse + " HMAC-SHA-256"); } EModRet HandleMessage(const CNick& Nick, CString sMessage) { if (!Nick.NickEquals("Q") || !Nick.GetHost().Equals("CServe.quakenet.org")) return CONTINUE; sMessage.Trim(); #if Q_DEBUG_COMMUNICATION PutModule("[ZNC <-- Q] " + sMessage); #endif // WHOAMI if (sMessage.find("WHOAMI is only available to authed users") != CString::npos) { m_bAuthed = false; Auth(); m_bCatchResponse = m_bRequestedWhoami; } else if (sMessage.find("Information for user") != CString::npos) { m_bAuthed = true; m_msChanModes.clear(); m_bCatchResponse = m_bRequestedWhoami; m_bRequestedWhoami = true; } else if (m_bRequestedWhoami && sMessage.WildCmp("#*")) { CString sChannel = sMessage.Token(0); CString sFlags = sMessage.Token(1, true).Trim_n().TrimLeft_n("+"); m_msChanModes[sChannel] = sFlags; } else if (m_bRequestedWhoami && m_bCatchResponse && (sMessage.Equals("End of list.") || sMessage.Equals( "account, or HELLO to create an account."))) { m_bRequestedWhoami = m_bCatchResponse = false; return HALT; } // AUTH else if (sMessage.Equals("Username or password incorrect.")) { m_bAuthed = false; PutModule(t_f("Authentication failed: {1}")(sMessage)); return HALT; } else if (sMessage.WildCmp("You are now logged in as *.")) { m_bAuthed = true; PutModule(t_f("Authentication successful: {1}")(sMessage)); WhoAmI(); return HALT; } else if (m_bRequestedChallenge && sMessage.Token(0).Equals("CHALLENGE")) { m_bRequestedChallenge = false; if (sMessage.find("not available once you have authed") != CString::npos) { m_bAuthed = true; } else { if (sMessage.find("HMAC-SHA-256") != CString::npos) { ChallengeAuth(sMessage.Token(1)); } else { PutModule( t_s("Auth failed: Q does not support HMAC-SHA-256 for " "CHALLENGEAUTH, falling back to standard AUTH.")); SetUseChallenge(false); Auth(); } } return HALT; } // prevent buffering of Q's responses return !m_bCatchResponse && GetUser()->IsUserAttached() ? CONTINUE : HALT; } void HandleNeed(const CChan& Channel, const CString& sPerms) { MCString::iterator it = m_msChanModes.find(Channel.GetName()); if (it == m_msChanModes.end()) return; CString sModes = it->second; bool bMaster = (sModes.find("m") != CString::npos) || (sModes.find("n") != CString::npos); if (sPerms.find("o") != CString::npos) { bool bOp = (sModes.find("o") != CString::npos); bool bAutoOp = (sModes.find("a") != CString::npos); if (bMaster || bOp) { if (!bAutoOp) { PutModule(t_f("RequestPerms: Requesting op on {1}")( Channel.GetName())); PutQ("OP " + Channel.GetName()); } return; } } if (sPerms.find("v") != CString::npos) { bool bVoice = (sModes.find("v") != CString::npos); bool bAutoVoice = (sModes.find("g") != CString::npos); if (bMaster || bVoice) { if (!bAutoVoice) { PutModule(t_f("RequestPerms: Requesting voice on {1}")( Channel.GetName())); PutQ("VOICE " + Channel.GetName()); } return; } } } /* Utility Functions */ bool IsIRCConnected() { CIRCSock* pIRCSock = GetNetwork()->GetIRCSock(); return pIRCSock && pIRCSock->IsAuthed(); } bool IsSelf(const CNick& Nick) { return Nick.NickEquals(GetNetwork()->GetCurNick()); } bool PackHex(const CString& sHex, CString& sPackedHex) { if (sHex.length() % 2) return false; sPackedHex.clear(); CString::size_type len = sHex.length() / 2; for (CString::size_type i = 0; i < len; i++) { unsigned int value; int n = sscanf(&sHex[i * 2], "%02x", &value); if (n != 1 || value > 0xff) return false; sPackedHex += (unsigned char)value; } return true; } CString HMAC_SHA256(const CString& sKey, const CString& sData) { CString sRealKey; if (sKey.length() > 64) PackHex(sKey.SHA256(), sRealKey); else sRealKey = sKey; CString sOuterKey, sInnerKey; CString::size_type iKeyLength = sRealKey.length(); for (unsigned int i = 0; i < 64; i++) { char r = (i < iKeyLength ? sRealKey[i] : '\0'); sOuterKey += r ^ 0x5c; sInnerKey += r ^ 0x36; } CString sInnerHash; PackHex(CString(sInnerKey + sData).SHA256(), sInnerHash); return CString(sOuterKey + sInnerHash).SHA256(); } /* Settings */ CString m_sUsername; CString m_sPassword; bool m_bUseCloakedHost{}; bool m_bUseChallenge{}; bool m_bRequestPerms{}; bool m_bJoinOnInvite{}; bool m_bJoinAfterCloaked{}; void SetUsername(const CString& sUsername) { m_sUsername = sUsername; SetNV("Username", sUsername); } void SetPassword(const CString& sPassword) { m_sPassword = sPassword; SetNV("Password", sPassword); } void SetUseCloakedHost(const bool bUseCloakedHost) { m_bUseCloakedHost = bUseCloakedHost; SetNV("UseCloakedHost", CString(bUseCloakedHost)); if (!m_bCloaked && m_bUseCloakedHost && IsIRCConnected()) Cloak(); } void SetUseChallenge(const bool bUseChallenge) { m_bUseChallenge = bUseChallenge; SetNV("UseChallenge", CString(bUseChallenge)); } void SetRequestPerms(const bool bRequestPerms) { m_bRequestPerms = bRequestPerms; SetNV("RequestPerms", CString(bRequestPerms)); } void SetJoinOnInvite(const bool bJoinOnInvite) { m_bJoinOnInvite = bJoinOnInvite; SetNV("JoinOnInvite", CString(bJoinOnInvite)); } void SetJoinAfterCloaked(const bool bJoinAfterCloaked) { m_bJoinAfterCloaked = bJoinAfterCloaked; SetNV("JoinAfterCloaked", CString(bJoinAfterCloaked)); } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("Q"); Info.SetHasArgs(true); Info.SetArgsHelpText( Info.t_s("Please provide your username and password for Q.")); } NETWORKMODULEDEFS(CQModule, t_s("Auths you with QuakeNet's Q bot.")) znc-1.7.5/modules/admindebug.cpp0000644000175000017500000000640013542151610017013 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include class CAdminDebugMod : public CModule { private: CString m_sEnabledBy; public: MODCONSTRUCTOR(CAdminDebugMod) { AddHelpCommand(); AddCommand("Enable", "", t_d("Enable Debug Mode"), [=](const CString& sLine) { CommandEnable(sLine); }); AddCommand("Disable", "", t_d("Disable Debug Mode"), [=](const CString& sLine) { CommandDisable(sLine); }); AddCommand("Status", "", t_d("Show the Debug Mode status"), [=](const CString& sLine) { CommandStatus(sLine); }); } void CommandEnable(const CString& sCommand) { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied!")); return; } ToggleDebug(true, GetUser()->GetNick()); } void CommandDisable(const CString& sCommand) { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied!")); return; } ToggleDebug(false, m_sEnabledBy); } bool ToggleDebug(bool bEnable, const CString& sEnabledBy) { if (!CDebug::StdoutIsTTY()) { PutModule(t_s("Failure. We need to be running with a TTY. (is ZNC running with --foreground?)")); return false; } bool bValue = CDebug::Debug(); if (bEnable == bValue) { if (bEnable) { PutModule(t_s("Already enabled.")); } else { PutModule(t_s("Already disabled.")); } return false; } CDebug::SetDebug(bEnable); CString sEnabled = bEnable ? "on" : "off"; CZNC::Get().Broadcast( "An administrator has just turned Debug Mode \02" + sEnabled + "\02. It was enabled by \02" + sEnabledBy + "\02."); if (bEnable) { CZNC::Get().Broadcast( "Messages, credentials, and other sensitive data may become " "exposed to the host during this period."); m_sEnabledBy = sEnabledBy; } else { m_sEnabledBy = ""; } return true; } void CommandStatus(const CString& sCommand) { if (CDebug::Debug()) { PutModule(t_s("Debugging mode is \02on\02.")); } else { PutModule(t_s("Debugging mode is \02off\02.")); } PutModule(t_s("Logging to: \02stdout\02.")); } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("admindebug"); } GLOBALMODULEDEFS(CAdminDebugMod, t_s("Enable Debug mode dynamically.")) znc-1.7.5/modules/log.cpp0000644000175000017500000004444013542151610015503 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * Copyright (C) 2006-2007, CNU *(http://cnu.dieplz.net/znc) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include using std::vector; class CLogRule { public: CLogRule(const CString& sRule, bool bEnabled = true) : m_sRule(sRule), m_bEnabled(bEnabled) {} const CString& GetRule() const { return m_sRule; } bool IsEnabled() const { return m_bEnabled; } void SetEnabled(bool bEnabled) { m_bEnabled = bEnabled; } bool Compare(const CString& sTarget) const { return sTarget.WildCmp(m_sRule, CString::CaseInsensitive); } bool operator==(const CLogRule& sOther) const { return m_sRule == sOther.GetRule(); } CString ToString() const { return (m_bEnabled ? "" : "!") + m_sRule; } private: CString m_sRule; bool m_bEnabled; }; class CLogMod : public CModule { public: MODCONSTRUCTOR(CLogMod) { m_bSanitize = false; AddHelpCommand(); AddCommand( "SetRules", t_d(""), t_d("Set logging rules, use !#chan or !query to negate and * "), [=](const CString& sLine) { SetRulesCmd(sLine); }); AddCommand("ClearRules", "", t_d("Clear all logging rules"), [=](const CString& sLine) { ClearRulesCmd(sLine); }); AddCommand("ListRules", "", t_d("List all logging rules"), [=](const CString& sLine) { ListRulesCmd(sLine); }); AddCommand( "Set", t_d(" true|false"), t_d("Set one of the following options: joins, quits, nickchanges"), [=](const CString& sLine) { SetCmd(sLine); }); AddCommand("ShowSettings", "", t_d("Show current settings set by Set command"), [=](const CString& sLine) { ShowSettingsCmd(sLine); }); } void SetRulesCmd(const CString& sLine); void ClearRulesCmd(const CString& sLine); void ListRulesCmd(const CString& sLine = ""); void SetCmd(const CString& sLine); void ShowSettingsCmd(const CString& sLine); void SetRules(const VCString& vsRules); VCString SplitRules(const CString& sRules) const; CString JoinRules(const CString& sSeparator) const; bool TestRules(const CString& sTarget) const; void PutLog(const CString& sLine, const CString& sWindow = "status"); void PutLog(const CString& sLine, const CChan& Channel); void PutLog(const CString& sLine, const CNick& Nick); CString GetServer(); bool OnLoad(const CString& sArgs, CString& sMessage) override; void OnIRCConnected() override; void OnIRCDisconnected() override; EModRet OnBroadcast(CString& sMessage) override; void OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) override; void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) override; void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) override; void OnJoin(const CNick& Nick, CChan& Channel) override; void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) override; void OnNick(const CNick& OldNick, const CString& sNewNick, const vector& vChans) override; EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) override; EModRet OnSendToIRCMessage(CMessage& Message) override; /* notices */ EModRet OnUserNotice(CString& sTarget, CString& sMessage) override; EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override; EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) override; /* actions */ EModRet OnUserAction(CString& sTarget, CString& sMessage) override; EModRet OnPrivAction(CNick& Nick, CString& sMessage) override; EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) override; /* msgs */ EModRet OnUserMsg(CString& sTarget, CString& sMessage) override; EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override; EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override; private: bool NeedJoins() const; bool NeedQuits() const; bool NeedNickChanges() const; CString m_sLogPath; CString m_sTimestamp; bool m_bSanitize; vector m_vRules; }; void CLogMod::SetRulesCmd(const CString& sLine) { VCString vsRules = SplitRules(sLine.Token(1, true)); if (vsRules.empty()) { PutModule(t_s("Usage: SetRules ")); PutModule(t_s("Wildcards are allowed")); } else { SetRules(vsRules); SetNV("rules", JoinRules(",")); ListRulesCmd(); } } void CLogMod::ClearRulesCmd(const CString& sLine) { size_t uCount = m_vRules.size(); if (uCount == 0) { PutModule(t_s("No logging rules. Everything is logged.")); } else { CString sRules = JoinRules(" "); SetRules(VCString()); DelNV("rules"); PutModule(t_p("1 rule removed: {2}", "{1} rules removed: {2}", uCount)( uCount, sRules)); } } void CLogMod::ListRulesCmd(const CString& sLine) { CTable Table; Table.AddColumn(t_s("Rule", "listrules")); Table.AddColumn(t_s("Logging enabled", "listrules")); for (const CLogRule& Rule : m_vRules) { Table.AddRow(); Table.SetCell(t_s("Rule", "listrules"), Rule.GetRule()); Table.SetCell(t_s("Logging enabled", "listrules"), CString(Rule.IsEnabled())); } if (Table.empty()) { PutModule(t_s("No logging rules. Everything is logged.")); } else { PutModule(Table); } } void CLogMod::SetCmd(const CString& sLine) { const CString sVar = sLine.Token(1).AsLower(); const CString sValue = sLine.Token(2); if (sValue.empty()) { PutModule( t_s("Usage: Set true|false, where is one of: joins, " "quits, nickchanges")); return; } bool b = sLine.Token(2).ToBool(); const std::unordered_map> mssResponses = { {"joins", {t_s("Will log joins"), t_s("Will not log joins")}}, {"quits", {t_s("Will log quits"), t_s("Will not log quits")}}, {"nickchanges", {t_s("Will log nick changes"), t_s("Will not log nick changes")}}}; auto it = mssResponses.find(sVar); if (it == mssResponses.end()) { PutModule(t_s( "Unknown variable. Known variables: joins, quits, nickchanges")); return; } SetNV(sVar, CString(b)); PutModule(b ? it->second.first : it->second.second); } void CLogMod::ShowSettingsCmd(const CString& sLine) { PutModule(NeedJoins() ? t_s("Logging joins") : t_s("Not logging joins")); PutModule(NeedQuits() ? t_s("Logging quits") : t_s("Not logging quits")); PutModule(NeedNickChanges() ? t_s("Logging nick changes") : t_s("Not logging nick changes")); } bool CLogMod::NeedJoins() const { return !HasNV("joins") || GetNV("joins").ToBool(); } bool CLogMod::NeedQuits() const { return !HasNV("quits") || GetNV("quits").ToBool(); } bool CLogMod::NeedNickChanges() const { return !HasNV("nickchanges") || GetNV("nickchanges").ToBool(); } void CLogMod::SetRules(const VCString& vsRules) { m_vRules.clear(); for (CString sRule : vsRules) { bool bEnabled = !sRule.TrimPrefix("!"); m_vRules.push_back(CLogRule(sRule, bEnabled)); } } VCString CLogMod::SplitRules(const CString& sRules) const { CString sCopy = sRules; sCopy.Replace(",", " "); VCString vsRules; sCopy.Split(" ", vsRules, false, "", "", true, true); return vsRules; } CString CLogMod::JoinRules(const CString& sSeparator) const { VCString vsRules; for (const CLogRule& Rule : m_vRules) { vsRules.push_back(Rule.ToString()); } return sSeparator.Join(vsRules.begin(), vsRules.end()); } bool CLogMod::TestRules(const CString& sTarget) const { for (const CLogRule& Rule : m_vRules) { if (Rule.Compare(sTarget)) { return Rule.IsEnabled(); } } return true; } void CLogMod::PutLog(const CString& sLine, const CString& sWindow /*= "Status"*/) { if (!TestRules(sWindow)) { return; } CString sPath; timeval curtime; gettimeofday(&curtime, nullptr); // Generate file name sPath = CUtils::FormatTime(curtime, m_sLogPath, GetUser()->GetTimezone()); if (sPath.empty()) { DEBUG("Could not format log path [" << sPath << "]"); return; } // TODO: Properly handle IRC case mapping // $WINDOW has to be handled last, since it can contain % sPath.Replace("$USER", CString((GetUser() ? GetUser()->GetUserName() : "UNKNOWN"))); sPath.Replace("$NETWORK", CString((GetNetwork() ? GetNetwork()->GetName() : "znc"))); sPath.Replace("$WINDOW", CString(sWindow.Replace_n("/", "-") .Replace_n("\\", "-")).AsLower()); // Check if it's allowed to write in this specific path sPath = CDir::CheckPathPrefix(GetSavePath(), sPath); if (sPath.empty()) { DEBUG("Invalid log path [" << m_sLogPath << "]."); return; } CFile LogFile(sPath); CString sLogDir = LogFile.GetDir(); struct stat ModDirInfo; CFile::GetInfo(GetSavePath(), ModDirInfo); if (!CFile::Exists(sLogDir)) CDir::MakeDir(sLogDir, ModDirInfo.st_mode); if (LogFile.Open(O_WRONLY | O_APPEND | O_CREAT)) { LogFile.Write(CUtils::FormatTime(curtime, m_sTimestamp, GetUser()->GetTimezone()) + " " + (m_bSanitize ? sLine.StripControls_n() : sLine) + "\n"); } else DEBUG("Could not open log file [" << sPath << "]: " << strerror(errno)); } void CLogMod::PutLog(const CString& sLine, const CChan& Channel) { PutLog(sLine, Channel.GetName()); } void CLogMod::PutLog(const CString& sLine, const CNick& Nick) { PutLog(sLine, Nick.GetNick()); } CString CLogMod::GetServer() { CServer* pServer = GetNetwork()->GetCurrentServer(); CString sSSL; if (!pServer) return "(no server)"; if (pServer->IsSSL()) sSSL = "+"; return pServer->GetName() + " " + sSSL + CString(pServer->GetPort()); } bool CLogMod::OnLoad(const CString& sArgs, CString& sMessage) { VCString vsArgs; sArgs.QuoteSplit(vsArgs); bool bReadingTimestamp = false; bool bHaveLogPath = false; for (CString& sArg : vsArgs) { if (bReadingTimestamp) { m_sTimestamp = sArg; bReadingTimestamp = false; } else if (sArg.Equals("-sanitize")) { m_bSanitize = true; } else if (sArg.Equals("-timestamp")) { bReadingTimestamp = true; } else { // Only one arg may be LogPath if (bHaveLogPath) { sMessage = t_f("Invalid args [{1}]. Only one log path allowed. Check " "that there are no spaces in the path.")(sArgs); return false; } m_sLogPath = sArg; bHaveLogPath = true; } } if (m_sTimestamp.empty()) { m_sTimestamp = "[%H:%M:%S]"; } // Add default filename to path if it's a folder if (GetType() == CModInfo::UserModule) { if (m_sLogPath.Right(1) == "/" || m_sLogPath.find("$WINDOW") == CString::npos || m_sLogPath.find("$NETWORK") == CString::npos) { if (!m_sLogPath.empty()) { m_sLogPath += "/"; } m_sLogPath += "$NETWORK/$WINDOW/%Y-%m-%d.log"; } } else if (GetType() == CModInfo::NetworkModule) { if (m_sLogPath.Right(1) == "/" || m_sLogPath.find("$WINDOW") == CString::npos) { if (!m_sLogPath.empty()) { m_sLogPath += "/"; } m_sLogPath += "$WINDOW/%Y-%m-%d.log"; } } else { if (m_sLogPath.Right(1) == "/" || m_sLogPath.find("$USER") == CString::npos || m_sLogPath.find("$WINDOW") == CString::npos || m_sLogPath.find("$NETWORK") == CString::npos) { if (!m_sLogPath.empty()) { m_sLogPath += "/"; } m_sLogPath += "$USER/$NETWORK/$WINDOW/%Y-%m-%d.log"; } } CString sRules = GetNV("rules"); VCString vsRules = SplitRules(sRules); SetRules(vsRules); // Check if it's allowed to write in this path in general m_sLogPath = CDir::CheckPathPrefix(GetSavePath(), m_sLogPath); if (m_sLogPath.empty()) { sMessage = t_f("Invalid log path [{1}]")(m_sLogPath); return false; } else { sMessage = t_f("Logging to [{1}]. Using timestamp format '{2}'")( m_sLogPath, m_sTimestamp); return true; } } // TODO consider writing translated strings to log. Currently user language // affects only UI. void CLogMod::OnIRCConnected() { PutLog("Connected to IRC (" + GetServer() + ")"); } void CLogMod::OnIRCDisconnected() { PutLog("Disconnected from IRC (" + GetServer() + ")"); } CModule::EModRet CLogMod::OnBroadcast(CString& sMessage) { PutLog("Broadcast: " + sMessage); return CONTINUE; } void CLogMod::OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) { const CString sNick = pOpNick ? pOpNick->GetNick() : "Server"; PutLog("*** " + sNick + " sets mode: " + sModes + " " + sArgs, Channel); } void CLogMod::OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) { PutLog("*** " + sKickedNick + " was kicked by " + OpNick.GetNick() + " (" + sMessage + ")", Channel); } void CLogMod::OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) { if (NeedQuits()) { for (CChan* pChan : vChans) PutLog("*** Quits: " + Nick.GetNick() + " (" + Nick.GetIdent() + "@" + Nick.GetHost() + ") (" + sMessage + ")", *pChan); } } CModule::EModRet CLogMod::OnSendToIRCMessage(CMessage& Message) { if (Message.GetType() != CMessage::Type::Quit) { return CONTINUE; } CIRCNetwork* pNetwork = Message.GetNetwork(); OnQuit(pNetwork->GetIRCNick(), Message.As().GetReason(), pNetwork->GetChans()); return CONTINUE; } void CLogMod::OnJoin(const CNick& Nick, CChan& Channel) { if (NeedJoins()) { PutLog("*** Joins: " + Nick.GetNick() + " (" + Nick.GetIdent() + "@" + Nick.GetHost() + ")", Channel); } } void CLogMod::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) { PutLog("*** Parts: " + Nick.GetNick() + " (" + Nick.GetIdent() + "@" + Nick.GetHost() + ") (" + sMessage + ")", Channel); } void CLogMod::OnNick(const CNick& OldNick, const CString& sNewNick, const vector& vChans) { if (NeedNickChanges()) { for (CChan* pChan : vChans) PutLog("*** " + OldNick.GetNick() + " is now known as " + sNewNick, *pChan); } } CModule::EModRet CLogMod::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { PutLog("*** " + Nick.GetNick() + " changes topic to '" + sTopic + "'", Channel); return CONTINUE; } /* notices */ CModule::EModRet CLogMod::OnUserNotice(CString& sTarget, CString& sMessage) { CIRCNetwork* pNetwork = GetNetwork(); if (pNetwork) { PutLog("-" + pNetwork->GetCurNick() + "- " + sMessage, sTarget); } return CONTINUE; } CModule::EModRet CLogMod::OnPrivNotice(CNick& Nick, CString& sMessage) { PutLog("-" + Nick.GetNick() + "- " + sMessage, Nick); return CONTINUE; } CModule::EModRet CLogMod::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { PutLog("-" + Nick.GetNick() + "- " + sMessage, Channel); return CONTINUE; } /* actions */ CModule::EModRet CLogMod::OnUserAction(CString& sTarget, CString& sMessage) { CIRCNetwork* pNetwork = GetNetwork(); if (pNetwork) { PutLog("* " + pNetwork->GetCurNick() + " " + sMessage, sTarget); } return CONTINUE; } CModule::EModRet CLogMod::OnPrivAction(CNick& Nick, CString& sMessage) { PutLog("* " + Nick.GetNick() + " " + sMessage, Nick); return CONTINUE; } CModule::EModRet CLogMod::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { PutLog("* " + Nick.GetNick() + " " + sMessage, Channel); return CONTINUE; } /* msgs */ CModule::EModRet CLogMod::OnUserMsg(CString& sTarget, CString& sMessage) { CIRCNetwork* pNetwork = GetNetwork(); if (pNetwork) { PutLog("<" + pNetwork->GetCurNick() + "> " + sMessage, sTarget); } return CONTINUE; } CModule::EModRet CLogMod::OnPrivMsg(CNick& Nick, CString& sMessage) { PutLog("<" + Nick.GetNick() + "> " + sMessage, Nick); return CONTINUE; } CModule::EModRet CLogMod::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { PutLog("<" + Nick.GetNick() + "> " + sMessage, Channel); return CONTINUE; } template <> void TModInfo(CModInfo& Info) { Info.AddType(CModInfo::NetworkModule); Info.AddType(CModInfo::GlobalModule); Info.SetHasArgs(true); Info.SetArgsHelpText( Info.t_s("[-sanitize] Optional path where to store logs.")); Info.SetWikiPage("log"); } USERMODULEDEFS(CLogMod, t_s("Writes IRC logs.")) znc-1.7.5/modules/savebuff.cpp0000644000175000017500000002754113542151610016526 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * Author: imaginos * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Buffer Saving thing, incase your shit goes out while your out * * Its only as secure as your shell, the encryption only offers a slightly * better solution then plain text. */ #define REQUIRESSL #include #include #include #include #include using std::set; using std::vector; #define LEGACY_VERIFICATION_TOKEN "::__:SAVEBUFF:__::" #define CHAN_VERIFICATION_TOKEN "::__:CHANBUFF:__::" #define QUERY_VERIFICATION_TOKEN "::__:QUERYBUFF:__::" // this is basically plain text, but so is having the pass in the command line // so *shrug* // you could at least do something kind of cool like a bunch of unprintable text #define CRYPT_LAME_PASS "::__:NOPASS:__::" #define CRYPT_ASK_PASS "--ask-pass" class CSaveBuff; class CSaveBuffJob : public CTimer { public: CSaveBuffJob(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {} ~CSaveBuffJob() override {} protected: void RunJob() override; }; class CSaveBuff : public CModule { public: MODCONSTRUCTOR(CSaveBuff) { m_bBootError = false; AddHelpCommand(); AddCommand("SetPass", t_d(""), t_d("Sets the password"), [=](const CString& sLine) { OnSetPassCommand(sLine); }); AddCommand("Replay", t_d(""), t_d("Replays the buffer"), [=](const CString& sLine) { OnReplayCommand(sLine); }); AddCommand("Save", "", t_d("Saves all buffers"), [=](const CString& sLine) { OnSaveCommand(sLine); }); } ~CSaveBuff() override { if (!m_bBootError) { SaveBuffersToDisk(); } } bool OnLoad(const CString& sArgs, CString& sMessage) override { if (sArgs == CRYPT_ASK_PASS) { char* pPass = getpass("Enter pass for savebuff: "); if (pPass) m_sPassword = CBlowfish::MD5(pPass); else { m_bBootError = true; sMessage = "Nothing retrieved from console. aborting"; } } else if (sArgs.empty()) m_sPassword = CBlowfish::MD5(CRYPT_LAME_PASS); else m_sPassword = CBlowfish::MD5(sArgs); AddTimer(new CSaveBuffJob( this, 60, 0, "SaveBuff", "Saves the current buffer to disk every 1 minute")); return (!m_bBootError); } bool OnBoot() override { CDir saveDir(GetSavePath()); for (CFile* pFile : saveDir) { CString sName; CString sBuffer; EBufferType eType = DecryptBuffer(pFile->GetLongName(), sBuffer, sName); switch (eType) { case InvalidBuffer: m_sPassword = ""; CUtils::PrintError("[" + GetModName() + ".so] Failed to Decrypt [" + pFile->GetLongName() + "]"); if (!sName.empty()) { PutUser(":***!znc@znc.in PRIVMSG " + sName + " :Failed to decrypt this buffer, did you " "change the encryption pass?"); } break; case ChanBuffer: if (CChan* pChan = GetNetwork()->FindChan(sName)) { BootStrap(pChan, sBuffer); } break; case QueryBuffer: if (CQuery* pQuery = GetNetwork()->AddQuery(sName)) { BootStrap(pQuery, sBuffer); } break; default: break; } } return true; } template void BootStrap(T* pTarget, const CString& sContent) { if (!pTarget->GetBuffer().IsEmpty()) return; // in this case the module was probably reloaded VCString vsLines; VCString::iterator it; sContent.Split("\n", vsLines); for (it = vsLines.begin(); it != vsLines.end(); ++it) { CString sLine(*it); sLine.Trim(); if (sLine[0] == '@' && it + 1 != vsLines.end()) { CString sTimestamp = sLine.Token(0); sTimestamp.TrimLeft("@"); timeval ts; ts.tv_sec = sTimestamp.Token(0, false, ",").ToLongLong(); ts.tv_usec = sTimestamp.Token(1, false, ",").ToLong(); CString sFormat = sLine.Token(1, true); CString sText(*++it); sText.Trim(); pTarget->AddBuffer(sFormat, sText, &ts); } else { // Old format, escape the line and use as is. pTarget->AddBuffer(_NAMEDFMT(sLine)); } } } void SaveBufferToDisk(const CBuffer& Buffer, const CString& sPath, const CString& sHeader) { CFile File(sPath); CString sContent = sHeader + "\n"; size_t uSize = Buffer.Size(); for (unsigned int uIdx = 0; uIdx < uSize; uIdx++) { const CBufLine& Line = Buffer.GetBufLine(uIdx); timeval ts = Line.GetTime(); sContent += "@" + CString(ts.tv_sec) + "," + CString(ts.tv_usec) + " " + Line.GetFormat() + "\n" + Line.GetText() + "\n"; } CBlowfish c(m_sPassword, BF_ENCRYPT); sContent = c.Crypt(sContent); if (File.Open(O_WRONLY | O_CREAT | O_TRUNC, 0600)) { File.Chmod(0600); File.Write(sContent); } File.Close(); } void SaveBuffersToDisk() { if (!m_sPassword.empty()) { set ssPaths; const vector& vChans = GetNetwork()->GetChans(); for (CChan* pChan : vChans) { CString sPath = GetPath(pChan->GetName()); SaveBufferToDisk(pChan->GetBuffer(), sPath, CHAN_VERIFICATION_TOKEN + pChan->GetName()); ssPaths.insert(sPath); } const vector& vQueries = GetNetwork()->GetQueries(); for (CQuery* pQuery : vQueries) { CString sPath = GetPath(pQuery->GetName()); SaveBufferToDisk(pQuery->GetBuffer(), sPath, QUERY_VERIFICATION_TOKEN + pQuery->GetName()); ssPaths.insert(sPath); } // cleanup leftovers ie. cleared buffers CDir saveDir(GetSavePath()); for (CFile* pFile : saveDir) { if (ssPaths.count(pFile->GetLongName()) == 0) { pFile->Delete(); } } } else { PutModule(t_s( "Password is unset usually meaning the decryption failed. You " "can setpass to the appropriate pass and things should start " "working, or setpass to a new pass and save to reinstantiate")); } } void OnSetPassCommand(const CString& sCmdLine) { CString sArgs = sCmdLine.Token(1, true); if (sArgs.empty()) sArgs = CRYPT_LAME_PASS; PutModule(t_f("Password set to [{1}]")(sArgs)); m_sPassword = CBlowfish::MD5(sArgs); } void OnModCommand(const CString& sCmdLine) override { CString sCommand = sCmdLine.Token(0); CString sArgs = sCmdLine.Token(1, true); if (sCommand.Equals("dumpbuff")) { // for testing purposes - hidden from help CString sFile; CString sName; if (DecryptBuffer(GetPath(sArgs), sFile, sName)) { VCString vsLines; sFile.Split("\n", vsLines); for (const CString& sLine : vsLines) { PutModule("[" + sLine.Trim_n() + "]"); } } PutModule("//!-- EOF " + sArgs); } else { HandleCommand(sCmdLine); } } void OnReplayCommand(const CString& sCmdLine) { CString sArgs = sCmdLine.Token(1, true); Replay(sArgs); PutModule(t_f("Replayed {1}")(sArgs)); } void OnSaveCommand(const CString& sCmdLine) { SaveBuffersToDisk(); PutModule("Done."); } void Replay(const CString& sBuffer) { CString sFile; CString sName; PutUser(":***!znc@znc.in PRIVMSG " + sBuffer + " :Buffer Playback..."); if (DecryptBuffer(GetPath(sBuffer), sFile, sName)) { VCString vsLines; sFile.Split("\n", vsLines); for (const CString& sLine : vsLines) { PutUser(sLine.Trim_n()); } } PutUser(":***!znc@znc.in PRIVMSG " + sBuffer + " :Playback Complete."); } CString GetPath(const CString& sTarget) const { CString sBuffer = GetUser()->GetUserName() + sTarget.AsLower(); CString sRet = GetSavePath(); sRet += "/" + CBlowfish::MD5(sBuffer, true); return (sRet); } CString FindLegacyBufferName(const CString& sPath) const { const vector& vChans = GetNetwork()->GetChans(); for (CChan* pChan : vChans) { const CString& sName = pChan->GetName(); if (GetPath(sName).Equals(sPath)) { return sName; } } return CString(); } private: bool m_bBootError; CString m_sPassword; enum EBufferType { InvalidBuffer = 0, EmptyBuffer, ChanBuffer, QueryBuffer }; EBufferType DecryptBuffer(const CString& sPath, CString& sBuffer, CString& sName) { CString sContent; sBuffer = ""; CFile File(sPath); if (sPath.empty() || !File.Open() || !File.ReadFile(sContent)) return EmptyBuffer; File.Close(); if (!sContent.empty()) { CBlowfish c(m_sPassword, BF_DECRYPT); sBuffer = c.Crypt(sContent); if (sBuffer.TrimPrefix(LEGACY_VERIFICATION_TOKEN)) { sName = FindLegacyBufferName(sPath); return ChanBuffer; } else if (sBuffer.TrimPrefix(CHAN_VERIFICATION_TOKEN)) { sName = sBuffer.FirstLine(); if (sBuffer.TrimLeft(sName + "\n")) return ChanBuffer; } else if (sBuffer.TrimPrefix(QUERY_VERIFICATION_TOKEN)) { sName = sBuffer.FirstLine(); if (sBuffer.TrimLeft(sName + "\n")) return QueryBuffer; } PutModule(t_f("Unable to decode Encrypted file {1}")(sPath)); return InvalidBuffer; } return EmptyBuffer; } }; void CSaveBuffJob::RunJob() { CSaveBuff* p = (CSaveBuff*)GetModule(); p->SaveBuffersToDisk(); } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("savebuff"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s( "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing")); } NETWORKMODULEDEFS(CSaveBuff, t_s("Stores channel and query buffers to disk, encrypted")) znc-1.7.5/modules/fail2ban.cpp0000644000175000017500000001765213542151610016405 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include class CFailToBanMod : public CModule { public: MODCONSTRUCTOR(CFailToBanMod) { AddHelpCommand(); AddCommand( "Timeout", t_d("[minutes]"), t_d("The number of minutes IPs are blocked after a failed login."), [=](const CString& sLine) { OnTimeoutCommand(sLine); }); AddCommand("Attempts", t_d("[count]"), t_d("The number of allowed failed login attempts."), [=](const CString& sLine) { OnAttemptsCommand(sLine); }); AddCommand("Ban", t_d(""), t_d("Ban the specified hosts."), [=](const CString& sLine) { OnBanCommand(sLine); }); AddCommand("Unban", t_d(""), t_d("Unban the specified hosts."), [=](const CString& sLine) { OnUnbanCommand(sLine); }); AddCommand("List", "", t_d("List banned hosts."), [=](const CString& sLine) { OnListCommand(sLine); }); } ~CFailToBanMod() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { CString sTimeout = sArgs.Token(0); CString sAttempts = sArgs.Token(1); unsigned int timeout = sTimeout.ToUInt(); if (sAttempts.empty()) m_uiAllowedFailed = 2; else m_uiAllowedFailed = sAttempts.ToUInt(); if (sArgs.empty()) { timeout = 1; } else if (timeout == 0 || m_uiAllowedFailed == 0 || !sArgs.Token(2, true).empty()) { sMessage = t_s("Invalid argument, must be the number of minutes IPs are " "blocked after a failed login and can be followed by " "number of allowed failed login attempts"); return false; } // SetTTL() wants milliseconds m_Cache.SetTTL(timeout * 60 * 1000); return true; } void OnPostRehash() override { m_Cache.Clear(); } void Add(const CString& sHost, unsigned int count) { m_Cache.AddItem(sHost, count, m_Cache.GetTTL()); } bool Remove(const CString& sHost) { return m_Cache.RemItem(sHost); } void OnTimeoutCommand(const CString& sCommand) { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied")); return; } CString sArg = sCommand.Token(1); if (!sArg.empty()) { unsigned int uTimeout = sArg.ToUInt(); if (uTimeout == 0) { PutModule(t_s("Usage: Timeout [minutes]")); } else { m_Cache.SetTTL(uTimeout * 60 * 1000); SetArgs(CString(m_Cache.GetTTL() / 60 / 1000) + " " + CString(m_uiAllowedFailed)); PutModule(t_f("Timeout: {1} min")(uTimeout)); } } else { PutModule(t_f("Timeout: {1} min")(m_Cache.GetTTL() / 60 / 1000)); } } void OnAttemptsCommand(const CString& sCommand) { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied")); return; } CString sArg = sCommand.Token(1); if (!sArg.empty()) { unsigned int uiAttempts = sArg.ToUInt(); if (uiAttempts == 0) { PutModule(t_s("Usage: Attempts [count]")); } else { m_uiAllowedFailed = uiAttempts; SetArgs(CString(m_Cache.GetTTL() / 60 / 1000) + " " + CString(m_uiAllowedFailed)); PutModule(t_f("Attempts: {1}")(uiAttempts)); } } else { PutModule(t_f("Attempts: {1}")(m_uiAllowedFailed)); } } void OnBanCommand(const CString& sCommand) { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied")); return; } CString sHosts = sCommand.Token(1, true); if (sHosts.empty()) { PutStatus(t_s("Usage: Ban ")); return; } VCString vsHosts; sHosts.Replace(",", " "); sHosts.Split(" ", vsHosts, false, "", "", true, true); for (const CString& sHost : vsHosts) { Add(sHost, 0); PutModule(t_f("Banned: {1}")(sHost)); } } void OnUnbanCommand(const CString& sCommand) { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied")); return; } CString sHosts = sCommand.Token(1, true); if (sHosts.empty()) { PutStatus(t_s("Usage: Unban ")); return; } VCString vsHosts; sHosts.Replace(",", " "); sHosts.Split(" ", vsHosts, false, "", "", true, true); for (const CString& sHost : vsHosts) { if (Remove(sHost)) { PutModule(t_f("Unbanned: {1}")(sHost)); } else { PutModule(t_f("Ignored: {1}")(sHost)); } } } void OnListCommand(const CString& sCommand) { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied")); return; } CTable Table; Table.AddColumn(t_s("Host", "list")); Table.AddColumn(t_s("Attempts", "list")); for (const auto& it : m_Cache.GetItems()) { Table.AddRow(); Table.SetCell(t_s("Host", "list"), it.first); Table.SetCell(t_s("Attempts", "list"), CString(it.second)); } if (Table.empty()) { PutModule(t_s("No bans", "list")); } else { PutModule(Table); } } void OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) override { unsigned int* pCount = m_Cache.GetItem(sHost); if (sHost.empty() || pCount == nullptr || *pCount < m_uiAllowedFailed) { return; } // refresh their ban Add(sHost, *pCount); pClient->Write( "ERROR :Closing link [Please try again later - reconnecting too " "fast]\r\n"); pClient->Close(Csock::CLT_AFTERWRITE); } void OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) override { unsigned int* pCount = m_Cache.GetItem(sRemoteIP); if (pCount) Add(sRemoteIP, *pCount + 1); else Add(sRemoteIP, 1); } EModRet OnLoginAttempt(std::shared_ptr Auth) override { // e.g. webadmin ends up here const CString& sRemoteIP = Auth->GetRemoteIP(); if (sRemoteIP.empty()) return CONTINUE; unsigned int* pCount = m_Cache.GetItem(sRemoteIP); if (pCount && *pCount >= m_uiAllowedFailed) { // OnFailedLogin() will refresh their ban Auth->RefuseLogin("Please try again later - reconnecting too fast"); return HALT; } return CONTINUE; } private: TCacheMap m_Cache; unsigned int m_uiAllowedFailed{}; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("fail2ban"); Info.SetHasArgs(true); Info.SetArgsHelpText( Info.t_s("You might enter the time in minutes for the IP banning and " "the number of failed logins before any action is taken.")); } GLOBALMODULEDEFS(CFailToBanMod, t_s("Block IPs for some time after a failed login.")) znc-1.7.5/modules/modpython/0000755000175000017500000000000013542151637016242 5ustar somebodysomebodyznc-1.7.5/modules/modpython/Makefile.inc0000644000175000017500000000562213542151610020446 0ustar somebodysomebody# vim: filetype=make ifeq "$(PYTHON_ON)" "yes" PYTHONCOMMON := $(PY_CFLAGS) PYTHONCOMMON += -DSWIG_TYPE_TABLE=znc # Could someone fix all of these in swig / python, please? PYTHONCOMMON += -Wno-missing-field-initializers -Wno-unused -Wno-shadow PYTHONCOMMON += -Wno-missing-declarations -Wno-uninitialized -Wno-switch-enum PYTHONCOMMON += -Wno-redundant-decls modpythonCXXFLAGS := $(PYTHONCOMMON) -I. modpythonLDFLAGS := $(PY_LDFLAGS) ifeq "${ISCYGWIN}" "1" PYCEXT_EXT := dll PYDEPONMOD := ./modpython.so else PYCEXT_EXT := so PYDEPONMOD := endif PYTHONHOOK := modpython_install CLEAN += modpython/_znc_core.$(PYCEXT_EXT) CLEAN += modpython/_znc_core.o modpython/compiler.o ifneq "$(SWIG)" "" # Only delete these files if we can regenerate them CLEAN += modpython/modpython_biglib.cpp modpython/znc_core.py CLEAN += modpython/swigpyrun.h modpython/pyfunctions.cpp endif ifneq "$(srcdir)" "." # Copied from source for out-of-tree builds CLEAN += modpython/znc.py endif else FILES := $(shell echo $(FILES) | sed -e "s/modpython//") endif .PHONY: modpython_install modpython_all install: $(PYTHONHOOK) ifeq "$(PYTHON_ON)" "yes" all: modpython_all endif modpython_all: modpython/_znc_core.$(PYCEXT_EXT) modpython/_znc_core.o: modpython/modpython_biglib.cpp Makefile @mkdir -p modpython @mkdir -p .depend $(E) Building ZNC python bindings library... $(Q)$(CXX) $(MODFLAGS) -I$(srcdir) -MD -MF .depend/modpython.library.dep $(PYTHONCOMMON) -o $@ $< -c modpython/_znc_core.$(PYCEXT_EXT): modpython/_znc_core.o Makefile modpython.so $(E) Linking ZNC python bindings library... $(Q)$(CXX) $(MODFLAGS) $(LDFLAGS) $(MODLINK) -o $@ $< $(PY_LDFLAGS) $(PYDEPONMOD) $(LIBS) ifneq "$(SWIG)" "" include $(srcdir)/modpython/Makefile.gen else modpython/swigpyrun.h modpython/znc_core.py modpython/pyfunctions.cpp: modpython/modpython_biglib.cpp modpython/modpython_biglib.cpp: modpython/generated.tar.gz @mkdir -p modpython $(E) Unpacking ZNC python bindings... $(Q)tar -xf $^ -C modpython endif modpython.o: modpython/pyfunctions.cpp modpython/swigpyrun.h modpython/compiler.o: modpython/compiler.cpp Makefile @mkdir -p modpython @mkdir -p .depend $(E) Building optimizer for python files... $(Q)$(CXX) $(PYTHONCOMMON) -o $@ $< -c -MD -MF .depend/modpython.compiler.dep modpython/compiler: modpython/compiler.o Makefile $(E) Linking optimizer for python files... $(Q)$(CXX) -o $@ $< $(PY_LDFLAGS) modpython_install: install_datadir modpython_all -for i in $(srcdir)/*.py; do \ $(INSTALL_DATA) $$i $(DESTDIR)$(MODDIR); \ done mkdir -p $(DESTDIR)$(MODDIR)/modpython $(INSTALL_PROGRAM) modpython/_znc_core.$(PYCEXT_EXT) $(DESTDIR)$(MODDIR)/modpython if test -r modpython/znc_core.py;\ then $(INSTALL_DATA) modpython/znc_core.py $(DESTDIR)$(MODDIR)/modpython;\ else $(INSTALL_DATA) $(srcdir)/modpython/znc_core.py $(DESTDIR)$(MODDIR)/modpython;\ fi $(INSTALL_DATA) $(srcdir)/modpython/znc.py $(DESTDIR)$(MODDIR)/modpython znc-1.7.5/modules/modpython/modpython.i0000644000175000017500000002217713542151610020435 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ %module znc_core %{ #include #include "znc/Utils.h" #include "znc/Threads.h" #include "znc/Config.h" #include "znc/Socket.h" #include "znc/Modules.h" #include "znc/Nick.h" #include "znc/Chan.h" #include "znc/User.h" #include "znc/IRCNetwork.h" #include "znc/Query.h" #include "znc/Client.h" #include "znc/IRCSock.h" #include "znc/Listener.h" #include "znc/HTTPSock.h" #include "znc/Template.h" #include "znc/WebModules.h" #include "znc/znc.h" #include "znc/Server.h" #include "znc/ZNCString.h" #include "znc/FileUtils.h" #include "znc/ZNCDebug.h" #include "znc/ExecSock.h" #include "znc/Buffer.h" #include "modpython/module.h" #include "modpython/ret.h" #define stat struct stat using std::allocator; %} %apply long { off_t }; %apply long { uint16_t }; %apply long { uint32_t }; %apply long { uint64_t }; // Just makes generated python code slightly more beautiful. %feature("python:defaultargs"); // Probably can be removed when swig is fixed to not produce bad code for some cases %feature("python:defaultargs", "0") CDir::MakeDir; // 0700 doesn't work in python3 %feature("python:defaultargs", "0") CUtils::GetNumInput; // SyntaxError: non-default argument follows default argument %feature("python:defaultargs", "0") CModules::GetAvailableMods; // NameError: name 'UserModule' is not defined %feature("python:defaultargs", "0") CModules::GetDefaultMods; // NameError: name 'UserModule' is not defined %begin %{ #include "znc/zncconfig.h" %} %include %include %include %include %include %include %include %shared_ptr(CAuthBase); %shared_ptr(CWebSession); %shared_ptr(CClientAuth); %include "modpython/cstring.i" %template(_stringlist) std::list; %typemap(out) CModules::ModDirList %{ $result = PyList_New($1.size()); if ($result) { for (size_t i = 0; !$1.empty(); $1.pop(), ++i) { PyList_SetItem($result, i, Py_BuildValue("ss", $1.front().first.c_str(), $1.front().second.c_str())); } } %} %template(VIRCNetworks) std::vector; %template(VChannels) std::vector; %template(MNicks) std::map; %template(SModInfo) std::set; %template(SCString) std::set; typedef std::set SCString; %template(VCString) std::vector; typedef std::vector VCString; %template(PyMCString) std::map; %template(PyMStringVString) std::map; class MCString : public std::map {}; %template(PyModulesVector) std::vector; %template(VListeners) std::vector; %template(BufLines) std::deque; %template(VVString) std::vector; %template(VClients) std::vector; %template(VServers) std::vector; %template(VQueries) std::vector; #define REGISTER_ZNC_MESSAGE(M) \ %template(As_ ## M) CMessage::As; %typemap(in) CString& { String* p; int res = SWIG_IsOK(SWIG_ConvertPtr($input, (void**)&p, SWIG_TypeQuery("String*"), 0)); if (SWIG_IsOK(res)) { $1 = &p->s; } else { SWIG_exception_fail(SWIG_ArgError(res), "need znc.String object as argument $argnum $1_name"); } } %typemap(out) CString&, CString* { if ($1) { $result = CPyRetString::wrap(*$1); } else { $result = Py_None; Py_INCREF(Py_None); } } %typemap(typecheck) CString&, CString* { String* p; $1 = SWIG_IsOK(SWIG_ConvertPtr($input, (void**)&p, SWIG_TypeQuery("String*"), 0)); } /*TODO %typemap(in) bool& to be able to call from python functions which get bool& */ %typemap(out) bool&, bool* { if ($1) { $result = CPyRetBool::wrap(*$1); } else { $result = Py_None; Py_INCREF(Py_None); } } #define u_short unsigned short #define u_int unsigned int #include "znc/zncconfig.h" #include "znc/ZNCString.h" %include "znc/defines.h" %include "znc/Translation.h" %include "znc/Utils.h" %include "znc/Threads.h" %include "znc/Config.h" %include "znc/Csocket.h" %template(ZNCSocketManager) TSocketManager; %include "znc/Socket.h" %include "znc/FileUtils.h" %include "znc/Message.h" %include "znc/Modules.h" %include "znc/Nick.h" %include "znc/Chan.h" %include "znc/User.h" %include "znc/IRCNetwork.h" %include "znc/Query.h" %include "znc/Client.h" %include "znc/IRCSock.h" %include "znc/Listener.h" %include "znc/HTTPSock.h" %include "znc/Template.h" %include "znc/WebModules.h" %include "znc/znc.h" %include "znc/Server.h" %include "znc/ZNCDebug.h" %include "znc/ExecSock.h" %include "znc/Buffer.h" %include "modpython/module.h" /* Really it's CString& inside, but SWIG shouldn't know that :) */ class CPyRetString { CPyRetString(); public: CString s; }; %extend CPyRetString { CString __str__() { return $self->s; } }; %extend String { CString __str__() { return $self->s; } }; class CPyRetBool { CPyRetBool(); public: bool b; }; %extend CPyRetBool { bool __bool__() { return $self->b; } } %extend Csock { PyObject* WriteBytes(PyObject* data) { if (!PyBytes_Check(data)) { PyErr_SetString(PyExc_TypeError, "socket.WriteBytes needs bytes as argument"); return nullptr; } char* buffer; Py_ssize_t length; if (-1 == PyBytes_AsStringAndSize(data, &buffer, &length)) { return nullptr; } if ($self->Write(buffer, length)) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } } %extend CModule { CString __str__() { return $self->GetModName(); } MCString_iter BeginNV_() { return MCString_iter($self->BeginNV()); } bool ExistsNV(const CString& sName) { return $self->EndNV() != $self->FindNV(sName); } } %extend CModules { bool removeModule(CModule* p) { for (CModules::iterator i = $self->begin(); $self->end() != i; ++i) { if (*i == p) { $self->erase(i); return true; } } return false; } } %extend CUser { CString __str__() { return $self->GetUserName(); } CString __repr__() { return "GetUserName() + ">"; } std::vector GetNetworks_() { return $self->GetNetworks(); } }; %extend CIRCNetwork { CString __str__() { return $self->GetName(); } CString __repr__() { return "GetName() + ">"; } std::vector GetChans_() { return $self->GetChans(); } std::vector GetServers_() { return $self->GetServers(); } std::vector GetQueries_() { return $self->GetQueries(); } } %extend CChan { CString __str__() { return $self->GetName(); } CString __repr__() { return "GetName() + ">"; } std::map GetNicks_() { return $self->GetNicks(); } }; %extend CNick { CString __str__() { return $self->GetNick(); } CString __repr__() { return "GetHostMask() + ">"; } }; %extend CMessage { CString __str__() { return $self->ToString(); } CString __repr__() { return $self->ToString(); } }; %extend CZNC { PyObject* GetUserMap_() { PyObject* result = PyDict_New(); auto user_type = SWIG_TypeQuery("CUser*"); for (const auto& p : $self->GetUserMap()) { PyObject* user = SWIG_NewInstanceObj(p.second, user_type, 0); PyDict_SetItemString(result, p.first.c_str(), user); Py_CLEAR(user); } return result; } }; /* To allow module-loaders to be written on python. * They can call CreatePyModule() to create CModule* object, but one of arguments to CreatePyModule() is "CModule* pModPython" * Pointer to modpython is already accessible to python modules as self.GetModPython(), but it's just a pointer to something, not to CModule*. * So make it known that CModPython is really a CModule. */ class CModPython : public CModule { private: CModPython(); CModPython(const CModPython&); ~CModPython(); }; /* Web */ %template(StrPair) std::pair; %template(VPair) std::vector >; typedef std::vector > VPair; %template(VWebSubPages) std::vector; %inline %{ void VPair_Add2Str_(VPair* self, const CString& a, const CString& b) { self->push_back(std::make_pair(a, b)); } %} %extend CTemplate { void set(const CString& key, const CString& value) { DEBUG("WARNING: modpython's CTemplate.set is deprecated and will be removed. Use normal dict's operations like Tmpl['foo'] = 'bar'"); (*$self)[key] = value; } } %inline %{ TWebSubPage CreateWebSubPage_(const CString& sName, const CString& sTitle, const VPair& vParams, unsigned int uFlags) { return std::make_shared(sName, sTitle, vParams, uFlags); } %} /* vim: set filetype=cpp: */ znc-1.7.5/modules/modpython/CMakeLists.txt0000644000175000017500000000745013542151610020777 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # TODO: consider switching to swig_add_library() after bumping CMake # requirements to 3.8, when that command started using IMPLICIT_DEPENDS set(modinclude_modpython PUBLIC ${PYTHON_INCLUDE_DIRS} "${CMAKE_CURRENT_BINARY_DIR}/.." PARENT_SCOPE) set(modlink_modpython PUBLIC ${PYTHON_LDFLAGS} PARENT_SCOPE) set(moddef_modpython PUBLIC "SWIG_TYPE_TABLE=znc" PARENT_SCOPE) set(moddepend_modpython modpython_functions modpython_swigruntime PARENT_SCOPE) if(APPLE) set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS "${CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS} -undefined dynamic_lookup") endif() if(SWIG_FOUND) add_custom_command( OUTPUT "pyfunctions.cpp" COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl" "${CMAKE_CURRENT_SOURCE_DIR}/functions.in" "pyfunctions.cpp" VERBATIM DEPENDS codegen.pl functions.in) add_custom_command( OUTPUT "swigpyrun.h" COMMAND "${SWIG_EXECUTABLE}" -python -py3 -c++ -shadow -external-runtime "swigpyrun.h" VERBATIM) add_custom_command( OUTPUT "modpython_biglib.cpp" "znc_core.py" COMMAND "${SWIG_EXECUTABLE}" -python -py3 -c++ -shadow "-I${PROJECT_BINARY_DIR}/include" "-I${PROJECT_SOURCE_DIR}/include" "-I${CMAKE_CURRENT_SOURCE_DIR}/.." -DZNC_EXPORT_LIB_EXPORT -outdir "${CMAKE_CURRENT_BINARY_DIR}" -o "${CMAKE_CURRENT_BINARY_DIR}/modpython_biglib.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/modpython.i" DEPENDS "modpython.i" copy_csocket_h IMPLICIT_DEPENDS CXX "${CMAKE_CURRENT_SOURCE_DIR}/modpython.i" VERBATIM) else() add_custom_command( OUTPUT swigpyrun.h znc_core.py modpython_biglib.cpp pyfunctions.cpp COMMAND "${CMAKE_COMMAND}" -E tar xz "${CMAKE_CURRENT_SOURCE_DIR}/generated.tar.gz" VERBATIM) endif() add_custom_target(modpython_functions DEPENDS "pyfunctions.cpp") add_custom_target(modpython_swigruntime DEPENDS "swigpyrun.h") add_custom_target(modpython_swig DEPENDS "modpython_biglib.cpp" "znc_core.py") znc_add_library(modpython_lib MODULE modpython_biglib.cpp) add_dependencies(modpython_lib modpython_swig) target_include_directories(modpython_lib PRIVATE "${PROJECT_BINARY_DIR}/include" "${PROJECT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/.." "${CMAKE_CURRENT_SOURCE_DIR}/.." ${PYTHON_INCLUDE_DIRS}) target_link_libraries(modpython_lib ${znc_link} ${PYTHON_LDFLAGS}) set_target_properties(modpython_lib PROPERTIES PREFIX "_" OUTPUT_NAME "znc_core" NO_SONAME true) target_compile_definitions(modpython_lib PRIVATE "SWIG_TYPE_TABLE=znc") if(CYGWIN) target_link_libraries(modpython_lib module_modpython) endif() install(TARGETS modpython_lib LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/znc/modpython") install(FILES "znc.py" "${CMAKE_CURRENT_BINARY_DIR}/znc_core.py" DESTINATION "${CMAKE_INSTALL_LIBDIR}/znc/modpython") function(add_python_module mod modpath) install(FILES "${modpath}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/znc") endfunction() # This target is used to generate tarball which doesn't depend on SWIG. add_custom_target(modpython_dist COMMAND "${CMAKE_COMMAND}" -E tar cz "${CMAKE_CURRENT_SOURCE_DIR}/generated.tar.gz" "swigpyrun.h" "znc_core.py" "modpython_biglib.cpp" "pyfunctions.cpp" DEPENDS swigpyrun.h znc_core.py modpython_biglib.cpp pyfunctions.cpp VERBATIM) add_dependencies(modpython_dist copy_csocket_h) znc-1.7.5/modules/modpython/functions.in0000644000175000017500000001455413542151610020602 0ustar somebodysomebodybool OnBoot() bool WebRequiresLogin() bool WebRequiresAdmin() CString GetWebMenuTitle() bool OnWebPreRequest(CWebSock& WebSock, const CString& sPageName) bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) bool ValidateWebRequestCSRFCheck(CWebSock& WebSock, const CString& sPageName) VWebSubPages* _GetSubPages()=nullptr void OnPreRehash() void OnPostRehash() void OnIRCDisconnected() void OnIRCConnected() EModRet OnIRCConnecting(CIRCSock *pIRCSock) void OnIRCConnectionError(CIRCSock *pIRCSock) EModRet OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) EModRet OnBroadcast(CString& sMessage) void OnChanPermission2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) void OnOp2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) void OnDeop2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) void OnVoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) void OnDevoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) void OnMode2(const CNick* pOpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) void OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) EModRet OnRaw(CString& sLine) EModRet OnStatusCommand(CString& sCommand) void OnModCommand(const CString& sCommand) void OnModNotice(const CString& sMessage) void OnModCTCP(const CString& sMessage) void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) void OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans) void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) EModRet OnJoining(CChan& Channel) void OnJoin(const CNick& Nick, CChan& Channel) void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) EModRet OnInvite(const CNick& Nick, const CString& sChan) EModRet OnChanBufferStarting(CChan& Chan, CClient& Client) EModRet OnChanBufferEnding(CChan& Chan, CClient& Client) EModRet OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) EModRet OnPrivBufferPlayLine(CClient& Client, CString& sLine) void OnClientLogin() void OnClientDisconnect() EModRet OnUserRaw(CString& sLine) EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage) EModRet OnUserCTCP(CString& sTarget, CString& sMessage) EModRet OnUserAction(CString& sTarget, CString& sMessage) EModRet OnUserMsg(CString& sTarget, CString& sMessage) EModRet OnUserNotice(CString& sTarget, CString& sMessage) EModRet OnUserJoin(CString& sChannel, CString& sKey) EModRet OnUserPart(CString& sChannel, CString& sMessage) EModRet OnUserTopic(CString& sChannel, CString& sTopic) EModRet OnUserTopicRequest(CString& sChannel) EModRet OnUserQuit(CString& sMessage) EModRet OnCTCPReply(CNick& Nick, CString& sMessage) EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) EModRet OnPrivAction(CNick& Nick, CString& sMessage) EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) EModRet OnPrivMsg(CNick& Nick, CString& sMessage) EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) EModRet OnPrivNotice(CNick& Nick, CString& sMessage) EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) bool OnServerCapAvailable(const CString& sCap) void OnServerCapResult(const CString& sCap, bool bSuccess) EModRet OnTimerAutoJoin(CChan& Channel) bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) EModRet OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet) EModRet OnDeleteNetwork(CIRCNetwork& Network) EModRet OnSendToClient(CString& sLine, CClient& Client) EModRet OnSendToIRC(CString& sLine) EModRet OnRawMessage(CMessage& Message) EModRet OnNumericMessage(CNumericMessage& Message) void OnQuitMessage(CQuitMessage& Message, const std::vector& vChans) void OnNickMessage(CNickMessage& Message, const std::vector& vChans) void OnKickMessage(CKickMessage& Message) void OnJoinMessage(CJoinMessage& Message) void OnPartMessage(CPartMessage& Message) EModRet OnChanBufferPlayMessage(CMessage& Message) EModRet OnPrivBufferPlayMessage(CMessage& Message) EModRet OnUserRawMessage(CMessage& Message) EModRet OnUserCTCPReplyMessage(CCTCPMessage& Message) EModRet OnUserCTCPMessage(CCTCPMessage& Message) EModRet OnUserActionMessage(CActionMessage& Message) EModRet OnUserTextMessage(CTextMessage& Message) EModRet OnUserNoticeMessage(CNoticeMessage& Message) EModRet OnUserJoinMessage(CJoinMessage& Message) EModRet OnUserPartMessage(CPartMessage& Message) EModRet OnUserTopicMessage(CTopicMessage& Message) EModRet OnUserQuitMessage(CQuitMessage& Message) EModRet OnCTCPReplyMessage(CCTCPMessage& Message) EModRet OnPrivCTCPMessage(CCTCPMessage& Message) EModRet OnChanCTCPMessage(CCTCPMessage& Message) EModRet OnPrivActionMessage(CActionMessage& Message) EModRet OnChanActionMessage(CActionMessage& Message) EModRet OnPrivTextMessage(CTextMessage& Message) EModRet OnChanTextMessage(CTextMessage& Message) EModRet OnPrivNoticeMessage(CNoticeMessage& Message) EModRet OnChanNoticeMessage(CNoticeMessage& Message) EModRet OnTopicMessage(CTopicMessage& Message) EModRet OnSendToClientMessage(CMessage& Message) EModRet OnSendToIRCMessage(CMessage& Message) EModRet OnAddUser(CUser& User, CString& sErrorRet) EModRet OnDeleteUser(CUser& User) void OnClientConnect(CZNCSock* pSock, const CString& sHost, unsigned short uPort) void OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) EModRet OnUnknownUserRaw(CClient* pClient, CString& sLine) EModRet OnUnknownUserRawMessage(CMessage& Message) bool IsClientCapSupported(CClient* pClient, const CString& sCap, bool bState) void OnClientCapRequest(CClient* pClient, const CString& sCap, bool bState) EModRet OnModuleLoading(const CString& sModName, const CString& sArgs, CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) EModRet OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) EModRet OnGetModInfo(CModInfo& ModInfo, const CString& sModule, bool& bSuccess, CString& sRetMsg) void OnGetAvailableMods(std::set& ssMods, CModInfo::EModuleType eType) void OnClientCapLs(CClient* pClient, SCString& ssCaps) EModRet OnLoginAttempt(std::shared_ptr Auth) znc-1.7.5/modules/modpython/znc.py0000644000175000017500000006477413542151610017417 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # _cov = None import os if os.environ.get('ZNC_MODPYTHON_COVERAGE'): import coverage _cov = coverage.Coverage(auto_data=True, branch=True) _cov.start() from functools import wraps import imp import re import traceback import collections from znc_core import * class Socket: ADDR_MAP = { 'ipv4': ADDR_IPV4ONLY, 'ipv6': ADDR_IPV6ONLY, 'all': ADDR_ALL } def _Accepted(self, host, port): return getattr(self.OnAccepted(host, port), '_csock', None) def GetModule(self): return AsPyModule(self._csock.GetModule()).GetNewPyObj() def Listen(self, addrtype='all', port=None, bindhost='', ssl=False, maxconns=GetSOMAXCONN(), timeout=0): try: addr = self.ADDR_MAP[addrtype.lower()] except KeyError: raise ValueError( "Specified addrtype [{0}] isn't supported".format(addrtype)) args = ( "python socket for {0}".format(self.GetModule()), bindhost, ssl, maxconns, self._csock, timeout, addr ) if port is None: return self.GetModule().GetManager().ListenRand(*args) if self.GetModule().GetManager().ListenHost(port, *args): return port return 0 def Connect(self, host, port, timeout=60, ssl=False, bindhost=''): return self.GetModule().GetManager().Connect( host, port, 'python conn socket for {0}'.format(self.GetModule()), timeout, ssl, bindhost, self._csock ) def Write(self, data): if (isinstance(data, str)): return self._csock.Write(data) raise TypeError( 'socket.Write needs str. If you want binary data, use WriteBytes') def Init(self, *a, **b): pass def OnConnected(self): pass def OnDisconnected(self): pass def OnTimeout(self): pass def OnConnectionRefused(self): pass def OnReadData(self, bytess): pass def OnReadLine(self, line): pass def OnAccepted(self, host, port): pass def OnShutdown(self): pass class Timer: def GetModule(self): return AsPyModule(self._ctimer.GetModule()).GetNewPyObj() def RunJob(self): pass def OnShutdown(self): pass class ModuleNVIter(collections.Iterator): def __init__(self, cmod): self._cmod = cmod self.it = cmod.BeginNV_() def __next__(self): if self.it.is_end(self._cmod): raise StopIteration res = self.it.get() self.it.plusplus() return res class ModuleNV(collections.MutableMapping): def __init__(self, cmod): self._cmod = cmod def __setitem__(self, key, value): self._cmod.SetNV(key, value) def __getitem__(self, key): if not self._cmod.ExistsNV(key): raise KeyError return self._cmod.GetNV(key) def __contains__(self, key): return self._cmod.ExistsNV(key) def __delitem__(self, key): self._cmod.DelNV(key) def keys(self): return ModuleNVIter(self._cmod) __iter__ = keys def __len__(self): raise NotImplemented class Module: description = '< Placeholder for a description >' module_types = [CModInfo.NetworkModule] wiki_page = '' has_args = False args_help_text = '' def __str__(self): return self.GetModName() @classmethod def t_s(cls, english, context=''): domain = 'znc-' + cls.__name__ return CTranslation.Get().Singular(domain, context, english) @classmethod def t_f(cls, english, context=''): fmt = cls.t_s(english, context) # Returning bound method return fmt.format @classmethod def t_p(cls, english, englishes, num, context=''): domain = 'znc-' + cls.__name__ fmt = CTranslation.Get().Plural(domain, context, english, englishes, num) return fmt.format # TODO is "t_d" needed for python? Maybe after AddCommand is implemented def OnLoad(self, sArgs, sMessage): return True def _GetSubPages(self): return self.GetSubPages() def CreateSocket(self, socketclass=Socket, *the, **rest): socket = socketclass() socket._csock = CreatePySocket(self._cmod, socket) socket.Init(*the, **rest) return socket def CreateTimer(self, timer, interval=10, cycles=1, label='pytimer', description='Some python timer'): t = timer() t._ctimer = CreatePyTimer(self._cmod, interval, cycles, label, description, t) return t def GetSubPages(self): pass def OnShutdown(self): pass def OnBoot(self): pass def WebRequiresLogin(self): pass def WebRequiresAdmin(self): pass def GetWebMenuTitle(self): pass def OnWebPreRequest(self, WebSock, sPageName): pass def OnWebRequest(self, WebSock, sPageName, Tmpl): pass def OnPreRehash(self): pass def OnPostRehash(self): pass def OnIRCDisconnected(self): pass def OnIRCConnected(self): pass def OnIRCConnecting(self, IRCSock): pass def OnIRCConnectionError(self, IRCSock): pass def OnIRCRegistration(self, sPass, sNick, sIdent, sRealName): pass def OnBroadcast(self, sMessage): pass def OnChanPermission(self, OpNick, Nick, Channel, uMode, bAdded, bNoChange): pass def OnOp(self, OpNick, Nick, Channel, bNoChange): pass def OnDeop(self, OpNick, Nick, Channel, bNoChange): pass def OnVoice(self, OpNick, Nick, Channel, bNoChange): pass def OnDevoice(self, OpNick, Nick, Channel, bNoChange): pass def OnMode(self, OpNick, Channel, uMode, sArg, bAdded, bNoChange): pass def OnRawMode(self, OpNick, Channel, sModes, sArgs): pass def OnRaw(self, sLine): pass def OnStatusCommand(self, sCommand): pass def OnModCommand(self, sCommand): pass def OnModNotice(self, sMessage): pass def OnModCTCP(self, sMessage): pass def OnQuit(self, Nick, sMessage, vChans): pass def OnNick(self, Nick, sNewNick, vChans): pass def OnKick(self, OpNick, sKickedNick, Channel, sMessage): pass def OnJoining(self, Channel): pass def OnJoin(self, Nick, Channel): pass def OnPart(self, Nick, Channel, sMessage=None): pass def OnInvite(self, Nick, sChan): pass def OnChanBufferStarting(self, Chan, Client): pass def OnChanBufferEnding(self, Chan, Client): pass def OnChanBufferPlayLine(self, Chan, Client, sLine): pass def OnPrivBufferPlayLine(self, Client, sLine): pass def OnClientLogin(self): pass def OnClientDisconnect(self): pass def OnUserRaw(self, sLine): pass def OnUserCTCPReply(self, sTarget, sMessage): pass def OnUserCTCP(self, sTarget, sMessage): pass def OnUserAction(self, sTarget, sMessage): pass def OnUserMsg(self, sTarget, sMessage): pass def OnUserNotice(self, sTarget, sMessage): pass def OnUserJoin(self, sChannel, sKey): pass def OnUserPart(self, sChannel, sMessage): pass def OnUserTopic(self, sChannel, sTopic): pass def OnUserTopicRequest(self, sChannel): pass def OnUserQuit(self, sMessage): pass def OnCTCPReply(self, Nick, sMessage): pass def OnPrivCTCP(self, Nick, sMessage): pass def OnChanCTCP(self, Nick, Channel, sMessage): pass def OnPrivAction(self, Nick, sMessage): pass def OnChanAction(self, Nick, Channel, sMessage): pass def OnPrivMsg(self, Nick, sMessage): pass def OnChanMsg(self, Nick, Channel, sMessage): pass def OnPrivNotice(self, Nick, sMessage): pass def OnChanNotice(self, Nick, Channel, sMessage): pass def OnTopic(self, Nick, Channel, sTopic): pass def OnServerCapAvailable(self, sCap): pass def OnServerCapResult(self, sCap, bSuccess): pass def OnTimerAutoJoin(self, Channel): pass def OnEmbeddedWebRequest(self, WebSock, sPageName, Tmpl): pass def OnAddNetwork(self, Network, sErrorRet): pass def OnDeleteNetwork(self, Network): pass def OnSendToClient(self, sLine, Client): pass def OnSendToIRC(self, sLine): pass # Global modules def OnAddUser(self, User, sErrorRet): pass def OnDeleteUser(self, User): pass def OnClientConnect(self, pSock, sHost, uPort): pass def OnLoginAttempt(self, Auth): pass def OnFailedLogin(self, sUsername, sRemoteIP): pass def OnUnknownUserRaw(self, pClient, sLine): pass def OnClientCapLs(self, pClient, ssCaps): pass def IsClientCapSupported(self, pClient, sCap, bState): pass def OnClientCapRequest(self, pClient, sCap, bState): pass def OnModuleLoading(self, sModName, sArgs, eType, bSuccess, sRetMsg): pass def OnModuleUnloading(self, pModule, bSuccess, sRetMsg): pass def OnGetModInfo(self, ModInfo, sModule, bSuccess, sRetMsg): pass def OnGetAvailableMods(self, ssMods, eType): pass # In python None is allowed value, so python modules may continue using OnMode and not OnMode2 def OnChanPermission2(self, OpNick, Nick, Channel, uMode, bAdded, bNoChange): return self.OnChanPermission(OpNick, Nick, Channel, uMode, bAdded, bNoChange) def OnOp2(self, OpNick, Nick, Channel, bNoChange): return self.OnOp(OpNick, Nick, Channel, bNoChange) def OnDeop2(self, OpNick, Nick, Channel, bNoChange): return self.OnDeop(OpNick, Nick, Channel, bNoChange) def OnVoice2(self, OpNick, Nick, Channel, bNoChange): return self.OnVoice(OpNick, Nick, Channel, bNoChange) def OnDevoice2(self, OpNick, Nick, Channel, bNoChange): return self.OnDevoice(OpNick, Nick, Channel, bNoChange) def OnMode2(self, OpNick, Channel, uMode, sArg, bAdded, bNoChange): return self.OnMode(OpNick, Channel, uMode, sArg, bAdded, bNoChange) def OnRawMode2(self, OpNick, Channel, sModes, sArgs): return self.OnRawMode(OpNick, Channel, sModes, sArgs) def OnRawMessage(self, msg): pass def OnNumericMessage(self, msg): pass # Deprecated non-Message functions should still work, for now. def OnQuitMessage(self, msg, vChans): return self.OnQuit(msg.GetNick(), msg.GetReason(), vChans) def OnNickMessage(self, msg, vChans): return self.OnNick(msg.GetNick(), msg.GetNewNick(), vChans) def OnKickMessage(self, msg): return self.OnKick(msg.GetNick(), msg.GetKickedNick(), msg.GetChan(), msg.GetReason()) def OnJoinMessage(self, msg): return self.OnJoin(msg.GetNick(), msg.GetChan()) def OnPartMessage(self, msg): return self.OnPart(msg.GetNick(), msg.GetChan(), msg.GetReason()) def OnChanBufferPlayMessage(self, msg): modified = String() old = modified.s = msg.ToString(CMessage.ExcludeTags) ret = self.OnChanBufferPlayLine(msg.GetChan(), msg.GetClient(), modified) if old != modified.s: msg.Parse(modified.s) return ret def OnPrivBufferPlayMessage(self, msg): modified = String() old = modified.s = msg.ToString(CMessage.ExcludeTags) ret = self.OnPrivBufferPlayLine(msg.GetClient(), modified) if old != modified.s: msg.Parse(modified.s) return ret def OnUserRawMessage(self, msg): pass def OnUserCTCPReplyMessage(self, msg): target = String(msg.GetTarget()) text = String(msg.GetText()) ret = self.OnUserCTCPReply(target, text) msg.SetTarget(target.s) msg.SetText(text.s) return ret def OnUserCTCPMessage(self, msg): target = String(msg.GetTarget()) text = String(msg.GetText()) ret = self.OnUserCTCP(target, text) msg.SetTarget(target.s) msg.SetText(text.s) return ret def OnUserActionMessage(self, msg): target = String(msg.GetTarget()) text = String(msg.GetText()) ret = self.OnUserAction(target, text) msg.SetTarget(target.s) msg.SetText(text.s) return ret def OnUserTextMessage(self, msg): target = String(msg.GetTarget()) text = String(msg.GetText()) ret = self.OnUserMsg(target, text) msg.SetTarget(target.s) msg.SetText(text.s) return ret def OnUserNoticeMessage(self, msg): target = String(msg.GetTarget()) text = String(msg.GetText()) ret = self.OnUserNotice(target, text) msg.SetTarget(target.s) msg.SetText(text.s) return ret def OnUserJoinMessage(self, msg): chan = String(msg.GetTarget()) key = String(msg.GetKey()) ret = self.OnUserJoin(chan, key) msg.SetTarget(chan.s) msg.SetKey(key.s) return ret def OnUserPartMessage(self, msg): chan = String(msg.GetTarget()) reason = String(msg.GetReason()) ret = self.OnUserPart(chan, reason) msg.SetTarget(chan.s) msg.SetReason(reason.s) return ret def OnUserTopicMessage(self, msg): chan = String(msg.GetTarget()) topic = String(msg.GetTopic()) ret = self.OnUserTopic(chan, topic) msg.SetTarget(chan.s) msg.SetTopic(topic.s) return ret def OnUserQuitMessage(self, msg): reason = String(msg.GetReason()) ret = self.OnUserQuit(reason) msg.SetReason(reason.s) return ret def OnCTCPReplyMessage(self, msg): text = String(msg.GetText()) ret = self.OnCTCPReply(msg.GetNick(), text) msg.SetText(text.s) return ret def OnPrivCTCPMessage(self, msg): text = String(msg.GetText()) ret = self.OnPrivCTCP(msg.GetNick(), text) msg.SetText(text.s) return ret def OnChanCTCPMessage(self, msg): text = String(msg.GetText()) ret = self.OnChanCTCP(msg.GetNick(), msg.GetChan(), text) msg.SetText(text.s) return ret def OnPrivActionMessage(self, msg): text = String(msg.GetText()) ret = self.OnPrivAction(msg.GetNick(), text) msg.SetText(text.s) return ret def OnChanActionMessage(self, msg): text = String(msg.GetText()) ret = self.OnChanAction(msg.GetNick(), msg.GetChan(), text) msg.SetText(text.s) return ret def OnPrivTextMessage(self, msg): text = String(msg.GetText()) ret = self.OnPrivMsg(msg.GetNick(), text) msg.SetText(text.s) return ret def OnChanTextMessage(self, msg): text = String(msg.GetText()) ret = self.OnChanMsg(msg.GetNick(), msg.GetChan(), text) msg.SetText(text.s) return ret def OnPrivNoticeMessage(self, msg): text = String(msg.GetText()) ret = self.OnPrivNotice(msg.GetNick(), text) msg.SetText(text.s) return ret def OnChanNoticeMessage(self, msg): text = String(msg.GetText()) ret = self.OnChanNotice(msg.GetNick(), msg.GetChan(), text) msg.SetText(text.s) return ret def OnTopicMessage(self, msg): topic = String(msg.GetTopic()) ret = self.OnTopic(msg.GetNick(), msg.GetChan(), topic) msg.SetTopic(topic.s) return ret def OnUnknownUserRawMessage(self, msg): pass def OnSendToClientMessage(self, msg): pass def OnSendToIRCMessage(self, msg): pass def make_inherit(cl, parent, attr): def make_caller(parent, name, attr): return lambda self, *a: parent.__dict__[name](self.__dict__[attr], *a) while True: for x in parent.__dict__: if not x.startswith('_') and x not in cl.__dict__: setattr(cl, x, make_caller(parent, x, attr)) if parent.__bases__: # Multiple inheritance is not supported (yet?) parent = parent.__bases__[0] else: break make_inherit(Socket, CPySocket, '_csock') make_inherit(Module, CPyModule, '_cmod') make_inherit(Timer, CPyTimer, '_ctimer') def find_open(modname): '''Returns (pymodule, datapath)''' for d in CModules.GetModDirs(): # d == (libdir, datadir) try: x = imp.find_module(modname, [d[0]]) except ImportError: # no such file in dir d continue # x == (, # './modules/admin.so', ('.so', 'rb', 3)) # x == (, './modules/pythontest.py', ('.py', 'U', 1)) if x[0] is None and x[2][2] != imp.PKG_DIRECTORY: # the same continue if x[2][0] == '.so': try: pymodule = imp.load_module(modname, *x) except ImportError: # found needed .so but can't load it... # maybe it's normal (non-python) znc module? # another option here could be to "continue" # search of python module in other moddirs. # but... we respect C++ modules ;) return (None, None) finally: x[0].close() else: # this is not .so, so it can be only python module .py or .pyc try: pymodule = imp.load_module(modname, *x) finally: if x[0]: x[0].close() return (pymodule, d[1]+modname) else: # nothing found return (None, None) _py_modules = set() def load_module(modname, args, module_type, user, network, retmsg, modpython): '''Returns 0 if not found, 1 on loading error, 2 on success''' if re.search(r'[^a-zA-Z0-9_]', modname) is not None: retmsg.s = 'Module names can only contain letters, numbers and ' \ 'underscores, [{0}] is invalid.'.format(modname) return 1 pymodule, datapath = find_open(modname) if pymodule is None: return 0 if modname not in pymodule.__dict__: retmsg.s = "Python module [{0}] doesn't have class named [{1}]".format( pymodule.__file__, modname) return 1 cl = pymodule.__dict__[modname] if module_type not in cl.module_types: retmsg.s = "Module [{}] doesn't support type.".format(modname) return 1 module = cl() module._cmod = CreatePyModule(user, network, modname, datapath, module_type, module, modpython) module.nv = ModuleNV(module._cmod) module.SetDescription(cl.description) module.SetArgs(args) module.SetModPath(pymodule.__file__) _py_modules.add(module) if module_type == CModInfo.UserModule: if not user: retmsg.s = "Module [{}] is UserModule and needs user.".format(modname) unload_module(module) return 1 cont = user elif module_type == CModInfo.NetworkModule: if not network: retmsg.s = "Module [{}] is Network module and needs a network.".format(modname) unload_module(module) return 1 cont = network elif module_type == CModInfo.GlobalModule: cont = CZNC.Get() else: retmsg.s = "Module [{}] doesn't support that module type.".format(modname) unload_module(module) return 1 cont.GetModules().append(module._cmod) try: loaded = True if not module.OnLoad(args, retmsg): if retmsg.s == '': retmsg.s = 'Module [{0}] aborted.'.format(modname) else: retmsg.s = 'Module [{0}] aborted: {1}'.format(modname, retmsg.s) loaded = False except BaseException: if retmsg.s == '': retmsg.s = 'Got exception: {0}'.format(traceback.format_exc()) else: retmsg.s = '{0}; Got exception: {1}'.format(retmsg.s, traceback.format_exc()) loaded = False except: if retmsg.s == '': retmsg.s = 'Got exception.' else: retmsg.s = '{0}; Got exception.'.format(retmsg.s) loaded = False if loaded: if retmsg.s == '': retmsg.s = "[{0}]".format(pymodule.__file__) else: retmsg.s = "[{1}] [{0}]".format(pymodule.__file__, retmsg.s) return 2 print(retmsg.s) unload_module(module) return 1 def unload_module(module): if (module not in _py_modules): return False module.OnShutdown() _py_modules.discard(module) cmod = module._cmod if module.GetType() == CModInfo.UserModule: cont = cmod.GetUser() elif module.GetType() == CModInfo.NetworkModule: cont = cmod.GetNetwork() elif module.GetType() == CModInfo.GlobalModule: cont = CZNC.Get() cont.GetModules().removeModule(cmod) del module._cmod cmod.DeletePyModule() del cmod return True def unload_all(): while len(_py_modules) > 0: mod = _py_modules.pop() # add it back to set, otherwise unload_module will be sad _py_modules.add(mod) unload_module(mod) if _cov: _cov.stop() def gather_mod_info(cl, modinfo): translation = CTranslationDomainRefHolder("znc-" + modinfo.GetName()) modinfo.SetDescription(cl.description) modinfo.SetWikiPage(cl.wiki_page) modinfo.SetDefaultType(cl.module_types[0]) modinfo.SetArgsHelpText(cl.args_help_text); modinfo.SetHasArgs(cl.has_args); for module_type in cl.module_types: modinfo.AddType(module_type) def get_mod_info(modname, retmsg, modinfo): '''0-not found, 1-error, 2-success''' pymodule, datadir = find_open(modname) if pymodule is None: return 0 if modname not in pymodule.__dict__: retmsg.s = "Python module [{0}] doesn't have class named [{1}]".format( pymodule.__file__, modname) return 1 cl = pymodule.__dict__[modname] modinfo.SetName(modname) modinfo.SetPath(pymodule.__file__) gather_mod_info(cl, modinfo) return 2 def get_mod_info_path(path, modname, modinfo): try: x = imp.find_module(modname, [path]) except ImportError: return 0 # x == (, # './modules/admin.so', ('.so', 'rb', 3)) # x == (, # './modules/pythontest.py', ('.py', 'U', 1)) if x[0] is None and x[2][2] != imp.PKG_DIRECTORY: return 0 try: pymodule = imp.load_module(modname, *x) except ImportError: return 0 finally: if x[0]: x[0].close() if modname not in pymodule.__dict__: return 0 cl = pymodule.__dict__[modname] modinfo.SetName(modname) modinfo.SetPath(pymodule.__file__) gather_mod_info(cl, modinfo) return 1 CONTINUE = CModule.CONTINUE HALT = CModule.HALT HALTMODS = CModule.HALTMODS HALTCORE = CModule.HALTCORE UNLOAD = CModule.UNLOAD HaveSSL = HaveSSL_() HaveIPv6 = HaveIPv6_() HaveCharset = HaveCharset_() Version = GetVersion() VersionMajor = GetVersionMajor() VersionMinor = GetVersionMinor() VersionExtra = GetVersionExtra() def CreateWebSubPage(name, title='', params=dict(), admin=False): vpair = VPair() for k, v in params.items(): VPair_Add2Str_(vpair, k, v) flags = 0 if admin: flags |= CWebSubPage.F_ADMIN return CreateWebSubPage_(name, title, vpair, flags) CUser.GetNetworks = CUser.GetNetworks_ CIRCNetwork.GetChans = CIRCNetwork.GetChans_ CIRCNetwork.GetServers = CIRCNetwork.GetServers_ CIRCNetwork.GetQueries = CIRCNetwork.GetQueries_ CChan.GetNicks = CChan.GetNicks_ CZNC.GetUserMap = CZNC.GetUserMap_ def FreeOwnership(func): """ Force release of python ownership of user object when adding it to znc This solves #462 """ @wraps(func) def _wrap(self, obj, *args): # Bypass if first argument is not an SWIG object (like base type str) if not hasattr(obj, 'thisown'): return func(self, obj, *args) # Change ownership of C++ object from SWIG/python to ZNC core if function was successful if func(self, obj, *args): # .thisown is magic SWIG's attribute which makes it call C++ "delete" when python's garbage collector deletes python wrapper obj.thisown = 0 return True else: return False return _wrap CZNC.AddListener = FreeOwnership(func=CZNC.AddListener) CZNC.AddUser = FreeOwnership(func=CZNC.AddUser) CZNC.AddNetworkToQueue = FreeOwnership(func=CZNC.AddNetworkToQueue) CUser.AddNetwork = FreeOwnership(func=CUser.AddNetwork) CIRCNetwork.AddChan = FreeOwnership(func=CIRCNetwork.AddChan) CModule.AddSocket = FreeOwnership(func=CModule.AddSocket) CModule.AddSubPage = FreeOwnership(func=CModule.AddSubPage) class ModulesIter(collections.Iterator): def __init__(self, cmod): self._cmod = cmod def __next__(self): if self._cmod.is_end(): raise StopIteration module = self._cmod.get() self._cmod.plusplus() return module CModules.__iter__ = lambda cmod: ModulesIter(CModulesIter(cmod)) # e.g. msg.As(znc.CNumericMessage) def _CMessage_As(self, cl): return getattr(self, 'As_' + cl.__name__, lambda: self)() CMessage.As = _CMessage_As def str_eq(self, other): if str(other) == str(self): return True return id(self) == id(other) CChan.__eq__ = str_eq CNick.__eq__ = str_eq CUser.__eq__ = str_eq CIRCNetwork.__eq__ = str_eq CPyRetString.__eq__ = str_eq znc-1.7.5/modules/modpython/ret.h0000644000175000017500000000233113542151610017173 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once class CPyRetString { public: CString& s; CPyRetString(CString& S) : s(S) {} static PyObject* wrap(CString& S) { CPyRetString* x = new CPyRetString(S); return SWIG_NewInstanceObj(x, SWIG_TypeQuery("CPyRetString*"), SWIG_POINTER_OWN); } }; class CPyRetBool { public: bool& b; CPyRetBool(bool& B) : b(B) {} static PyObject* wrap(bool& B) { CPyRetBool* x = new CPyRetBool(B); return SWIG_NewInstanceObj(x, SWIG_TypeQuery("CPyRetBool*"), SWIG_POINTER_OWN); } }; znc-1.7.5/modules/modpython/module.h0000644000175000017500000003357113542151610017700 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once // This class is used from python to call functions which accept CString& // __str__ is added to it in modpython.i class String { public: CString s; String(const CString& s = "") : s(s) {} }; class CModPython; class ZNC_EXPORT_LIB_EXPORT CPyModule : public CModule { PyObject* m_pyObj; CModPython* m_pModPython; VWebSubPages* _GetSubPages(); public: CPyModule(CUser* pUser, CIRCNetwork* pNetwork, const CString& sModName, const CString& sDataPath, CModInfo::EModuleType eType, PyObject* pyObj, CModPython* pModPython) : CModule(nullptr, pUser, pNetwork, sModName, sDataPath, eType) { m_pyObj = pyObj; Py_INCREF(pyObj); m_pModPython = pModPython; } PyObject* GetPyObj() { // borrows return m_pyObj; } PyObject* GetNewPyObj() { Py_INCREF(m_pyObj); return m_pyObj; } void DeletePyModule() { Py_CLEAR(m_pyObj); delete this; } CString GetPyExceptionStr(); CModPython* GetModPython() { return m_pModPython; } bool OnBoot() override; bool WebRequiresLogin() override; bool WebRequiresAdmin() override; CString GetWebMenuTitle() override; bool OnWebPreRequest(CWebSock& WebSock, const CString& sPageName) override; bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override; bool ValidateWebRequestCSRFCheck(CWebSock& WebSock, const CString& sPageName) override; VWebSubPages& GetSubPages() override; void OnPreRehash() override; void OnPostRehash() override; void OnIRCDisconnected() override; void OnIRCConnected() override; EModRet OnIRCConnecting(CIRCSock* pIRCSock) override; void OnIRCConnectionError(CIRCSock* pIRCSock) override; EModRet OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) override; EModRet OnBroadcast(CString& sMessage) override; void OnChanPermission2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) override; void OnOp2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override; void OnDeop2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override; void OnVoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override; void OnDevoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override; void OnMode2(const CNick* pOpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) override; void OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) override; EModRet OnRaw(CString& sLine) override; EModRet OnStatusCommand(CString& sCommand) override; void OnModCommand(const CString& sCommand) override; void OnModNotice(const CString& sMessage) override; void OnModCTCP(const CString& sMessage) override; void OnQuit(const CNick& Nick, const CString& sMessage, const std::vector& vChans) override; void OnNick(const CNick& Nick, const CString& sNewNick, const std::vector& vChans) override; void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) override; EModRet OnJoining(CChan& Channel) override; void OnJoin(const CNick& Nick, CChan& Channel) override; void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) override; EModRet OnInvite(const CNick& Nick, const CString& sChan) override; EModRet OnChanBufferStarting(CChan& Chan, CClient& Client) override; EModRet OnChanBufferEnding(CChan& Chan, CClient& Client) override; EModRet OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) override; EModRet OnPrivBufferPlayLine(CClient& Client, CString& sLine) override; void OnClientLogin() override; void OnClientDisconnect() override; EModRet OnUserRaw(CString& sLine) override; EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage) override; EModRet OnUserCTCP(CString& sTarget, CString& sMessage) override; EModRet OnUserAction(CString& sTarget, CString& sMessage) override; EModRet OnUserMsg(CString& sTarget, CString& sMessage) override; EModRet OnUserNotice(CString& sTarget, CString& sMessage) override; EModRet OnUserJoin(CString& sChannel, CString& sKey) override; EModRet OnUserPart(CString& sChannel, CString& sMessage) override; EModRet OnUserTopic(CString& sChannel, CString& sTopic) override; EModRet OnUserTopicRequest(CString& sChannel) override; EModRet OnUserQuit(CString& sMessage) override; EModRet OnCTCPReply(CNick& Nick, CString& sMessage) override; EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override; EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) override; EModRet OnPrivAction(CNick& Nick, CString& sMessage) override; EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) override; EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override; EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override; EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override; EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) override; EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) override; bool OnServerCapAvailable(const CString& sCap) override; void OnServerCapResult(const CString& sCap, bool bSuccess) override; EModRet OnTimerAutoJoin(CChan& Channel) override; bool OnEmbeddedWebRequest(CWebSock&, const CString&, CTemplate&) override; EModRet OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet) override; EModRet OnDeleteNetwork(CIRCNetwork& Network) override; EModRet OnSendToClient(CString& sLine, CClient& Client) override; EModRet OnSendToIRC(CString& sLine) override; EModRet OnRawMessage(CMessage& Message) override; EModRet OnNumericMessage(CNumericMessage& Message) override; void OnQuitMessage(CQuitMessage& Message, const std::vector& vChans) override; void OnNickMessage(CNickMessage& Message, const std::vector& vChans) override; void OnKickMessage(CKickMessage& Message) override; void OnJoinMessage(CJoinMessage& Message) override; void OnPartMessage(CPartMessage& Message) override; EModRet OnChanBufferPlayMessage(CMessage& Message) override; EModRet OnPrivBufferPlayMessage(CMessage& Message) override; EModRet OnUserRawMessage(CMessage& Message) override; EModRet OnUserCTCPReplyMessage(CCTCPMessage& Message) override; EModRet OnUserCTCPMessage(CCTCPMessage& Message) override; EModRet OnUserActionMessage(CActionMessage& Message) override; EModRet OnUserTextMessage(CTextMessage& Message) override; EModRet OnUserNoticeMessage(CNoticeMessage& Message) override; EModRet OnUserJoinMessage(CJoinMessage& Message) override; EModRet OnUserPartMessage(CPartMessage& Message) override; EModRet OnUserTopicMessage(CTopicMessage& Message) override; EModRet OnUserQuitMessage(CQuitMessage& Message) override; EModRet OnCTCPReplyMessage(CCTCPMessage& Message) override; EModRet OnPrivCTCPMessage(CCTCPMessage& Message) override; EModRet OnChanCTCPMessage(CCTCPMessage& Message) override; EModRet OnPrivActionMessage(CActionMessage& Message) override; EModRet OnChanActionMessage(CActionMessage& Message) override; EModRet OnPrivTextMessage(CTextMessage& Message) override; EModRet OnChanTextMessage(CTextMessage& Message) override; EModRet OnPrivNoticeMessage(CNoticeMessage& Message) override; EModRet OnChanNoticeMessage(CNoticeMessage& Message) override; EModRet OnTopicMessage(CTopicMessage& Message) override; EModRet OnSendToClientMessage(CMessage& Message) override; EModRet OnSendToIRCMessage(CMessage& Message) override; // Global Modules EModRet OnAddUser(CUser& User, CString& sErrorRet) override; EModRet OnDeleteUser(CUser& User) override; void OnClientConnect(CZNCSock* pSock, const CString& sHost, unsigned short uPort) override; void OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) override; EModRet OnUnknownUserRaw(CClient* pClient, CString& sLine) override; EModRet OnUnknownUserRawMessage(CMessage& Message) override; bool IsClientCapSupported(CClient* pClient, const CString& sCap, bool bState) override; void OnClientCapRequest(CClient* pClient, const CString& sCap, bool bState) override; virtual EModRet OnModuleLoading(const CString& sModName, const CString& sArgs, CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) override; EModRet OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) override; virtual EModRet OnGetModInfo(CModInfo& ModInfo, const CString& sModule, bool& bSuccess, CString& sRetMsg) override; void OnGetAvailableMods(std::set& ssMods, CModInfo::EModuleType eType) override; void OnClientCapLs(CClient* pClient, SCString& ssCaps) override; EModRet OnLoginAttempt(std::shared_ptr Auth) override; }; static inline CPyModule* AsPyModule(CModule* p) { return dynamic_cast(p); } inline CPyModule* CreatePyModule(CUser* pUser, CIRCNetwork* pNetwork, const CString& sModName, const CString& sDataPath, CModInfo::EModuleType eType, PyObject* pyObj, CModPython* pModPython) { return new CPyModule(pUser, pNetwork, sModName, sDataPath, eType, pyObj, pModPython); } class ZNC_EXPORT_LIB_EXPORT CPyTimer : public CTimer { PyObject* m_pyObj; CModPython* m_pModPython; public: CPyTimer(CPyModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription, PyObject* pyObj) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription), m_pyObj(pyObj) { Py_INCREF(pyObj); m_pModPython = pModule->GetModPython(); pModule->AddTimer(this); } void RunJob() override; PyObject* GetPyObj() { return m_pyObj; } PyObject* GetNewPyObj() { Py_INCREF(m_pyObj); return m_pyObj; } ~CPyTimer(); }; inline CPyTimer* CreatePyTimer(CPyModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription, PyObject* pyObj) { return new CPyTimer(pModule, uInterval, uCycles, sLabel, sDescription, pyObj); } class ZNC_EXPORT_LIB_EXPORT CPySocket : public CSocket { PyObject* m_pyObj; CModPython* m_pModPython; public: CPySocket(CPyModule* pModule, PyObject* pyObj) : CSocket(pModule), m_pyObj(pyObj) { Py_INCREF(pyObj); m_pModPython = pModule->GetModPython(); } PyObject* GetPyObj() { return m_pyObj; } PyObject* GetNewPyObj() { Py_INCREF(m_pyObj); return m_pyObj; } ~CPySocket(); void Connected() override; void Disconnected() override; void Timeout() override; void ConnectionRefused() override; void ReadData(const char* data, size_t len) override; void ReadLine(const CString& sLine) override; Csock* GetSockObj(const CString& sHost, unsigned short uPort) override; }; inline CPySocket* CreatePySocket(CPyModule* pModule, PyObject* pyObj) { return new CPySocket(pModule, pyObj); } inline bool HaveIPv6_() { #ifdef HAVE_IPV6 return true; #endif return false; } inline bool HaveSSL_() { #ifdef HAVE_LIBSSL return true; #endif return false; } inline bool HaveCharset_() { #ifdef HAVE_ICU return true; #endif return false; } inline int GetSOMAXCONN() { return SOMAXCONN; } inline int GetVersionMajor() { return VERSION_MAJOR; } inline int GetVersionMinor() { return VERSION_MINOR; } inline double GetVersion() { return VERSION; } inline CString GetVersionExtra() { return ZNC_VERSION_EXTRA; } class MCString_iter { public: MCString_iter() {} MCString::iterator x; MCString_iter(MCString::iterator z) : x(z) {} void plusplus() { ++x; } CString get() { return x->first; } bool is_end(CModule* m) { return m->EndNV() == x; } }; class CModulesIter { public: CModulesIter(CModules* pModules) { m_pModules = pModules; m_it = pModules->begin(); } void plusplus() { ++m_it; } const CModule* get() const { return *m_it; } bool is_end() const { return m_pModules->end() == m_it; } CModules* m_pModules; CModules::const_iterator m_it; }; znc-1.7.5/modules/modpython/cstring.i0000644000175000017500000003123013542151610020053 0ustar somebodysomebody/* SWIG-generated sources are used here. This file is generated using: echo '%include ' > foo.i swig -python -py3 -c++ -shadow -E foo.i > string.i Remove unrelated stuff from top of file which is included by default s/std::string/CString/g s/std_string/CString/g Add "%traits_ptypen(CString);" */ // // String // %fragment(""); %feature("naturalvar") CString; class CString; %traits_ptypen(CString); /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,70,%typemaps_CString@*/ /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,4,%CString_asptr@*/ %fragment("SWIG_" "AsPtr" "_" {CString},"header",fragment="SWIG_AsCharPtrAndSize") { SWIGINTERN int SWIG_AsPtr_CString (PyObject * obj, CString **val) { char* buf = 0 ; size_t size = 0; int alloc = SWIG_OLDOBJ; if (SWIG_IsOK((SWIG_AsCharPtrAndSize(obj, &buf, &size, &alloc)))) { if (buf) { if (val) *val = new CString(buf, size - 1); if (alloc == SWIG_NEWOBJ) delete[] buf; return SWIG_NEWOBJ; } else { if (val) *val = 0; return SWIG_OLDOBJ; } } else { static int init = 0; static swig_type_info* descriptor = 0; if (!init) { descriptor = SWIG_TypeQuery("CString" " *"); init = 1; } if (descriptor) { CString *vptr; int res = SWIG_ConvertPtr(obj, (void**)&vptr, descriptor, 0); if (SWIG_IsOK(res) && val) *val = vptr; return res; } } return SWIG_ERROR; } } /*@SWIG@*/ /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,48,%CString_asval@*/ %fragment("SWIG_" "AsVal" "_" {CString},"header", fragment="SWIG_" "AsPtr" "_" {CString}) { SWIGINTERN int SWIG_AsVal_CString (PyObject * obj, CString *val) { CString* v = (CString *) 0; int res = SWIG_AsPtr_CString (obj, &v); if (!SWIG_IsOK(res)) return res; if (v) { if (val) *val = *v; if (SWIG_IsNewObj(res)) { delete v; res = SWIG_DelNewMask(res); } return res; } return SWIG_ERROR; } } /*@SWIG@*/ /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,38,%CString_from@*/ %fragment("SWIG_" "From" "_" {CString},"header",fragment="SWIG_FromCharPtrAndSize", fragment="StdTraits") { SWIGINTERNINLINE PyObject * SWIG_From_CString (const CString& s) { return SWIG_FromCharPtrAndSize(s.data(), s.size()); } } /*@SWIG@*/ /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,201,%typemaps_asptrfromn@*/ /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,190,%typemaps_asptrfrom@*/ /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,160,%typemaps_asptr@*/ %fragment("SWIG_" "AsVal" "_" {CString},"header",fragment="SWIG_" "AsPtr" "_" {CString}) { SWIGINTERNINLINE int SWIG_AsVal_CString (PyObject * obj, CString *val) { CString *v = (CString *)0; int res = SWIG_AsPtr_CString (obj, &v); if (!SWIG_IsOK(res)) return res; if (v) { if (val) *val = *v; if (SWIG_IsNewObj(res)) { delete v; res = SWIG_DelNewMask(res); } return res; } return SWIG_ERROR; } } /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,28,%ptr_in_typemap@*/ %typemap(in,fragment="SWIG_" "AsPtr" "_" {CString}) CString { CString *ptr = (CString *)0; int res = SWIG_AsPtr_CString($input, &ptr); if (!SWIG_IsOK(res) || !ptr) { SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } $1 = *ptr; if (SWIG_IsNewObj(res)) delete ptr; } %typemap(freearg) CString ""; %typemap(in,fragment="SWIG_" "AsPtr" "_" {CString}) const CString & (int res = SWIG_OLDOBJ) { CString *ptr = (CString *)0; res = SWIG_AsPtr_CString($input, &ptr); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } if (!ptr) { SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } $1 = ptr; } %typemap(freearg,noblock=1) const CString & { if (SWIG_IsNewObj(res$argnum)) delete $1; } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,53,%ptr_varin_typemap@*/ %typemap(varin,fragment="SWIG_" "AsPtr" "_" {CString}) CString { CString *ptr = (CString *)0; int res = SWIG_AsPtr_CString($input, &ptr); if (!SWIG_IsOK(res) || !ptr) { SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in variable '""$name""' of type '""$type""'"); } $1 = *ptr; if (SWIG_IsNewObj(res)) delete ptr; } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,68,%ptr_directorout_typemap@*/ %typemap(directorargout,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString *DIRECTOROUT ($*ltype temp, int swig_ores) { CString *swig_optr = 0; swig_ores = $result ? SWIG_AsPtr_CString($result, &swig_optr) : 0; if (!SWIG_IsOK(swig_ores) || !swig_optr) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ArgError((swig_optr ? swig_ores : SWIG_TypeError))), "in output value of type '""$type""'"); } temp = *swig_optr; $1 = &temp; if (SWIG_IsNewObj(swig_ores)) delete swig_optr; } %typemap(directorout,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString { CString *swig_optr = 0; int swig_ores = SWIG_AsPtr_CString($input, &swig_optr); if (!SWIG_IsOK(swig_ores) || !swig_optr) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ArgError((swig_optr ? swig_ores : SWIG_TypeError))), "in output value of type '""$type""'"); } $result = *swig_optr; if (SWIG_IsNewObj(swig_ores)) delete swig_optr; } %typemap(directorout,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString},warning= "473:Returning a pointer or reference in a director method is not recommended." ) CString* { CString *swig_optr = 0; int swig_ores = SWIG_AsPtr_CString($input, &swig_optr); if (!SWIG_IsOK(swig_ores)) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ArgError(swig_ores)), "in output value of type '""$type""'"); } $result = swig_optr; if (SWIG_IsNewObj(swig_ores)) { swig_acquire_ownership(swig_optr); } } %typemap(directorfree,noblock=1) CString* { if (director) { director->swig_release_ownership(SWIG_as_voidptr($input)); } } %typemap(directorout,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString},warning= "473:Returning a pointer or reference in a director method is not recommended." ) CString& { CString *swig_optr = 0; int swig_ores = SWIG_AsPtr_CString($input, &swig_optr); if (!SWIG_IsOK(swig_ores)) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ArgError(swig_ores)), "in output value of type '""$type""'"); } else { if (!swig_optr) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ValueError), "invalid null reference " "in output value of type '""$type""'"); } } $result = swig_optr; if (SWIG_IsNewObj(swig_ores)) { swig_acquire_ownership(swig_optr); } } %typemap(directorfree,noblock=1) CString& { if (director) { director->swig_release_ownership(SWIG_as_voidptr($input)); } } %typemap(directorout,fragment="SWIG_" "AsPtr" "_" {CString}) CString &DIRECTOROUT = CString /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,143,%ptr_typecheck_typemap@*/ %typemap(typecheck,noblock=1,precedence=135,fragment="SWIG_" "AsPtr" "_" {CString}) CString * { int res = SWIG_AsPtr_CString($input, (CString**)(0)); $1 = SWIG_CheckState(res); } %typemap(typecheck,noblock=1,precedence=135,fragment="SWIG_" "AsPtr" "_" {CString}) CString, const CString& { int res = SWIG_AsPtr_CString($input, (CString**)(0)); $1 = SWIG_CheckState(res); } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,254,%ptr_input_typemap@*/ /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,117,%_ptr_input_typemap@*/ %typemap(in,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString *INPUT(int res = 0) { res = SWIG_AsPtr_CString($input, &$1); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } res = SWIG_AddTmpMask(res); } %typemap(in,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString &INPUT(int res = 0) { res = SWIG_AsPtr_CString($input, &$1); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } if (!$1) { SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } res = SWIG_AddTmpMask(res); } %typemap(freearg,noblock=1,match="in") CString *INPUT, CString &INPUT { if (SWIG_IsNewObj(res$argnum)) delete $1; } %typemap(typecheck,noblock=1,precedence=135,fragment="SWIG_" "AsPtr" "_" {CString}) CString *INPUT, CString &INPUT { int res = SWIG_AsPtr_CString($input, (CString**)0); $1 = SWIG_CheckState(res); } /*@SWIG@*/ /*@SWIG@*/; /*@SWIG@*/ /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,183,%typemaps_from@*/ /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,55,%value_out_typemap@*/ %typemap(out,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString, const CString { $result = SWIG_From_CString(static_cast< CString >($1)); } %typemap(out,noblock=1,fragment="SWIG_" "From" "_" {CString}) const CString& { $result = SWIG_From_CString(static_cast< CString >(*$1)); } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,79,%value_varout_typemap@*/ %typemap(varout,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString, const CString& { $result = SWIG_From_CString(static_cast< CString >($1)); } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,87,%value_constcode_typemap@*/ %typemap(constcode,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString { SWIG_Python_SetConstant(d, "$symname",SWIG_From_CString(static_cast< CString >($value))); } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,98,%value_directorin_typemap@*/ %typemap(directorin,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString *DIRECTORIN { $input = SWIG_From_CString(static_cast< CString >(*$1)); } %typemap(directorin,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString, const CString& { $input = SWIG_From_CString(static_cast< CString >($1)); } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,153,%value_throws_typemap@*/ %typemap(throws,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString { SWIG_Python_Raise(SWIG_From_CString(static_cast< CString >($1)), "$type", 0); SWIG_fail; } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,258,%value_output_typemap@*/ /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,175,%_value_output_typemap@*/ %typemap(in,numinputs=0,noblock=1) CString *OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ), CString &OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ) { $1 = &temp; } %typemap(argout,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString *OUTPUT, CString &OUTPUT { if (SWIG_IsTmpObj(res$argnum)) { $result = SWIG_Python_AppendOutput($result, SWIG_From_CString((*$1))); } else { int new_flags = SWIG_IsNewObj(res$argnum) ? (SWIG_POINTER_OWN | 0 ) : 0 ; $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj((void*)($1), $1_descriptor, new_flags)); } } /*@SWIG@*/ /*@SWIG@*/; /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,258,%value_output_typemap@*/ /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,175,%_value_output_typemap@*/ %typemap(in,numinputs=0,noblock=1) CString *OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ), CString &OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ) { $1 = &temp; } %typemap(argout,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString *OUTPUT, CString &OUTPUT { if (SWIG_IsTmpObj(res$argnum)) { $result = SWIG_Python_AppendOutput($result, SWIG_From_CString((*$1))); } else { int new_flags = SWIG_IsNewObj(res$argnum) ? (SWIG_POINTER_OWN | 0 ) : 0 ; $result = SWIG_Python_AppendOutput($result, SWIG_NewPointerObj((void*)($1), $1_descriptor, new_flags)); } } /*@SWIG@*/ /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,240,%_ptr_inout_typemap@*/ /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,230,%_value_inout_typemap@*/ %typemap(in) CString *INOUT = CString *INPUT; %typemap(in) CString &INOUT = CString &INPUT; %typemap(typecheck) CString *INOUT = CString *INPUT; %typemap(typecheck) CString &INOUT = CString &INPUT; %typemap(argout) CString *INOUT = CString *OUTPUT; %typemap(argout) CString &INOUT = CString &OUTPUT; /*@SWIG@*/ %typemap(typecheck) CString *INOUT = CString *INPUT; %typemap(typecheck) CString &INOUT = CString &INPUT; %typemap(freearg) CString *INOUT = CString *INPUT; %typemap(freearg) CString &INOUT = CString &INPUT; /*@SWIG@*/; /*@SWIG@*/ znc-1.7.5/modules/modpython/codegen.pl0000755000175000017500000003424413542151610020204 0ustar somebodysomebody#!/usr/bin/env perl # # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Parts of SWIG are used here. use strict; use warnings; use IO::File; use feature 'switch', 'say'; open my $in, $ARGV[0] or die; open my $out, ">", $ARGV[1] or die; print $out <<'EOF'; /* * Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Parts of SWIG are used here. */ /*************************************************************************** * This file is generated automatically using codegen.pl from functions.in * * Don't change it manually. * ***************************************************************************/ namespace { /* template struct pyobj_to_ptr { CString m_sType; SvToPtr(const CString& sType) { m_sType = sType; } bool operator()(PyObject* py, T** result) { T* x = nullptr; int res = SWIG_ConvertPtr(sv, (void**)&x, SWIG_TypeQuery(m_sType.c_str()), 0); if (SWIG_IsOK(res)) { *result = x; return true; } DEBUG("modpython: "); return false; } }; CModule::EModRet SvToEModRet(PyObject* py, CModule::EModRet* result) { long int x = PyLong_AsLong(); return static_cast(SvUV(sv)); }*/ inline swig_type_info* SWIG_pchar_descriptor(void) { static int init = 0; static swig_type_info* info = 0; if (!init) { info = SWIG_TypeQuery("_p_char"); init = 1; } return info; } inline int SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) { #if PY_VERSION_HEX>=0x03000000 if (PyUnicode_Check(obj)) #else if (PyString_Check(obj)) #endif { char *cstr; Py_ssize_t len; #if PY_VERSION_HEX>=0x03000000 if (!alloc && cptr) { /* We can't allow converting without allocation, since the internal representation of string in Python 3 is UCS-2/UCS-4 but we require a UTF-8 representation. TODO(bhy) More detailed explanation */ return SWIG_RuntimeError; } obj = PyUnicode_AsUTF8String(obj); PyBytes_AsStringAndSize(obj, &cstr, &len); if(alloc) *alloc = SWIG_NEWOBJ; #else PyString_AsStringAndSize(obj, &cstr, &len); #endif if (cptr) { if (alloc) { /* In python the user should not be able to modify the inner string representation. To warranty that, if you define SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string buffer is always returned. The default behavior is just to return the pointer value, so, be careful. */ #if defined(SWIG_PYTHON_SAFE_CSTRINGS) if (*alloc != SWIG_OLDOBJ) #else if (*alloc == SWIG_NEWOBJ) #endif { *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); *alloc = SWIG_NEWOBJ; } else { *cptr = cstr; *alloc = SWIG_OLDOBJ; } } else { #if PY_VERSION_HEX>=0x03000000 assert(0); /* Should never reach here in Python 3 */ #endif *cptr = SWIG_Python_str_AsChar(obj); } } if (psize) *psize = len + 1; #if PY_VERSION_HEX>=0x03000000 Py_XDECREF(obj); #endif return SWIG_OK; } else { swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); if (pchar_descriptor) { void* vptr = 0; if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { if (cptr) *cptr = (char *) vptr; if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; if (alloc) *alloc = SWIG_OLDOBJ; return SWIG_OK; } } } return SWIG_TypeError; } inline int SWIG_AsPtr_CString (PyObject * obj, CString **val) { char* buf = 0 ; size_t size = 0; int alloc = SWIG_OLDOBJ; if (SWIG_IsOK((SWIG_AsCharPtrAndSize(obj, &buf, &size, &alloc)))) { if (buf) { if (val) *val = new CString(buf, size - 1); if (alloc == SWIG_NEWOBJ) delete[] buf; return SWIG_NEWOBJ; } else { if (val) *val = 0; return SWIG_OLDOBJ; } } else { static int init = 0; static swig_type_info* descriptor = 0; if (!init) { descriptor = SWIG_TypeQuery("CString" " *"); init = 1; } if (descriptor) { CString *vptr; int res = SWIG_ConvertPtr(obj, (void**)&vptr, descriptor, 0); if (SWIG_IsOK(res) && val) *val = vptr; return res; } } return SWIG_ERROR; } } EOF =b bool OnFoo(const CString& x) { PyObject* pyName = Py_BuildValue("s", "OnFoo"); if (!pyName) { CString s = GetPyExceptionStr(); DEBUG("modpython: username/module/OnFoo: can't name method to call: " << s); return default; } PyObject* pyArg1 = Py_BuildValue("s", x.c_str()); if (!pyArg1) { CString s = GetPyExceptionStr(); DEBUG("modpython: username/module/OnFoo: can't convert parameter x to PyObject*: " << s); Py_CLEAR(pyName); return default; } PyObject* pyArg2 = ...; if (!pyArg2) { CString s = ...; DEBUG(...); Py_CLEAR(pyName); Py_CLEAR(pyArg1); return default; } PyObject* pyArg3 = ...; if (!pyArg3) { CString s = ...; DEBUG(...); Py_CLEAR(pyName); Py_CLEAR(pyArg1); Py_CLEAR(pyArg2); return default; } PyObject* pyRes = PyObject_CallMethodObjArgs(m_pyObj, pyName, pyArg1, pyArg2, pyArg3, nullptr); if (!pyRes) { CString s = ...; DEBUG("modpython: username/module/OnFoo failed: " << s); Py_CLEAR(pyName); Py_CLEAR(pyArg1); Py_CLEAR(pyArg2); Py_CLEAR(pyArg3); return default; } Py_CLEAR(pyName); Py_CLEAR(pyArg1); Py_CLEAR(pyArg2); Py_CLEAR(pyArg3); bool res = PyLong_AsLong(pyRes); if (PyErr_Occured()) { CString s = GetPyExceptionStr(); DEBUG("modpython: username/module/OnFoo returned unexpected value: " << s); Py_CLEAR(pyRes); return default; } Py_CLEAR(pyRes); return res; } =cut while (<$in>) { my ($type, $name, $args, $default) = /(\S+)\s+(\w+)\((.*)\)(?:=(\w+))?/ or next; $type =~ s/(EModRet)/CModule::$1/; $type =~ s/^\s*(.*?)\s*$/$1/; my @arg = map { my ($t, $v) = /^\s*(.*\W)\s*(\w+)\s*$/; $t =~ s/^\s*(.*?)\s*$/$1/; my ($tb, $tm) = $t =~ /^(.*?)\s*?(\*|&)?$/; {type=>$t, var=>$v, base=>$tb, mod=>$tm//'', pyvar=>"pyArg_$v", error=>"can't convert parameter '$v' to PyObject"} } split /,/, $args; unless (defined $default) { $default = "CModule::$name(" . (join ', ', map { $_->{var} } @arg) . ")"; } unshift @arg, {type=>'$func$', var=>"", base=>"", mod=>"", pyvar=>"pyName", error=>"can't convert string '$name' to PyObject"}; my $cleanup = ''; say $out "$type CPyModule::$name($args) {"; for my $a (@arg) { print $out "\tPyObject* $a->{pyvar} = "; given ($a->{type}) { when ('$func$') { say $out "Py_BuildValue(\"s\", \"$name\");"; } when (/vector\s*<\s*.*\*\s*>/) { say $out "PyList_New(0);"; } when (/(?:^|\s)CString/) { # not SCString if ($a->{base} eq 'CString' && $a->{mod} eq '&') { say $out "CPyRetString::wrap($a->{var});"; } else { say $out "Py_BuildValue(\"s\", $a->{var}.c_str());"; } } when (/^bool/) { if ($a->{mod} eq '&') { say $out "CPyRetBool::wrap($a->{var});"; } else { say $out "Py_BuildValue(\"l\", (long int)$a->{var});"; } } when (/^std::shared_ptr/) { say $out "SWIG_NewInstanceObj(new $a->{type}($a->{var}), SWIG_TypeQuery(\"$a->{type}*\"), SWIG_POINTER_OWN);"; } when (/\*$/) { (my $t = $a->{type}) =~ s/^const//; say $out "SWIG_NewInstanceObj(const_cast<$t>($a->{var}), SWIG_TypeQuery(\"$t\"), 0);"; } when (/&$/) { (my $b = $a->{base}) =~ s/^const//; say $out "SWIG_NewInstanceObj(const_cast<$b*>(&$a->{var}), SWIG_TypeQuery(\"$b*\"), 0);"; } when (/(?:^|::)E/) { # Enumerations say $out "Py_BuildValue(\"i\", (int)$a->{var});"; } default { my %letter = ( 'int' => 'i', 'char' => 'b', 'short int' => 'h', 'long int' => 'l', 'unsigned char' => 'B', 'unsigned short' => 'H', 'unsigned int' => 'I', 'unsigned long' => 'k', 'long long' => 'L', 'unsigned long long' => 'K', 'ssize_t' => 'n', 'double' => 'd', 'float' => 'f', ); if (exists $letter{$a->{type}}) { say $out "Py_BuildValue(\"$letter{$a->{type}}\", $a->{var});" } else { say $out "...;"; } } } say $out "\tif (!$a->{pyvar}) {"; say $out "\t\tCString sPyErr = m_pModPython->GetPyExceptionStr();"; say $out "\t\tDEBUG".'("modpython: " << (GetUser() ? GetUser()->GetUserName() : CString("")) << "/" << GetModName() << '."\"/$name: $a->{error}: \" << sPyErr);"; print $out $cleanup; say $out "\t\treturn $default;"; say $out "\t}"; $cleanup .= "\t\tPy_CLEAR($a->{pyvar});\n"; if ($a->{type} =~ /(vector\s*<\s*(.*)\*\s*>)/) { my ($vec, $sub) = ($1, $2); (my $cleanup1 = $cleanup) =~ s/\t\t/\t\t\t/g; my $dot = '.'; $dot = '->' if $a->{mod} eq '*'; say $out "\tfor (${vec}::const_iterator i = $a->{var}${dot}begin(); i != $a->{var}${dot}end(); ++i) {"; say $out "\t\tPyObject* pyVecEl = SWIG_NewInstanceObj(*i, SWIG_TypeQuery(\"$sub*\"), 0);"; say $out "\t\tif (!pyVecEl) {"; say $out "\t\t\tCString sPyErr = m_pModPython->GetPyExceptionStr();"; say $out "\t\t\tDEBUG".'("modpython: " << (GetUser() ? GetUser()->GetUserName() : CString("")) << "/" << GetModName() << '. "\"/$name: can't convert element of vector '$a->{var}' to PyObject: \" << sPyErr);"; print $out $cleanup1; say $out "\t\t\treturn $default;"; say $out "\t\t}"; say $out "\t\tif (PyList_Append($a->{pyvar}, pyVecEl)) {"; say $out "\t\t\tCString sPyErr = m_pModPython->GetPyExceptionStr();"; say $out "\t\t\tDEBUG".'("modpython: " << (GetUser() ? GetUser()->GetUserName() : CString("")) << "/" << GetModName() << '. "\"/$name: can't add element of vector '$a->{var}' to PyObject: \" << sPyErr);"; say $out "\t\t\tPy_CLEAR(pyVecEl);"; print $out $cleanup1; say $out "\t\t\treturn $default;"; say $out "\t\t}"; say $out "\t\tPy_CLEAR(pyVecEl);"; say $out "\t}"; } } print $out "\tPyObject* pyRes = PyObject_CallMethodObjArgs(m_pyObj"; print $out ", $_->{pyvar}" for @arg; say $out ", nullptr);"; say $out "\tif (!pyRes) {"; say $out "\t\tCString sPyErr = m_pModPython->GetPyExceptionStr();"; say $out "\t\tDEBUG".'("modpython: " << (GetUser() ? GetUser()->GetUserName() : CString("")) << "/" << GetModName() << '."\"/$name failed: \" << sPyErr);"; print $out $cleanup; say $out "\t\treturn $default;"; say $out "\t}"; $cleanup =~ s/\t\t/\t/g; print $out $cleanup; if ($type ne 'void') { say $out "\t$type result;"; say $out "\tif (pyRes == Py_None) {"; say $out "\t\tresult = $default;"; say $out "\t} else {"; given ($type) { when (/^(.*)\*$/) { say $out "\t\tint res = SWIG_ConvertPtr(pyRes, (void**)&result, SWIG_TypeQuery(\"$type\"), 0);"; say $out "\t\tif (!SWIG_IsOK(res)) {"; say $out "\t\t\tDEBUG(\"modpython: \" << (GetUser() ? GetUser()->GetUserName() : CString(\"\")) << \"/\" << GetModName() << \"/$name was expected to return '$type' but error=\" << res);"; say $out "\t\t\tresult = $default;"; say $out "\t\t}"; } when ('CString') { say $out "\t\tCString* p = nullptr;"; say $out "\t\tint res = SWIG_AsPtr_CString(pyRes, &p);"; say $out "\t\tif (!SWIG_IsOK(res)) {"; say $out "\t\t\tDEBUG(\"modpython: \" << (GetUser() ? GetUser()->GetUserName() : CString(\"\")) << \"/\" << GetModName() << \"/$name was expected to return '$type' but error=\" << res);"; say $out "\t\t\tresult = $default;"; say $out "\t\t} else if (!p) {"; say $out "\t\t\tDEBUG(\"modpython: \" << (GetUser() ? GetUser()->GetUserName() : CString(\"\")) << \"/\" << GetModName() << \"/$name was expected to return '$type' but returned nullptr\");"; say $out "\t\t\tresult = $default;"; say $out "\t\t} else result = *p;"; say $out "\t\tif (SWIG_IsNewObj(res)) delete p;"; } when ('CModule::EModRet') { say $out "\t\tlong int x = PyLong_AsLong(pyRes);"; say $out "\t\tif (PyErr_Occurred()) {"; say $out "\t\t\tCString sPyErr = m_pModPython->GetPyExceptionStr();"; say $out "\t\t\tDEBUG".'("modpython: " << (GetUser() ? GetUser()->GetUserName() : CString("")) << "/" << GetModName() << '."\"/$name was expected to return EModRet but: \" << sPyErr);"; say $out "\t\t\tresult = $default;"; say $out "\t\t} else { result = (CModule::EModRet)x; }"; } when ('bool') { say $out "\t\tint x = PyObject_IsTrue(pyRes);"; say $out "\t\tif (-1 == x) {"; say $out "\t\t\tCString sPyErr = m_pModPython->GetPyExceptionStr();"; say $out "\t\t\tDEBUG".'("modpython: " << (GetUser() ? GetUser()->GetUserName() : CString("")) << "/" << GetModName() << '."\"/$name was expected to return EModRet but: \" << sPyErr);"; say $out "\t\t\tresult = $default;"; say $out "\t\t} else result = x ? true : false;"; } default { say $out "\t\tI don't know how to convert PyObject to $type :("; } } say $out "\t}"; say $out "\tPy_CLEAR(pyRes);"; say $out "\treturn result;"; } else { say $out "\tPy_CLEAR(pyRes);"; } say $out "}\n"; } sub getres { my $type = shift; given ($type) { when (/^(.*)\*$/) { return "pyobj_to_ptr<$1>(\"$type\")" } when ('CString') { return 'PString' } when ('CModule::EModRet') { return 'SvToEModRet' } when (/unsigned/) { return 'SvUV' } default { return 'SvIV' } } } znc-1.7.5/modules/modpython/generated.tar.gz0000644000175000017500000133445613542151637021347 0ustar somebodysomebody‹ŸÓˆ]ì½ÿ{Û6’8|¿Fã>%Wql§éÞÆMú8¶“ú9Ûi·×O½´DÛÜÈ¢V¤â¸ÝÜßþÎ ¾ @")ÉM÷ÖwÛØ03 3`ÞÆWã»Ét´~ýËúÙØØøæë¯øwó/Ï6ø¿ð³õlëÙæF°ùôÙ×[›Ï6¿Ùzll>ÛØÜü`ci±Ÿiš… %Mn¢‹dpWToV9uFu þý“ü"ˆ×áè*J±u¦ ކQšwÉ4x?JnƒÛë0£¿ÂI  áñã åòEÄ„…›\†ýHvw”fÐ)âÌ"Gìq°ö¤ÕZ°ˆ±J£>²Ö ‰@Ü£? /¢!ð)™7Qv ž|'1ŽADýaò‚có$̲I|1Í¢´Kã·&÷f ü™@Ý1 Â(“@—Ç©,ºAˆƒÛdò>œ$S { HñÇ!î‡#”~2™@(A †Ñ Rˆã¼ûÕWèžÑ œ òñ%I|9ß?Š"œeL•à6ήƒÿJ‚Ç;;« ÐðMüùã*L=œ0iðýI°stv@ý|õô¯›¯‚õ§ëÏžaoâÁep‹Â Ü a}Œo¦7Á9鉃“èÓx‚ó $©K\ƒÑÏ€ïÓág»¢;üôÙ3л8 Míî§Q•6Xu3¶õ…ø»†ØFK©;¦GoŽöÝAì‡Óÿ× þùÏ m Þ½Ûíõhh²1??=Ø=ï!c¡†—+pHRXòu|=0¤ƒÀ&W£8z—>.ÜI~HâA°:M¡ @8KÝ.¿;zw¶¿çvYöŒè‚‚‡m7;TåàeðÔþðy#?Ÿb½Á×’-V§%P[÷*·œè‚æ¥f˜§µ¨ ˜æN”œ%_4Áé"Ï"ÎÚÞáÙnïÝÑÙ»““Óý³³Þ×Ï6ž9ŒÆ?îŸ ºÆ“ðê&T#ÕÄ)-ÏlØ `ô§£ItM`]ƒQ&°^—Ó‘PÞ×°_D0Ë'Ñ ,‰B_•P':p²szH4ág6¸þîbíö¸œ%²N0.cÓ¹vŽ ´Èˆ•%?Ï÷O µ57ðªåL®P ‡¶œð3Qè —C$§+ÃÌ'¨A}D•жŠÀ£&šRÁw6qpBTŸ:BöeÞìîö¾ß9Û}»svöãÁÙÁ«ƒ·ç?Ëé¡zSVIM–IÙÿÛÉñé¹#¹?=Ý"ªMé*DëëîÏo €iUtv¾s~°ÛNþ°¿çQoÑœ€Ihƒ¤ã¨ß ‡b :Ž&Í}ã|Výœ*¤-§8>Äi,ÌÐö Ô§Ãl¥Sª·x'µîTA»Üµ‚qý Öåä6§ÒÏÎ÷vwÞ¾]Ѐ1Z%`èuš ¨E`Èue/‚YI¶ÉaÜŸ$ir™­¦¸ªÁŸÁ¿h"ÂÊÒLÚ5Æx¿Y KœRwzzé…—4î˜V§ç½³ýÝw§ûø×Þ>èÞ]° ¬aÖz×^º‹š½PT¥q•²ˆGd:éþ¢E6Œ/&áä®°§ ¦M{ZÔ”õ´ Š¿§;c0›WSÝ5X~VwÒ4šd‡!ò`ýz5¸œ$7Án8¹HF/'áM„¦y^K¼ÝÏ[U0!÷÷‡;»§Çg@Îkпر³ƒã£3äóïßÃj»Ÿva½å}©ß:Øà=€õdÝÓŽ þ2$W hå™÷¯É§>a³8’•§ä~†`ƒy†ÖYWÖÑí7°ŒÇƒØ$á€cšFäç)ÈVasß’ç…®ixKÿ5Äéh5ÃVƒõ 8KÄß§€Ùïï¼å}´s¸€\q V˜ªpŠlÓ»÷ßïŽÏ÷É“>zÓþØ ¾øèT³içh¯‡ÿsëú8­]ZKA:-–´yJ ²ÅâçdŠ‘&¡ÌeøP²”¢dìoénÜЪ‰£ÍA „±*¯up7 oàWe$Ðꪀ›ÑM-,`Á_ÿºþ×/Q`°¬B¢£º´>Œ¢h@aÎ#:op WÊÕõ€y…"‡Ò9ÁSXýRÐ:Eý(M–nG],ÂêuˆáÙIJÿ@a.@‹ BoÒiÿz¿Zq>pcVòÅf·b÷=Ž‹ÅS/æÝÙ0]÷.x#5ÇÅôT¬§¿å¢G½Wï^¿Þ?íü+Ϭ$ØÜØúšƒ~= ¯R®v„O1¶47OŽ©Ã½½ƒ³ãŸŽÔZ·ñqÓ®¶»svÞ;Úÿ©w¸x|ú³®¶å E·mrñ÷¨Ÿ£dø$J)ßÞeË"ÜI”MÅŠò¥$> å¤|š* ¸‹Â¶KŸ³“lÒ•`~7…Ú8æ ØbC=’d Í.$”ÂËéÅj”dëÁÌ0¨ ¿“R€-F87hZ^DèÙvE¤R©NŠ« õG DiGôäœÊ—ÉVo²äiÊ>¹$ÖÂDJ£ IÑG‚„ÎULAœ/0=PüzÐ!P]A#NäŽ{;M§´es;‰Á½='`"º ¤@ó³ ƒÛý0ÆfwëDc'xø–ãNð{KŽè“'Š}„W|þD¯tÆC^%·4Ý%?ÉHO|÷ãL’Ã` øE0›¶í–Õƒôø‡6´íj}Ä:´B›VAª¶¹Éá?×Eàbæ6(BÖ‘p˜‚BLùhñk@åv…Þ´)øº¶Öi?‚y;fµ8Šn/þN­Ì°ëëë­ƒheœÊüøQEYTƒiëÑz—˜ãt—%ç**¥Dp]“|Äö1îú¨í3\}¨B¾Ç¿@Väº4À‘Hú´›´_ÓI*Üš¼8"zËÁ%%K8%Pc:ÌÀ5ËÔ‹œE-ÅP?ßÈ(‡À#Î[dþ·PˆB“¼É‹d!.Ÿ¬ûN•€FDåÛ± kÊŽB;ÙfÛj!;",éýŸŽ_ý/Ϫ j”™ ßî¹ õï$¼é«»é'-Vø‹».[ pˆÉoV7ÚRÊ;Oo¶Qä:« ãá¶ìR1JA˜–VÁ]™QÔ•æÜééñ)jàpt'Å aÐò#”»´Žh‹GBÈUE¯¡§;G?ô÷öqì£ú®i@ ñRó‡ó6e"ˆuVÉÛŸ„£÷«]ZF¢!n0ÚÖZRJ,I./“dÐ$S@Öq¾Çmø´ˆXÉÔU{j J&²Æ¬n®A{3xü2Ø\ßè˜Ê±¯òÆ*#ÃÛ¬½Á`ªµ;OƒÐ-:Ãu¬Ý†7Žâ¬4`ÜãQu±üòü;ãëX]»*‰vIq4õ#lkÑÕïæ‰ìNʰ[ýžSÿk1.O Nw_’YÌç/–Ùbê‹ ¿D\_"åÀÑMw'B@7àuˆ8Ð,Ã*&0 Ã!^’Š™½”%cµç’[)%*¢í* ×Ùò­Ä9ŠÄwN‹ù*ÀhdŵòÕr,³É€â ¯æ€nga2•Uq®ÀÃ/µ!Ñíó'{n1á; -.<“<¶Å V¹ýhœb¬Ñ4ŸDãaˆÇøé@DÈöþqŽS°@뉮0mÛ®Äâ¹û‘c#À(ˆ÷ß’ûçÜ] éiœŽÅ© °íâ,ĵAÇ™”‘+Jaòˆ$W˜²»®¬ˆ;¬"r3Šnoè(¡¥ðÛí‡(“x!â!õ_9¤´Zpwó9,vvI›€x¦sÁžŒnè&¬l¼z;ªÚÓÜ 2½•ðM§­y¦:½îøü³5°†³ìŽDh[NIè6vŸz?r¢vï˜ùµÐ4µÔ„#p‚E¢ÙÃ,d¯ƒ–I†(1<5šd€õžôcòXHy鸂_:ø’j›ßrµ-RNºËbAô“{QNžûQ!<†7R¡7íè넘‚"§šT9Ó4šäœ ·NˆžÒÎ¥(7ÜV`MX .ãhÈnA#V¼a½LÙ^v z¤Ñ8Ô7¶qBà*ôø(3¾Úzü„¾[’¤ªmpcyÓÇ<fúUĪä2O¬ý]‡jÜ$i&*çr]†Û„Àb·äˆ½{ûV‰²0h h&c’QË…B5Aãð"Ð ¶sÕÒmc\§VU, Ò¯¾RZœÌáT[×~ú•t¨˜´÷„|‰Y@§;Yc’1¥ren P !úfé¦#©á4Ì+X) ©¦SåÊÅfíÁÛoÈvüdhFpX¢gÛbüܪ¬&3ÊF¨¡ßµy(V-£‚õbŸëORmŠY²1z˜õ9r„ñÀÇ¢ lqVÍ^ñÄ%/µê}’-þ18Šn ƒ—Â8G!2V…Ë©¤ç,Â%FŠJQÔM¿³ö Lcº3rÜ&WÁéàXýDWˆ& v¨ÎTˆJD˜ò2Åé5«EAÑd%aƒà(É¢ç⌯)@€(ùÑU<¢zi©@q/\%òÄï·á] nà“Žt”ND5«-´‡‚ ÈôÿžF“»CêR;'dÆ\þ'ߺ%â<æÇrPólZM¥±EhqÐ ›#ÂÃH(›"\:äF¡üf¬6:^ü8ØT*FøÒ­”áWâØ ±7UÚ/_âF£L@´Ÿ[t$ä„£=0 ¾ÂÍD¬ºÝzÀ;KÝhLøô—øW¥ôPWˆHJ_Æ _HŸ¦-Qm›jA+]Kú±ÓÕ £&òÄoù-kHtè¿Á/Á&ú¢¬ÉrTeð_2øC‚÷•„-8@ õ«¼¦!nx]‡ã1Läµ>§Tæs(»K”zmóOÜ©Âuä‘ZåMõjªƒŽš‰Ë"¡³Ïˆ_<‡tI ½0I•òÇxse|ˆˆ¬u}ÍVEfŽ»a2 Ì%åàˆIyŒlz8ðã¶»þ/­âæÓmåJͯÍpCì|ÿ$Ø|®äJÛøÂ˜ÇÌ.`ROî$'½›)k ¨*VY¤©ÅÈ QÔbBCS¥¥¸Ã?bV°ã§ŠÔ­ç(YJ1éÞw¤¼$`]T•¡¸Ÿ‰G¡ÑŠe‰Þð•lˆ_GÅf+|¦òµ"¹rûðí[¦Ü1,T™:z DÏÎ šzªIfv:¨¢ +·•Š£E:ˆŽóâ!©PÄ~™\óÚá×ðébàÎÉAªó„š‰~ãE’]«Y¸V8ÍÄÙSÑ9G/ô`x¨#B*u–‰Jí™äêæò0>tí'‘|ç¹Ìˆ¢ôÞâeKu ÿD·ÊÌŠGZãt)¹J€?×vñ²aŽ–½hhOîžâ@¹v9‰"sbP¤2÷Äqª– d'Ý…ïL ‘Äÿ>›ÇjaíËM#¹@D·òo€T-´ÑHšJ°r19Lß¿þO6ÑD3{îŒjnuƒG}ñ¤Ê.áÊÜóÚPA.°Þà¢*jÂbFÿ5Å@åßööwO÷_k ÌefêÉÒ¸–ŸýŠc[ü§¹¤ÓQζ°Ð cø¥3S<-F™¨ÎKŠ1É‚eT”ÍÚîw¶ƒB6ÚõñØî`€ôžõÒí™^’’ÀÖ‚ì´`]þiÛ‚ÿÜö¥þ´sï½:>}»s´·ë&åûiç|÷ø°c©5NŽþ-Ÿ!×®Èë¹Éùv‚þ¯íxô‰IŒ,.Ä4è¾+åäçâl)V™/EF|Œ’hyˆµôâ’«/ô{t\(kMë/´kÁ…Yd¢‡mјÂ~ípÜ ®œ¤¸ýAñµ à„ÑšÐïª ‹þ¸#A@OÚò/å"# àŽ8þ "MÇp<ù²®€OZ±|Û˜‘l)”¦ÞÞþ[Ãaþ•ý ý’°ÿ±ß;Ë’ñA‰$ßò([C!ø"ÐÄå [2›Ç+¾ñnF†·Ë2]Ï›(ÄfölðÕÀ|ù :ù(É”èS?5'qÜZߤ½†éx½¼ó›n縶¹âà,ëxÉäuÖ­¹fpŽ~?«þ*ÂÙHiåƒ)‰‡4<+º*ÛÁÔÁÈWj\âµ”âíOþá:‹þ1ÅÓÌd×ëâF®‹–Ý3 ûûm4ºÊ®ý¤½J’¡ölê‘F‹›T}-£ú˜m¼Ø$ïq ˜†”‰*^@ð­áÉ4"UÒ{ÂR!ƒ#²=Dm®Ä®`ÄÌP6•§+*¡¥/ÂíÁ”Ò•ß܈g .îžËZìa‰15ǧ%ž ¢OÆÑ8Åÿ<Þxúìé“/ÌuºÇWÓxaZç\{F|ð,¢Pï u{ï3*wôm*Tñ¦CÛLW²; ÀpÁýåG¢üàˆÁÅD5w(êhtos„àÒ;B*ÿ°*¸u +Â\ϘgJT4»ðÜš…Õ¯¢ ·ÃD°•êÛZ51ùTĪ:[uÓ誟€"4°?¬Z¸,3€öŸÛÊ q?¹·ÊPuHydÄGIÂõ¥'‡%¬#¦ Ñ3dcÛš91é&‰|c0eU¼,6{–²­öˆe4 ¤JÚôqlj“å§Õ Qž ±b)¤ :;`íÀîaÞësô“ÀÏÿk‰ýÍàÁõ§`zÓ¿³oÂPú 6‚1ïiF¾6E;:Û¬´ÅZ«­æ m›’O­Þ Ü¨Ò+¡2ë’B/bPKް:ަùP¦ÜÓžx…F†t§Œ•Þˆ/¢X©VžÊOÒ$á=á¥B!˶¨‰€ñZ:L205?AÉ÷Q86¤n×îó ½Æ$ à¿ µÁ´Qîü×ñ©ÎëùâÆ6!|‘r^¼ ¾!DŽ—·åÓ‚–å-_O;N~N¨Sµ·»sröÎM eò»HÝÙ&‡{­³B;õòêm·=W r—®Ó¹y¼×Ç0£oÏÙ’öTÙµzþìEi""N1àÔ–Ÿtp>w¿¨”ÓÑÎhè†-{×azÁ Jì¡cÉ ÍS‹A ‘6ñ&ÅãéP_’^( ªñ€Œ`œmqm ·tmq:D*t XRڦ埇UL"ãç$ ²0¹Y©Pçú–ž “N{Z˒–ܠ÷4çÅÅØuªjº°°½Nzåi®Ë [Û ®= ð³ªTÊʃíd•Ba™²=0Xi!“GÛÀ–P sl{)Ð¥…ìÜ vÎ@dé© OÌËà§V«à¬´œu;ƒµ>L¯X„e-¸‰Ò+×éàóÏ|¥”^ùÏÙ$ìG¸ëOEÒÄ:Á™×;î÷§“ ï4rðËk4ÛÄÕ‡GþÕ0´‰F%Ö¡‘µìf¬ì2…<—ž ËÈø ²±ªŒhw‡`}·]÷7é0‘ ù"%\ù2 ¾LWºàÖÛ°¹ ·¤Ì%b¦@RRX9Sp¿›žXû˜‚Ô³(“w^H-xŒ>—êäçóïa)<:³w¦^¶ñÕâUð´‹òòÜC4EXÃ=óƒúèœaÅ©„'¦ð]JnTøc k®™óAŸÞBé7Q&ý"ÈV˜ÜÓL¦õÄ„T@…LhÍØ°)ÏT>W¯tSó˜]q˜â“î‚fy!¢Šz$E5ÌþS“’fº{"0… #¨P9I‚íë+~QQ¹äú¨`Ïš)U&–îà.v£›úþ¬.¾–=¤wJ†²¬Y®«¬²E¾;ž5&éë3t÷&¢¼Ïª³âyHù±è‘Ù“CªµóTé*®w !›fªjŽK,ÍÝ!+ú9å†WÎTm2"±E+G)í0 aù)­ÒÌë0½*jðÀ‡êãÉ£›þ4ŒS¹f hàÃô;…3­m ³:úOF SÅ º(£Ô+2Ø!6ûÕ-9a´­âN޹-¡H^MãaÓ¹ƒÚX:»»¹H†ü†Xô›»tŸÑ>‰`0÷^p¼~§Yo“9 Ú7uD%íøÁ•ëaT¸‹-²iÚ˰ùî»ROúaƱ?¤t/ÆÓ QvEª€[ÝH°…À«;PEmìºdÚûf îè¹)#ÊG0Ï™³e–HkÆæ?++K—³O-ëšI(Ì31½TÈWœBÆ7J•ë?@' O³ñÔ°pM‚é²àT»_m¿;?ywÞ;w‚/£Ë¤Žò{B`±c("÷“(z!n½˜ù†?ì>B!(såÿ¡œÇâ~·lk®ü3iØ(ê¶(d'¹ /›:+€ü(‡·­8µC»eex³5‰¬§&Œoy΄™Rãšm÷ËÓíÏ‚ãçS°ŠX^ÎhÑÔå´øz¶Þ;8ß?,áuò´JFòT´×㣋Q¥ïó€–é‡Y;Ù‚–Oó¸•ÿô´xHÙuR™£ gn8¹šÒó5œŸ½êVŠ5}E{ê"S€˜WÀ¯õ]›xdÿ~ä:•d*â¶4¶"lhOG¥ ]ÇMˆ!“U:Ù2¬#qÎÁRq:.ú8äÑ ø2ýr ù=C4ˆ®t‘ÇNt§D€ ÁwÁÊJðúÑ…·wp&h9Ïz‹`@ïü„Îü<ð÷Znuü V¼‚>T?Ì|ŸÜ¢·öûQš*ëÙ}¶¹÷ÓÁÑÓ-'§}szôv~ðÙ}‚Ùœ<Ç>ìÁ/Gû…ç´Ý*Þ#Jn¥Ü¹,kO¾¸¥(—]'PÓ‘û…g10‘þh³' ÙQùLˆÑ?A«g5Cÿß½_‚v!­c=Œ1 èf޾ ¸âDn°²•P'EÛÎË}öJŠ’pev|Ø™pá; âþ».ªË°:‚VÎ.… s7ÎàÖQ2r.ü1‡"zN@Ÿhñ^ªU˜Þã&ž}»Ú$¼Í}SÆ1 ààÕD<‚C‡¼†ªþËZÌ Ú±‹¼kÀ=y‚É¥yÛÇ=hyTö^°çEâhžòq‡v¾¤C±§44‡©ÍwôÏã—¼[ú1»²á¶/BZY—lÙ-%«àKåú©Ìzä¹{q‹F¡ð‰²®Êp#>~¨Âüu£NþZž¨ åÝc²ãUÆÕ›%ÞM­1•I½db·‚J‚ 3]{ÑWõ<­¼ÍÂy¤£*|>² 681äŽ)YtrçC¿jÜŸD&§¶Šå†¶"C\°s³CÿGP!Q2#_'Ĭ¼ &Ê¢9ý…çÞO Ô)Ä«bažR–ˇ’ø¨ «á  Ù®ôzЮ×[áaXÅ —Üw8dÑvëË7úô@‡žd¤Ðjà¡ø“%œý”ã°UÙ ‰Ia‘ºTJK7߇˜…‹ÐÝŠÙñ¥,Y¢©ZÖf¯xh^´|6‚æÞä´ÝlëježŽ Þ?3\²{„f¹ÈK¤ÝB»ÊdtcGw•ûE1e³Ìµ‘æÑáþù÷½c‡Ô¡´‡móQÐõ:Ÿ›–4:î½§²a„gùÐ5D™XÍW¶ül+oœ«[¹¯é*ؽhèQ…æ5$–¸Ð™,þ2-²¹BÃka~¼°¤ª–‹Ï ßÏ ûÔÎÎ^+0é…}‡¡3m$·#×lÁçŠÏ÷YÖL̲v|²hÇSÕÅ@ ÌÒ‡Ð»Š²^¯‡8z=þPr(W„6™£wHqÛH¯wêk烾‰ýkÀð6¡§Íß4{h㋎mS3íX;f ˜¯Û|s«J·ñ¨»Cçç´Î«2™€™Mò©¾‹p\º9×D?/Z+ÍVðB?}gGå½»ÈY7Àî.zÍÈsáCÇMhÍv·€`ÏesWSå.Th±¾Úæ+=Ðþ@ô2—×tåÄêN×´³#Ûià°íN[õd±³ØÙ»,•Ç7ég¥"䆕/“•î‡ê2t}l€ãã,| ::Þ9}sf£DãI¯<ü?«b×Z}¨évw•ö29{óò¾;ÓÙv&ÆxR ŒR(V¾ERÙéÁukõËt_búrür¥«SãÓ?σ•éèýô3ÅÎe6ÿ&õƒ|ÓE:ÈóÌž,# 0°ÁŸœB”P·UŽÕùàÈDàÛVËYÙm9¿'”‡’OG¹a‰h»Äv(£þitIE¹¬¦-Ûé©J¨NHvF´ . @õÄ™›ãɶ8ÇÀÅš…ç¼’/²åÅÒþp+&’sÜçú}[õìVS(n…ü³¨>Æ7ãÛð÷Kñ÷¦|`A'ú•w‡ÔÅ£õÝà–|‹³ ¦IpA/Â^N‡¼ÞÖúÇïTškOò"K(âþuÕΊ‡’“±½Ú¬©Œ´ñe ñíÌýÿÆMJýçÑ~À6÷劜Ë.joþåŠÍn¶ÐævÆIÛfÐ#ݸí¼x±A Tz!éãü¶t·‡y&¾³fÏ**À“ßëÚ.3¦dÌεñ,p©1“ °Gä…A„þ@0¼¤hb/8¡d|à 5¬u‚| 7œ¤÷Õ(ê¿•ño®ù^t'¬ju(”Çà|áPqšúEÁøq10dåÌA´³‰ föŒ¥Sbžs‚1Á&ØÑYNmSoõj"Ã8HϦT’ŒõÝ@‘%ñÓJùÈ—HX;X'Ç=±5¼ÂQ«WJrÙÞÛüƒ^z~|6]âcM ¾Btê|Jû­XþF‹çÙsé@u¶óN¦ k‰ ZÎVªä¥ò.>ÏG>†zÞŽ2Ð|òýÅ‹ü^zù&× K¸…%ñB¨[Hµ#Á*4ê }»¡TõY· è‡÷€eKUÄýôámx‡Ûê?µãy—E&®" þýè>²(ÞZO2èB1Â˜Æø2ùð.L’±„ˆÇ/ChøAÿ£Ó…¯ÁÁˆÑ3¢ÓŠã 7gœLÂÉ¢.Nâ}™Ûëhás›ÇôâQO¼,Ò‚cÂãôÊ©¼œL ;}8½vq¡ÉšÄW×x¼èV¼JoÅ¢h]M ˆItÆ ›0còtœŒÔl¤õ|R @9ZŸÈÎA”‰óS!ÞK(MvøÞòþ0ÓŒ•ÇŸ]ÿ£2wPÇtXõS`ǥǢ‚{ûoÛ%Ž·Þu’ÕCq´×à'¦ |½õK=Ø CËîLÚP‹ØÃ“»ÉUï$œ¤‘8ÛGž¤ŽÂ?Ä­ &€9¡ß…SÊC.”Qsˆ {,+êŠñ!|‡ù¡¸ •iŒPR%v°Ã9l¨È©`–l P­ÜlŸZ iMmz—Þ¬¨ Bæ£é˜¸•fZYô¤†%cLÁÐk…VÕ q«æUq6k ˜Ævr÷f±m§0ãl³ÍÃ8§ÚRXGœcžµ÷\ (µûŠ{Ý3;ìÖ»Ÿ»mØQR{hóÁA;ú-Œ—íJ½~MF±n­Éþyüõy­âϰð3`~þYDÑ5h‚‹AõM‘?¶Ó1B•B(h©·ïÔé(7¹é@šªV} m;DTtc1Z¬È>i|b.Û„k+‡û ÅWAÚ¢O¿ãcâ^™ÆUòÙ³vjÉ©.*©}€FhÔÁl\¦¦½­ÿ)°#QÛéŸØ3œrÁÕÑ ‘ûf/ºl¡¥" àž¼¢þ vÆ¡û] ’ $‚ÎR(›°ã¡ª0Þcc"’ ¦è+G“ô:«Wêå!ЕO] ©äÑJ·©¬Ó-B*Ë«#•Ý Êz*ºÈžJï³Ë{Š‘>I£¬Fo•9SÖ[ª£X|Ü•F´³ð$ô‚ý*:{«Ò¿qâê)ºZŒPD1¥žÊS;`Ï”bìÑ.A¯·Ò-Æ(ú³1JŸ «G©ºŸ-næÂÿÇÛ/ŸT„éþ„_‹Ä½J¿ë}Šÿ½Ë¿¯¿ËÅ}] ˜…±æ ˜õ¦Ê–Îãæ˜Kža–¹›ª¸(wÙƒÕöQ…Þëx4Ó®Ÿsö“ÌÉ\“öš( ßÛ;&<„OÄ1䃤O“ÂÄŠ›Š1Y°ûéÓ„Jj)Ú 5‰ý˜Ž-«êe©O`/âQ8¹£”q04OÖF½p0q%_i:½ÀlÿYI•›é0‹ÇÃ;Yå ¸å (5í$ºI>ØÉËã{¯>T*0懯ž%¢I Ùë&Ñ]§äYºU'·À”·FÑUˆáÍ’*ã$gT /Òd8ÍtùŽUPˆ’ÑoÑ$‘56ºtÕJbÊÀã)‚º»ôLŠ ÂÑÀóõc2ñ|¥UÆ:AMúI4é»#gØ‘;rÓU̪ŠËl`ø+Q œ#.i41-$oCÙ9æ‡^“p^“~¦d!1ó¬ òuôQU†_ ½%‡‰ÄÓ|0+Ÿ®? ô`Îø?9‹ãÑxö#ÔÁã—üËM˜Mâz3ÎT*6*QQBÁ™ÀÊ]SNÊ–aÈÖú³ŠÄÌ"g&Î-ƒsk~ˆ/¸Q¢ú> ÿ†Á¿1ÿL¼É$à哽±=_\éÆw‰Ù6Ý6U†ÝÞ£´¢®ú«~N†Bàö[r©­ôD5þœà…J9ƒðT*ÝR“©Ô6:-~fXÏ4»žÚ.ð(ÏϼÑË ­R˜ ej]¨x°\l!›=ë„h×ñ©%ly¦q_á¯I94³èÆnÝ6;Ž×!¶âº¬µüÔ 5í^TyÜXÒ%MÁ¼¦”]Z~ ¬%ÀQHªÕ´:Œ”Á¨&¾´LaSµN¡9zt}³‹_åI õq#¸˜f”s€.¨¸½íߌóÌ’ º6¥ p®·hðçh¿™Ã #nZùíS‡a¢¥±^ {²1ùò$›øú_ù ëöX•µ´ ÌÒ–ø`P3šÓl’?{༾íe¶ì¤!Ú¹ZëW:9é½óºÒÛÛ½óîí¹žh..5i¹WåŒ4ÕRàá É %«Wp˜hÐEß´d‡»r:™/ÍpßFá{ÌK’\^¨UJïP i¼òL(†áOí«µf Në£IR6¦ç–³fm/¦‚D—Bšµ¤÷O¯š’,š7î1Òm°~{²›éšæ– ÞîlÔ_nØÏ´wÕÚ Šô6›My?ì_7ìi:½ ”ÔMiVjÙ*%zíiC½6ˆ†Õ|Ó.*xÒ) ¯ª z*¯è2aîšÈÆ‚Ût»ÇïŽÎéuݳ¦¬á âDi*³áG=µKÆåYCv'чœ¼Q¥½V3€|%0ç$«CXÈ=äÍíJ>QÞº< ÉÓÕçä‹·€¼>ÂÁ]ûQJ1)/ØÚs7nÏ·¯|›«ÆiçâÚþO–ÇÜõžåægôédu~2xò~K 'Bæñh^%÷X#VÛ6ƒÜÝu%f¡ùŽèu½7RÊ%M,DZuy†OÍâ«©qFÛ øZXB—zÁûYN¦ê‡Îâ›Ã2!þcò‘ˆ®m]Å"ÒÐæŸèèÍ냷ûÁÚåXˆ™s€H<2 9"ãä/2 Òë×û§”¦ïW¤ír<ÍRußNbXéÂçζJˆ(N Až^§ƒœ*ÿ&^´‚ïô ö޶ÒdHåýT¢*…¯>+€êû'MÝ Å‹ ªT‚z)ÝØÆ[CAP>‡%kÙGÍÙŠL[WìY%W!%‰xû1ý2Å®3tŠCùGë ó s—õЏšf S+÷y¸ÒÕé ÌÊMkû²›Øöy³Q%tW…Ñ_ååFõõ2Ÿy½Ñ…)=•;á%!ýÕ,WnÕ‡­5I‡ï”mþ’žìtî’Þ¬­jÙn17Í\"|7ÍJ¯˜Iþ+ffÍw«´9Sˆ¾#ô»œeµÌ]ÏÌõ,Oª›ÐÂ[T4Ñò]úбï.*!´!ª¯òp2(c°‡Õ=(ÓÙŽgŸ¥/ð gƲ Ï&”mÔÝÃVÐË¢ )ƒµ7‚D»?r#Èž¥Amq7ÅÄ9¹)æl>è Ù´Ù.l¼¨íHoÎÌØz±×«†[/Ìàš±õR3"ÿï­— Û©½‰òï­ª7«ÇŸaë¥NÓÿ{[/õvOþ½õR±å¿·^ê6ý÷Öˬ†ÿÞzù÷ÖË¿·^¼fm½0§t![/ Þ[/ J£­ËÕ®`t·^LlÝ·÷_œ€†gûEÔ°£peÛ/&øàC.:4ËtK1}Álˆþø®-¢hš~}?Ó„Qp;Gî)˜gGG}&ß÷E "€ž7aX$†ïéP{ ¹R¶`+(Ð{A|¼\ÞÛ£&®ÎÒƒ±ÖµÕnàËÒHUÂSWŠU髞æ.=1í¡àZÇì´ø(MzH¬±²î׋ñ7ô…úel›©÷“ŸPŠ þÌêr¶ÃJ“Ћç ίã”=80;z¾‚×ÀVDx0÷œ‚)LÄ£’ݪrlA€èh%¨3­¨¸ª¢v=¿ð¼£qööø'Ìø‚¯ÊpFl‚ºçÇ{Çσƒ`ŒV³‘×âµýP.Ý„»Äª¤oÀoé\D"<•èò^³w¥­gÞD–WLÚ,ïÎMš]Öl•úFÌVÑÈJ…–KtAuJÓö"©§˜Ê*…çÉÝO`×M¢Kêd’|¼k©å*_¤H‘s”þ¢…@UÅÜ=ǯþk÷\Vezœ*?zÌè¡¿¦‹”ˆF'ÅtJzç”Þ‹ŠXäNðçäqF¸ƒ´¹Ù,{¶ÓѬQÙÛôK¶ì=Vëm’¼ŸŽEµnÀ¦‹z§ÔÕ~fh)é5žO ˆ:Þ”a‚hLÅì²YU(g«'•±L2­ «åKM…ß© ÔoTÆý˜U0ÂM5þ A‰L3¨T®:o+H×)T÷;÷}w=oiÚ=ç/«Y–¦cÐÈ@ž0k¼XO¤Ó-{Ÿ!ðçëwòô?°WP•ÊJXʬE&#QŒî•T÷áÑ™Dæf+ᑜྼG|~€z8‚áX03Ä…ænaf´µ:©øÕI„ùñ°L²ÆÖ»”8ŽÂAÑ‚ÉEA÷¾U¨M…Šä¯‹îˆëí@·zGÌûØìä‹v8Q«Mn ÔB;#¢÷Ô¬>æ n™…8)nô™&Û …ì³ÊøAí¼öí†Zåwº­Z›U²°jg48¶Rå03·ü¸EªÅ¯k†¹£LåöÍ3Qíø«GzòÕýèDñ[lÔ±&£?r9'€û§§Ç§l6²g‚iªXxyÚz̯/™¿&Ô¿ýäA?þAHrËÊö'q¶´G2KL¤ø |k,ÝÓíu<Œ|ÛA’>=g„-cY4sÔäRÊF ò…7Ì‘¸®F¦UŒXÎMÃ&Å l1 ‚ PïsÊX•iW‘Öç)÷„ÎÊyl*ã9Å–uŸ“ªí*;{X)¬#ü£ËQt+Sù±ƒ,±0DCoÚY¿‹lè>Ò ;v+ÄÅ€Êö»;gçèÆcŠÂãÓŸ]JtdÊ…„Cs†w˜¬ûFž.¼ Ç(.ýk‘tˆ‡ 1k•‰ð1êéÌ:Šöº:Žˆ—%êêeC¶Q‹ B\éŸz;c÷ÿSËÿ»%.¦è“/P&x ŽÒ®vúb÷ÀÑÈX׫ŠÄËl®%Nª6E;S R]¸Ë¾W-4+¯É›JJ/ÿÎ83ø[hòy${Š'½,a5­¾zØNýxøÙ$å+`û`€˜„“¶‰W£¢úª8—"NE¤–„JT%éVåÛNÜ@,$Èšçå=©>{ž|r)³ ~r0Èj.`[Å嫉‚‘×7±e€¨³’l;%žÌµ®q`Rvb2}0Ipí<¸†‚xÿ@i[ójbñã]fÌÆ¡'á(Å}v´[M>"Pn«Ðh5¯Ög~æ²cg0 5oÒΖU=ŠnÃô}AmÏB4 #å òZerdU¹!>y1u¬•ÕC{éyˬêäÔ´†iRs‹é!ϬÊiÓÂws,SX¿ÇÔ²‡Uê& QnÏâ!Ï®œwǸAiæY›P8‰¥-‘±,AÉSåß© ãʇ“ Ó•G€| r½ûïõ~ÏŒçF0Ñ3O^Åݳ&«¸éÝ éß!ž3Q?p(ø', ¾Ç šVÓ‘ÊšÜÊŸ+\*ø¾~9Q´§õŽØ#‚ðê,*þ*ØÜ`ÚGc¶a>¯†Ú¾”íÏ3,T„Ë­S‚a™¦%6d}ûQY™éþ5¬šC<Ï…y î¢Ìk¹åžS<)°¾rjøSNŒ•_”óHÅ~†˜€õÜRjYaëå·â¹èu‡Š6yÌôKÓNÚÃ,é»—Fz¤OõÐö©€}ãT}gŸêjâiw¨`í¨‡ù/eOg—¿Ój¿ú¾¬§æ¡{V}^:‘·Ñnc¥iF:§G¶œ{=q%+J È”~xÔ/¾˜fÑzËO–ƒ›K)¬ôg×á ¹U!ç‚ç%»¾½!Üìñå¶©¡Nd¦ *ÙîÛÅúYþh¥’Nó¬ÐKiÆC™h+Ë*]ûEÜ®ˆc%‰MÕËzÕ"û-µ W ª ËuÉGÕ”Ô¨6zÓL¤Ûõ>ïß=â ǪtVïš 6‘«W©Lßñvð¥¢;=¡õN¯‚˜(šŒïP߯ÀVpS Rv9Üí¶ui¡c´|Q¸RZ­«,=ý‹G8JûVÈEÕJ¼ñC°ˆ&é¿þ—›ýqçíÁžî÷ùÎ¥ðÌäDÄy.]œè:¯–y9ô– 8 oݧ’õ»¡²Ÿê­Xóù“÷¸ ÂWûkeªb³ªª(à‡Ëú¼hÀ Šnp> ‰ÓYëdŒ[«‹§„4uçêI1%½\e0»†?ë€Õ¿ŒG½¾ ¨wÇ5¡VgçÕKvcZ}*§ŽM#sêŒæÌ®÷õú~çÇýÞOû;?@Ó3NÈ­Øñ£‡/ìcPy(ov[ü,þnïWE‰–fG”¬þ”ÊT™мï|‰ûdl>óž©`Uv&Œÿ){™¶j«bý±x‡Ù·©ì[IójÃüJ¨ìûÚš@ üj4šFkïŸÊ×WÄHÐ…-J ,^‚¦×Uj"Ï)”OAËû@„sfåÖ1ãœ'"¬ôä„ü²¥ïþ>ä°Ê~ûÊŽ«'&Ž­«EPϯªóÇl]…M­Q_W æ)$éBúÎã!ãÕ ê*†'Fu¦çí¨EÇÁÖ0Ò¼‰Äû€Ìè…¿Ól~ö€Ñ?ô$Û[¢÷ôý”øôf˜\„CôvÞ5Š;ÛÞcµÄó›d0š³ð¶±qH…mƒ…eïa+”•ú@T¦¡TËû ýÐ=Í[†ËxBÛ&…‰"ˆÂáomÈ'=e(Ûä.àœ—’m† p;¸‹¹£©Ò«»Bö ³½Ý“³wo½aéÇ)²ïŸÍÚ²™lÒ;Ú9Ü«{Œ>Cê CYÆ4:“é(‹o¢²yEöDôTù&ÝÖƒb¿P5ädŒ³ôÎw^Iš:ü½ûY{ßÞý¹²á- n´óòÖ±mË÷­0Îu¸ó_ǧªÁ·ÁNÞ“;!¸[*Þñ» S´Ë&P¡o=‘9Úƒà±'`)Üb`Xµ"ï) úÉ8FÕ6Í0Q—h÷M§c’u̪ÈÇ?åÍ6ûtýk”Pæoà¦FžFf¡ÞtÙã£ÜMÜWé”W&7%L±?pSãeK9ùZ°št©œà¾8o\Ú› êŒÍÃd!èGÉè1ºAbƒh&æsg%Lé8?xLËõ‚AnF”´`DH¨gÙ÷T’ºñÍgÿPíÔÈgŠE&ѯ³»¼RÕ3É=|앞™%öeqNZdR†¨›NîÚ>°d¬ð„…Ð$’ãìôqîÅQÚò.Cù¢PóñEaO¼ä+ËEÖOJV7[ÙìÙÈb¼g…b_PïøTŠÑÊÀyé(Š}>zî˜0c#db{T«;׌¡u½xÖÍÞ±8(«fáï¸YߎƒÛ¦Ä²Е¹à«¯âÒ×Þ ì/ñ¯|£›LiáFÚϳ gͬÍ‚ê¶!Š"{cÒH¦{€>yªBˆOJTé˜u*m›à±ó>ø;˜ÞÜÜ)­(Í\ž$HïÒu¥0H=0…®„ãäN,ߨè$m5r.‰¹‡í“ðâ; JöèeøÂ¶xå.ø]$_’)˜Ä/Ÿ‚Ot|à (EÃ’.Pd¬õÝYvÜȲw³+\+Ë2øÙ@{gv7(TDz½PHÀ)3"#ÔnÝR¨|fV¯/(ô›[]çÊîa{[uØÞ‡—!ÒdÄÛ‰ê˜L1cì;»‚†›4½(-ƒ8ücMî”ù5#^(NÝ@[_r>Õ‚8‰ùaÇA—Ë*•W¸`ìÐòßH{›Ÿ "ŸÕ±E Ûé7=±ž·¶}—WE˜'pƒÚ¦gê!¥]i¦šMW(]J<Î’‰’ï)›Ó‗h¦—Q´lÅ–gÌVoPrnì¤jfˆ°‡qI¸ÎZô‰¥ÆVE‹ }|‡6¿2uí)™©­HsN€šÍHs5-§qû^CRK@Ž} €G…¸:NÐÑÙŸ1ÂbŸ¸ö]ÔË›JÆä\â¢%f>¶<ÀÓ‹·ádP¾¨,¾ˆ‡1Ø;Éhx‡çvìkÅ2–¶ÿ·Ýý“stçâ1x9½Ë0ânMGDü&Ùäêµ*µ‚«€â‰U¬j¦àÔÉí Òìú3î´ àkFéSkÁ |{ ®“d”ÞTä"/ÞÌz™@ccÛù.Néy ð½ÊèBdzÐ…äEYÿºýHt쵇uu&áTfìO©òTjK' )`ƒ$0ñú›ÜdgS© P!öÔ£Äi"æ× ÚW¾Lʲ+X+R`ºªt'%E* 4TÍõÓ2È•`  de®;­À¾$'wOÛÕ7ç$8O|3·»éœ”Ô9™”³ÅOȲÉ`P${xéc€™Kb ]ú¸ÀP ÎB Æ )%P”Q>¿l=ûæW-g½t$2^¶Å@ÉÌÄ4àµ#“-~9x¾¢fœÇñÎÏ2u³0±²É‘‘|óÅÜÎÀA PmÎ6¥/ÛþßÍ6¹³äõ÷>߉ŒÐj›Og †ôÛp*=VVf{T:f“3Kºãä«ñVzô°¬ƒ»âî8Y‚òP »µ<ãÒ²}²<‘êÊ¢ªxÌW §|à‰åðU(‚8àFÇë¬rí/Ó•O¢~ÀIJ-rU[>R=Ї!Ø –¢$WRQB¥Nèž½Ø s-‹´ØAAWÍñœzÀñõEµTl®øõ*!atÞ²ŸŠ½ÚÞ ÙLÆ~™–°Óbh7è=6KʪŒ>nJ^ÒÄIÐ̃‘èý ¼6=+ÌXt\§RHÓ‘‚ œ%Þ!s£ä9*×+ ˜†# ¦Im£æoâ0÷¯]L¸ ­3È9Õ_t»ÜÙg’â‘p^¼oÚÑlm? ^óÛ”Z¥1j\é4 U{' Ù…‚³»Žm2˜ féòo©¨Þ*ËHS¶ %£½;P*q_Ýu‰Äp¶,˜Ug§¸ÏÐÖášËvUÉз?E£~2ˆ¤Ý°„ª¤å¶.Õ‰q'ìñ&¦›ÑyuÀE:8zÓ{wt°{¼·¯M7—ë ]RÃDã»QŒXA‡à?¦ÍN*ƒîÔ {, ÎÀÞP-÷J‰ÃC*”#*Gè1·¹äfŽÂÌ©3;„²’§lÓ®’Ð÷D§i¯ã"’ÑtéòÐê—ë[éêŠØ]È/6¶åô8oAš¯æa }.* ~Ô8—¢/[)ù®¼£žŒ" ‰¤Aœ˜¤f2ËO64ÊK;fNµ>:I ± }¶;©3ÀêݶK›ÔbQ .¸xHÊo_rçuœæF2vÒwç¯ÿ“Ë!·æ=þ£†Z= ì&¬ dË-*#läå(© îÎN¥r|Œ»a•zLgœ³—b`œËx¢ÇíH¿¶xØïItš—.GâåõÊ`´í2<¥ûýÎéþ^ïä\¥·Ñ¸¥Ò6ë‰}v¼Þf–Ûúá”îÜÉ7«k¸×ØÃë­Á/%~5ìòyÓñ Ì"õòw»—b´/_oµ X;ÚŽkl$²î×µ›v÷ªbw¯ »ÛÀ2Íõ³ÌB4—2ÙçY¥êž °Î|Z×MmÕžŒ~‹&‰µÏR圠Í™7ç`‡ÑÈ‚šfƒçϱͷÁ®8̼|þ\Ø™àÎVGÈs|ø Ú0î›õ*F3Ö‹Õd4A¹%Ô v¯\·¨3]úDéopü ø¿Ê’ãëPg«·[ð^u\82ð„î«õ¨Ï“ær jÀ|º™ŸQ~@Žô¡òs€ô¯xBUìn—Ú&9™ANZLNm)E5NÆ3ç¸éjU¼*3åEÒ4cßVekÙ²qq¿oÔ6Ô”¬­ˆêoñ:Ò@e˜nñŠ[÷Xõ âÀŽ °ÚF3»£–¸ªÈT6r|‰HÃ4h&Õºîg4I£^]Œoß&U:×¥§—}:fm0ÖÖÖÕÓKá̮蚵„܃ÃRK=¼øÖ°Svs&u“0ªjøÚâ—^Se¤z”VÃE·=îó0ÏŽê»{Â&ò/uŸÈÆªŠ«Åÿ-@˜þaC2M¯ S—®Ãsè7ébe«î Íà3åh‹ã¢qúÄ<ßøjÄ£ºåëËêòWV‹"{T&‘^·,<°N¹çBàakW¶êª¯ì0›’û™<>kœhåiØG«uå]aæm¨Ä£Š*¶n³`†+ýxpº{e·Éä}z_~ç½l÷åÞ_T…ãþ<Â*E‹«8 kV>D}u00‚µÊ΃ƒ¹v„¥{IL r›Y½ÌG^lˆ³â/Nç—€q͹®×ìÎRC2y\sÆd yQ-`‘—›åeòbS7*³ÈÎV Ï0.ÔÀyóÜ+± Êwp¯4Ï•÷ÀÀ™=²Ö‰‚øQA¢¶móG‘Ä—ÿÇ’,ü‹G”<}½×¸’…ÿ³‰.ÙT-<Æä‚oiª}æ¦ÆBêRùïÀTõÀT“q©¼Z5^?Ôåÿ¢^ dM›ÍíÅ"âc ìAme±Œpša±A5ö‚Ck¹Åc®Û9¬÷Ë÷=Eå<²°´ØœËÞåEèlL ÓÙ¦øŸ3Zg³§YÌîþ¬œj!>«MÓµ¨q¸¯ 7*zµ6…¢ƒ÷F]³`bòjÿl2ÆïŸÎÅ„*m s,›0¡VdÓ¦vÎøæggó7S‹›:óvžèégÇãFsmΨì¿íý×àżQd Z•X²kŠG”‹k–Ãi»¥:Ƭ·ŸYü¹^,Ù4ü¼bÇ 8…XÖµ?æ#«O•bÖ·3ó©% ˆgSuŽUÞ§™½KãߣñïÐøög’Át¥?’Vº¯É´÷ò,¹ç½îMpôŸÍÖ„EÔÂw&èÍ®2 (5^ôË#n~§™#¯rÿ¶¬~Yçòv€4ëns¾¿Ë½âœÇ·˜›Î‹çuýž,õҳݢî>snT»ì•›å]~öŠMã;Ðów·Òƒç¢ICqZØ…gpý{Ïs+Ñj¡LÞ¤!Ó]‡æÝ«è2YHkß‹žaý ÒcÍМ…¹ÁMé…¡^LPЂ9ÇÍiÞ­Zq>‹€E_¡ö¨©æ7©çÓ_©vŽÏ`Êû¨ú\j¿ùíéùµú×§çÇÙàþ´w9Z]Èš»„[Òy=¶„ËÒ9qž;Ó~þ6îmÓËÓs[ oQ;`ª„0¤8‚YX±JÛ)4yòÞbùÖÔûоŒ÷xqÑÝc¦8ùó·0zœ-ŽndQjÌU k󋹊ß_Þ¢¼wù8 ‡63‹ïò’óÈqT‹‰¯,‡Óµ:²Üœr¦EEVl.TL¹æHÊsÊ9‚Ò8¢2g7+…STõú²³¸äqfý0Ê|j²J9]»>‹ENìUÊ·e0֛̅­~ÌÄFW+Í›AÛ `²¼‹H0gÀÍ(±»S#ÍœÁ¾ðDs–âi ™O pÎøŸk`¤¹o™saª™aƒxHÁº²:ÿ²¹Œ¤q\G-#móÛæ ‚1µI/›F@æ3š&‘ÓfF>,ó¡(‘œ¿NQÛ¶ù®£¯¦—oãQto1…ï^"6²û‹o(¼ŸGtCS³ØØ[+²1À×`Êö•gÃW;¦áÁYâeW¨]ÜŸ|Cƒ™Ä`=\nƒ!š+€±$¶Ö ©a ÏœA Oïëeŵ¥cya [8ê-J»Y m¥p…¬]W`«Ð+G*æV{bªn]¶Ô‰OxúQÅ9Ó¸ªF&æÅS9&áAT'. VF, ãâXý(„§Õ#ï¢ã\ÔŽ>Ì-t Ž;hëüs:4ÔõC‹[=+‡²zØ¡l‘Xsé[B¼i¢%DŒUkÀiîŠL-áPS²i·€U( 3ãl1/ˆxkøÛµÕWs¢$QØ¿ü«KIö¹½øåû‘¥uùãc%?šL" =Ò0˜ŠV.íV8#¬ñA‘&ÄU8ã°° `e®¬>]3¯XÉ·–ytÅÊ“3ÿÁ•Ï~äk0d¹`Š“5?þÒ„M5b*Î ·Ø“2Õó7•œ“™•è«›ªûÚ Î(µ°s4µ“0Ýß2Så M½|KtƒC6ËJü ‰ª{géÕ>ª³ìEš²ú§yî´Eøiž+ižþÖ8T)=R“AL{6>´ü‰±è#CŸQ:?_è®é2Õø´Ð=š+µÝ#mõÏ Íµ*¯Îi”,ã”’Q«Ë8£¤ã sœPšåõÙÐðÓòíµ¦çœª¦¨bÖ[Ñ'oJ*ï×¶új¢–»Ã8e÷wƒK⻟û[²{ŒØI¼ŸIÄNQ³àˆÛìÞ–h_çt¡ÁØüÎÇZåQYý²^嵌43Üe:ºäp—A´˜{Z‹çn.,7@eáYÔý,ÞÿŠ‘K6–q²D£ñͬ9:X阓¨\WVIRëßÇj®þª„ˆdݺŒit‹÷¤’G©°Õ¾ƒÕSýûWU­ˆBÙàîÕü8†QÀæ¸uÅ;R#¾¢0/<¾ÂTJóûVÍ…oÑe³¦“†J¹ù-«9™ú7¬æ@Öàv•w•Xoñ[FÄÂh eD,´?5Ï*?+ë÷¯é}ªæ ~Óƒl?;Æ`–ÿ¢ƒ¯†¿][}51†3dÙ=f‰‘øî'Æ`!»ÇƒÄû™Ä5 Ž1°Íb ¢}9g061p¬U¼à²úe½òD25¤™1ÓÑ%Ç ¢ÅÄÏÝ]XnŒÁ³¨ïEƒÅ’%Æ,Ñhc˜£ƒ•b ¢r]YY\ŒAA¬ch®þªÄdݺŒicà=©ä|)lµc 1Õ1pTµü}…²AŒa~œ‹ˆ1(`sÄxGjÄæ…ǘJich.|‹Ž1(›ýs14SÊÍc s,2õc s kcð®«ó-~ˈ1 ´Œƒö§æ‰1øYY¿Mc Íü¦1Ù~vŒÁ,ÿE1_ »¶újb ÿ=&ñýeiQøî'Æ`!»ÇƒÄû™Ä5 Ž1°Íb Øþ®Î”3›‡Ò*>pIõ’.åã ÎÌð‚éä’à Ñb ‹æl,7¸`áYTpu¿¢¡b Æc –\4Ž-4ï_¥Ð¯+(‹‹,(ˆõ# •^•À‚¬[—/ ¬#•.…¬v\¡)¢úa†©–‡¯06ˆ*ÌrAlŽ ëG˜‚B¼ð˜Ó%Íc oÑ!e¢®!…FʸyD¡ùÒR? ÐWƒx‚omXkÁ[F4Á¨žeD´ç4O4ÁËÈúÝkLh¼Æ7%Èö³c fÅ/Š%øjøÛµÕWKØ=Ÿ„£t¢B9]&÷SpñÞKlÁ´,Æ€%1, Ó‰_F"ÞDƒ†Z7Tq_ÐÚ6Ãã"í9-zð†¢2àÕáÛ/+épáz¼òk9D]E#xWžŸ§ºž„ñ$ƒN¹+ã§½[¹_E+ü¬¥=7c>ë'Ì]jgê›<ÓŠôNiÍr8m·b–l·™ê¾ Çæš[nfS•a”¦ìÊ›?yË8ŒÙ½8º¼™'®ËÉõ ·̦:Ϲf¸GwÿzûÞuöœúºšŽFnèäÂQÂ6Fœ M‡¡êAº—Ü„ñˆ6˜˜ÀNLwÁº>fþÂýÑÕ0N¯=…bȯevŠE¥Ÿ0C…AÉ”ãÉp: ‡Kì‹)ŒRoq|4½‚Xÿ­Ûo_|½æ”´œàü¼ ᕲ0SõwáÍ2]m2K0pB’±U« &„~ÝžF2´;sР.†ÏˆØ‹†K%¢þ"¬‚?EP˨f [Å€gõG*W{þY§U(_jÜr?ÍPßrQU㬦ç½-«ÖûYX=(+m·:ñ°R%8kÖØÌfÚîsž@ѳ§U½d×+ƒÑ¶Ë¼Ž½Pm ñ¾O†hòØŠ ÷n:zñ7÷âu¨Æᎈ^}>g¹/¦¿Ö:â´­¶¬”5ª ½]RÑL0»hðG8WyÔ÷3QŠð6™ •öG|Lþ ¶JN£4~àfuW#ß—ž¨ú ËCš=³<Ø‹gÔŒÊ3¡µ=ÌÌ9&f‡Ã?bêxpßÏÜ)D¼¼ÉããóŸvöx:Ótúx@Íž?>üÅhVíÙðÚ¾fíVpŒïoùßÏ,*Æ\Íœ?^Þ¶—äÙ²íkU"Ü3«W€ØöVù&ÿ,Ê^v‡Iö?FýöåÀŠì±(NNSxÚvZîG«Cn¡šcï²xxo§§¶û™E Õ¦`Ûç=OˆÆ™Ë · NJ6 ~jlPs‹r¼o“ÑU5Ü¢f~ ¦¸e '°^gû“I2™Iˆ©ê£ÄTÒv-‡Qš†WQ5jdåBz °Òö³h:™$7ã²í$RÔ-¤Hƒ*k=‹žzK¦=¢n!=TYëYôœÓ²# ¢¨[HUÖº|^…Ã,|¦×'¨ý+Ì/»EÁ<Ë i6U©+¡©„’ü‚ÐýgHëL*¬Ú>Z\påfÒuöýÎÖ³ojfSg §|ìªJV‰<•HÑlÙ9§•„‡*­\Ha»r^%ɰ2ºr-XiûršŽ¦7•IRu (b ÊZ—ÓsßÌ^Êd½¢ƒaDQ«rü‡ñpX•U·€ª¬u =»•(Ù-¢a·ûî ¼¯“ÉMXm(LU ’¶3i7 ©ŒÂnp_ P†·)W_¼A”ëîâÑ@í>TuÄsýñâíÀ³©¬æœçhNòâhtàÙ4VsØs4 Ç¹í¿æSJÕ²•/™å«‹Oëé^tN‡YÎÿ"]¤«äªÛµn§ø7cµÿŒl‰2ðÁãj¡‰¿ï!¹Ý€¬¶KG™ÏqZ^v;Ešüpæ•3.¢ÕƒKÖÔ׌ ä{bÜñ{錋ÎߟšqG&„° U2'Ñ4.4³‚ îzž,Wìv}ÙúΚµœÏ¥q½vîë“à6myŠf†r”k_Ÿ§e+_2+šà‚®‡Ô üú!¬@„hÓ²?”EœÊ“o{l¬Š†–ÑÊœ@àäk߯‰‚Ýïe8ÝÏÿgÎy#(MàŒè'Ê8ú\Bªáεmå fÄò”§¹}¬IiÄD‡Äša˱]üvŠÿ-Ìjï…iì”úqÏ $ç_N‡³Êº™µly¾Î 68„h¿6!¬eËóuf„ÁšÊß/ðË`R†£#¸‚"µp(€f¢V G¸JÍxÜíôm<*&ð°2_s0-mW+@a™>åÔ"oÒËà«¢¶º‹á¯!S§nCµÐ;ü÷vÞBc¼Ÿ3ºY·÷ÿÖ;»žfƒäÖqÚ4œ«¢šœFiN²’²FáÉBsÜâùþ9%X˜uæÃ ßg~)C”MŠh¡v½[ç]•ž\4ü· µXAqÏ_§¨mÛ|g7<‹áýÝP"l÷toàZÂ1&Á¶Ï[š‰Æê’¼3ì&ÃéÊ“…%†Ô¬Ti{Ï ´c!=Mn‹2ª,í5ZCÆÎ®^GÙn4Z§©ëôÙ×ÞR¸:ÊÒéÁà#ˆã)F¼ç.ϵÈ£ m2ÄÀü²ëj,C¿{ q0:vk&-“ w})ËÊð-[”|iúꦔ xrA½øzS®Üצ-¾ñâ£Ëøjzë†kœ÷uÜA¸¼ÛœŸÜ-ŠÊK#wæQ ¿¬ÜôÆgÓ ÊÍÞÃôx½òd@ ^•¦âUõ€û2•ÁïVíZ§e—’÷×*nßæ%îD¾ç9|ŸÓw‰8ˆsìu§W˜9‡ó<2BŽöa8VùÇK—)‡y˜ßþh°`l.D§ozzxêÒ&]tA[½\^`Ë–ý!ºûçÄIOf˜ÑPò£˜hM“‘HšJÐ*6‘ºªêyxå'°tÉG|R“~«jŸ’}DhªE £úu Œ'"~$n&o?€½›fô°³Œeuƒ‹}LЪ&œO¦Q=²Ë¨P(/ñÂ>¨ïWäðçÙèpŠ×)fÔÅ)%LBÄßr·Üw~£^ :ƒÄ¡úÝÁèÿ'ïí›ÛÈ­tñû·>+[¿ =×™ÌL’Ù*ofªdJk­·H²}“­-V‹lI½¦Ø ›”­¤r?ûÅkãà t7)Ú¿¤‹ àyÞƒƒƒUœÔk)5ܨÈïFz´‰ùùûôÒHjCdçàê¾\¶ÌCÅ“zs!BÛ僖©!'åšmârr+s2Iä“ùµ•ä$¡!±»š=²Db`^}¡—ƒGs£Eò¦Qq‘.éÅ9”"¾-f¢ŽØ¿Â_7ò:­îÚè§ P–ÅÊ#Dq<Ÿæó•¸ãéë³±ó MƒÑn€K¼Æ}‘æmZä“ë{riÏÊlt5>>{¿r|0¾:½Åx8Lï®F÷Ùòõš?¥±µmàÜÎ^À!l³•/®ŠðÖ'õ:Íç°dEÚÝÞÔqãµ¾ãñ$›á€& &üX ¤c„=æï¾XþôCb6ÀWWåä#[Pn±ñkÆ-5}L·°)ÂoàZÎ(ÕåþÑxÿì¯V³Óc\G=>;¼ÅåáÈ=ëQöPÌàLÝ8Q@+9½(kÿ÷ÿ›Ï‹l>üá§1áà ‚ÈÆÃ'Ç?©Ð½ÒIgÁ8ø˜¡‰\[X”aê('9zÕ…}å/„­âñ ’Æâà÷Xk#)‚Ä"`]‡ã§€SÀ¬Jö.󿯋¥^tž«S¿zuXÇjUí4‡•AGŸ'Q"$dcîÐÀœCÆñ¥šïf¶Q¥½ÕWçvf‡°•Ã7eµšû¶^ ^´<„÷'ö{RÕí¶Ïæ5¬šRáCØÝžÙ@.â—nǬ¸S¦@26iÁfqYNòªBcQx(…ˆ(5Ú‘Õ}KL˜x…ø;¹/–?ý†h'Cl³E6­n­Ù*b£YÉ#Û[Eؤöô‰?—ïêêäxúyØ(‹@|8Hòñ&&>ÖN˜Cfš(öø…xÀwå JÙ¸a¢ (;ÅžõZauIòZ÷ëbÊÄÞƒ?í2¬$ÏõÑÁøo‡—ç¬ðUàí”Ï ƒo#Ì2aÊ{ú¢Ó ÕÕá5ÛæÊ–<©Æ<ÇÒ8¾ { &ÒK®¬¶úf$8¾J’!Ôž,8 …øêÈ!¾IF'—ý•E ¤`ߨ7)Áx|‘ËË›ôpSýãHêÑÄV]|ËÕiÜÈç¬T;†?üHí Y\#½ØÓ¡HXýQJËö1³b.w0îŸþ8öv¯þá×_ëSîåm9Ù–N¸—íý|6Ÿo/wþ.büzg¹ÖV„«³ò¸“bÊøÆn™¸íóiöyô4™©Óì¤7ì$|Å¢êÄàFoóƺOï^dë*éiR¨wóv`(ò›'­{H…µs¶|T»Pw„˜Nr„ŒÛ€ù°…m`ÛMp’߮ڢÛà Gn4PÀ·k›Ïƒ8(J‡¤åG^hóf´(q ÒqÔŸ›ì•#{‚‹hå$ÿ¼º\Ï[¶”´èõü?Ë›ô& ’íÉO³(;˜H1ŸÄÆâõÉùèíÕñßµcøÍèÞOK6!•Ë£ƒí)ßkÊ-iß-¾M¨ßM)îötmŸ´ÍV÷9KQ•Ë+†3Ñ3×CQ\æÙôéhZéw\Åk|õjû¥0y€ðÕAágøL4ùŸ4¬6Ýò)0~²\¯N¯±¸€}îmJ`“1Èu"Õõ}¶º^wwù2Ÿ>k‰$^ë%М hçÏ/Q²_h^ýâcÛ:­?:°6Ž…Â:|Ìç+‘gaЫs7’ -“Êúc[žtZ>´VTürŠ›t fð) ê¬ç<8iQЭô{0,p^@Gò¦‚p@ÍŠ|T>ø/ò¿MΉÔß­Ól•õ¬;fEþ U÷?ÿõ¢žåÛ¯*qV‘¶rˆÍØ]dÆî¼k³B19ÚÜPÑvà -ux~ó?Q¦#3‘+$1òøéjƒ3PýáÅŒ_6°]'|€9r$R;iÁU.ô}ƒ ÿ»>ØOÁ·Ad!œ¿»~}þîìF"ñNޝ®Ï/‰x:HÄ;>óÁ©ëòpÿ`|x~DDÓA Þ%Ūƒ@¼ý_÷ϼQE¨‰=:?;»<iU(”×/­ˆ5ºº_]ï_R-±«cœQ-G…Ô±^Ÿ¼s~åìà îáÕu[†Ö±y/=ùÐU¨›. ¡NCö` ãœ0©ÎÏHTPïìüƒ' ©cí]^~¸<¾>ôD6Œ‡l¬bÿ;ùpa1«î‹[{ifÜðÎW {@à 6Ÿk…t¤²LMZ ÷n^|ÖSüE¶ºoï’Ù¨€—ß§Íç BÊY9YÒ6E7xôþ„¯ÛàšÈr¸W\Z+¯ºëM]³.‹vDa,¹EX)ÁÙëÕÉhVäóÕK¸HÆ¥’#pé<³5¸“ÜiÍmJÃNjt° ]V”¾4™Ü.ÝÄð\ Ólï•i#2n>6Ëçàv\Ýå‡fV YàYޝÊI6ã%ئQ» ”áòÉUÞ'‡§ªÂÓÎäúÛN‹oÝX¡é—odã!‘¬²á›3·!Yz£˜i‡CÙ‚Á®õdbÎ0œ¯}æËCùúÐg¾0ÌÕ'U¸û,À@ù²ÙŒ«çH’UÚräõ‚X†aü¼=é R ]8©eWl)˜VJÇ®¨“ŽVü«n3\Ù‰å^ïô\ì³©íž ªãùÐuXs4:¼ Öï&ÐÄ=¡¶*ueiѶ…y(ŠÚM«±ïàŸ‚f×QÌ`Üm¡”qWjt'E))LË“m”=¡\Øš€™àÂ-Œo]Z‘k0 vÙuuÏo‰«c*Ö:â!¶Û_ý-_– O…º¼Ë,˜0>a€:Ïf¼ÿ)_Î*&röA‘|bØ¡ƒ…zÍiöY†]ß/ó꾜Õ,õ‡]'ݱ˥´hò>¤wèè¾Jô£«rÌ!¾on,w]ÐÁb. yIÌÙª;±,ìaÜÇi¨5 `­®(ø„–œ¿~Z啵&J’ܰ$§à$÷‚kb>®7‚tá%¿K’š¿,úx6ðÅUö°˜é% ÏÆ7?ÿðý÷Ê%“ôé•1Öa† ‹>© \JsP»È05Çõq ʃà*<º [¼ .y>·÷=¢Ç«€Û‘Ѭ¬ÝVäNÐIŒíÏx°ý"OøêÕaUDR ñ V:!О•ó×3ÍÇçÉ›H§„ŠN˜ ÏÜêk{…@Ðo²Š^ÆÉK%ÇöK>¶ÍQ `ªÙquX­²›YQÝ·h4€£³>žç«©Ûq’”×.†CSVµå°ð“-¹ÚßZ«É¯ý¬›¬QÔÝ~eHa ifæ#1!÷æç7Ÿ«œqN+8¦êNm ÚšYl«íFÈpÀ»,Hqz§­æé :¯bþ ¨&­QÝÄØUÙÄaz6|Au­²xGÚbÑA·rxðÂHøí³xV0Êë(R :•ܹÀÒLæ6:zbóÁ²ï6UÔJˆ» W–¾½`?æ¥Ò8°*:ȫɲX(ß­m’ S¸]Ÿ}ð±¬R à¤ÆMmí˜]䄳˜«žØØÁdzŽK_ ƒ*©ÑÊ3Z'V‰Yž^œ]}¶uX“[:z"ò °\8»:)Ëʲˆ5þA)ãuÓŸ—oüxqqi®ï­êŠÜcZIñ©P¢“ÖúˆðÏÚÍ«¬–ÕãP–ò9ZèìÛT“û) UÝlV~BƳó`Ó–hIÂYÚ—ÅÚhvиH–R¶öAØxïï0Ü–|”Øë!\Û<æK‘Jû|9X(!8¦pÓ[­Êev—C'iÊ߯Š%óå,Z¨ 7kö±¾8•#¿|FA«™\÷A¬‚RÜq‚sIÔ²)4ûôzçxñt.î¥×ù3"m mÐ{2ÐÏ &R Å'p“Þ,F·øÒA͹­—,Âþï:"cn¢vw?ÿô}Äë¦6ì+_pÇ/ë›<¨DqO>ëì¶\3Ú±ƒÖçY¼EäSLv_ZD¾Å`ËS+ Ýs–neáú·bÇUâ)Š… ÒãY¶'×è˜ÍvŽ—¨­±¢ý’Àa‹ÞhmàðΣ7ZØŒÚæùÌÑH{D@•` d±XX¶½zûƒ?‹Ammao Zߣ¸¡lèXþôCV5ü.Œ™JQ¤ˆÕ ºwo’î˜GœÉN¾By|çTævvÕ†[Û»pCÙh\»Yñƒo„x#Q†V èßR[¿Í×Ù4ã–v,˜ns6LI~O¬×ÂÆo,ØÄtÀŠvrßv¦Õ”c /;AXìz¶†¶’w_ÛCdÏʾë.Rlpi; ôÍöm%Zè‹®OiDn¬¢¬C¼oÕײ…v@}¼¯;Zø}5{¢w؉@rü¦`þS˜Þö.°ƒ@8}GYl¨¦WêýDÜ|mr[…oŠê˜µÇ—vh¾¿@ÎRyÙϳ;ËëZêV¨ÜQßj(‡_—“5"kòkšÈŽ/¡¬ñ Á ·7N9çG]þ•ðDF§VQC0U,“‘2Ù3ûU~Þ9á`µ·»Ÿy›l×R2 îËé8ò—IO ‰øiée6Ÿºg³@àæ%5˜’E³C>lÔ©¡¶¢„éA¡”iÏ÷XÙ(Ýw|žXó/&Wâ…‚:à«ü”/_—kËМ…¼c£%ÂÖD—yUÎÖÊæSÛ ýá'}=+Qâé°D¶Ðc:åèú¤·~–ÞHxŠ^‚±1ÿüúɺ-ÖÉû&–¦‰ƒ_/Ûˆ4$)Lôà.â.›HõýúÝ„.üšà®Š»V—2¹®Õåw¼„8´Ð²ÍÁM`ãÍçíˆï ¯a„ÅyŠîÄ^x¼8c­Bi¼ã.o\4¬npÂÑú*õ>‘µºãÃY'ŸÉæŽÁ£¹Ý|áÅuÉÍxS%_„!Y ,ôOÙBÊÄ_ÉU"埬٧8_ÞóL±ˆ¶D‰«‡©ÃE Еvq¾,îˆêj-&AXzòàô–MÝÚ§‰ðÝzž’¯Å9}hÉ®ãÔ „A]S  ŒÄÜ>Ûô׳ËÔz€èùž ȵm4Ê7Ä—Œ•tb·¤2m=L[æÓGlÝýÅ—Sb/¤2M—“•0ü~/„1ÄaµÖïog”ÞÏÄk¡ú«ï–öÏÎiWý_ ›Ï¢¤ó׿Ði1;­´¥WnP¹¦„ oclÉÓ4lNjÆÚ¡æ0A…(3òÄQ„§Ù­ÁCç§Ë AçêyŽ Pv6g5¢[Á`3¢D¶xfÎßʧ¹j‰½ £rÔé2Œ2.¾.ßçËâöÉþú®|G®&µla|Ç™ÎEž/]¾\0VÂX$Š4€e;ܹ^®Ù@7µâêB¬ª£ ¾R½Rì-rÇa€óû³ÙˆÕªŽv£?&žîQ‚°–UŠ5ru ª€ÀpsyñöIÂ~wÌ HäMÇj™­:9ÊÑá|RÖW³_ؘøc/=ˆÀ¥<­%ûh¹²Ü´×Aþm ƒN7Ô_™Ðû—ãã‹÷EU-û—I…ï‹/Óuß ÐJ »×Óáç“‹gÀ€ÀX˜Ì€½›·ƒÉডî…i»“ i‘õ~5Ñ¢FO”89¶rãêûÐVzì{ª ÞŽB­SÂ[ØSsª‘R¨8!**q•¯LoôvÒÀ4yùÈÇÁ‹e~[|ì®d±£Ø´–Ô ceËæw9KÓ(•ŠGËc@|éBjñìc„*©¯è4á]ïèCèD5"ÉwöóáÀ%–ß÷Äßþí­êÆŽäè#ú4Q³p•ƒ)¾>M%ߣš[”JÕrº<8áþjO†]Õò°â²Ñ'œ–S¾Úgš|1µüwí®.¸6tД’³±ÝeƒÆ—ŒN°~yÛ™^_æU•ÝmÏÌLñmg…È^t\Qé’zÞU×óŒßÍ?ÎËOs\¹J¾1Œa’ìO&üúI ‰Š“p™‚)êw4äïOÙS(: 6‘GÙ"»)fÅ*”ÄD ¯G¡$,ØDªÕ@ln¢Ï?J(¾Œ`ügY„Jˆ›Èo‹ÉÇ@dl"óA#™›Ègaä3„|V²i+„-#€ë‡|YLB)d “ä"[†Ú‘ùЈ̂Aä2¹„‘ÿ².Bbð`ù:ÿŠÌƒAär,n¢àÞU Šot ­00ø— ^½âÁ§†F à¼ëïël¦¯ÊŸ¯îÅá­N{&®9\0|¸X±zˆ7qšÈÁ‹ÿ³|õ©\ƒ7nT­¾6Ü’å…`U) .éÄOž!Óš'/,ÎÛhVäØm„üŸ-ˆ€r»üÅó$ÿj‘ ÐÊ [’¡¼°ß 9©Sã|èÏœ”ý-òÀþm“ Êjgu=cpÌ“/°­ÙP¸½™Pþ'Ïÿ·MÃHVm”úbnú6°b ®òrP©Ÿí­±a]‘ÐÖë-Ù2{Ð#Ôc%2ö÷‰îO- i=l£xw9¥JÀ4£rVê6»–¾B¡f…ß·“®{Ðן÷C™lNÉAH«==%j;X²ºzi~6™wCý‹ŸÑ±Ojÿ2(γ2J‚U¥¬ô™BˆVN²;è7ç´åPa`pVôç—ƒ‡ªâ¿X~NÛ÷RÏÉ8ÞæO~ßáiÍ£:9 3²€÷rÿÜCëÄlZnFç“ÙzšïÏfôªÔ„‹èl“ÊRšžz!£ÀD¼àƒIx`îUÊŒw:ICÂziUÛÝé…u]æ©eM¡ÁW*¶/eä+­E“- ˆìB@Ì(÷ç# H`$1#ß||às›†¹øÞšàŸ¸0ÌÅwÛøœÀå€a.¾@#¸Àç.Ìâ;}Š ¤ð¹€£ÔP”($…“€Ä¤oé"}ÛªH0ÌÅUøœÀå€a.®¿ ¸Àç.̾òÏäàe>§ ]6˜ÅÅ•'øžÂæÀAUpŕʉ֥¥† ò@¿5*L•ãáÃt•^%Ü_×Dþs&*n¨¿š{ëxbªÃ#Ž £•lÇ|@ ¼uñáÍÞóø òeœ"–»û»ý¨‚ èÖ# nÿ»=¢ Y›G\hþÅ/„1ÄafDÛʯw<¹üêF'oQc ÷¬²˜=¥Øí¢1JÞu„‚ÀÛŸ _Ÿ£ìK»=6I›G&X\þqÉËŸ~C̈•O_ïˆrùÕHNÞbW7oó§Ä¡P!9ô׆sÆq’9°­G ØÞw{Ô’6°°ü£†/–?ý†˜Qª‘¿ÞQäò«5œ¼ÅŽ›ÖfXñÝÐmËúñSwxbÙ>~Fd•¶Gk·¬€¬4vëA v§Ý”€¤Íƒ,1ÿ ä‹åO?„!`PBǸ_ïêåó«[_¹Û Ö±mE«ûÔkàö¿ãã”5b$A…K¼ñBCFl¤ñ•­tP澦Å‘±Ø!dÄV»`‰¾ç9Ç©uÆ­oÇ;46¢Gã tiÄ ÊÐ 4½ÚB}½«„·ýldvràä-ZsÉæmv4oñ–ÃÆÁzLØyãñoÇØêw{ì’6°¸üc‡/–?ý†€±ÞÙûŠͯoôp2=|ð”©ã`c <‚ÔßyOç?:Œ!“Är²µñqÑÎSo#ìÒ;>2Q#†FXb±Ñ-€0DAÈøs=Ëç¬ð¶çºÓpnÉ}§M>qܦòë€ÜT†8zB)ºy;zsÍiÏÁÿ_šÃMD¾6FAG¡á+žäãêq®·u'Ï}O¬Ë§C»‚”ž—¤€Ã]”BªÅÇâ"»ë¡ 0"ÙgcΛ|¶ ÏsR‰\4Dö&«x ÀÝíÔ÷¤Ì¦ùÒÚ€È^Çþ¡±,˪ùÛl=s_²!úw|ý[ø¢rVû®ï°«G0 h?4 {_Tpƒ{TÀÞ¥^Y /VS:Ý¡/Z SÃÎòrpÃXyWûæç£Œç鄿]æåàVþBS_Ý [d•·[îE=O¾~ ÆjÜöyÅbìÕ!A±ƒN7Ô_õsšþyzSxM86ÁƒìuYQ˜½‘~;g‹Û#E¹µâÛÜsÛ 0ŸwCB¯mÅïlä ¯hUÆ:6µ”HáÄh‰Ï?¨ò¼În¤Hü‘0¬h®×÷¬ “…XŽÖ󉽞5i_½=Ly”.Œè¬7í†0¶g \—'À–ä\é£'Û“bÞå]Ciƒ¦8ɯQ÷ã18ŸP‘¼©‡ L,vÿ6u”`a”{TXDFÖF[64ڦѦ^€_†®J+ôB]ƒ‡ÎÏ®ÏÞRçïc(b¾Ù?¹&cñ€:ÆéùÁ•7¬cŽÎ/iV(õ—g'çûd<„ÖÃ\›©ÓüoÞóø¿ £G&6øˆhÍÙø†èUo}Öœ ï|¾›ÏضL+±Ð0¡;ŸŸè¯lÐçóYA)[IøÛ½%€ "_õ:Ÿ¿.K¨ÿ‰'0 ܇üæ2ÿûºXæÕIyWÌ[Ó$Åþô¡+€À*¸üæ4Ÿ¯¯‹ÕŒPÃÅ 6­±Œ‡÷è*YÈQ1Ë«®ðl6œ|™óbdc±jgìÛU)}[¨?åC•wù™˜½<«¦ø& D¶œ…d ô‡…8«½ÎÙÙ*å ¡–»IhÉDŸÍ ~,nÒŽ®.F÷y}ø¸á⎀.z¶Ç¹Zß@ÙBýf’]ó¤òWâ í‡… öYž-ÕçªÅðM¤Gý‹€~orT5oÏTóQœÏnòé4ŸîDóm&ÔŒÏç¢ÇÞgÕ}‹ŠpR#à²ZuA¶’Ch¶Ž9(*V„s¶YÈÛ¬<ɨ+Ã(Þ¼ º`uóQ~c6þܲEèü.ó°3B—Ã'L9?\.Ëe£DmÊÁn‹r)ö±Ë ž\pm\p¹žšÄ·ã©Zs—y6³úßo»¬OH%—°ãuÝ’-'YÝW‹Êv"úüéù‹|ùPTüZÂt½œ/ÐkðÖãðlOË’Í¥ÿ“}™0^.ûä>[²Ÿ7û|@Ò‡ì÷YÉ#Šì‰O©m((¨”¯KI£¥ì¼ÿØ>ïk•÷Úˆl;…ðcC!¬Ó A!~1E€ämWç‹5ß9;»“ ŸÔ­«ª™ÃÅNK|—ÏZÒ‚äÏWÚ{¤ÔïËb’?gS¤Èþ|EîÒG·”Çç.uZ„4ùŸ³±»DÊÎÇzÁûg,5Qq¹;ë}#uç,.NÓÌuª}Uµcùµ*´Mn/³O©U\ñ”]R¹v:'”™£¥9”2(B*Cñ5¸½ìøª+˜Ï l·MŒ…ë rõ £€”ú³+7‰„°Ü~;‚àðNò„¨LW«lµ® ]+>m5ÐWÍ„HìaªQ”¶íÕ‹$x7ÿ8/?mT& »Däþ­‡!¡¹]l„FÜÐíÓY@ Ôù¸ÃGµ÷jª’ò²itG6ÍŒeÔ›œ€Ù’rˆÜÇö#›—Í+›§ ÕL›*C‹Ù’r¾ •!Là ìÐûfþÊøŒ'ËŠZôÖ…Á.÷½¶V‹¶©yÏ‹UîžxR¯H-O l>Eãh`_¯ooó%[R-W¸‘ƒbóXÓ´“,Hª¹æËQ¶ØÌŠwìSoβ…×:"þªrŸ–ä2¯Ö³UXŒ—ƒ›«õd’‹+¢­¬Ôýt×)w¾¿^•@™Ó§ÁSɱ?bÏ,´»–qóöÒR vÑG ¸¬ë%ÜPŒ´]¤ °X l>½.噟w¤èch$òŠå=gìùtßÇIžìËȬ²¶Ph>Z Ë’è–‹»“pÞÌR¾ÉæÓY£³áµt2Q§6˜ë•!~KcÇY"=î£ÂómLÌ(o ôÍé¢bVÓ-GøÚG$eS᣾òHãöÇ£tòÛ®Z"Âq´ap_E(½|­²ƒbÙ‡ø ùº‘®´îQ$‚!¸Ì:†àÝ|VÌ? ñC¬fù‰ ˇ(Š9ʳ÷MUg"nÃËRІܯó»B®€ Ÿj5}õªÊWh²—âÓŒM æÛàù5›ÍÊI¶*—0hðË«WBîq±Ê—<4F^G#é¡ÊÉNÈi c¤<)ª•#fìâØNŒ}H•“yí¡OþmDü•Ø*=x¸£¡ízawµ^ó凴úŠRñ_AWaJšøNGãÛOÆò´hM‰š´þHµiÖ¡ó!‘PïÛ-ampteMéƒ`å¬ÚuIà²Í@ðøJc»Ù“Â@ÝÚ¾7ùà¿–™ÐÓ]T«Ç%ÐrX]…D÷» r·`EéeùèEvØí€ª9¶!…¡@W(³©òžõÚkl®Üäú*{Ì;@»É ôii…½ß›kÉ ³•¯ÎÞë0¯#Áê½ôxM©Ç>,Ù0v]ÕG­"ûùz¹ÎËÇ–C“b¼Äo”¼ÍŽƒ¢ö\EÆ÷¢ÊËÆ;w$Ý©úüêUÊ„âàéO…u¡(ÖB p„càòY«#›Ü@ ç uhO ߊÛ:@º=s¦Ú7UþyÁVõd‹S~µÊ+ªÞ}PhÜÙÀë=j$ ¼Ú³ç¨iãkT,jon)N ó×›z!ƒx¸möñ@šjÔÃh}½Á§Õ¢Á'øè×J)ß;J9ÎH{ð(Ñ}p¢ ÍÅÔþÁ¥Åú^YJT;nñi¥V’µyOi£µÊÅŽ¼TÔIv¿èÖkÇ牒Nc·ý&Q+áZ=DÔïk?­äÞþ?Ĥ¤ ô¨þwÙøë_žÔç¦èwR  åÃGÉÝ_>J ì÷¹£tâæŠëå¡DÁÚ½”ê ¾­Pñe¶ÅâJ*©ÍR\ùt{(Q¬Ä7Z¸Þn%P\Iux(Qª”7€}D'JÿXR·'ÅJ|ç§…3ãVÅ•Të'~eŠ×gsú‹´Ç:=æ“(UÚ >›S]¤=wÔåÍžÔ®ŸüPr=\·&¡ˆ¢ß j#GÂCAþƒ•–4=ÅÓâ…¢Dì3Z¿¾“²Qˆrgà ӄEië—vw…qÏë´xЍ…íå¾·7uwó‰éè$jG!t§âZ¾›“X±å´|b¨•4q ª·rk0ùY“hSE×ÀàTd›qk2êœ%бí·o+-íÁº¹â ¢;ÕÖò}›Äê‹}Ô¦åS@­¤‰kN½½d“XƒÉÏטD›*º$M?Ï×$—öfÍ&wB±üD?“½Í`äÚô³/IÆßéo½x0ú8žlñ’JÒ 4-EinÁ±¨$ à9%ý)™6ä1Yßà›WÕö½j#YÜ«WÜ­L\+DÄ/o!)ªÈkð>x ÷F)ÿC³{%ìÑÁëuáeÀqOt-ø²ôÒr±´®f´uüöÈÿ,Ý[»v@À¦Ë܉Ү&¶YÒ~¡ë²ö2‡.nãyþI8Á1„ÆÙÒàçAµÊØ¢JzkÒ®Td ™ÏªÜLÝ(w=š$“Nà— @6¢„åC.žâ$DI<2Ú°Ha9òÛŒ‹ñR‚1d#J@>5\òĦ$Ã`áômï XF–—Šìos *˜ÚZ ·söš¶îÑÃkòr÷ùܺ&[mѯk‚lÏãÌ5AÀçðæšr&µ ®­å‰PuòÛšÞ ¾Ç­ÕnznmSà_ëÖ´ûÞ<Ø›‰çñךœ™/ÄIkB¾vÍ3kšè)®Y—lšzÌÑnkÚN"=…Vû8­œV¤—ÓŠtsÊGežb×5LnHQÆŸm—îYuó ¢7î©,êÍ[‹lªÔ›+[6X*Ø_"I;W§dp«§Ÿ+ ŠOìy#Dn\1Á®±nò=OpÔ¾‹vÃÄv$>ó‡}ï mˆàGíFãƒ<'툩ÞÄ·¦C¤­^½’ßùsŽ‘í^¢Ø :n[¬¼5‹KããòæØV,ÆEs'·Éò¼.Ígr;?Ɔ Q„]óD*ö¦ü‹âÞ'Å—y•Ãû@Žc¹àcÊ@]d˪V™ŠkþYEÝÏO!"1±[]®(à_A&bÜ» x'9Bæ®AJq®—1„„oËUñ|vȯ%ñÑ‘Ž—y¢Ã¿¯³™Ž;g<ЇÈU”Ë ¸{ö7-x#M×B«æ.Vû#Bp˜‰·¿þˆ àÙŸN¹“K2á¿R¡RƒŽ{ú !`p·ä_®VË–ý¥vpY‡ƒÀ\øhT“ÖÀ¾Éª>Ê„€Á²×-HÔ[t: !›¦Û`8CwGhá”G‡I'7È£YY_v¾*×ËIŽLR:+ õ.+Ú¼Z"°=o–èÚA´{ò£Cí)†#•cµå“ÝÖV Ò—Â6V †IR? ¸´x”±ø.b¼Éf·ç "Š qÈp¶?}(æD°ø.SšÛ5&øwãtÌí&³%i¦b^åÖjȈ2HÅc[þ&p>%£Ö¡*¶ôØr>Ÿ=‘ÑM°ŠV*5~EÆ7Á*þùBØí‘‘U˜ŠyR<töDˆŠõ6§eßkF™ ÷µŒSÐ6Nǯ3ªnÅwCnÈH2È»wñ?î5¹¸9žÊùmq÷ªö¹¨?Œä_ßüÌwL{"1¨ÃqEMP?ËŽ ŒáÍ#ÏEüæ1yÿ%*’Ü]—²xàð.¿4â´ô„7ÎoR¤µA þÓd–'g¤2PÜœz§<.@Éô` ½Ze“{ø sd%[y¥Ðä(J º|¸/ë.ïó¢ç¼s‚<¦)â9B¼4/[px¼Mâ³CO` f0ñï<δýòø>¶|ï&×¾‡KãíÛ©ñ¥;9qè¹½P _ââÝO†*¯Üù™•Äeª€'ô£rÉçâiðh| ‡Ë<[òÊ«ÒÇ4+)6¨š 0°‰†×`7+ÀIÔ¾ ³êþNVÌÃú,ݤ\H—²aJlÄ6"n¾=óˆ°%ˆŽ #œÏ¦þ¡Öï6E$/©aÀÝAº¨‚A~‰Ú‚ëAôQ¹F „Úh,ªQ0hb°C_ÖÐ2­¦$7¬ÃNj‹‘Ÿ²Y•§,Í£q¡Îü>_]…Š1ü\„`bÅHWHÂ’3P¬û†€†©¸îÁ„5º:M6ax¥[*¿â=vAA"ô µÔ}À£µì®^Tz…z±»òX×îF•ÇzP¨…ß[n¨¢Ü¼J{. Žu~Pwe€üm^{~ë¾`˜9šé΃à&¡zê™aœYíÏl¿z׊b>cõÐç6†Bżüj¨ûŒ‡ÌŽí2€èN„=Ó7£ÚSž/jòÔ粪™ï¹k{Ø:“?_/×I“;e0s ±é0ÊX0˜d´ÌÅ;”}v *<Šª¾ü˜¤í€é Üá¼Lõ„k‰®—Ež¾Ás[Mµ=4•‡uxÛX/A<Wx*L™­´heÓ‡º€Á%s.t¿mu(µ£hØ_ên÷쉪Ä=²æ«q˜qæ![üY¼šùî:^аY^U2pð‹ü’Ífå$[•Ë?ÄïEV,U 13!Á/ü¿ÑËV(l6çmÚ˹ÓPxËÌr·“ö°©Å@Ñ*¦Ö¥ª%š$/ ¬WsíK¢F@¸fõÖ`¸Øf©Ö‘¹,õœc©"ø<OaPƒ³kŸʱn ›¥n‘Òî´Ëº©…š&Ub´h›¤S}·u±ª79ØŸ—x‘›ÓæÕÝq…diãN WΙ]$äœ>°û•X`µmì.* ¹àjU()žZ%k ½K!¶*¬+tò½  јZR…ºZ Ž~-…$²rÆ­ñ6®ø«¶l_ý–MN0‘b(>Ë&q»-Ë&yÕ|–M† 5lQ"Üp{ì’› BäÙµFØm³.¥Šaö!ìÚÑÎÛ±™ÑîÚ\%äÂŒ}X–Ï›ý«7ã³ó³CÜÌBfbžüÉ‘™xWoöüÓO¾¨2ÔÄ>8<Úwrí‹®‚E|Ú¥ÄU6[åS6b†¼\@“ò'püI;Ý<¯ÑÍ}>ùxÁò§ûÿ»ýÑ à"1±’Ÿ ­ŸXþ€ ¹¾Ñ‘< ŽO6'EÜ>gQ“2²´i¸|âŸU (JÇëj‘M„)VþÉUpÇ5 X¬­WÀFÓöl¤i‹PîÓˆy!sÑÈ+p[H°ìl6Øñ Qbr ߎ߅ ¸’ÄË_Gzþ\¸òÄäy×ÞÒÎRR¦e—Îç“46«Çbs-ÍÐÓ4yjÉä&7àâÁ;éÛ-à¥*eâ Z¼æ•Ê©ý xº,ÚcêU cÝ2A=é1vïEƒynµDydÛK˜uDnÃ-f@hsy_—ëù$g“§lméûQo>­òê2ÏtËvì<’Œ=tÍ;¨é‡e±Zåóþy-àMxz¡'ýYÏTàFüh®€ßV©³úÔ¼2Ѳóf{•~|%h>Ѳäú§$@1+ÐÐ¥X!k|'9¶}]ÏVÒÍÆ4e[ÂÍŸ”×òŽ\’ÕÅø½æŽ$Ã͉Û\ºä†@Ôr~±Ìo‹Ï­/næñ ’Vªüôª'KU“mÙ²7-êp>)¡{Êîì4.æ(V=’Z€xæsÞðæ|ŽñX´îx’QÃcÍ^¬p‰Z=v»·yê±?êÒ o9æà½øiÛ›L4-Ö_ÖùòiKry¸hÁú3ø®Gæ(coÜ7‰ÉO²ùÝÚx”îa´¶­Ž’3h©)ï:¿RPÖe ½cþõ¸ò{Ø÷åÙ~·ÜzÐ<”l²ì“Ó‚sÚï=÷gò¾ÈúªCã¥ñܼþÃìJ{ªUˆˆù°qÖËAaZ‰lžµèÍ>ó}±ÙpÖºíc1ïwSd#:™³4=äÏFt(Á`Ø#-…jmÙËëev{[Lx+׫ž¸}°X©'tŽúƒÉpêL‡$9´H(R%ÔF¦(Yüú#%hC|˜_1>:øîHC`9–Šz¸ÖjÿB(þÚÐûàíÚÝ´, TmB/>©ˆÒõê89BFûñöùÀ0øz€¥ûiOâ á;AZÔžÀ@8ÈÜúûð‡ B…þ*×AÑË¡âæv=dÄÀØC'eß%ÊWÆ"9ÊÞäIë€~±_éõqûÒ Ñ¬!ÖÑ“tc]0:w`)ž²IòAÐ$píÝ–a8ÓŸtßyú30P)ƒu iš+-<ÿ5zÏ´ƒ_Kië6S%uÒxG霂í&F7ˆˆR’~F@MÄQ¿¶o&.u +[;Ì7$¯æÑ’¿§4ŸÀˆÑWwêÛrˆ®fòvÜŠ€à•µhÉCc!:¨$N_РÔx$WºV|“ê´Õ8nCá…S7'OõÂÉïYèWR5Ú’‡B²*ÄÕv¶ä"¡z»·¨Ç¦{‹^f+N&Ž&1mNq“;3y­VJï+890®@& Ä]Éæ “ÒÆãXС#‚24nN tïµI¤ôjƒŒð¬\鵊“c3,¨@oa„…’£Â ì¡“ËÃg×LiÂZR¸8]ïŒ ä~ïŒ*HÿQUNεіÆçIFçõ¥Pà¿ê)†#e…&,Фò±¾P6ôÝñz9X¿Å?*bŸ’ÓâQ :_Ñ—ÞŒäÖe™aðš§= „/ ¹˜ZÎô;<@bçêL„ÌQ…Ö‚·¼Ú£n›¼µ;Ćr;7‰m¾ˆ»aºSû¯^Ð1N¸fPc€¼·žãÞû|/ _p6Òª4ל¡¹«÷iõ*ûa²³4P7D'§ZeËHá Cš«|ùˆ'ñ” Ù¡ëãî› äýqV ïwËlÚÎ$çAó* xËëÒ€×wiº‹4€o²”nc".ˆMq>Ÿó$E”C!`ŸÏ_÷u;uÀ²#AŸW4!b¯jðb²2nNâþoððÒþˆÒ_ˆ½Í±¾¥Ù¹’8ĉÀV޼qÆ=ý_YÅvÇòшâ¶È—Þ…\ïGâ@Ö DØ€¡n,¬5ŠC³Äû-€•@³Œ%€ÑHìÂ<†ÕÆÅÍ¥Ÿ+è¸%„/¢ãK±)wÀádF€ìØ T,m»{¨»}wç°Ë N¥ç ŒZ,”ìÿâ{ÛËPZã•x׊êŠzŸ)y“F “ ¬›Ç‡b6 &UH$…eoòвßR Ø’Ý[ôFA×ÒÃÂŒ§Üã$4ŒsTQ¸þIëÊú?ª6U@ËvŽhq³ÀQå­eHiN:Ánì@Sš}LI¥JjI‚›þæ ŠÇ}"ž;±S„xÕø(¬[ŸH».t®n àN¹xDa£: øß½”± k¥8êÜÌe8ÕÎuHË!Á£¦àÞU‘R2làþ.ƒâz‘Î`J/vñ)íNÿËÁú¢\® ruÏ>|ÓÙ¯¥)‚Â(fÒ׊Ý~ò%`,-ÛçŠs³?}ÌæJÕ—\E!|käY/—ùÆlOI`áØ—#\} 9°µß³‹b! zñWËýžv'Yå–nÚÈfCà£ÿåºZåSÖ)ïòå‚•%ÒH\µŸB¼À¨·¸±tù¯E¦Tov6.MÒäåÙ2\9iº»œÝÍ”¢Q>ÕÑöŠ–ÓÇhTËžŒ–ÞêýP6ÝUI¾ÿ¨BT]§ c¦Cꎗmû™…f3Õ—pàÜŠÅ ÙÍ\t«1ñhkÛVÁœ¹ÆÎMò¡€ã,‹¶ÿ){j=È¢ôvÕ!=ô"ˆÇ ÙÔ[ÊR[Å‚OZ–âÌë¬Ãäz \¨ê<“ÿÙ~^§€aéü¥…rÇœó’V . ¨zî€ØHÑv† PŽ“vÖÛÖ„w™}JIÌžæ,´ÞÀa­UH^$Cön1ÍVyO|!0›òðs6YõÊ@´êï´\M»W ‚jÐ ìR…(»@ûb ¢Y)]v/J¦Ü¥8½`vöÇÚ€g*m¦\¦Cíæû­ríÕöR§µGïé®kŸ2õvïµO¡6{smî&,æ ÜSíxËón¶»acy÷lzs#h©\6ïLnÃ¥ µè݆cAL¹-÷‚˜5ìî¯?Og˜uKžÎ0©ßßëAG³²d«Qô"Ù´\ßÌÂ×Åq7´@\‚×ëeE^C*÷T&€†Ê‹ñrp[`E)3Õ®ýÀ„Fº—ƒµùâ4´ÅC žT䳌¼ö™ZîÊ5cÕzʳŸ "4”ÜD4_ï—ú£µ0Öµ‰ÒYõ8ŠÚJIÀ¸ù¾x{Œ„a¿½k¡69&ð‰ÌêXíóY#ôzmø> Í乨»gg¼›Ú¶g‚Ýïå¹gé€0Âez»[u€£ß»uØ{ÃNXù¯×õgfqQ¦ ~1âlÒm(a”ùŽ_˜>í…¾=ê¿sè‰äM=ú"R€Ã›MÔ·œë$.ÎeËÛWꂜ´;ÚÖÝ8Á¶kq€JsÈ^ÌKH$à?½·Ðü&)¾G¬šn¬) /i]bž¬ªíàµ5!²Šqc­vE‡Zù%J-!èÆ ßÚa†E@zÌØ‚#e)F´'e>Y{4©O€K2ÃÒž¦+N%¸“–æ¼½f]— Ñו¡ºM•žúèŸ?Üp*ÍP~{Q¶ÜÓÑë¬Ê·6ÞjÂí ¹˜í…wlÈþùöã'ë®ï2+ª|°Ï0‹›õ*w!‡¿9+eM.×| Á Þ7Åʶ솅f“ÕoBC}ô°§ó?òq—Óå]1?žß–zá—bæ¾ID˜² €2²æfbêpüogI‡ãZðqH@®˜àX3áSˆH«Òµ¹kUËAþËüv]å0ßU¥ßæ7žÜ‹í^cœ·?j: ±è"ïCá€1†P7q 7Al`œ<”«<ùU.ˆ!€ Åü‘¯L±~3¾šíä{&È?€“Q<)‡õg3’ËkSü;ÍoÙø5fCÖ|ð_uºÿ6Ù$Ò~·' C=ÖŽÙÈù  ÿü׋Ýç “µÔY#.sw‘™»óf®ÍÜdçªÍžÀ½¢×e˜oÜ0€6VßÙ£FñÝÞC˜\ÄO§íFÃäŽ Ö—O»Nq€ÌéLsÓ^ç9 ž† ž<ôDò¦‚{Tj›¾Tk¿ª}hë*Ú6IcÚ R£±Ëœ H/]RÄ É,HlÜsh“ÆØ"B(ØLw{žx8þ÷^›’Äf¹ÑÉÑzÖæÆ£aÀú@¨ñ(‰-ËâƒÿËéCt¯‰Ú¯I‹­æC¶øó€ó½ôä]îHgyUÉxƒ_œ=ªø½ÈŠ¥Š!ZˆOìc£ÝTë\zŸ¯>®x°`=“NTQª íɽՆs¸`A÷ÀáܶÒÁ×:l ä«ßм' ßãâ-­™zÀœ‰vÖ™*>å®óW0\u+›¥7…Ö8µ²;Ÿ>ͬǨµqÜ«mĺ lȼ P4Øwµ3rø~+'¥Þ%g¶jT3DóL ?§ï92ÿX¯ÒISã+L‹2«-æ­s¸T_äZ|Î:Öz96ù£‘-U/^î¹>4b3I‰¤>»0átèbY®Ä®>üØ«ÊNB›…9°H{uHÐ'ƒƒNW«V+’vxK9–jò¾€z±çYZKÌõ`ùœåe[W5áv®c¶¦[¹û£ÑáÅ5÷‚ŒKQ£ŒMÿÍõõE8S쟜„°^M¯ÿ-í¨Ž¶…ywy,Ÿ»ñì(¯Nô~òå ߟNù)Ç!ÿ—ïeÄ71ÈðÔZ\¶¨—E”F]sÝØô£&Z`(E‰P³î¶ZZg¬Q/ æ–É”é¬n! %žÌTMкöâ¼Öƒ¾µ-ov v¨ÑÍa)d¸+åî#ë6˜à÷†E7dráðRJ·è2ea««êé.ß,Ll¦€Y寅8QÍï¥bÈÈ­:LjiU= $^tÊž‰á_xQ<)‡õgsëÑj— ©g¾*ÙŽøÂ¬u9öõæîy}Ýlµ9ùéN:`ó\ŒZˬnLu¢œe¡Èñ3­9ñãúQ½Aò.“<««ÈAŠ8ö3+×iÆùÍÿt“0ÆÑ’&vÜʹ(’,îp§ñ®Þh„! 2#íñ|R>°ì™ þÊÆ[7ƒ_ѨëË\+÷|¼³xÝnxwj¹Yßø—M [¶fË·•ÖâÖïJI ßnOnÎ⧃žmIšìn:Y\l”ñ5 ò GnDÌhɕұâNÚ êLuwËçèËõš§ó‘6$ð^ª28•#‚9Ñ|ËJw–óutt;:hQƃ@ÜØeÄÜ·` î5Üæj¶–&v%+üšï‘+ûšÆNn€ÏçȧˆvŽB{㢕°¯³ª˜`³žxÉ~E¦‘‘°Ù]οäæe6ÿ÷Ðæ|ÐÐ"Œ¿ {TÔ>S®êÖ<4hÜü¡Á ¬ULhÜ85ºâ¶zúUÚCÉ5®Ü*Ô¥Xpám:Eá~'ÓüvÁºƒUc-I©ñ±z‘*l5 •øÔƒ,vœ•«£r=O:~ÆÕà¨?-–úLÑKNÚŸƒAßAµ³$&ç íØƒ ’ò^øñÔõ0]É ÓŠ6E¬”‡äK%1´¡³ç‹lYåìÿ²‡*pìlèMtêÈ£5@ãWö‘~­!œØ²KBn]â1QÚ@é±xlµÇ”œŠJ•šA $´NiZ¹x…˜>¯"HLK£²üXÔ}ÿmþäm¾éÜ4uI:F€Æñ7iÖq)éñ÷ œ\–e¯¨Á×ÅŒlÙr—OõÊ%õåjÈcCÙ}fuß¡Y™äð Q¦Ö‹‰ -ýüu2ˆ¼ Ü’€ºÜÍx•>®¬ewJ‡ ÖܺzÚ™¯9µìYóÑ;ûcøWÆ7rGÛÆ$š.B…Ží>»‰_•+.ÉúU;¯¹] d}ù^ÿìHu>‚— Pfk˜„‹N3@™“#áê)⹇‹ÀÚ3±üºY2Š'å°þ¬-©¥éPÖ/­x¨MðÅÓ©ŒðÞç#§iéŠ!<Ì}âÊçL-!‡«&ñªxàú¹Ÿ¿§:cÃ)A \‘kW¥ç¾Î3öá:»{“ͧ³-UºÔÛ1¯ôñnÀ‘3Qº»}Hå ¯‘– Þ××®ï®ó› Î†ß¯¢CÎ׫Åêa£7nnÆ”F±#.iÆvÖÌîg ›µãÛÝÏ’16cb äÍÞªÊéä\t*žµSìi­K“Âhn@ÇFq"¹–mˆÜˆ6$"¼pf%ÜÖ§Å»Ý9‘npBÐ…úeÌJÚø©@¬|ôZ¼›‹K†±—À‡Õ$[äµéZQ½zu(ƒ“ P‚ñºìOCî9Qš‡*fgh‡º#ÁIY.„àójë£àÞîˆà÷rÞO Ç÷.ʶ!zä•îÁmy‚ŠT¶wf7Ä~Í?ëƒ"û誯Õ[ó MtTA:À§RÞ;›‰Ê•©_”U!M7Q¶ÖvÕ-q±‰ ¾vßþEŠ!b·‡vF­Ê›• ªB‹‹µ˜=·Òf³ŸBŽÐùyÈ÷eßu¦†£œgš0¡+ Ûùå¢8|æA°1¶V âˆõ²W&ˆg—³î”¢Êé¾ß‘Ý&Á"À-^@ÙÍבǷÔã×1jxdwMÖ0MóÒ»oHÅpדC½¹N4®ÕÉv̺Vg«ƒu­?gÏc^‹³ÔëÊwKËÝ]XãîO§@¬úèÂ|â&ºÂ[É}¶Ì§ãÅ ÿ&Úà—Ô̸‰_æ»wÆŠ““>kL&þ·Sâ¢{±åì1?)Ø`”ÍtÆÕ®¼‹ÍLÍb@‹î"ɳÆ7 í>óÎË ·ŽÀf'©óۘĜ‡Ÿ¬Œ½jÅÿö^’sÎ|Òuvûy ‰»€q=pâÒ|ìA¶Ý *aº¼ºï¾Ÿ¨€ó4û˜G“&<…Œì0ÅãܬžXÍÖl:8ŸÏž¨_Z‹Z /žCLšÕ/%7ù{Œ¯ÈxAh`hfΟcáß’ü±ÖøvrËP$½äï”v:Ó6§kñÈ౯‘®êõÙ“ïÈ+•‘@µ9ÙXÏÙüï¾Xm\ìIvÙ¸…I%uA±Ö„ïz¦$PŸq«Ö´?ƒ E³Ã —…™è#L.¶oÿì/>wÖc—“ÞUG7 «VÆ„,Há9­—P»Þf\õ Ø*š†Úu'd.†¸ÞVµWèŒ)$Gÿ؃²sì@¶uWõøÑcÄþØíQ-bª• ¼QãQ¾x4.FÍò·³ØüQgý‰wš]„ÓÀ w¹ä“ÓçÑÈYlõðʇüF8¸f \ýÙì›7( ±Û& HæxÓî|¡Œ¤ÙzYiý#Ž?^cˆÃÌÄH^Uü´g[æ†r;V6_+w,ÇÔ+×üûE* ÔåýÃã‹Ýî¢FàøþɦöãiËõáŒMÜãkƒMÝåkñ!FõÜZ:ɪ•ó ¸4-O·QºÞèþ[cÇÕþô!ͳ© è;1%“¥Ò¸zè4 ÒþWZ…klþû›VµkÙúu{˜¯Ò“Ô6€ÁƒM³™NL€éÔd¼†þÓ/jGÚ<è˜ÿj=™äæ¹—Þ% ñÙ< ¢ù'iO$oê!ÀsóúF\©ÞæÜ,)·77C¾6ssÜa#(Ìç;n¥Ø<ßJiç[~4Þ?8=>s¡Ä«ð ØÖ’ IÝu±š!:iÁšÍ®—Ù¼b£ûÑŽ!ãA"îfcWW$@Š“¸ Ïoò˼݌ª¨Œ¾,Ñ‹ßÍ{¼²ßõO ýþ"+–-$‡@{0,a#ÅKšã<¯ÉËWuÏׇJ,½‚Ð>»Àº3a]Æ27B¿H›ZjÔÆÙÅ"fÉcÇ a qîBµc}ñ8QªÓí˜úSå«‹âÓŸ³çQw¢,5ÙŸ]ìÿz8>;¿>:wvà¶ q%F1‰..Ï®)D¸‰~pxtxyyâÐQ@¢ó³ÃPìWuò©«Ûû—â)Wɯ jçQÿÎùFÔ‚=³kD#FœgDt¢'½óa©PÛ0äå`qZN×3‘DþõÍϼªÕ2PZ¼:Tñ'qgÍ[ïÚM›OD#O-‚kÒÂ݉AS0¯AÑóä0œ36ïO¹þE+œ Í"W梟‘d¤1B­À®{³kAj&÷Á/Qü6îóx~…Ò¿òÄ^wW‹9¯Ü€—;H£b{ݰpzT^ûY1ã!z¥ø(¼öp“:Èø ­Zb¡ôæ3ºÌÂæìêò±§åjp±ço†î–!¢5º‰¨FIBG¡as•«Ë#á·}k± ,=6‘à 3nt¥„Е¶!쉊A§ê¯ÚùÑñ‡•î5‘]¡±bT¥´ñ LìaÃãàLEA9»4Qcž³5õ ãÚŽÒ¦&Ú€ï ^`»½qaF©ÔGçgGÇ¿òè›ã³_#Œ±':<<_¾Ù¿zHh"¹‰?\_6¤qܤï/_Ÿ_FA ¸êàðdÿ¯Í‚ h®,yw|Ý ‚L4Y5ñΘtzÊQ¤µ¶ M€3i ·e±Ê/ xç¥`?ÕcUñVBcÐ » `”x"1ÈDV¬Ø~zt_̦'%šzãd'ÓCK¾JÞŸÍÊOæÝhþé4«>¶Ÿx9užýð#ò•4Ú`'^„ ´u«ì XÖ'ÈûË»Gÿn”»`±Û+Déx( >ÒE¼Æ€£rSÙÐX¡Üwð>‹üÂÛ ­xeyúQf¼¿S1˜4’#&»7ŸåŸdÌ(¡S»xÝÄKeI-O;Ý…ÍEK«Ç±—K£ÓÏû¬ºÇ‘;‘{éëlòq½qÎç“z'uµ¾õhlãû]»AOðžMW\?âߘq Ñ£!00Þ”a9®³»fX$¿LN¦óŽÊ‡ë Ê¡•ª„FA¨TÉ<q˜Ø*pÁMõwª ¦µ,Æô»ÒÉ *5²@/Vû5f)³ НKöOëµK’Ml¿<½X–Ÿ‹¼]qRØK€‰ðÔk¹ú€qÙn†> ÇÐe™M'™©¿ÕŸr¹aŠ{]÷å`qõ±X m¿Ð±«€Ñ¬Èç";ò/¨€=RB‘€ˆÖê>O«¼âïœi3¨Sæ–Äÿ¥Ì(ÁÉ'uý’xŸ´.¬Z$áKªÙ¡”({ cáCún ›%-36éNøA ´',ù«W0‚°+╇#\—«lŠ¢&'ø4[ÄL>±…hŠÞöµúT.? Å!¤×ûæs!—›ŸýõêUóŸ£™<¯u•xèë¬Êã}­ˆ>à¡ÀfŠrÇ¥Ö«8^Šù|ý0%"¤°ÓИ{t2ÊTŒ6 E'ž¼ÏlôBI€bÚúAÙ«âµê£¥@EJBbÖýy9?¾8)ŠU?œ U¼ùò1_^ß/Ë•±OíHJcZnNX`>Y™“×ú-ŠWi)N?æ}SLsµÑèFHYuɺ.ŸÄß™<žîÆç…sF®ò9ÈgÙS?µI!ZmèêdT,îs£ÒQ?»÷S²#¯ÿrRÎêˆõ‡nKÎ&t·$ò¥ãå§—r p©IAhZú­~ÕºÏoÍ’ƒžb¦g±fs¶R& OJ«Ð(KlEGbFÑåÐS^êS$L߇‚Â Ø 8s\º…½&ql_ô»r)Á¿)òîø°ÝñˆÓ5€Â·mr×½$ÚâÝ?­B©í>Ñ%Æ÷*ò‡î^m%@;þmþÔ Þ@ðoÄuŽn$1ÞZgnmº…cŸ!æmÎõÜ´HxJ“ø¾…ð^¢Ø©ztlmˆÂÚ6~Õ™ÀÌÎ.G:åCÈ„E?妳xL×ÅCΆí%~Ù>â 7v[“¯½±”$M¶ë9×ÁÁfÖÖ¥‹ƒbw#¼¶mGâÂàÞ›$t¨ž+­MI…“×¹Icð`àu ^ó§/‰¬ô68^Ë··ðø_TÙÍ,Ÿúˆ*i˜­¢é(Q“‚Ù)>¸UhU~ |0&Lm¹`P®æ“12™çhÌG‰JLœÖv¦u¯' ¥5Zæl?sÌF÷l> ½+.ŽyPdªd¸ B¸›+ÌS7d5¸¤Õ[d!X±)\À0¾±T­!}t¼Îè¶nK 5ÜÄÊ€H"Åv\‚¢TæbF{­ˆ×1 K*᫱†ÞŸÂ*ÀçxÚî½Ws#–=ëå¦3ö€Ô¦l†ÀÝ¢ñ‹ÁÖâ=¬_ÇWƒJ£Á`X‹ˆÛ±^„êó:úZËË^®“ç=9+9^C‡ü_þ,¸îsfqÕ(a µâÁíÄJ’âõWU9‰€:‚ƒEø‘ƒþœØü 4ëô¢\Õv‡M>g¢/\L\޽“Ò˜Ž'#%Õ†Â$´Ô¯Í~‘BæÎz¨sëR\bùø!í[pD¼Ô–ÆAYÕÇ«å_Öyí¬x¡¾òÜ_ŽÔ¯Ä‘ÉÝÛΘ¸`x±^ÄÆG# µ7‡¡Jà !f†¨s¾FU‘lÙ¢ ‡¹]èB⅀ƛ몇Uë‡N>ëÒ÷á|RNµ_øx"1X€Ío»`“É¡ ;'g~¤¡: ç÷Ïë äËõ»ÓmF9aÐὈ<ûë+¨ê5–ø! ±ìƒoSÆ–f²w±- ‰Ùªsa„ÐÞiý Ìw›¶MuDrÇa¼)©êdòâé\\8‹X—9ÂlØy¬ë2Öu«ïbûáaÜ5B;Ñžõ%h¢Œx¹ë\ý*‡Š€NvتÿÍõéI³ë¿þÙeP Fìe3—²N+3a/œ`É e%õ9C¼0k’Öƒ± OÑ.Õc…Ë0â–(•jøÚ¨ÜA¥¦k“ý¬—+Þâ%Aër ´¥I‰Í “lú¡¸1‚Ô£ÔÐ\‘ÅÜÍ%!´T‘ƒ£ºy+×Ã[»|+é¶sÿrmÎߥ*À/À×¥”TÅó+ÝÁ¹¡d 86äŠ Jy-´-‘ÐÃòlX‡#‰b¸^e#gÊUÁt–‰ xÈIOœ˜íצ-­+L‚è¡uÚq%¼.p…¯¼Àb­ÎJ@-Ú\ÌF˜=ýÝ¿Ð""©†ê£^qÑ„ÃJÿ£à Ô¶õÅž'JTiè!û ¿YßmmÄlÛ°U“{;ºÝ Ãèi¹^W×× 4[Á4ÆÑ©Fë6`„dK¬Aª‘âäÉW"zL)‰?<å£A¼é‚gi1xÙ½ÔM¼GlŽ#I˜XF£½òÌœ¡¦iëÖCvíÝ^F˜Â ú3•Åá¹Ýp*Íp¤j_ÛTŸúíÑÝšx±GDôw$€Œ˜,ˆD{îǦn•‹l@­JD%…eÑÜ·!½j¼±9×mþôwfH$ûذzÇv2ü¯|zRÌÛûc Öâ5÷x8;3Æ<{Øî-9·8SCÂ^žC¨ñ»”¬ªgf¡M£#ËŸ~CŒçÃÏùD:xþÛÙ¨g•lÇÜ;ëluñïìÍÙݳ¸wÆYڀϰº)<¯ëv.ÆÚ¸å?½Cw“!›ÎÒ˜;í·ÅL{Z-®Š»¹¸˜›p“¨¦qÂk”ø±mQ²:øQòûÞGRrarRÓ=ô©•ÙœzD-±D)nCi˜@1Ofe•×IŒ¿.KvGòäjpˆ ÙÌ]Ç÷³dOÊaýÙ ¯¯×·|™°µ™^ñmg–Gd›Ó ê2üT¨JÔø|]*£]¦¶×—ƒ‡ª’¨°¯§Øˆf¤{…’iLS|ûÆÇ¼¥P:H-ÅCK$ 2¯±ßŸÆAóØ©Áló÷uVßz=*—™È¨*ªX³5ÍC a»5ùMOC†¯ ™¦õcêkýP5 ç÷BkƒZ”Eíô`Å[ ¿žÃ†¤.|Ñ"ËîtɳĹm3‰ÊÁ³¯ÄüÖòô„(@¥¶ê[0=¾H„Si†ÚÙ®^o^<©ëŠêzeª"_¦Ú1=¾ÎT=¾/cÏ£ÆÇ9j³z¶ïzznÉ«þGå¸+z¯#üœßPTo›ÏoËW¯¥Øâæ"ãäÆñ,ÜÉ«GÛ.žXIÍUJù£ùÑźéjO°*& @^%œ’²>ï€ÃMŸôeIWtöÇÂr3ú©tŒbßd®«!a]U£SVáÔEzµZ¦ËV¹@Žß&Ñ Iý1¡¸, C’þhC K¿Üð!¿Ñ‰'¿ÍYCÓ $Iò‹ç‰ïÉså4Ÿ¯Û¼LKß…ÀB/–ÖK›ú]H6ú¨?õ “±6›• T¶¤Å|9àoAòý(g;ɛĖ<@xý¸šIk?³¶ñ".~næ,Ÿ…G>²ÌkñMþ a‹ÄH°ŽE›à¯_´;ôº¬Vݰ-ÎÖ E5‘·ó¤kæ€D±hFÝ9F1Æ¢}Á>ê¶©þüÆLÜEˆXÔ\æáí4)ƒËâ§œ ç2µ+ ¼-Ì¥Ø4,³=÷f±&<+&íoÇSuø?^æÙÌêà¿í^¸>1•dZÀçäæwº é£@rŒî³ùE¾|(„3m‡°8_èâåÿ²R´~òdó\ óüOþ€.ãÍ¡&jrŸ-å›Ó¼¾ÿÁ~Ÿ•<Å]­JoRA™¥¨µ„J0-àGÅp¾èõ²äð;Ù å>ÈËg–œ Rö÷e1ÉŸWxJ„è’|~ùi!"sÀû…_|W›?ç{Å¥ïOˆêöp.PS?¿Ì>¥f›oësÊq¹dìàWd– äQJ¡(í,éÞ2ï:XȈUº¡†æ¤Á^WB4vcn¦}õxÑmÎÊUasëìx ‹@‚;¥p=ºØ?Øÿ²®¶°zUðÕ§GÞÈy7z¯Z{ÕB<‹>á$ñ‘¤<ŠGÒ³ü“µ²ìYR‹ÛP’’¾5±±ªâùÔ+.5–õØ"ÑDhì"Ë–ÅÜìLlQ»$¶ÃN7Z’”r±°i.²¥§¯l¸Ö,â¦j:ž?µ-ºÝþxRÿU¥¶{+›Q9Ûå°šûpÄ• ŠÎ1í&[V³y=œO·/¦CÚ äÅ,{‚V® bö¿æŠbÌnÝÉŲx¤n^ènJ\bëÏ“vÁ6‚ o]8lHÄÁ6·%Ðv¾*¹Ì³úÊëlyç8“Ý€~%@îLuŠç’4ZÈý TkmSLŠ9 èiu÷R:´ñª}›RRÌAÁº¥‹(çÛü©g RÉãˆ.>ñ6SŒq ¯ËE1iSÄéYJŠWSÑBâ6R֞Ģ™©ÀnCUI0àiÓΛ·±×;£G8¾Ê£øæe#§~Ñ¢v4},aÃÝ•çÍ7Û)R‡2P¨!ñ¶V¬„ÀÍk¦Èí”*æ ©W°­•§-jsa¢™|;åéPŠ4$ÞÖJ•8\°pÆlºï9Ûf‡Òº“¶t£6ʵÛÓz2ͽ hY¸/ïÙ*,ec=™äâü¾åéŸÐ ãšåœ÷׫¬.ûÕ0$‡79?r šô£Æ‰}ùY€,àí©‚bHjɃ„7þu;õï’/¸t+a9`³Îc¹MgŒ¼Ýä ðX½d>½.¥Å«é]óçc%Õ~22+™ ioH|ç8]ôS¾ÖÞá “dÀÇAkÖ›‹‰WÞQ¢™sœæ öy„FòyÐüfû<6‹—îmH:ØòØ«¹òø¼à¶<_j€k-¼€À–GHÍ`Mþ†»yYà´`ÃÂEQ:õ Kbñ+Ù½Bñý æ#ÅÛ¢dqBÉm³W,Ü›æ¼:­îzì¡ )éko+Z¢Z¢hÞÍgk¡ä’ùdm9gyš2#=ðjÑ]QU’©/u‡Me®é|vC™ôÉYË‘Ñúdš¥Ðîn+žœË~ern°é0H­èè‘㤠¼ó ÑÿRãƒÍ¤á‘\bÜ_­ò‡…Iö׫’ð¦XÝgË|:^¬ø[ë<àuVåƒ_:Ö¼‡4á± ¦Rjªiý^É(ž”Ãú3+FñjÏ~eü?¡B•«Ýö8Ó¿Ø3¿Œæ³z*HµbK‡Êh[7dÜÒÉ·¿Gò…ñD§t"ÑÎù¤RuqIçÉÖsy¤ùiåÎÌ„ºöùþèxκû£xKÅr¥º=Mfâþ·Pd7È\ö­¼š, é’Š@tŸÇs²qÖ ƒZèZH-–@Ñ=¯Ç¹Ëõü?ËQ ѳœÈï¦ìǃÄÝ»Üò_—0Û ˆ˜ÉNr…æ:7n¨¿ê‰N¨Íí`¯ÑS‹³yféÚ…9£ÈÊ«'®ÉWÑü7uJ‘©vnN‘bu™T|{®Y樿i¥Ý0¯šLÝHw`ôî2ÚÊìlj¸5èíÇ[‰Ñ8àÖ"·t§Dõz†kïÜN!‡üÚña©\'ÞV¸(­S ¬]æ·ëª[qØ(`ågS¾ÚW= Ù+é„HM |ë1Ëù”!}ÿÇo£•ƒ@´„÷ºmÅo²z0Û°–CHQ7êÖþQÅPºAZ+öMÄкƒˆâI9¬?ÛK<F ­z- 6/<-&'y5bqßdùñÅãOãˆç‚AܽúoÄP5àWW'±Ø2êžþÓAæ ðˆõ!6·Ç‚›è{ð§C¢$oNç§ûÿgt~v¦ˆÌ£޽"Pó¼Ï—Ü!àiö?å2Š 'س¾Ø„0Ìá,扜2ÁžõÅÇÉÃlNE7-×7³¼™‘yxlŠÃÏ«e¦xžžvíY_<”"L­—õKYãbµ½×¨éVžé [½ÖñÙzwáŽ?‡íhJ~»ãsèíêeXÌÞ…uÔK¸ÝìÀƒ‹ÙºâÿKXáRÁ˜%ÀŒðRŽaë䱨ÆyíÖîÁÑi7µb| ¿G( qÌé]†ø£†(èEýb‰,”êx‹äÜÎ[ya‡­pešRÕ¼ë…Å«¾¸. sÛƒÕÙ„ÚÉD£‡;r¤™„©ý3ÎÃXWŽ5{ ,+<%£…ç$149°_Æe(X>Å*œÖQÊ$¡©ŠUB H¼@Þ¥È ¼Y‹ ¹ü;J_,ú! y^žºd[‡­>9·3Ž;„ ë+öÏ·?Y+­eVTù`ŸÁ7ëU.]÷ÿ欔cÕr=Y±í C,æùô7½¼6åN}sÎJÛáå9éePFT¶Uú;n±Ýkn"æÜä  Ã¡cùÓaˆÕã^³¹h»ý3n±·ºÝìk7dáRoÂ=-˜2ÜÏnšû™Áq{™‘•)_× NaªÑpêÄÆ"»— kè\N_Ú¡ùŽ6$꽯¯é Å:W_Ï#ŠV–žux0„×ZD_Ú¡ùþ<°{‘[Û(+ºm=±k¸ÚlcŸ¦ø|ª,ïDr[,+{‡¢Ä‹°ðlÒœ<<¥ˆ8 c°—!A{¹*g½kêU6,Q#Ö©"RLn •]#í Ð,gù\O„Îäù#ˆ'[·'"~†"è;Q¦/eK’„/ ­Xåu?(æÓüó‹WƒÁ¼\ †"`ðÿ ~|›¨&¬¹L3ŸU¹?®”®Ñ)Iİ›¤1b°êaIÂ)@ÜÈWšyý5®9êz¼ÓìD S ÕÇz(/Æ¡I9›ÉCúê»ÓõŠÂ_ñ )óIê²#€´[K‘÷m¦”¶}–•ÉûĉŒ+ijU ŸÃå±^½ºbÿñt¬‚ÃZLA:ÆPpªäjïXÃ;R-¤æåüù²LÚHQœ´¶í2è1W ¿wñ˜óÜŸâÇ‚üy ô/µ¡Ç/ƒ_^½’æ-O‹™ÅOဠ­¸õm\ªÑ²yq§ý™ÌS—võœõM‡yI€ëi™×S]‹% ‘ìAçU^¿Æ“ M¤FRs?óÝ 51³ŽâÙ"›h‰³©… ¦ŠÖN½ÒMéeŠG3å)†ï±NŠ;Í_ß\dwyõÿKÕÈÿ×­¡r2ºEEàÞ}”¨gµ†n¯½B.D hÊ„E馯 Š«$II.Z™àlTgáܰV “õ§Üz®šKÌðfõ\WŸê®`á$.T&·A½—Óâ:©¿"K!Z¢=XçºhÓVûS¤AÔvú´žg‰Åˆß¦ôZ«Ù‚YÒ@1ZéÛú¡â-(C’Ú ÊÒR·!aúPÅAÀ޹`.trP¤ÞUsÖÐÙMC×sCï[Uw­;ª±{–™©›ÊoS˘vº¿MIÓR 7Ñ~óœË’Mèñ°¼ u"RtÕ*FÖR»ÌwQ/ö¼Nk«gÍêF¼jói}±üé‡0D»*‘ªÊýéôÇ«Õrùâ5…/þ3¨ÿýBþóûo¿ëñ?{ƒoA¯ø”Uƒl½*X¿˜°…þÛoÌùº™uæ›§ÁÕ‡ã_ÃûÕjñê÷¿ÿôéÓw|€ü®\Þ½øŽãhß2øîûï~ø‘}Áàì_nRͶ e€«’íŸyVŒ‡uÖ)?2«ŒM«ƒl0_?ܰÁ»¼åX“rª¡Ç|..Ø\¦Æ†V<,–åc>à~þ³›bƦ—ßÞ“"ŸOž¾”Bˆ‡ìc.ï³9ÏyêU-èz>Ë«jðT®üɃÁ§ûl%~±Ùp0-™¿ûë†ÅíK”‹RáX™­§ùà7lÀû=û+”[V÷¿ac ½ó±ž‹vñ×ë7çg{ÿ&ï¡O¬ŠÛ=4–aãƒãËÃÑõùåøì|üþzÿõÉ¡„•»Ÿ‰ön°Çš#?Uyσ–|³²ä=¾3oÄ0­¤útÇ_©G¬ÿÌWüDgpýË@ݲqþÉ& y½I„²º½(E)‹ Áàzð-[›ü‡øÛŠ1äa/¯,ÂýñÏ<ÿú¿v<$<ê¨hV¬ßøÍ ¾}üyè-ï+rýí œM›…’üóûÿÐð2Tg©¾?Õ2ªš¿åQÊò/ÖœϦ]DP.95Û1þ|ý‹”JÞœf±¾™“WTZQ¸ª¿×Ü,àõo+Û®ÑÕÃbÈ&ÜÁõpõâÅhd¾k}XPå¢q Ebÿ³Ž§’WW)k:ÅoE«˜VÄýÇ^ÝD¨^›¼³½?ÇØ«W1×CVVÿª;TÏc´¤å@ZÉ[3BŠñ™­WÄÐ<ãžk+qÆ+aÿ˜- >¬ „iÎ:+>pþ>Ó· Ù‚Š’lñ“/Åšˆ ^ü6!W;°QVnhc%U7÷ñž-Ë5†ç@‹Âg>þN²9¸ÙÒnÉÊ€Íl´Ÿå\B>þ÷ÿfcËH¶œrd8^ž^œü?öÞ½¿WþÛþŒûk"9ò5M/q쾊í¤Þú¶–Óîž>ûÓ;–Æö4²F«ùÒÖ糿À È!G²“twŸw}Î6öAAÚ§»;{öÁ›½wïÛR±Ik0;×&ÝnçýáñÉQw{»)ž>üƒx-§æí˯W›²`º2׌GVNN?w }˜¦°¦r#ãóÿ•%b©Ý~&Wùþüé™0XÍ ññhvöpœo^|·¶úF´—W_,¿| £•÷ÎÅ ¬<’z‰\Þn³«É•¸V+2Rpœþs’a±“’ÔBªIî—’î“A–b! øÅË—Ò(>°n<ü"¥ TÅ‰ÃæO6@#¥>O÷÷÷w}&šu©)þøC4lÁ»Ã÷ÛÝ.²ö ãùéÉÞöi+ ‘½YêC¡ÂÆS­E] l~1Ì 2¢À.å‹6~°m‚ð§R’ñPÚ…?ä÷‡ï;»;þÕÈ/Y𤢑CW–û÷î‡MÉp úp°w(W~YoS|¥Èâ š0‘µÍeå†GC0´4 ´¦ D4¢ìÁ,ùâ1}†XdúsYÄIÛ=èlwßvÞŸìv:ݯ^®¾ô 5~Ú=!¼Fãäâ*Ñœjô³m×W6…äþd8NÕñr_€Ã| Î'CRÞ—ÒÊ>Kå,§Wr$}Uƒ à¸}r€8ù&Xp¸PRŒÔ‘DÕ£:2­(Ãv(G€‹ ­,Õùxº{"MJwnÀ7PË¥Z¡tØjÂOíÂL¸JGjº²žùµ]¦· Ra#¡n*©ŽÂ“J~g&ÄìS‡d_ áÝöv÷‡vg{¿Ýéü´×Ù{³·¿wúw5=ôhê*éÉR#)»;>:9õ$÷ç½Ã눵 ~…è|Ýþû;YÀ´‰.ꜶO÷¶»’’?îî‚é76ç©zîzƒb”öýÁ€Ñô4jâÐY S*Š[Eq\gEF{ÄÆ‚¬LåB³VoñAjlý©›f‹ ‹èÏr]Îo**½sº³ÝÞßÿD c¸*À‘¨HEE 2”TÎJ´M²Þ8/òóòY«œùËÁD”+[‚3iÛ_㉷\â´º3ÓË,¼¨qå¾rûä´ÛÙÝ~² íìJÝ»-m‡ÍFïºKw¬©Õ ±*¢VÙM'3^°ÈÙÙ8ßEG*Åô±#5e#T ´=’fó³Â M.?ÏÚœ`$@ƒåËgpêv%¶“ñY>\:Ë ˜æU-Ù>>Þß­ZUrBîJÚ´·OŽ:·RÿÂÀ:{G‡)ȧ?½?•«íŽü´}$×[>–‡·«| Ðcð¬°øe€[%‰{"ô†HšÙYï^C8ñp ›%´Ò þÌeiKó ¬³–ªŸOJ‚¼’ËxÖÏ$™œTH+P +ÙÜ7¸ó¿QrƒÿµdÅðY ­úËrßœˆ_'²ÇB¢-­Õž, Ü}uÒô•ç[ñjeåBòrr¶,QY÷ ý'+ŠIZ¬¬}·N{ÀüUYÑ›° +Ö‡kä~wûèàxolpרÚ¨yùݺ!°+;»oÞ¿sd˜{p –¢(ÿKb •Eï%¡úéÙäBÜ“  É„YEd¤a4H!÷œ\$È8š Ê$  -•óë5Õ_¾Üb"¤*)uªú·éxd4‚»«â­lÚ·EûxL­5 JSŠüS¾ BǬ—i†OŠ¹Þ‹“á7„ùPn²ÏÀÙã>[N Ü›¦º €]ƒä.Ÿ”"?Çqãi`7žçÚ¯Úgš Œ¼¨8ÓÆ’µ èak?¬ìLŸÊ6å®É“÷‡§{Fˆ…¯k^çôïÇ»]ôWvÛ»BÎï¯`M¯È5+»}tº‹»ÄÃwÛ¦øâÖ« M‚öáNþç× ðZû¸Ö‚ôZ4€×@d’.ñ÷|^RTÊo­HŠ ö·2¥¯pEîÉæ=8OÅh‹‚NÝ “+ù«^qåÐÀ-wó~*…V*gñÝwËß} •¤†÷ÖEÝ7LÓ>n‰ÉU…x^ŸQ—Ï–áû ˆHg_yí¥R*¤m‡n¡a 9D%.-‘¥-(Ïýeçã\*´+8DF…# ˜ÇKަ˜ô.Ù‰+¹Ø­¡¦èâ’[ïF¹CÓ ¶sqaú[ñNi޳ \^Æ›–¾MÙ}óþí[©s;{ÿãË3+k«ë_qÐx¦ÊÕÙ°è?**SñøÜÝÙëý|¨ÿWo×ÜjÛíÎi÷p÷çîÁîÁÑÉßMµu¯Kpüên)fX¼KÖŸêRÉ7Á[ÑvÀ%÷,-Èà±–O;Bmݵ@ضñsy\Ž[ÚÁ+§ `wAmqi–vÆE%ÙB“¢ L¶ç“ˆÕ0/—E[Î0 *„JQL!ŒÎ œ–g©êLêÙF‘¦¨R±N‡'0ꪟMÉ{5•ÏóÁ ¿A+§ìÊ9’VN¤"-)ú€é\M€Àé"§g.¿azNÕ"aruÜþ`´“b‚g…7ãLšÎÃWtËwÎ$†ž ÉÜÖõH¶¼[F›âɦXZkªù³²¢É‡ýÒç{ܽðJçI6à°ÓÃü§»¢'@r—9ÈzY©Ð’l„K9bSLÇN–Ì8öŠ£²mÓbBÖÃUVqq%T=‰› 8dúUR±%ç¶T„l É  1'ô!Ù);õªM‹‹‹ÍÆSÙ¢ù±sZ¦7"ZY¶ˆåååù9uÞe±¬ò+ª¢mo9]n!q¼á"¡Ô\e¢•¬kŠŽÐ>ƒ }n «V(“ð—”µ.õSuɬfqt.јŒ 2ÉqòGŒ;ÝG¥Ì9&²ÆdPÒû<È.H³h^Tò/Ä98$lIqÚñ_ËBšüÃ/R…°|²á{UrDŠÊëa 5Õ@e;ÕfÃi¡BûØÝŸÞü…—W¸è4ÊTÐGû;>hó{ ÞôMÛmzoÄ ~1¼k±µXŒ{Bñlµ¡¤¼¹²´Ö‘k>“:1“ûØó4­J˜ŽV¾…Ì0j)sîääè4p2¼Sâ0pù!宬#\À²!©µª˜5ô¤}øc÷àhgxŸa_ÖW4‰—ž'ÀΛ‚‰ Ôy†;Ùq2„¤Ð°Œ¤· ž¹Ö‘½¬äò<Ïû Ê.Ôô¾g ù‹Ô"´’é)6èöØT*uœÈ¦wñlí™5¸¶¶¼Ú´•³PåÕg Cn³Â}¶mY­Ñ\!Á¶¨ëX£I†7Ž~Ÿæ9–<ò©RM®Ln=R•M¿Þ¾>Ìöø‚Bµ:õ²ò“MÖkS|/Æâ•²à¥~ÇFMµ!KŒõDRd?»’òV$w…¸”ð $ê,%7FïCßš†ˆ¾¥…iï`ïÔ¢´&^¿ß6uR·$Å©¥¹’ÒEs×{Ü €•2)@è¥Y¹B=Ò¬ôG:ã Ýq¸Ðá"1X3œ^ƒŒì¸l¸ûLØ_^%#u"Œ2‘^Éír2ˆZ§ÇQr¦ó+³)MŠ»—&yE^W=1Ü×?ú±¢Z¬²øÃ§m34æiÍ-epà8‹¤ùÛï㌖k¸”0É~Fâw¿¯Ä„‹wÙ$ßÃĨb+e}졼“fƒöTüï à¬yÒ¬P@ƒƒS~€çƒó'q¿¯„q¶q2²†Ç94=Îzp{…„öq2p¤`@¹,v`ä{>Þê¤ÎÄìn´§óG U‰#…ænð —/Ø©–sÛþ›î•7FG6ÕŠÃÕNŸŸz½A4Ö›NŸ!ÕèêŠF@W5. ^s¥¥=VÊsðÍùÊ©¥1õ↖½sÉÈ’F¥ßו¡+iz.µ›^aÔš#… ®,ÅaËêT\*˜Èe«t) Ì7ɺaŽ\[Â…éJK›KE=z ¢1®ÒØ¢<$°Ç&÷Uk×o—×ÁõºÂ˜Þ´XØ^#Ô­a©Š´ƒj,¢“vùò·šj{ÕBš-JsH7R—=Ÿ¨†Ò¿28  1®>Øp2Æ“„¢CšŽ¯p+"ðÿSrÃ]ÊÚî€[t-såòŸE¸Ô¶177'»”fÄŶ °Eö¤ª‡8Ù§p9¹Â½—º¿ã\ê× ¤}‰8µÍe‰~~#·Àâ2KÇɸwy§À±!#L²XTÐÜ ~=“è TìU2êDò-÷E†T{ƒLî!70a;t›Àc8ÍÎÎ%Þ* ŠÀŽ»qmì†÷² Ù\¶Oyïq8*2 ¡¢nRk¿”¡¨1`âDDÉÒõwÍ@+]†.ðIQ\{ð€¨€6,r£,Í(¼ªW¡w`b!`óIQJc_æê`NÒy¥z-êc(gyMøªEÁ˜ZX£qz2ì*eI–O ‚iyfZûËΘq¨_(•˜# æØ“¢T]F•à„câ#KWBo8ÄQÇ8iØT²‚j`«o3ÂÖjÁÑŒUÕ¸_Qжž&c”ÝP>üm8ý]v£t,'…(>d£‘vÝ#xcKRÒ¡AGÈ8•s\ P°¸÷²ðW!ñ^؆G¯%Ó¶¨Ðü-¶Z"-{èƒ9!ûf•Ž:ñެD5ÀÎ*4`WI|`ÝTŸp%®`Dß9.ö+1Њ›¯V«ÌEßi9ý ˜vNO¶².®è¥1ý1ß»s‹ ßqÁ}sIcW¬Z:nñLóq:$pE/D$ììÖá¬èÃD—LÛ†/±p/äÏ‘c+À Ðï%÷?Cr·Ñ¥gDp2¢[Ò¶ËÊÖãðdRy®È•ÂäI¾0•w-UNXÉs3Lo®Ò«||ç(üFã È$\ö‚ã×Ò&X-pºùJ.vnIZxvpbGy7Ì #+^$ß gieÙÑ*øvÐÎ<Óƒ†Q7Cû³Ei —åŠÐ†š’rØ0|}ŸäDŸ*Þ1óCÖ ÐÖÒÁ‰¨ÈÃ, ¯×-“ *±<±šhHë=ïe¸cQ×G•_!,|IuÍoµÚÆ”“2-ˆA„ä¤QÔã÷~´K®á µëÍltÈúÍ?@,¤"G—šR9“"W6áa#>µƒ)3P¸-È5aAœgé€=¿‡^™ó†²`gÙ‚F'Št”˜P0!`Z:“˜Ù½Ú²?ÃÞ-Ï Ý6—p3õŠx®þ I•Ÿ—r'Öø¾‰5®røMo.—•»†¥8vø~_‹24rŒ`&C–Qg jù°)LƒJµbÃ×…SÊDñü¹Öâhƺæð‹çjCŤ½KòE³ow² Ö$cJ¥“–¾£XÈ%¡Ù€z€éHl¸#V•F¦•†…ÎTÓ©je(3»öÀË. ;|²¸IBpX4² âŸ_•ÕÄ{JÙúÝè'´jYlûÊxzk£Ï’ñèIÙ㌹‰Ji‹³jîŠGÿU´ ~ôªw¯ZÂ<8Loņ †YC ¬r:Ó–SKO'…%F‰JÌ릮ß9ç¶1¾‡8j ò ñúG0ÄÔÏø$ô&Òl©l}>˜JÏVÕqYÖägß=kê­â¤Šk-Q›×¯ÅWªc;(‰ò| ÙhimµY«Zj˜¦˜R"þhg×U,ô¸>¢03¢YÇ‚²A ŠH0êŽg$kÏ\Å¡žßU1žùI6†ô9Âë/‡FœÏ´Ü­äøü߀Š)|HŒß àe¤ºQaD©…eÏך£lq¬íœûGJ›%ïô…æS ÞUzU¤%¬jR|>¹ûd-p Ö‰^(véiRF øå "£±ôöýÒšWiïÈ”›:ë^º¥¦+b>œa?½µ °ÎW^ón†õõÒ«³“AП|øæîÒqNu¾öêÉÝôù ¿Q°°Î7^ÎݰLnݱëÕÁ@‘ÎßUàezåÑpÕ«ÔÖQ‹¨Uò)}€ÇM$ŸÔ‡“ÁàD%Óu—Ö^ÌÏÓKxâæÚ§ÿ:&Ç ý8àøï:C÷‡Ý¿¡èvõ…Q¶¯Žïð‚ÝÙ†7Mùé_ét÷нa']ôر¡K¤2|z|¼D†6´½a©`ݤý|xaþöªµ (eõ̯â[i‘zUÙ§@åj¯ºùÈP¸t… )‰ã»7weZðoÕ¥NÞ3xÚç~4Ãû¢ó+ð:`ÞÖ/¬¶o xǃSçkµQó*ðæË\µözcãøÞñ˘îéñÛýö»N÷‡öO»] ûÅ¿¾iwv!úE`l•ÃöÇ?›F]ÎÖ"Èlóu¾ìÐAÌ«õ¥‘šrÕ”ÿ]ÚÊÏÐcÑäêulûx¯0OíDÌÏ)0½š…ërëõBE€ž2½Ç +Ùƒ!©ðDŒ>šÐ"3µg’kš«rh?S4¡W* ޾Å}/lõÛc¸ñ•ÞhÛZ®9Zã´0¢N.F ^˜VpÙI²Ûã»À(i£ŸÓÔ^¥˜Gö‘ Ý¡›÷´‹mù©!”øß§ÓX[S=uR¨¬‚ôFý- ÐÖU:Tö±4W˜ïOß~Ë&5sg`{Ø×s«%žöè +So`·é=½ÆlÈ Ê^’FXRTSZ0ø_[,±üÛÎîöÉî[ƒ}ÁŽ#ùBí¨Ôç°âØÐœ¿ÿ(ét8 ìlY._šSÅÓ`¥‘IftU@ŒQSpFY0Ô ¨í^sCDÉèÖcd„»Úý>àÛéC<(?G%Ïê í"².¿ÜÖåÿµC±LÝ`‚oŽNöÛ‡;Û~”ÁŸÛ§ÛGMG­qtÌoÕ¿nE^Ï6ؽ1¼Õ èé™^A=bøn€œã¿ÇCä8enåæ³Jb>€¬{–\Åá:éâ±dd4…Ü¥üèvQ¬£oME÷Ø Æèëm$£–pÕ$…ûך® Žv*9þÞÄšrÑ5È$¦þÒ~€!i‡_¥HãÝk®;­Êý_HZ¡œG>·K¡2õvv÷-…ùWöG:KÂîm¯Û)ó%lÖ§:ÉÙcç€B®Ù‘Ùj¿ôïU¬ È*FÓ»´ÛÝ ¡À°:!¤N>ÌË=-ú•PÏIX#×—×ð€i2Z®üš?x®k®x}Ö ¼fòzëÖGÍà þá>œa„«Ðf£À•ONI¸™XÉ`«²!epwÖ²X dã>Ì.;­à‡ qµ2DË™Ó û{?^”—aÔÞ@>o½³yj¸¸)Õ7oUŸ³¯¹EþÖIÁ4¤ŠN²)‹$ÁORT%Ý·‰\*”ñ±wˆ¶ÕæÚ‰¾x©˜MŠŽbˆ1«àL¸ÀøëWW”tæìÅÒØPB%Hd³ÒO¯WF騀ÿ,­¾xùbå û†réb’Aæa:…j/1¥‹*ëu@·wO!DtÓ<¡o´Át%kÐþ›† ü.ß;¤ò½C¢ݨƒÑ½Á;”›@|f‰ª?œ ~hE9Wäg.Fíß><¿f´úEZÂ(yر¾û§S"Ž¥¬ª÷·S·H/z¹Td„ûéË2èþ¹¡m÷ã;zJªCÉ#ÛAÜj÷!¬ï,Þº\š4Mˆ™!«ÎÌÉP7©äÞXš²ÚIšÙƒjÕÖq{dÊ…(¥JÙôYÓsŽV§ÕQžâ q|)¨ š·Í`åÁîB ïSØ'ÏÉŸÿ3O‡ÚbnNÿI€ÝôïìJ×tú.¾÷Úèíhn°Z²-Ôj:m U hÖÜÛnÍ©ôê,£"•齑%½N-Åa}Q3ù@ÅYIŠ.弢ƒ²Ò+úBÅZý³òB}RûHÞc)¼XH²ìŠ,ƒ¼”¦æ½,ù!MFÕÓ9N ‘$îßHmp Їí¿˜`®››àÛx ð)†¾.Ø_ã~Dñ+ØòE¤åj}Ë-ñ¢ée•uäTín·;ïýx°²L}§x­ Üp/6ðz†zoÝ…³î…HÀÚe¼¬¢ž@>L9Ó…`ìÖé’öBÛµfþì@Ö-ò8݂é¡>çªüÜ\Úêk”׺ÒÐw[v/“âœÍå3ÆU¦`™WÉ0Mæiü'í½jü¸(ì%@+fGƒ. öÕ©Mw‚”F—¢!×”†­†Q}§=¥ÄTíÈæf¥¤ÏÍÛL A°Z«’hKnÑšóâxïæX&„€)Œ¶7G6æ¦,ÚÚ=Ì €€ÏºR=(çÌ'É)Ba§B¬4 ÁžØÂ ÌyRS…à6€¸<8}ŠÍ4ƒ<1[„ÖÁûùùÈ y5ëÚý>¶>(.˜‹eQ\¥Å…¿ëàóÏ~Å@nÕÏå8é¥^›Š”u 3¯{ÔëMÆci½7ÁÊ/oÁBl<¥/O¤ü×À06–8W…!2ÌtßrëÒÕþ`å›PÕXW†n·ÒünXÃîojÇ„zœÂ0jÉ E.|Yˆ/‹…äÐ3‡ï¯·ÂBÚKHLê$îS•°*¦á·#qN¯ ÕNZª-wUH.÷Úì%SIº§?œì¶w::YO¨¯"T.@y%·N¬W OÁþãe¨Ðý6D§ pUÉ¢À€¡ñnoßÍŸáN×Ñ©„Њ©ú •†I>‰õåpɱIZêè™ÇwÆÏ³”ÂNó\ézáäCQZ›A©L¬ÏIUx}»žY•:bït¯½»[Ëš0–Õº(_Ròº§‘ØS4à À‡¨fÒ”!›KOÅ&SÛ•”MÚ}3È¥ÚÐ2@æùoƒNŠ ûÕR  y”v)æ¶©`SlªÜ6‚§ÒTÒ €1P'”" åSÝÊY~ŽŽ•{A7Š;æð¤† i°§R ¸ëgwXLÆ)hÀßÄÿ­ù;!¿a1¸ß˜JË6„ò›…–TŸj±H®KH”“£Ì@«RRÜ×S1QRBk¨~:òwÕÉ „Ôƒ„ŒÏWÿî›Ýw{‡Ý7ûGÛ?Ö°^téò<}:ƒOÓAïîÀ"añÅöþþÑÏ54u;ÀX³¡¨‹Ž¢L¸mfü‰[™ÙU’àÚ^™L%u`ÞW»z0á½ÉT%Ùo¾?” Á¹Ví¬é/4Š;Gƒ¾Z9àK‹rˆÛ# \Ýä΢DCúï ܾ%[]ÂKkuÙ¨WlArV“pGUÁ™™OXû¡Áyˆ=n4Èâ‡IÝcF3k7¦n$]¢’§Ã\‹“6تaHkÙ>3Ûf$üÌ„›ièŸÑ£®å@Î*Ì © _äFO…)P~°Ï•ö~¶ð­ŸcøÛ9^Z,<ÚŸ-—éíÃÎU²áü]'Ä_UJÞì¶!ÛÎK%k_iÆ¢B+Î#4(—µ½ú¼¡1¸ÓC'& }óA… \™/þ³½Å‘rø=oÌNªäôp·/è**¹Ð»‡)˜^—“ÝDƒV{´µÃ¤¥µÄÝÆM¤÷y-_ué<)à„éöî³HÉÔ IA_¦6·Ã¶Ž ï̪Hp™Ä–cìbôº˜›LxXË„€þŒèx娝ƒ…qŽ»â÷ß?‹Èî¦fäA[y@%ƒ$^Æž0SpkuÐ}NÎñäƒü,˜L“Þµ.™àgTb˜)SßoÕŸ15Wrã„îuuí*Iqð)ù¶Tö¨Hýö°t3Œ´jU2uÌÒQ`8½Y¬†ßˆRNÉ6„\~3|ì° ©n:±B+áÍû½ýÓ½C/ÉDz£bØBø€½1»Í`*R²"oØtð“÷9ÜŸšØ¼Ç=•[|JÏsïÎc+L%¸5 0ªUôÇak¥™—y¢‡ ¦@ºè Ò¸ƒìxÊÍ `\`¥˜  ˜ábf:36éA¬;È7(ÝXÅf±Â7SQBÒiV"¬h8IÕ ìS Mjš™á‘k ²@’UN a÷ KXc̨\*cÔ°§Í”Y&–à6 ü›æþ´!¾U¨7kXY׬2TVÙAßçç&é*³îUŠ¿õ`)/¨úËn£Fr€µ>Ÿ,üO(Ë0nuŽb\§Ówi©BaðpRÁÞi°™ ¹¨ÒÒToF!Ûfºj…J,¾¾#‹ýt¤rƒggº6Z‘Ðb¾‚)2IFa…1¥Y¸¯ƒâ"Ö`.Ô‰¬·*ðìíºR0 Þ õ«HSÖ2h 'Jqá´š‹¡Ûá§Ú»à1³cŒs9¼â‘Uæ4*Rí]'VVån劈¹Ñ¡ž}àVt>ÂS¶ßHÇcÒ$ì¨võnŸ 1ÏŽ7©qÀëÅóÎÁ©úRç#2Ϙ§Ž¸’€ì˜aóÕSZïJÌNE:dÓŸ$Y¡ÖL‚&÷0½ft¦5aÖ×ÿQÀ°!•^Ñ¥%ÆÜQÞ:ï×/å¸ÑµŠ›âΓ"y3Ée†WŽñh©swu–ø+±ôŸ.uñM£{Á¹d|äH´ÞÏŠ²Û†(^ýÂ-¤Ï”[= `W· 0Ðÿ>`ߣ§‹öŽ÷÷¶÷N»ÛG‡?ùðvö:„!äås'g@÷ôoýÌ…Ç#[®7à ½V¼Èf¿Í"~Èo`·•ôziQhëÙÏ×Ýýyïðź×¿ùA=ºÛ' äg?÷¶½{cØ‘¿îFojûU‚—”üJ•›YΡ|¼%•«¡#¨ÉÐÿÂ#Xˆ4XîovA凱úGÌwf°ÿ÷Ÿ˜€]ˆëX| }|œcž.xž¨ìÕɇ醗‚wé}&E‰}IÌÜ!„zg `è <9õƒXãA«'—î ‚vN¡Öa>ôýLjƒ=Ï¡¸Öêž>À!žûÀG*´qrSù¦cæÀW«9e?Â[^]þÌÔA-D vì1žºÂäã¼¢tvTîYp R´J•Õ£Q-ibf*–CÅPÛ|ÿ,mña™,†uìvßB:YmòìÖ"U E},sr¼òßn!· }Tuu”úø½Ð…ÕGÍê#´*Rb>xÆäú«ìþÕÔìnÄSØKçñ+èèÇræÀ֞ƪó«÷,œFÆ«Âç#«à‚£y¤NLÑ¢S³Èn>L:ëÞ8µqÝ U¦´5ôÆÎi÷?„…ê’ùæ;vÌÀ‡`½,†Ò_^Nñà@Íh¿Ú(eñ|0vºZ Z—íB·+Ûu» Ü «)ÁáâöÆg‡*Ú˜Ÿó à{ŸæŒëIy žŠç*©¡ì}…ÂNeÇ%¦„EéR%--‘|H  Á>@êVH‹ dÉMÝòÁäEí£Z­ ù9Ým¶óº²ŠÇ*Ÿe—ªÀ²OÊY†W.ªé¶0[e4ºa Ûzû…;bŒhYi£Ì£ƒÝÓºGªÅ´' ‚ùT4¨^³’`Û`Õ‘Fo{¨l X>L *£5Ñ~eËφÞsu«Î5}»“ªÐ¦ÁbÁ ½É.3"[)´´&ócÓýQªZ->›¡Ÿ)ö‰T;íyaãJ‡nC—ÆÉo†¾Ùy2â÷ûk&c‘;îÜáZuHÄ,çºiÙív¡n—¹€¯knå’k“Ù1愎Ìz§¿6¯Ícì'PC²GöFzÚþ³¾ðÞ66±Ó޵cÆ€ýºÁ·f6Üu÷ð¼öîA›H±:„ýµœ å¸ã=ÖǹGp‘¢ø»uBm‰M“óÐõÊO)€²¾ƒÝ_<ÌšQ¥ÂuÓdÎN·$Â÷æ&¶¦Ž_¨»…úú˜¯öFû²Û´ÔÄ&ugjº’ÝŠÈø9v|Âc«ž*ö;÷”efþæ½²V„B°ðe¾Ðºž]†.ÓÛGôq;­¾µOÞuÜnÇéh\íWÝþŸV±å ­¹Ô xû§J‚¥¤gÉN¯!áPsÛ£qD•P,¼T„jÙ™`Ýzöeñ Rp}9ÚZh™œøÏ+±0¡øè;Wi®mô•ÌDZTiæN–¡DP¸‹ ѧ¢Ô gõãà¨`àN$Ëiny‡¿æ‹’OGu` ݶ ÄN(ÓÞIzŽE•¬¦âÁöFªƒªc'ía,ƒ§Ø— GâÍÍÑxƒî1p±†›Í­T*¾ªXºnh"Ïᜃôû†ùkÙù¦7 pò+DR]Zƒ¼Ñòï-ú{MeÖ0Á~Õã!ýòhù¶%n0Ó_VŠdPäâ SŸO¼Þúòí÷:Ôu ~‘#YïrÖÁR†ì|ä®6‹:*mvÞ…ôB2s÷¯pHiþ<Üìp_­È•£îá_¥Øžf“6w£Nº6ƒá ÆMsss¨†DhSáÇéíènxÖ¿³èÎ*,€›ßèëÚ¨3¦”Ïηñp…5“£¸„ÔyÔ‰Ðëaå.)» u¨ßë‡\ ‹MQmồ ðžæ¢ù[ÿ.wí÷Ø£°YGl\¡Ür‡ÒmêÍÿ¸X´*æ uÚ¹H‘ã‚™=#eÄÔ˜ça²)íè²¢¶q´f5Q 1öŠÎä Kò‘I#ЈʒÅoChå£Rаvruéhxw­ÓÓT"¾7x*ƒÍ ¾Ôÿ˜þXÛ_´;}?eû¬Xžœ'ï^m šÕM¦ «Ÿ’S­b+Í´K×Õ-äeÄ=†Îkˆ±Gð‹Ä©çŸé”G•X´-¬ñʺGªë ֮рëÛw¥êϦz?|¿‡\¶tE8OÜ$wp¬þSû¬ÏÉãmYTì*>nBvMtòR!Kàa,2HI?¸ýq>R0e=MdÃkó ¾,ÄÞcaþØÉı/ä6g”“ñ¢NÂ{™›ËtœBžÕ_!ÀÄ9fs…§Á‚_cz[õ 8[0nqÌxqfÐg—p½è†ÒÄ–ðt˜¦}9ÔÜ‚§WI&uDMžŒò¡ž˜J1$ÅrCÏX LÁ7–-*ܸNjÙ2!Ôô_glkI­X04Ùb QH´ò¬ixÊ}e¾ÕT ¿IqÈŽÃØ°C_»€Âd,ÿænÅ|¤ÉjÃ4±¡¨pg¾Æ ‰¤ µ”  ]x{~Bu‹qÔX#»3äß='šàî=œ !ßûÃíSis7|!Õ<¶ 4îìî¿ 4¤!5‹Ðg³qEO5¯›• ®¾ÁÙd}{†`Êï‡ã$+`6°.)Pq](jM:㕌— úÐ~ùø•ÞÎÞþ.³Þ=ØßmÿHH9q/XZb¨ô§uEtöÓ’îO%ð,ÇPÙÉg÷±fœX¶svùÿ 붃Æ?`ܪ÷Âõ5ª=ó îìî7j6ÞæÔIUOèj¯-¾æ7¦üÃÖ/´Á¸–ý™´ª±'ÇwíñE÷8)Ýíäñ½"ä@È9ajå¡–GŒ…h(„–Åî!B—ù¥¸v Ê5F¢o©s×Ùá]6ÔhÁT°K¶DP¯ÜìœZ³§ØÓ‡ÞµÌ›æ5Èœ›A‰_iº£•yO`ÉXSEy0ÌZá»U A<ǪM'Ïfm„hì ò^`ÙúY!gœk¶çUû,¤CÊ1Ï9{ŽʃǛлî©öëý9#ö-ÚGÀõ’º¬­:]ï7/«3ô†5úº&ûãèèóX7HŸAðË`~ÿ™¼è4§ú…m6mb¨Z‘–æøN/žrSKq¤éj³3ÚµC¨¢ï‹1ÂàxöI»'æ²=G[[Åî½2ƒ4hL¿Cù LÃ*9gϬ½ZjªS%}ð¨nôÁô¾lM÷Xÿ^¸ÌÈõqºgË\ãÍ à7;éùÖÏ0¦õøÀ0-¯Êº äæ™K IYú‡ª°(·X¦r÷ªB÷m6ìÓ´kT眛–!ÙgÒáKQ÷½{bÂ]øˆ뼟÷p²£›XS@Ä1Û+p}ÌÜ&ÔR‹Þ£IÜ„:®¬êì:JŸHžeÃd|‡1ã$kV‡gݤßW~¥Pi19ƒ€ÿeM•«É ÌFƒ;UeEnËϤ6Âà´ãô*¿v£ Ö%ãg¯¡®*°æG¨¹ûé¸m ë*7CÇàY¦Vå7À„·'Ãô"÷fM•Q^dSª$gE>˜”¦ŠÊe†tGùð·tœ««-|ê†%Fà  ¤º;Œcɰøz›_ñã,<ÄA`“^žŽ{>ç,9*WnZz€å¬â2üŠèÍ—"K1¢·ªíûƒ Ïyò±æ½RËBnçY¤òez«+Ë_-¾5—‰(=Ÿœ•/–_ ÃÌ)ÿ§fq6 ’^ :B,mñ/WI9ÎnÍÜD×)w*‹Õ™°¨Á D`ež®©GeÝd}ùåŒÈLCgjŸë¶Ïõ'}ƒ=öiý¯ÚþW§ô?µß|,øD¹w×#væ +Ýè.·Ç¦¶¢±Û…w”Ž×Õ|5eÐîæ“COíLiªáçTª·Rñ•š ¥¶Úœçw†ÍLsëéã‚€"ü¬ÀÛˆ.<\®Ja6”ã¨õ¡ÂÅr:B¶g>Î;j× ©%hy–YO÷ÿ@Ìeó¬L¯ÜÖ {2àí:è(®ÅZ«OëO/fIp¬ðR¦`USª‚–­¾g ð@DQ €à\-f‡Q0³‰/.SÐT¯S`NI=º¼Ö‚¯ê&þ¸*Î&%ÆÀ*þh{W£*±ˆ–‹©\-üU fßÌaà7# OÃö©G0ji­×G Kùh*û$›°žÉ¦=Te-]³¶%¤ zÎE9®Þ=ð2p‰­;d·ÕÚdêä¨wOñeHwg÷mûýþi5§G VM:Û«zB÷«¥ä–²$?R²zð‡‰ÞQ MKvy±¥¦“ýò¸¾oÒäÄ%ÉÏÏ%×f ïððNàÂÈ£Wž1ú0Bü4{õXkàôá]SÔG6Æ”ËåãÚž%$|ò¸–˜õâ±(SóGð¶øðöh3>N×<Þ2×jY9΢{ñHlÏÐÓû¸‰ðXEÞKz—i19ÃÔÅY«5f«ÔèµÔkýt0[_?²XTà¦S™\ÌÒÑ •TüágCˆ]“º½À1ÝöÑûÃS̯³Ýyì{$a¢O¦ÙK<ã/‡U@6øÇÆ#¡¡mÄž@Q1yü^½y»·¿+ÏG$fÞ"J2@‚‡ŽŠ8ù‹Š‚ôöíî †éûàv>š”…~o§zXhÉÏÍ ‘n É"¸½Ž9uüMxh%¿ã/0:o´—DåÇ“厇ðHH{ Éõ‡ýa}Qáºe[}¤§]y¤7í¨Zµû4/Í|$B/ÍjŸ˜)á'fvͤ·UÆœ‰vß$ýÇg9-+ϳ€}žÕá"}E…­:¤ë¦ûvQ ¡{ QU—“¥2–ö°~Ç!ËL´ãéwé£ ŸánÂHñ‘wꎂFVêþ„£ ­Íÿ ƒ %ƒ>¢vÿʃ wNÔ5èmŠõsrSÌ;|0AªéãNiTãOu<©øáÌ”£w½zäÑ 3¸¦½<Ð#ÿߣ¥vá¢ü÷è…¹êíêñŸpôò¦ÿÿ;zyØéÉ^flùߣ—‡6ýïÑË´†ÿ=zùïÑË^‚¦½°Mé'9zað>âè…AyÔÑ‹³ÕžÑÁè½Xßz膿xÀñ Õp½puÇ/Öù/ ‘‹‰Í"Ý¢OÄ<ð”6Dot× /šÁ߼ϴn8ÎQg ¶À;ÑÑŸqï»)´0†ybø™¶w:wCÊFŽ‚„9 âüòiïržÎbÂXçÙjK„yYë©ÊY`ê™|Uæ©§}KD{BTkÚóƒyÎ%ÄɰÄá•ó¾žr¯šõŸãØLçO^ÁA<Íêç9« BOé N/³‚%˜î=_€g` 䬤S ™‚@<:ØMTE:Gf[¢i” Ìw¼âºŠ>õü"G£³ô3D|¬r§?ìuL²îéÑÎÑ+±'úùðY) ‰¸¤l!&Q.¾„;‡UjoÀ_™XD3xxfÂ+ø<Ì=•vÒ¼KK(EªØ*xXÞÞKœ]ÎlUú†f+5rB¡U]`Ú°}‚‚zÒTÖ!<ï~–vÝ8=§®ŽÇùíݼ^®ªE5Gñ/\tUˆÝsôæ/»Û§ª*ÓãXùéS1e„á1Ú!b Ó[(1Ï)æ‹#EL±Â1y<77?‚cÏ6›†4:™½‹¿" õÞeµöóüÃdDÕZ‚M§Ô×~–µôî' Dão*!@4„böɬ«?Q³5ÊX™ÖõòEhcá÷:õ;q?ÃK q@'$¨‘)kÕÊÕœÅóféšS€u¿÷ó»›xƒÓîϬæXšžA£yŠa¿ØH”Ã-Ó„ãõ{qúçÜT‡²"+B’B“¡Hü¯dIõNE²º0;ÔÅ=âóCª÷ÄŠ£\BÀ+Í zÐÜ%DFËA«£Š6N!>”)Ò¸zÇ¡»BÄL. fôóQmJ*’gmÓóv‰·Î#L$D‡<)0µƒ‰êYmúv“Ð í”0ŠÁ PÓÆX5¸UþAŸBܘ;M®AL…쳎øí‚öíª^å·s|­ú`R©v’TíaÿÈ •ÃÌÜúëb試_-q‡¥Ží[%¢>ñ×Iº*ëƒI:ÏÅÖ»j#ú•+¸{rrtÂf#KŒSÅé—‡­‡øúŠø‹¤þÝ”ýèG’äy'ÚŸêsÞìH¦‰‰?êo‘…{º¹ÌihÇvM(™ÛsVØJE³Â¦¼úS5Ê.¼)=0Ï)p]Œ<«˜²˜›–Lš@×l1âLªe¬K5€«Qëñ{¤³Ê\]›*y B:²îqT ¡}EâF‹ ÂÂ?’\ÓÊe rÄÂ"-GÓ({- Cë©iØt[A_ ¨j¿ÝîœÂ6BüÝÇÄ„AÆXHÀš³¤?¸ƒ`ÝWêváU2qé]RTÐ\.„¨uN$Â%ÐÓWuìu}®Ìuã²EÛˆ¨CWüçà`ÜñßχwÄÅ݇üu‚Çàh éë`o,î< uƒªˆ2?²¹–{¡Ú4îL1(uá/ûAôI£òÚ¸©¨ôªyv¸ÀÙùÃs¡©ôHî<¤”^ްÚÖ¾Nl§‚ ~ÖP •%PÚ>à FáÄcâgé-UF÷RèVDáH¨êª&ܪÊíÄ Ä(BÎ<¯Oö¤ÇHùäcæ@½÷zPÕ|À®:ËêW £ªo2ÇÑ?v%ÙðJ‘k}ãÀ†lfh<½¶ApÝ8¸„¸Wýˆa[«E51ý—û~èq2,àœìVH*·g²Ñ³ªZÃ>«37JŽv¿jÞ†­«z˜Þ$ŇHíÀB4­GŒ "ªæëþ¾÷dUoCBòbëz Ø(«'.1=ƒcV5+jÚÀt ©ÈÜbz(0«*Ú4š7Ç1…M>nÀàAö°ÝØBÔ[Ävgñ„GW®nǸAiçY»ðK;"ãX‚Цz§#Œë=œ ˜®wä”ëYÒû`Σx d¸7žyð*¾=kB°Š«îÕÿÀ=üCLœrùÈ!§ÔÜpµ¯¬`Ôä®Äü•XhVBÁ÷LæDjë’‡œð: ?k«Lû¨kÌ.Ì'”5ÔÝK¹Ûƒˆñ<ÅB¸Ü:EŽiZcC>Ü~TFàV†fº)WÍÜ炸wiiµÜr¯(žE"ÖWE ßWÄXï‹*;R:Ï  ø°m)¶œáèå·ø\ n‡b‡WãPŸÓmÌ¡…Û ¦w”ß>”ÃqNèJ˜¾eØ(V¯V™¡ëír/•Þ™ mNêxè ½É0ø–õÝøÅ n ÌÝF±»Ñp-4]N«Œ:’*µÕZÚÒ3¿„£vlQ*êV”ãa!Nj¾)þ—Ý›ý©½¿·cÆ}Ú~§že@ED\ÎséâH?„ñz™WÓÉ9É.N’?U²ÉªÆ©sÅÚÏ÷Áë&_Ÿ¯Õ©ŠµYUE„>5N‹GP"@‡ØÅ NÁ:ñëÜŒñkµà–ÁîT§ÓÒËU³kxZ¨¶´• »=å ÑyÇ ¢Î`‰ò:ÓÛ˜ºÖŸj¸âÕqqd›:«9+ˆ›óA3…~hÿ´Ûýy·ý£lÚáˆÜЉ^8Üt¯AU¡¼Ûžçwñ·»{rqÕ˜iöDÉO­LÕÉaÌóEïÉØÝ Þ Y•½ Nà.Óä`›mU|ø‚?a*‡VAÔØÂÊ” ³«<°óŠB¹óÁÞ[ÏŒóRD8/èqò˺yûû„à ¤ZÁî\h‰uüÿ€ÀÌV¾çòŽÍÔµŸšS¥_VÿÁÏ‘.Á :ñsç ¬ŽÈý²¦Áx[ÀØ´¢®ý¶•ía5[ËJí¾¡²IŒðO ò15”ÅŒu*MU]¸ Ï`N0‰VU ÞÍUiá‹1;ÉÄ£-Æý¾,cþúMÚ†û ?_¦qrë2|LgßW¾é¦€$C@ê.û—I¸”BÉ¥œ_JtzWwžä O:­ìQ+ÿ¤„N²ˆüT‘ÒœÏ&àP¯«²—UqF«‘®³V ]÷´:cÕR®«¹ª°øðªÿª²=uù¨j ²ºu÷ÇÜ~”2]ÝpoÒ]6¦g'þ‹±%ÀøéèÔ"cÆTÍŠû¾ØLR©0ó‚ÊÍìÆ¿æ[ †o3*¥yën«—mšÅcu6ãÇØQnI:Ç‚ÕÙ†vCxu~hïýÌò–yön½+ÂvÒB<+f7û¨ÆAö•ëWÏmüWW“S/¬ª«×l}…­A_ÏêÌÓIá2ô½ëÆÂë êÚ‡G\Èõ©ý`‹àéïRzq/ÐŒþäÎ/ 4›Ÿ]I車ìó4zü~‚tz7ÈÏ’ìvö%6š:ÁkµHó«¼?Ø»ð®±q€… Û ‹ÞÃV('ôUFVêå}Ó$ºÇy+ÙpžñøÜ¤r¢"ŒáÕ†Jé©\Ù6vçeJv Âíõ§ŽÁÊ$-ÖvIvå`»ÛíãÎûý d¹t'£È·©Gˆj¦štÛ»´ ±dôUJ(Ú2FîŒ'Ã2»J»@æ5©Þ›´æçæè¼P7ä¨6àgéž¶ß(œš<ßý´³ïàù\{cÎFUÞš  •ß ü\í¿è1Š×b&ïñ $œ–*EcNün’ì²±¬ÐsRd@Œv!Ná{.-…p ëV¸{*D/e Ú&%ê¢v+Ñb2–,CT ¡’ª—mì‹å¯@BÙ~5ª82 õªÅ’òíhîg¥Ó»2u°¨`ÒùÀÕ2[ÐiªlÁzÒj6Êí‹—ãÒ=dÐwlžäŸ¤ûa>\‚mMíyžmgLµq–ôà>-,åfoˆA "´¤zVc/è’Ôe9Ÿü}R£ÒS&Wç®»R=2E=HöŠi¦‡¹0{Y˜“š!êª9 uÝ=°",í„IhòfÍõGvû¸’qƒ‚ úP¾ˆj>¾(ìP&_µ08[d“R2ZÝe³´‘ñ~E`…b_@ï„TŠÕÊ’òj£Hç|õÜ´nÆGuFÇ£FÝùf ®ƒ°‹gmÁìÑEY0 ~‡ÃúF&6W7„Ärà“9ñüyV›íÁþ’ýƒt£)MÛH×1¸p6Ã]3ç°¡úm$ËTäLZÉô/ÐWOÍàâSU˳æLÇ&pí¼ û“««;­•™+…'Å]±¬ª¦ÐµpßÑò ŠNáöÀ…œKb%± rßPtÙ£[B†mÊr'~§àK*ýr/îñú@G2(¦ƒš! gìqØ·¦aØô=ËÁ Ïžp¬,ÇàgŒÎì–ˆ*"³^èNä¦ÌŠ ©ÿʺ¥» ™YÝa6·ZÚÏU½ÜÃ’{;uØÙG Êd„׉úšLœ0 >åØÙ“0Ü”é…aè´øç$ßiókŠ¿nÝȶ¡à|º6ðóa‡Í€]-«X>Ãc—¿î ~ƒ ÷¬žHA(ÜM¿‰“Þ9v=^%7ðÚvdúvЧÒL5Û¡`¸”lTæc-=ÊßS7§é‚53Ë(Z·b«; ö¨wPjn´ =3Èía·$\§-úHR»ÖE s}[]™Zî”,õQ¤½ G ¦Ò>M«¨D8¾7ôP!P!>€¦çtôÎg¬°¸7®Cõªf€–15—¸hÑ̇vÒp{ñ&÷Æ‹*³³lI{'îàÞŽû¬XùÒvÿ¶½{| [Gá=<–»œîy’ à´¦© "þ’l|ñV—º äVÄj_Ÿ¬5œÈM:Np M¯?åM[¿/÷iqÁTÅ¢¸’è CŠë8–Ro9¶‹·³^ÐXÝð¾Ó-½@ä«LÏ(Òƒ)ĽQZö.Oi`O±½ü×TgŽeÖþT*O‡qtÒãÁq¶Ü)L¼þ¦ÙÙTŠ8*èLE·‰Ø¾Žp_ø²e—HK!0}UÚ.P‘*íUûü´òL0  Y›ë^+i_ËNŽï^4$ÔМSàðµÊì‡ðBRWdRÍ?’eÁ &{ð裙s$ >ú8W ÌBpÆH@ 4 /(ƒ|)~Yùõ?Œ~,z³ F7AçØFuÅðã³ÀŒEoëT i2Ôh³Äd/cÔ¼"åzÓd(‘é¥#TÛ ¹ àUVÈž{—þŒ¶ ó3È»Õ{]î3) ^¹·A}Qd|½ ¿e£­ÄSDúQp67ÅÒšëÍ6öèµ°MiTÃÆ—N«PÍîàX Gy‡®àò®éšÌÔ.]á#=úûºˆ4u úa>ܹ“J%ëé«»“ØM ïÈ‚Yunˆûl®¹Ü­*úî§tØËûiµ”`•"ÅØÖâ\߸¡7aKknÆÄÕ‘[¤½ÃwÝ÷‡{ÛG;»Æ!¿¹Z_ð©fjPPŒï‡ô*uücÛ´ åtÇf0bUБö†þèl¯´8<ÁBÅQÅ¡%ns©ÃÝ3ÇΞªJ°C»™Ô€yß@ƒÆ³Ž³T%¢iáã¡g_.¯¯®Ïèt¡ºØ¸–ÓRÕ‚´7^mb s/ª! ~Õ¸¢¯9!ù.rx£žS ¥nLb3å§ÎØå¹ñ³Mµ¹:‰ ¡ ~vi"ÀšÓ¶sÕ¸( Á.)ùÐ¥r_Çkn%£]¼?}û-—CnÍØÞÖ¬Ö¼—Œ]ÆjG¶:¢²"Á8¯¸¤'¸?8–zãc·NiÀt†9{Nü@•×v7§Ïõ$·_9¾Ì}ì©Ï®´²ëv{£Á¤€ÿñRwßnÖ/Úö¶r§%÷ ²_ñ»:?S¦¯.Ú ÏÐ`CïŽ5V›Â--)ØïBî]¼B$Wݱ‚’„@\x/ä='¹âV K²çAþãyø@¼‘ðÛ0mun[Ñx³ûnï°i ñ C]¼WÝmåîžwÇÝvѬìv·•øtq}6k|ñËê?ª@FÝí6ÄË X‘\¤¼þZ¤þ¤¼|¦YÕõpÕ7“ó}øÆj¾ˆÖ„çä¬âWáŠÛ§ÛÇ\_Fj_&C^íëH5<<ã¿©«à•¿T·çÙ¯ø]]ÅÝ!ăâô0LVJò×I:IO¥ ;d[‹pm;§§ðjŸÂ>d·™C™µ ·Ç¹[/ÂÀôlâŒu-Â@¬(E4M®œêÊ Fr—öêN«Cw2—(vîËšWްs÷6íuòÞ§n„£o+ŒYpó-ÜŠåõ" „;üýþx,u^=·NO}l×#¼Û;Ù>LË›|ìÖŽ0PÖ®Ž0OUM©µáÙž\Ç®¤âRâíqe=¿È]S@¬G˜øcÖûªáã~2¼˜Èº^>rÕX„›p« rd8u# àñ"ÂM©è·ó«+|DËjGø)kûbò"ÂLYUÝÒâ•#씕ÓÒ†ÒêäÔŒ0‘jVà‹ÔU^5Â@Uu¯ô—û3W°¿Š°î0,F_EØw˜—Y/Dº¯"<œ\Až•P‹#P%ƒˆ¢ü*ÂÒãd\†z‰°TŸH;u#L=¾;IË7y>p*GXŠ•ÉpqªGØ*mäŠ^yá©Ü´øºøe„­x|èTŒ0ô¯“,D¶—vÊ}Ö ¤^F˜Ù·_Õ$zab'¬2_F˜Ø ¢ábç fe>~»ãÔŽ°±ÓéìG‰p²Œ„…Í1Ó"¬ì@F*·f„“4¦‹Ä×vBíƒd(¹é°³*{_lj5C c¬T¶ûînÑKÜ%çë;UºÊvç5аõn9#=MÆiHÖ¿Ž0ô4½ àÑ·¦#üÔu÷ó|$Ŧ„§%¼Y„¹ºé¢ßorœxNˆk_ïˆ*ÆÃZÄ)tæõk§ÉÁkê…¹LŽËq*Í]L²é4 ³»Ÿ«Ú¬ÃLïçÏæY‹ø…ÎAJIåêÕÍu“„Ü­Oz#Þå*¦Ýv¯E¤wÕÁGôš©£ Oç½ ±fÒHƒévÂ$Ã&0Uƈ“8€ª—ÄE«(‰šyç"Á þx4¢S3âÔþS颥â)ˆ¸Í(y~ØÅÍW¥VÄK@Mmû>#%€Hâqù“gÚGü³±UbHåAaŒœ–DMÝN†p3].¿°Û¢ÿ>}Z=¬Ã€Õ¬'Õá=Äøƒ{ ±ä­f1áïÍ\ÀéºnyŽ>Ö«Åk(!‹À à7mi$üªj÷aøD5ä$ÍëßÈQ6,„$€É´Åû¾„È ‚UƒTPÒ„m×,~!OUäp¯nËã´ú=|&»PkÖ‚"-í^œOI½=oÜý^j!õ¢-Ý õÜ ëUÖí¨F%QGtd௮úc +VV¯í#Gœ¼ïXA1£8r4Êz!'­;@ý-Ð-š2¼š)ãœ>ËÕgoT5³ØÙŽêÛÑ~ûšÉè´·7Œ}5ÓÓàÝŽðÀDyã`ì鳩nfú;t:ž÷!ÔͺØß…P3ÌËÄ º rœìÁÔ>¼ïž·fbX¸ã<Œ+}¯À¬‘yó#öÌ‘³m>ó&V sO£»fJØÆÑÒ°Êéí™(„[§oÖ#gín?ÚÓY鯏@]ì×#§òžÉ¨= U¥l|£>Üš¹öSÔ…9ËìÓz$„-+«Àže©B®ú^9à ¬3wf±ð£&ézä.Bµ÷©j8ŒÇôfŒf˜ÝõÊxL\ÿ¬Á :àq›³òïúXF4 Tévn NAèVÈzä’Ffs{ˆ\Í€š×ÉÀ­žÈÿàw=r)c"wk_ûuóm8¨]ÜÈàÛ ·~XîM}Ü¿¸-Âr‰Ï+‡šë‘[þiþ:ÜhPAÇÌgqJU[_ûdžSǦb ÜŸm×ëë«”‘•þÿ~ÃAŠ…£¼‰îG²ê)ƒßî_ô´Ùy /i?Ú/›¹‡ø«ÄÝÃÿMb KËk•¥e•2$ÁCñpž–íýv§³· UTX؈Ié‡ù§ÿœdcu‘2Ìž¥b<bª9L¹ùl üd½g"G“wÁ<ÓÖRWò›E¼€Ÿÿ§Qâ5èæ«MÑýmØ“fÁ8].rYíÁħFÄüBÎfHeBO~÷0™žF`Þ„ÌVÇÌ{¼.‘„WÅgÏògÁÔ[pšêðÏ„ÜÚºpÛëbVÕü›8åZÐHši³/¾Vá#ÄVƒ&›úJ±QL„6T0)úZÓïm1i¶Æ)†ÔSÞé¢ <ì &ýT¼– =íÝ’Ÿ0Å(QW3ð)5¥ Bm_Ží=(óƒ}¼òBwu1”?Ô˜œ ²û Mñ *6Ô üßÕCópe¢ÿù©&ê‰AHðÇrƒñ87|öþp²ÛÞéâKãî›ý£íѽÄ}ŽÃzC 'òaì½Øx‘ä4KpBèŽ!¦¤2Š%fªó„%³-0º:ÞÈÜ$ÍÁЧR ‘)°9…WÇËb^¨^ï;ß»*Ó„n°13'ÍëÿEÌå€QàòüÈ¡…°¼iÒ³)ØPJÇAI ËRCÍ6&ž ÒÒÖ¬äÿ0 LHwRª{$ ?%LX^…õ‰¨Ô´ÙUTøÈÕf 1…Ù9Oä¢!<1uz¶bJYõtwÊM‘*&Ou²¢Hcµí¤Ä’[öÓ‚\‚VðÈòå‚÷ùôÒR èЫú|¢Õïê9hµN²à/“aõ+œ[V¿Z?Jµ -°xtAÁªÚ›R-ÑϽ´S;Áj‰Ü™Eé!ÿ *:ªßáV;Eðº=ÂTÙ cTKôKûj ½‰t¿KóudFÈÑ@i°xLaÌ º;HS~ŸŸøØ ì¿zev†ŽØ‚­­˜áÀcñu»ïßow»háf,…þ† Wë‰O}8Ø;<:»ù»¯¡¦p͹ÎéN÷ðèàhg÷äPþ±æ²cÝ:¸¶|ÃFÂ[¾t¿fêhË$üÙ£ëÊeÉšý½íÝnûäv’ÚQ,Ac™NmØ‘vQZm­F×¥E™”_v ¿“’qu-Û–“™–]ˉ¶ÂD·HÿI¶šk͹€œ(’ÿDƒKþÛ€ßãÍè?nù]gãr"·óÿëÁ”ÊZ-@++^[ICÓ¸)„{KïƒúâìN%Hq`zaÁôªE1c5ì·ùãø>¸GÌE)Eㆺ¤ iÂÖš66­îë\éìY÷èqn6ÛÏŸKKpRb8,ƒˆIS‹H?µˆ¬,Wg+/Çù'.¦³ìKlO’a?¿IøÅÌøÉ¼L‘Øô3Ìñ§+‹·‹+!ËB£+u9¯±@k6È;࢒ãè‚f8´®%¾ò×? .’»Š×+uFRNÑ´–¯½|ta7+a£iŒMÀHr?—dTfªT£³«Édš‚àëÑL["èqœ.¥CÞ§k1 ÅÍ%"Ý¢8H>¤ÿQ’R¡Y‹®‘Ë·6KŽÙkv1»a·áŠ¿êƒè1våþø:Ë'EãAÛÅ©´ÄÉYI¿¡ìÉèvÆhYÙ?3ÁJú×8+íDé%C±Vö÷ŠéCÐõ8¢¥¡#è œlÖ¦Þ O¹§â¶)âû œ¬ÛéðŸÔÁ‚b÷¦›á^|h¦Ãç²Ãi43Ä6kxÀ€.=h˜ì.ìE†° :NR5K[3!Ï:XzláXX¼‡‡óøvÙ¬<‹,[¼ÓWÐ ¾È4¬gEÕ¥p÷™“ù³ ¯†ø -Æ,V¥žO“ܼzåÏVXRæT·kÆ3çŽ êàŽ4B0ý ØnHVµl8ÓÔî}¯¤¾íæ“r4±'¾Ý³I6(3'+úèŽˆÛ  :Ф*q"vÒ7 ¶hóªøIëíâ§d ß©ú¾2õÌ;ÜDd5ÄÄàƒ:ŒæñÝÛAž”ß*%@aØKªÙ.v°ÉÛO_Ø+¼v’9ñH«à°ž¥ÿ­)¨A»ØÏ‡uHx‰D¨/hèLÑíljuÃT!_c}„¯=Ÿ‡ÁŒ¤Ð 1HŠ@©8xM}$Òîœv(Œ®"ÕMÉÆz6“J©_Ï»ªT»ßßN Ê«)GŽ¢¢Â@£o{ÆwšC<†×à>àÅ\cýhÖ/iÅ=ç“–67*ßLŸ üöUR^Ò7;×U²3ã·“!à×. AâE:nèYÞ7þ*Úß“[¢¢úûVޱ¯'|CV7Â-øná7¨¯È®ZœC‰®ÔñÊP=(è¥ÙÀû>!“°oårt~‹‚—_‚Y$!½’­0³Y‘] nfrH >éx<ÌÁÚÝ9:hŠ?þìÓIûðÝ®GU $Ü0ýrru[Õ‘ÜÁZ©˜…ižû±[våH±$G *2m!ëo…êËïKâÖ­oêðFF+jùÜ´aFI +PÎ1…¢×âÛÅ7ûÝÝãÎÞþÑ!Ãc±°6êúÔ™|lVŒúÅœ´w:ôDÚ_Ztš˜¸Âˆù`æ>O××)y6ɃJç1:š>žuª\§c)ä7f=TD£ßfB×®.Qmõ^Fôç-"³øcV™ >ËŠ£L»wl'wÍp¬0˜ OûMgaÂj{ÅÑr6MÌ©TæOûx作âïºí¿…°†Cçf£oÓXÐZ#˜º /I¾è®Nƒì*+ Xо¨ÜÅ8<êîô¼Ë¶†Xñj³B~Åʺ…rzk÷¯$*õÕöEcÉ6YkAžÕ{o -’bQ¬C2ãçbí=Õ¯xÉíŽÀšK‹`û§öÞ>Ü}iúw,u*±Ñ£g×Ô3jl«¶gṲ̈òêgý¿\÷™ñÕ*û°2×Û «" %Îþk6FwêÏ>@3‘ •ióoL?¹ˆJ{vÂRÊ_¿`@´O»;{ïÜmAdxžJ‹ gD­BÓ¸4›!.VÙñi»ˆ’¸QWRžñ5ºæ«El–D~3Çã&=ÑZI°yK©Ô÷Y&ë45BQ9ØnŒ~õÅ]U0O˜Í$ù1ó<·ÒþzMi°j8̹å\òRTØj\7g'3Üg®sL­Í8âÏ;òÚÝ¥—v²„*BYÔð´°xÐ’£ÄÕz½æ]ðfÄ¢ÁÈ… CP^š J )7zͦý}ÝÌäù~ž´8."i\>T£WÞ€Ü ˆÀ–ªÛ¬Ÿ„~úa•õ¬r­àö°©f`pñ M2®ûê‡7ól ن܎…Üb¦bv4'ô¹Q7Æû*Ž>¢Q¦/aó‚uƒÇ¢ÿT¥êøâ…[A iú^¬© W¿Ï ZJðqQ(uûq;ÚªÛt&oå÷Scÿ·m3gqüwSéHZç¶Ä”­å'ÞQ>v_S»—ù¤[˜ÈÎå?oÇRk¦ü'nN 2¸;´¤ÿ‰{ÝýçßÊ„zŠïhþ 72ÖbªìelÑ'ßÎÌlcÍ8M>ånGûømËã, ÄjFöÉ÷&þg<üJù8+/¯Üã/zp¹¾õíž“¶f1Ú¼›­©÷ÃíOÜÂÖ(H«À\ê![ÔÙ“ô™Ô‰‘‹þ¥N~ñšž üoÍ›K©Ãœ@•ã$+ Åm¸:’um;ÊÚJwZö5iZ¬3{+‹¦¦èÉ®€)\Tà ƒêH¥(îª wðÈ`ÃÓM·Ð‚~7×¥Ô©Á——I wm¯3ˆÒ÷Gð9ä¸2·ItÿAèn55§KÝ÷°É·m¯æÂ‹NàN”„rDÊ£0ÒqëÕ+NJø›Á£é3êô¶”ˆ¼PÅ_ÿ‰weðV&]ô¦'›f=ATŸoб¸Z=܇¢Ë½®„Òh: I]÷ðkõf_ÿ»)†*H·­FÓ_Ú  3@¸Ð@~ª ^@Òžü7û.žÂeH%Œ…h0*6 1Ø€x¹¸õ_ò;äŸ2‰¦#èL$Ki=I¨®™$çöC-<&kuXQgú— ‡ŒáxEL®“4ɹ*qE·‘ÕÙ‰õ×°¼¨Ò€hÔ«¯ Òªwwºp7U6¸¤Î"#-õNv[Q’­RJ’zM=@6} FhÆ+€J NƒkÍe*Î庮n¢?Dcœ+‡¢«-¬a å 6¹¶ÐÎo ÕšsÏkØ-HfÓ›c’G ¬­ÍLÑÜi°™8B½mk6(ÑÃÖ#žÎØv˜Þ`KÜδÄÚ£1 «ãŒ#’tõñ˜YúLÃÏÖ|8–ì…<ØR$õŸ®£gco%ŸhSL™X‡02Ë)6â=‡YfEž/Ñ™²ÕJR¬ž˜aŽTNqá^—†`‰ïÀ"‘Xt8MßFZ›ú륽j­×j>Í«EVÿ{åmȇ×é¸<–è  ™°Ø|:j±ê-õRšìžœÄ]ŽA¢Á½+®ËhCÌ Sé'‹Â²­´`ÚòB‹)†v€¹0²ß«œ•ŸÃ˜9Œ5’ÄRL&WöœåÖ´ŸŽðZ;ø}0êÎQ•ödm–º-‰¿#qwzÈ"W/¼T©xÆB;çȇ\™`IB ¸ 3H%¥©ªãŸØIa%;HŠÊI5ì™sgÎ^¿uC%¢sZÚl½Ù$B­½‹ÍÆ*»ëûâ 4ðƒ„%*-Bý|<#5$§ŠC]‘FÞÆ%‰¥i^ãN†Ÿ¸$1Q!'C'Ÿœ­¨ªgR@³Ls+- ˆÐ·GhŸ×d庾OÆ¡¤†KÁ§™] ˜ä-7×ÕuƒakN ÔѼÂûãQQAj_¾âÕ+š¨ÐÃõñ¶h ï*@®ƒ~í3Ó³„A ÍÈt=›)ç¿ÿû$\X¼Æ‰H_* ^È%|Ú qí.ÚS ¯ כ؆¨‹×¤‘•þ¾Þàš9¬—¯ƒúxeE¼ªX<Ùoiß0äº%uíÔK5 ¿´]ôëéåù9NãÅënƒÿ½Ø”[U¿ ½æð±i–̈\þ+¤rî*½*Ò²è·V[>¾†‚Pþ°Õ(&´‹3Ií⿽Ø6™ò¿®. ÿvœ¶o-‚‹Ï,ËO­:Ü\‚”Ê2Vƒk-Y~3ÊôÁ‹î˜fYŸg¬íކ>FtHrØB¤s\˃[Ç;bôÜ÷L6@2=RõóN™GcØ`ù¼ƒ´6 cW¤8)¦KUÏÜ´ ¡òÞ¿©ŒTÉ`ËñÇ•}ïTŒíµ!»xm…"ÂÆ¿è—Ð&?{¾n1OÃóZ+.¤³7ùU†x2⥆Ý=Éz—ÛùÕ(§p+­!û½®»û§aFám< ay•ÜAĶ+s‘i%§"?‡HY âT2cÒ‹e!{n‹-øçoôÏ¿Ä!ÁZ¯y±ºÔж!|µ }3y¶à"S ªH~² ´)ô-kêË!= 9Šá³Âoöˆ*})88Ú¼(w"W=ÚÐ(âÅòªÅ a)‚‚§&ƒ›[ô¥AЃöàåOÐJÆùdØç-Õ*t-‡}Ãv)5o7ßÎófÌ×Ë,{«ÎÕË/yßÂ-Ÿ‚H×W¸©yñË`Æ'“ì䵯ÛY3,)îaÃâ-ƒÃr+|¢aÝO9‹÷6÷ w"ä`σ¢'0ó aC;È<ÙVÐ-Å0“óß8 5v\ šXÈnÑ-®­óg)‡_^ èçÞt IRlµ8<Æž¸Í'5Kb…¢èËŽ³z:1ƒt[×;%a±9µc€á.?9¨KÎN“ZZãwL¢s~üНäßH³n6ì§· [Sdæ¡ ücâ¬é¸ôíLà¿Èà´p…¼±h,eæºRÓX¶8Ï©L ÐÞz²• ø]T˜j«Tš+„åòÕ`€6&Hð•˜2ã>Ÿ”Ýü¼;N†icÉ%ä7X’ñÛBÜTvéNvvZ×Mú¿NŠÒ£;ûëW´L2ã2ylauŸfnÛ§¿þ:•mÈÁk74ˆ5âK9Äî’kùoé8_¨²kmqÐ$M?C¢½’"#ÅB³¶EþjþÌðO&Q(eܘeÜgÉ9/k2º6‘á~Ã,ÔЊLoË+@*Pü¾Põÿõ×â^1¶ªâ{I¡W³õ ²¬é‚ÍÜyRÃ¥5Ξ¥µ–úò+û‚Dòy´´V¡ÒÒÚ \³³ÉçMƒªg®c‘‹7R«‚÷,L!.Õuž%~ýµé¢þ+ R-¸­(aë+AUo¶fº¶œÙ*6‘¬t‘–£¼hè²E±†E"u7[ø"ä^ìkh¼´u–^d&B"CÕAÓò¢å,9Y‹šmMíš×wXò"ªU;t7,€Š*PÖ#éàeùùWQƒ]-4¡"uØûOmS×°ó)ô–ÁFOOÙni‹€™¢™ÐqM*¹O‚À®ñ†ϪĠ*žÊÝžìuq¥”–A°F1j§³ÊຸÌ'ƒ>,Pæ.˜Ôl°E„VêÜ_…žÔGMÃÈœ!5M.\2g®)ë~3.z–¨z´Ø‘ ‘ñŽØŠÉ{dëíµ E¢O"õ>|_ŽkL8 þôyRœ…§ÉLmÓX[g’g-¹†‹ÒÖ¯nÀ(m9ë€ €yc¨²ïj0(ÝÆH1ˆ0ý¶éB`NåsvfÈk3‡^½ÒSÃÀjáÚ¾Ì|NæØ ¼B¢bO'"Æ+Îl“›Ë ^Çdå“ÍÂYŠQ ¥­Ñ¤¸ìž%r³µ˜•¬?ó«Ád··¹º!z¯ǧ·ÀnˆçÏ{MÖJ¿|þܹ÷i¯»¶ô™0 úcH.©½$îœäKÍ£§Ž& ŠþxVÙ¯I£@üI€ÖG–1ÄŸ Xã×_YÙñä(*EÓe("AKSDˆ wÊë Ï#Œ)ýeo8š”²Zu•-´¢ÿ¯—eÝ‹*úOû´ðßl hQÆ•š… ªZõðÖJ©YaÀ†X‘bYFŽZ’ ~z;J†ýlx±"-Š;¸± ÷øŠD=jç:löyìãd„y¨-½B-£fÁCIåš–DdƒJMÝÒZœ§õìPÿ¬%\ºWɳ<Ô”§R¹õÒ^>–¸MÚ îl3¢ ¢9wÒóZ\¿¬­®õg #âxÞ…-±” fKȺÖ.¬6×N§/(NoK9Fi¢““‰•.´ügÉJ‰ƒ±#25~-‰j€²3™OñiY'£´Z†%Å­¥+'¸8jãÊ8î½æc†uqÜónÚÁÚ÷2[nfE[TÖà Áõ$AI>áÌÖÛ}ÈF‹ˆgmÅíó™¤3&›ÿ–’9«\j¢~„LšFì¸é¥̪AùéŒÊfL2—"¢9ËfÕ,ü8gš²÷úR¦?ÖÞûÏ5ç·p×,€Qûð± }í:_Å+‹ét%ζΊ·R6´êª½’næên6 áÙöÛ§À…ÃÒÒŒj}ÝR³ã¾Y]yŽø1Ã2SÄ?" ΰÆóç’gËgð{³é¯åŸVÃ…ǵÞ}%¿XçýáñÉQw{ÛÐzò3$ ûi÷Dg«Ä|¥¤b{§»'íÓ£“îéI{ï´ÙÅ(Îj Y n5Y5¾l]G6™¢ü–JVwƒLíåM ã¢6‚Áxb&­cÙ‰åQ†îàÕ+vs½'ö2ë†þ;Ö–º²§¿Ÿ¤ž{B=þ´ëeñˆðu×8rÎ2#½¯ ¦çÓ–íL÷bÀ ÿ^„.©'ÔéLÄ8­Áþ´r#Ç9#÷Ü®m̆.nǹ¤øçJ‚º-^½òzÓA'WqëŠn÷<rO]ù. QÚ\!î[BZ‹@©9Õ+hÕ‘ÑwÏŸ«Â üuhÝg6{)}½çá€jn¤Xʹde™‘Mî–î©x¥“ßyEŠ<1žæ3 ÷3ŒPG&)ÙÝ!y»­ØôpL{ êp%pØÌ¯ÞàÕ܃ä—TMv@¡“¶ÚÜPÖ°g€Y ÉµÈûx §S]ݬ.ûUÙààð?Ó³ÃA_!ÈêNŸ& ì 0æèßI¶èpB•Z[ ‚èì¡% ÐPø‚-‰…K[Î@«ÆÞÜÔKü†/¡×D,[ÝÌÉûþ„ÁñY¼ˆ­?‰F†Dó•ô˜ÁWÂ{“÷LB}q]- øön• GO¼$b™FO…F;°JØ 7N‹É€WaøõU<£ŠßFÅ-=J^ª jÈ–À7²¦ÈŒ…[£AMvôÿ±÷öÏmÜÈ¢èÏö_1Ö©§ŠìX¤NÕ½¶£-Gvöxבó,%Ùs÷n±ÆâXæ Er‡”í&ïoø`€`ˆ!'U±Mr@7ú ÝnAÒëX–¨z·B%&"_hNt"¼³0ˆi %9/Km61œVÜ ;A^ B§ø+ÄrírÓÆÂv°Y‚€gÄ®ª¶ —Ð9À¯*ûÆ¢?tý\%ºDÉWq+e©ž ŽMÏžîŠ%‡ Šý7Uìò eR£9å€åŽ±Â°ÄžY<~ŒdÞ×_ +ÖDQ£qÓ¤|wØêI?v´Ûü>_®³éNHFÇê·(¤^äL% „¯È@øÚèÆq‚ý/hð zè)£†$æ†@ùÐöcyÃAÕ=Yq¿‰8RXd‘‰%#¦ô¦…[Õ%ÑöàjAãAº)׎èÈeõ%i¹z¡õºÀh ÏËß´š÷„5øÌ=±Q+øAÕÏ“XôäõÄÒÒ÷hYÇÒ—`Mó¢²^ÌhåSÍŒè¬0àñDxhÈÜøDÞÌu@-*nñåªlUN<Þ;„'¡NÙÉûì#[Jù'vIˆ$ÄrnX”‰[ˆÔ ø±i’nñ@IR²Î»W‰Rʨ¯±Á³Ó-º8ÊÖøç bçv0AËÃ3¾pXµ8ס1áýî3xè»8PÂ^£jù8¥#£8-"¶•ƒ¥Ä(éŒ ‹fó u’ÿgšÀÀ'xjÈæ³âGqÝ_ÀD7AaájôÆëÕþœ=ùò)ÅÇX¬~dõ ¡Š¢±ô·´Ø,!ì ÷Æ¥b޹s„äs©â‘I°d }N¾c´‰ç°ó–Jà½Èùòc¾üí^ÇÅð¿ Ÿ%·¬õa³KŒ@òsÑÊúñYaP8É{Ï Ökз«_¹¢s .yÃ=éCÙQ`zø˜‡›!Á ™…×{åéb èôú:[¯‹Лô¦p׊WBéëÅè9ý—Ù_ÎýrD+ÈÞ F8%§·Šˆ '¢ñy¿•¨ŠJ3@5À`@c+Ÿ=!0¡ûi¤sñ×Twªç{ä0ߣ·Jð¤8,€ñò×_'Q>~ýu!¤ R¯4ÒãÇòH×ékØ\ },Ä¡ JÁ“ «Ñ¹ÁC|~à]“¯“…¡­ÿØ}ñ.þ±¼xy¸b¦ÄžàØàŒ¼õ„ ïÚ¹üB30ßÿýNHRËy›+u|)T')úo¾I.¯ÞÂelÒ,ü%OWÐmB ]¤´^5ÖÜŒƒó%ª&bÔ‡@A§ÓN|˜C~…^hA­ñÏq¥¿â“ È•ÓU™ ®3¦âÝÐCñU ¦R\pÇD•;¤ªõ©(.ˆa^¼‰Š$À÷Œ2®“Æÿl ³ìQئ\Nk¢„‘32ZI)ƒ²júÿT°ÈVöäo¯^kÞ³ãLïGbo xŽ€¦P¨O˜jô‘ù¿eQuò¶è›`£5ó©á„ÇSq~)§“ŒcÒ Ï«Çä=#Vkî8¨††r\–jز©§Ä6"x¡Z°åøI(“qeHÐ?×ÙVŠC5Ta£Êòè|Rhòm§x–SÄp¢'¾‘³2fˆ…k:fìØŽÀW iŒ½ ô R414ä›r¢5úÒÆ@ݳ!yIö¼¿[lf·ÔE@Žû‰P˜”ÍÒº¹R/Õ˜vàЉ·I;ÐyRÇF5³qÓ®~,jI3m”M6ŽÒd=‚ö¾ÃJsॖ“ÕNOÅ/™å»Ì¤^ú>—ç`ˆ7ùËÅÉ>©Ê*Jt”\¯69-5Ô0É ¡ºšêN˜gßr0ù4C¾ŽÖåÕû7çW“ïþûêõäü¿^¾>¤ýø¾»ßdk¾!É壿ÿ´˜]/§™ôÉ„þå„=z‰ÚV¨ždÍç é]sè9Ï‚ólñܲG¶ ‘ÝEXƒ‡¶k®D9ü䗌ÔEƒ}"–e‡—ؾ̀Mw‡¸Fît¸'•àõ¶iûÀÆBÄ¿‚7ØÜö^UÀ<¸ŠjP•ÿt~ùxô üó„û’ÑʪühiòÓÕ÷ÿ—4êþ‘«w¯Þ >|º&?,ó ì8°OçÙÚ ótW!Ta+ Bñ<·“a)D(¶è~¿\ƒUü/¼¥B÷ŦEB“”a.^ÿò<ç[¼QÚz¹Æ£PÚÇ%G!€¿ÀÖŸ3’CŽ>LEVo±¹àv‹› ¿!+…Uop4÷Í"Yá {y·F(©X@ÊꤰKáf™Ü.ÁÐ÷dÇéÞ&»*mLrµL¾¤yž.6÷¨¾Á1œü~yG8½*PìËï©Bº½øóå1ØïEöå"ƒ”g$KÄÓ¡×?ÜA i(Iï×dKaE^ôûÕ'HÓ»9„âSúy†®¤$ð·Ew2f|ã‚¿®å1*˜={7òðÁÑ7‰^”ð«b]Fháí“ùö †aBö•ä[^Ð#h åv÷0wŒÐšI¥rR¶ílp›Ý^¯îQßøÕß%€cßÉ?€ ]Sá¹ü8€¿ äWª„Ã+IV”Ñ U~C¦*¬ìM0? Kù‡p!Á)8[Â;‹ÀØ„Òì’1Ì+ØK¯?%Ÿ€Å„dYBXšÐÓZJ@JðÒ¼˜÷òƒ‰ ck`œ'FQç\NèhEnÑM¨’ð¨õ§½€çÎ*¥5é:9“mRM2šütñæüÝ«×C‡­úTŽ898ÇU¹€8¦(@¸r`Ô Ï4^’n’%P3lGJøz!ô¼6¨è"µÑ q A©×”fÕQØ–êC2*…<)RY«’¤—¤½šÉ‹GCÊ:ÇÂrµ Áž*³ ýïXõÓÒ…)Íû”3ÿC¼í¿”-cÙĦø+™ÞÜ5ù·bK }~„Ú¼ðõÖX5q¹ÎágdøÊã¡8Ta¼û+K‡ÀÛO÷q€I|ˆ¦#g+ãh%‚ÁØ @_ÁkàæÁæ«ä]%1¹¯Ù&¹#ª·úpkÆžcN(wë¥?%èÔƒ)½ÉsÞéFΪ b¿ÊÈ5Ýêó Þ0øC1^†L¶ Ä”»úФÈâh$´¼Çɉ Ôfîsð÷@%w{‰­%n—ñTõ~²müš3¥öT)pÍÓ‚?„Óe’”™‹;eD ¦‚‚¸Ã&¯bU<Çèó@hë¬l>{OaY¯Ä¶ÚnÄüŒêÖäÊnAz†€­’«‚5¯&ß¡ÞñöûôEHìÆ÷X©jíDù̳‡£ÏÅæ«;zPJ ]<(Îôm˜Šb…S©‰rBü)0mRbx¾8ò5<ÌÜ 5OI“p(|ÑB9SÈÖg ˜qòÃË¿q-ª˜¢Ÿü⟒…¢îÁÈu8"öPêdÝ-óŒÚ»“ŸG°–™zã¬éwá £&>ÜÑb{À7úæ ¸³.‹Jφž0s‘›—Úi¯2ø´Õl§»žÏ€RQÛp X çБŽÉúß!óoòî— Îó&¸È•¥þùDL:`'©ßÒj^P_p§ª‚ FÞÖ«; !'`±._7,xŸ—R>@ÊL©ü8µÇêßjî˜e>$lfš‹éì˜ËÁçóˆÆã:Êr½j I¢æÞw@Vœ/¿`>`R¡ Ú (y †4pÐŒoúwñÓÛ· 6“’Da()Ò÷’3BÝ%5ûw:šÁŽï°KaT)Oþ½£#ð/žš\šIèÝ8gWå4E^•‰¨4d%@$8ÔÍ¿,ÖìZ'ÆJ à+ùàµÒâ‘QD¾,íѽQÎMA-p‚kÉ_æ¼ÉŽ!å:tË}¹cЃêS  Š¥$œoœÉoª%AçßÙS"bä$ÒmŒ»WÆÀ)'—ìl3¹¼™põ±Jø(À%w‹=>¢ž‹×o¿ʉwh^åU5¡"­à+}ÄÖp"Ì@u(NáÒ3™,– Øûf2QÃ7A%/ÿ­† kÌ 3±jHAWk×4Ï5–T.mø‡Á•q”p® Z`sry956©æ&¶C·>½}wñg¬Ïþô›lo—Äuó~Ÿ‡n9@à‹ ú}/xrÐdgäYâá 4úãåÏ/ß¼}ùÝÛ×5AÔ‚ê Þ&0³PvŽ(b°Š¡tñHÆTa¯0S–Yk/Òb |#–^Evž:(¯£#TÓÌÕ«üwßÀ®Êë;R•¼záxõ4ªrÙvË—aàLÄ?šÁ±I‡i¥þdB۠褖üjÁ#çèÎ,ŸûµÊ`Yp¹V\õD%Ña\ÓšÁ4™ -yº ØH]W%PÇŽ;¨V®h8i ŠçŒ$еÐágKô}®Zx;¤Žáaʼn›Ò8¦€{%qi­®Â‹›-P…í¸ÈÚ-M”’ÉÂï/!ZYÅøÃqYeåâH=H‘×éôvÂ'.É\âÒãxjzçIŸgb®|ÔD©¬hf˜ÿýu¶Füøß“Ë·oÎ_O^¾ÿ3YÏq"ß9Óì89pµÐðÆm/1å;ü5íàhrûYµäŸ‚]šó“å^3Âi,»"!¸žÖLª„#²zúD¦3£zí‚€êé…§YU7J²¾î‰eŸ‰EmqÑ¢Rì­# =qÎg+V.;ˆÖŸ£Ä…3Ä˸üF!âð€]ý­Î^éà]-WøØjp“ëe†š~ ·¿Åç`\TŠß. Ôæ˜ßŠÆ°ÿ_1$úL=¿'D¢Bœ‘`‰„ÅÔ}ÿMûJÖÈšþfÏz,Î¥[/: Õ?k±ñÁ ÿ-úW3Ú¹wøÜûRkù¥—¡Ò”J€H…Lô€ÀpÒŒŸMp!/:’ºƒDÿ&Cf¤yaýMvF¿þ"°p‚° Ú‚BW-ÅØ’ó7ïÏ/²Í—eþ+*´ˆ¡Qùe™LXLs𼴋ݪž´û$Bág`Ár Ѝ§Ð[zøeÎy¯ÂNIMXŸÐCÑÈrŠÙrÑg·øsñæÑ‘:z[Ž@s³ 1hM—Ööu‹CöD‰f/Y‡¢XB£É$<Ó)bÒK©"ÓÚôÜzqi²*™æ¸ Þ<9V…§ÅÕyRãù‘-Æž\ã±®V`á(â°µ¼R[¡§@vÕjøv˜¥˜†–CÜU«å‚Ý5« z[-´lc—XÖ‚²Ë!93u›§9.Y?ï/TWµ.hôÁ<¥¯$‰ŠÈž3ÖN"Àšáy ñ ¬ÂŸŒ‰ÚjÄ -ÀU…F¼Bí-ŠZȺc¢ ~ÙíDë ?+O­¯¡Ä-¤³"ó,Q#!ÕžJƒG.])ÔÊ|è‚ìi+l”ÓÕÒè «'¬Êˆ¨ÖÈ”¢m®Æ]ˆC‘—0©«xµJácƒM"¨~ö–ÅT([­Ë8­fÜñ!×&¤¤ûØ«v\!þgEmQýè¬o`p¢ÓwÈäbvöêœÀêÒœû"pä>-rüSU­ÔU:ƒ½·n«Qø¥'J%É…{m@‘Mà³\3nÂ]|wn€ªéñÃ$òè´™˜ô•"e÷ÁÓBl*ƒJ cÐ2ÒWÉÑ Í ;|^=>CŸH•nÜ{æ„•*ÆM ŠeɲWüK¥64'E™kÚ;f%Vè†ÍzBUÀ!ølQø£°ª‘~UwÉJx­´®‘ͺFźX¿ Rõ—Ó)×÷æ$9à üÆÞ3ôi(õjä1ÿÔ7ºe¼ (}ê2¾¸ù•È ”—Dñ³ÄúÅI´:®^K=K¥ëi#?üãŸ__M.ßüŸ×èwhƸ '–ã×â7W¯@HŸ•ߟ i_Z1Þ¢¨~"ÿNšI Óô殮hà—úÜø:#Íû'ÃçJ¼º¤£€º$˜095KàËr ™Áe½• 8tI(÷7t £"`%gÝÂøûÐu”MqXÐ5ö‰Ùk¬ ˃B£”Ë®põr5ô§\5t¨Xž`£{üD~œ ®š9_4]Ôì–z»N¾BGQM›Ú.¡+g£iÅÊÙð2lŒiÕ¦žŸ!#@7@Dè’ø¯Ùýd¹ÊrlÈV †‚½~˜¤ùÍìQÃ5R(žæ øÝ\|Šû*3¢$‰á@1ù<Äs¦ŠbÀó„ª3™‡aÇò¡sÐ3íjŸ@ÿînC“b¨(e}ßÐÏ >¾i÷Bpˆsn~HWôÉÉŽB&Îù|¹Î¦“«ÂBØ”Çl5gÂ(†p#$°Ê1¿Hjó_Á“ç1·+°•ÅÃV+,ÈÖ7Àsr§ZÔhÈöÊ(ÐÛAú¸ˆ›ö@`Ë•;’¨÷ä¯Ù½b[ŒŠ{R±Âx¾÷ÂfYÎøÐ/£CI:€‰q„~âSºàf°´.,È0‡zÀ¿Ç‰ô=Jô*}›AkGÀB‚œ€<„åáL}Š Œ49™ ;a\4¢ÁB<Ö¦BÄGo®<Ò¡4b(þå“1Ú·KÒ68¤SM£R뾿²SôçËÛUšgôãKÔ`YÀ'iðgÕâÙc·éêÅ_¯ŽéÐdÌäü0,Y ba$Í»ÏL-û7í³lÛ÷,޹öŠE fâÅ9Nà? c\ dµye·!ž2Âu~3Ýóà{­Uú|µo} YºWÿõþõËW“ï^ÿùÍÅä»·ïÎÿÊœ¯f×›ò ½tl†1²5:[á/&çé|þC¶ù´œ¢óíØ~€<8†IG¸„¹/oÂþûæ(y›ÅÂ&QÉøÉoÉæS–PÙ˜¯ò}e3@¯$]Cž Ú‚Žq˜P-J]ðÀ›¬ ß­Èjü€ª#^ÑhüOBbôYòø„2Ê Hu¤k]u‡¹ä,ÊÜ].I*QJ„¤[n݇#t! umù0~Ц|ð… #`i<‘ÀFg,ÎÉ3!2¡y 3œøï¼& ç}Wp¦BöزiÉÅÿgá­+ÓŸe‹HQ¨Uv‡ÃúþtØ\Ž¡?¤ ©RÀŒß,õm|å JɃG{Ôdk¾'xù6TÙˆ%Ìqá ï „ë׺Ù) þ''€<ܲ‚”À—‡½ž Ñ7­„­¡Kˆø²• ²Ò…+%pžî\™Âß» ° í¸òí+ó*¹X®‹´¹„¥^à-L<š– Ñ›WÊRï*©Ö03tñÓ‚ÏEò’úµc¥”ª#¤ÊgG–ëõq˜.¦H)M3Üÿ–ñÈ©-¦éãP˜RÖ ††ÄÇåÝbz Ú-–cÞ–RÛáMh€~>j6ô†|+‰ò)]C§¯FŒ~{ Ä.태§¬‹`üuí¶‰ EOnYª ÉçªCI‹«´:÷àEWÄ F“ŽHžHvõ½1jÔòvF1à?ÐQ /WLöÝ˨¼±üJ½ tƒl°…úÿL# .i¶ ßoPÙ†2¦Ì8¸˜ŒÝˆy‘o´gßž}-ÙŒ»OìKÀU°¯:tàÄ¿dðFü‹Ñ=ûöì«b_øG‰…!ÉìSxe&>š5â^:l}w¹æ´wôÜ ì0Pmü×ó É#¡ü`â$þ|aõ@–B-OãlK'…¦–|âyɦÇÞ¸âFßë促1þ¡¹¨i¯ÿI„ÁÖ(Œs†ø8¨V‹×TwkWÿêm*¯l¶™-ìN»³ˆ¿Ö]z³]åÈË*¹kŠO’›Š¦+ŠÕiIŠ n?,§o`.ä72GíÞp¥<ª«³DN‘Jœr¤€ yquv„R»àß|?³£R¶Ò±œ›°Þ¶ÝÝ:›‚ÉÑ¿Óù—ô~Ì LŽÎ¦ºÐ>—.C~•<ü7Ö7\®ÕX%ÿ†&µªªނĵyíèhmÕÎ"´À[[&ßW4¿cX_XÁoX·½+ªçœÉ1Ò̃¢ðf!4‡”áa™ ‘r™­FHh0ËAúŒ© 8;F¬¦–áñVÏ͇ƒýN¬R«×Ä–T÷e‡jN¾â„šœÔÐ(«Mˆwâi­ §]‘OµÍ×T>Åþ¦>ÃÚl¢TëD ƒ7ì¤}5Ër4.0ms÷K™ÎÖ×iîy9Ø€­±ÅAÁeMRQ“Šj&Ö+5X wÐ?dcý74hÒ™òpX6èO-ZBR™j™:ýÏýîKýÓã¡Fû3ìt@ùs ht?ƒÆ³êf.k~OÓ*FÔé}aA%µo³W­ÏÍXVú)ñ§òàÕ¿þ‚šë{å Úõ+µ½jÕ@„Öõü¶OÛÛsÓ:z¾éZœ´<·­’·YPC¯Yƨö2Jú]ñŒs¯žvg5³¿%UÎ5Ò(kó@*›+c¦ÕÚ’âVÜj€ôM4|«oÝüÊ>•xiPC *wZ˜Mî¶Ì_&ö2У¡}†JÜ(PQUvTÿdöl•Í3Z„Ñ¥yFõžÚwÏ0#D®£!Ê'äªw†€mçŒÖI¤Yç (c+€º°ùï›áAй@Ú…jâ[îšQ½#n5Å댶o†,›É éõT¦o†‘â*TqDVO7úf5zO4=ÑèÌ6ÎGÆÝãµµ ´”Uòb:YŒžZh%©Ü@û _ƬŸ>Zg³òr ÒöºhØP~{m44Ñ Wz0í2Y©K/ …V¿nS' Ëå{è¤Q{É5Ý Æ>zv“>N »hÔØ7ÒkØLCGÓ½2Á¡o¥QkH¾£ü¯y¥jî$¶•ZÕ쓹Zu=`¥š>B¦AU!j³º>åNÓÊ>Pajûh@bö}¢@fè**üø U-F_åÇg|H=²E¥]°È}©6#Ý2íëý¨Ï ”lœß±â ojÖ¿LÄ‹±®VþQ;v`;ºUˆÛC ýñ9âØJ5 Ÿºz@šcnKX S— èJw»6CyÃÊ@­²Ð~Tâ˜Y_¨gçžT ê2;ÇZ-H<ɪëõìܳs¨ÊA]æé¸ª §Gsý _ÇÇVj‰Ç‡6ümQÔ’ ­6ßN-!p­ª yspÎ……Œ W–Ÿi¸pó Á+ qðêk iŒ§êBþ•BÓ Cè•5†\69D!ÍZ••†j­U[mHñlÈ+IRøO4fkn+NèºÐVŠ®‹jy¬µ][ QÖØ1_±Ì:h ôüY:+ꌑŸÏ%¡Ò‘°§Ÿ9îÉ,ð)-Gùô¶–òÐî¤W#•ÀÒIí rŽ’ÖÈ:œ*fЧ–xÄÏRÝ"Lο™=VOÞw4–+Ñ‚)˜ÛÓ‚=-t*,Ѐ>’¬u=øþ¢ØÂfjÂØ2'wÓA|ï]ƒ}·½ùžbíÙÔýŽÞ BL¾ïÅX/ƺ/ÆêåtdS÷ˆÚ¨î]ùm}X—éL7³ôÝÝ`p¹‘å,4¼È Kè¯u©k´6Ù‰Š¤2C†¸V®!m¼Öq¼9Ü/Û 5[_U«Ú¶“]ضfCú/®Í•ÛtòpñN×ÏtkâÉû­¼HÕ¦š»àHÝî½¾­ì²Ó}‡HVô¶¡]W'2RIEÂr=·u‹Û<Þ¢´ëMÓi…ÒSw©»ùÎ “´'íž´;AÚÏFêø¹õ¡BÏ(¥z˜œŸ «šnÔÁ½çð½§¥Ð^º«mØúZì–ÄCk7lÅ~yŠËµþ ÜO–A“h.{j»Â÷J5¿ÇÛ‚;¡M7×üºp(ü𮇥³@ŒÜìr²7íŸÜh¯7ûC´ï«ÐçóY¶Ø$!oBã)TõÅ«jú¨Z®èKÕÖó-Vå·š/·ª–/‡“N$‘È`éëørù¯â[Z…²†¯·%è†5Ôï-­PU½×n.™"lȲ د‚Z U{K«GNU5 Ó³Aêõ– ¬¬ÖÛ:´.uz©¨5nµ}ÞjìÈIÚÂŽæÙ U—·„'mUÞ-QO³z¼*ðŒEC›@鿯Gèu¼Ï[®Àk%°œ|Æu‡ [yW%I›“') )öT²Òn%Vªò.ˆ³ž†‚U×­´zê ¨ú|¬¯ÁZipùîSÀå?ì#¯AõñµÍ¨†˜¼CÖ…ßçÙˆ%nôó½wˆ}(HÑoÖïþ:/ ©1|N^$`1“Þ\$¿ÿž|HC_þmXMdçÐ0ï>gùÇùò 2™ˆI€êÏ^tÃõ¢UC©‰b)“k@Ì/ЪÏÅ9¾À³y1B2™\¯æwkørx(|<û6==9y:~ ËaÙëe²ù”nÀ`™}àÏOÙæ€T™ÜWËü! ÂÙ¼™%7óå°—,ËáI’\¯ó,ÏÀ‰eeå›eò9FŇló%Ëàs»šÍ34 šõ ¨¹'àüüCú+XÛØF.sb3M²ßfë *E–#ù’æ °ól€ì7`-’ƒó¯¿>€ËϳÞÍr€¨taý˜§7·ðú1Üsp"IîVš5Üyø}ý ù7 ¿àõëC¸mârÀo…™(^_@s >›\=œ-æpC!K ›:ùx·¸\ã ñÆÝ’®0§ÃêCšÛD'ŠIÊ3˜üpy>ùùõ{3ÍM´$7gý»ÅR[ñÍåÏïOÑ€³ÅõüàòÅ,˲«'ŸÎŒÓˆ³,ÀÙÿáà¿£¿¼¾ÎV0(áÆ²€€¬ä‹lT rç`÷/à~J?ž´r -Èo)yî? óp™…ÿCXë÷p&Úˆ…×=ø¿‹$"”’|D¨‘AðAaèeüa#½æÀø)iüu¡9¦Ë;ˆ,½î 8h=dŸÃè “îH’ÿЬg ôxâEÃo_á/¨<_±0ù%[ûÝý&[Ð¥ô£iºI™³¢°•á!è Þ“› u #j‹~ÿúê§÷“«÷?½æIK~øû—o/_ËÓÿa<»G7…œ $‹‰"x–KÕq®là"Ò¯ÈÆ¢´ ÿ4£@Ææ–?ÒE øñþÍÿ%ÚéÁ€xônvŽhA÷ó€ìMo`Ú 8lN&ú…äþ”r²®–„¼UN;ÅØy¶j2¸FR³óËX*Mß½}õ(Ŭt€Ç’ãÑào4V…ð s½Ê®] Œ@áË 4-€CÀ\/ÄÜ‚¦ÞªËérñÕ ÛÐP½øé-TŒãLß&'P­]ÓO#ô "üýþãï'ÿ&£'ž³·ñ /¾ÅØ+Ëó?|À&·Ùíõê~€°Ž€~8‚,? Ðñ€9ao®³ |3ù:!H{zLVÿ3”Ç ”lÙš‹×¿€=C‹œfól“ýýhY`Ü¾ÊæÙ—Òõ¯h7ذø/QÝ!MTLªŸRš¿À‹ ¦ªŽhïõä]"%]bæ@¯ ]9a4øHM„ÅQ4F›NϲhO¥Ã‚fÔ“£éù½|Ž¥€¦>#S žV¿Mð÷äxúÀh/ Ø sÓü¶*Œ’BûáèQo“Îüδê0(P­W·ˆ„}­±¦TËéÝœ×4è3ÓZàÏÙCìºî :z§@*dðä4IÓäËl>O>ÀØ4†¦(ò“,–ù-0U§³ë “ G$óÙ¯YrüûW—˯þÌŸ¯>¤ùWÏ啳ƒžæ¿?Àa{¨O‘Ñ3À¤þw€^8(B©Ìdœ£ñÿ\œOˆäÿ!]¦_”\Ìmç»ù…Ø_˜&à\:à\€éÝf™ÜA9²:¾-N’ˆaHâñ^Cdâý‡o&«ä™¨‘Àº ß]œŽÎ–óŒ”.P.ì`¶ ==.Öí’Ë’@r™mÞl²[âÖÁp'«'(­èÉ5Ô-0ßT`rþöõË÷é·Â¯X<À o±ü©"#ßjd×Z«»~¼O}»…Rä¾´[ùèM”€Á®qßéÆú€Å)†¿þ%å²Av\Xo¥›Ë¦§U·™ w´›Þg6-ü¬ºãl^½×{Ïðœ _â'ÝC¯‹Þ˜îCW`¹w¤- ½;]ï÷©­×«ºgt±3éïc[ƒ§¸§]:—»ÛFAä,‡ê±£þî·K:íTE’¼ëë!î[c­ê>y‡°çpÝ+ÅZ_Z¯¿)']Ûû×ÝD  óÖ»£»Hÿ®ø¼„ï‚.Ó%ã°æý4 ¯1b»p9r»…¼îµÓUÊÀ3-5à¢ê‚q« (Féy$,x,ˆP›?êX‚]ò=í¶A»ÍË1Ô6ûzÂí ·5Âu:/pWmiƒÜä9gœ¯óŽŸjµuÕ(òóqyã½²p˜¶¢KE/lÛZ! Ï¡µŠ–ÈWUÒðOØ&Êt/¼Q5›¦Òƒ%F E:ü#¦y1öÜik*býnó¢!a1j*0–¾<°l³%u0ÔÑ9cH[÷¤jM%Qj«G‹XJó }—òKöáòîÃð¾ÎŽÀò×{{óÌþ‹Û›çÓdŽ˜0ÓzîˆY†ì^óG®Š± ‰"W :‘"¦MaóžïQ^‡*±Ãç"ØÇ”ÉQ^¸"eÃzÝÎz–¯ÁñD¯OÇP¾#~mŽ}N„ÈÀ(c¤*Õ"n̸fWø¤6ë ¤Ÿté.ÔaÞ@eìëR%¢ÄºÏì%*LÎ “÷кqE[¢ä4øÜG÷ðAØÙƒæ6(•Œ"m]ìG =´ÃóªyÀÂÎê‚ îi³MÚlžŸPmxõ„ÙfhÂt´Ü«2ªÍb#Q›3 jž)üäTë‘Q|'Çy¶›ÑXJP ­ÝŒ¿,ÛZV€ŒXUøßIˆ÷çÓ„deh ¡}@{ŠåûÔ¿ƒ°2No÷¶§H½|™‚òž)à +5‹Ã¡H.5 7ÇØk Îe€põó0Eáåt:ºÜä“úx”`;D‚ù‡IZúæ®P&Ë8´Zâ„iðÞRß ÌÊ£ø<ÏÒMÆíÏ@š•h+M»¾šmæìk´äÃäóižÞ®¥ŽwßÏÓ›5^&¥"¶:ŒÐ.ÏdF:E1*CAÊ_sãòÕÏiie]’É—<]‘²81Í6„¯þtñÓåëW?¾|ÿRðÀ¾/~Os UÂ}‡‹p€³*£ú0ÑÄ»Á«'à‰ú×aò4ï"â€Ï®àÃø;R<±øB,Äø”}ÿUl~™ßL ×ÙÕÝjž à²q‘¹£áÁ»gJ4ÂÑ€Ù…Xôc:›ÃAÉÌè»sTu;½ÀGa‘W¸ÒcøãÕÿøz²š@ð&ÒȤ0- ôêÍå»_.’ß°lMmÎVž}ý‹ªÏ– ´*R‘3¿Á‡Aô88ÎÉm¶ù´œ&_$j“ƒ¯ŽY©é|<98€EgÃ×Ô»spð0Ó’‡øàHv2ÏP¾Æ Ð7í¡|99 ,!Pñ²Ð¹Œv0Žî'?À–—På<ôü!ÿÙCÉ.Õñ”i^\ÏI¬!yyMî¼ BOHVx˜ð•ðÔ£{röGý›üž@Çv‹£Äá@M)´œyøø ðð9Y8]"/®7àä‚-X3úpÂê7Ós*°6œdô`ƒ0z™mFa…'\ºþ ô†Žs,±æPx™GQcWâë¢HS~ž-®sfSFÄÖÄÛÙ³9y lñˆ=]/§ÙÈAÀï¹!•«¬)-JâbŸH ôçÉ.È ÔÖU%Ûw n.…ëüCD£ê~#Nð›X!/ÔÃËHÆ Z#ÆDC‚ñ0*õ´~6``¨Ä£†ÉDÂ%Áº#ÑSÙ—q¾+œ}•®'p1àœEŠå ñDÖœZ¼žÄ$^YM^e¢A$öÂ0¤åd#z±N,pâ;nÔìÏŸàËk‘+Á7Ÿÿ>†UU1âŸ>$7øpéLdFă$JЦ‘x ΄?%*—¾E‡ð°«*|UJÍpûøÉ÷§@ÿ†#ê;þšÒZðlöT¯¯äϯ¯&o®^ÿ€ÅÂlÆ(u A‹ù69a½ûLH¯ ,Â>Ó–4ìw®Q'$ÐÔOÿÕ>j³RM„'ŸÙhi—@g\Û¸ÌÉçR‰je€÷!T$lðQw/"íÊnÄôB«9«\ÃÅ×+&{ÖðÓZcüiãrwÆÙ‚¼úaM;’],7onÑB)žMqòÀÁ/9ì=²¸»ýå à$Ól§â~ød ¶c¾L§Ù4m ‘àüJ±Ø¯žüßÅZÔ`ã%àbØ•íü›ó¯¿†ý:7K8Õ Ñ劯ÄÒ1TÄC‰hÙÞÊÅþ ³9è5žÙœ\;Áv›äÂ\Kë AàHúS·Uj ““¦§‡Gªã9L¯$ø›0p†81¥aï¹Éût¶Î ûx°ÈÈåy¨Ø­Dùà!@˜u8ÄÅf 3€Å'…¬Àw¿\@ZUŽy ²j0°s‚<ÓP×]&^E¨ ©{FOáìýìŸwé¼Wˆ– U4ò  ÖwNb¨z-X_ j0Øè}ý¾õd`ËO,{TÂýB"¶Åw½\ÝǤ÷âõ{CLíß’ªðy[‰*DËÜ€ϲ„í‡^d¿mv†=½_ØÙ!–DàDŠâ¯…fC”ÙðSà{´y“IÏ«:^¥Ú!~e u…g•ö|K¶ ùóly·îùVÇ·C;Ä· ¤®ð-£ÒžoɦÓϱ…0 uê”[¼×´X‚þsÝR¸¶.TɱEœdKù±ZìÈŽM¶Òê,Y>ÊÓ$Q– •'2^)Ù­¤¸É$ûg\Gœ½ˆ’a´ïœ¬%`Åã‚ì^œL‡ÂÎÊüÐ$RV+>¶\‘ï¿ýÖ:J[úzÁ¾ÁѾƒ‚Õ ö&‚] vßlO°?ê²`Ÿ¥Ói\¢}Ÿü$ÿáe¼˜n¥¦£ÔÞw↞-:O’Ã,ì¾þvŸ](m§wªXß}èåóå3Âÿ~Èg j/ŸÝЗ|~ÜËçVåso>oU<·d=·î!ib*{w‘D*ã³—_÷¢ºMQôwŒ¥ÒöKd·dP·.²›XÏû"²ã3¡Eöã^doKdGU~-êø£×z$½ÀîÃzÄqHïø Dºª¥fÈJl­è«êYWÕëPq¹ŠÀ‚rOf·¨7çVgN65*KÍut l(‹ür m·ÎŸ|:·/õ˜úÍÅùû×ßÃŽïb?^V•~4ˆ'impòìf¶_4´A‘¬´½hÅÏ{(¼ Ä’ a‰v¼Z ùçóíUºIv¶¼øŸC™xð@ø2HóÉ5ƒå’SP€^°Öœáís Ð2‹]ùë°d,S3[]»å%ÈüÈ ¶'‚=]ºƒõIà¸W‚8üëX^|¿™lÂ[êJH«ítåöÛZèÊ—ÝŠP@œ¡5_ξP/eÊ pöc½%Ö™c:¿?“Éb¹øW–/DÁp{#>®™¿ûLƒ—ÝgRØz|êxžváV”Ò©ãMž|Õ$%¹ô'¨s8EÌÃizÞ{¦BÊ>0´k\G¨¶›,7Ï;Äqª¡Ÿ=Ã~H=™¡kx+ê™Óq#$]ÔBóáM¶YÏg×!®¦5`F5?A· öIc®b‘~ëÇǾ„§ÆâSãÚÁ'ñû‘AÌ£¯ëòÈ<«Ÿp KŸ‚H„ús´Ó∃|ë‡ç8òìñS ÿØp©EÏ7+fç23êð6Âxkñ6vÅÛ¸ ÞÆ^ð6n€·±>ÄQÌWNó0§üc¬*r¼¼ÛL–'yº¸ÉJŽUûñf1Í~#Í|áñÙ—Oé†$¸–P® ªgðä r-»®Ölƒ¥ö†„oC¢¶%°Þ[K`Ý[µñÓ[õðŸ% Wç =°Gj ñ¶¤fý§rF«f]Nðâ©[ ©OM?¥¤ñîí«wßýÅ«ú¿×PëNzý9îµ{¯Ý{í¾ƒÚiv'!‹“òÜ$HHœ’®WXrŒÁr‰w"ÛŸ‹d8+Æ?m²A§•d„µ”ÙLóï\ÌjXjågoB¢ŒÔhªeBžH&ä±+¹ñ¹Û§ûc€B#|s‘}Ž&Â;Ólžmeuj6TGhdÐzÊVÿϘ²ÕOÃd«UYÒE2/MSš íÈ3GGÃÁSzE®C™ÑÅ¿ìf•g·˜¿Xj R~v¥£T‘¡]L Ï•?í© n*0ìŸá^X¯P½27 UÞáÁWS+Ó#hz=÷‡õ ¹ž+^#ÀÊîà—| ^ÜÝ~ÈòˆTd•ë„jÏ5´KpМ/Ói6M>Þ-®Ñ=á¯tp|õäÿ.ÐÊ€2X]ðaž%çßœýu²Ê—›%œc fÈžqê‚Ò²2³­žnqnÅSVX2ïëzê¨ýѧ„öDm=ZTìò¾E‹8È{’#~zR=¼ÅâO²9êsò¿ù‹´Î6ÙíNäbl±|“µÂ+ë;Œ~¯•>bWtä^Ϲ¡'5g)®%¹’ ÷0{]?ý>^ýãý%ÔÑÜ|äÊ·ðµç–ªR!½–2ÞË ïû&È ·.ÈÿÍÜŠ­?=Ùû ú+;  P k‰˜Xæ`j^ ”cb¡¬÷RhïbŠõ®(‰©\…?ËJÃ/ع=@úUmØZ©VöÀ¶î•‹A” 3é[Îê—³zFY=c׬›´+²«½dIêi@"ŠÝsztFH£lž=r*sqÆB.ÎØlz8ŽàÁD‰*;=‚sl݃¨Úbèm…ÞVsµä'{ršl=fÓ‹Î>Óý`̶D§CÀ¥5ÑYæð^tú}ÁófÏcLF/в#Å ÃyÀ†,×276/T#þ¶\œ¼*1ž:9z¡íb¶`ß)Ä…Ìò˜Ì BQY5ÌÓ•cHQ§ÝI(R¯ô3Ôªx‘}àzkkïU#cÌCrmo?É —ùIöð‹Bmšå*£•%Kk‚²õŽZ¨ ÚÖ½aífã•óMzÃ:¸a]q‘ÖlÁ¾ k^f•l`—×íìr¬4š×²S}ÔaóºZW»'óØYã}ÊO„fyDa¼ r‡ß¶ r 0}–¦±ÏRÎÁ- Xf½v/õG’X»ìc ’ŸôžŸÞCW°¼ÕѪ»Y5žŽa§1ÃÆý1,È1¬œ¨át ëL‰¡Fø34òP¡Å¢>‹{õ êõMñ ÎìoûÇìÒŒ¼1SÐùf ›>rÙô­×à sÌ_ëŽù *Ù4˜Õõu++\Sº§lÆ5 ï­–«˜ü :°qË›µ`¸ÚýökÈ­ŸÖq ÝùpJ›«Å® ­IW«l1‰‘­<…oÍåZóâ4ðñÙò¿(0š÷%¬N Ýº0°÷AÔfñî™|P#WT…sO‡;;¿^lî§ðÐaÀyžtòžˆ:äbRz—4]á«?#Ám3ªáøÑ`%ÑÙÑø'§¼VÄz½ä£gÒšòÐdž(W4PocËû/^ÿâýb¿z›Ûͪ+iX[…ê“xÞ•¨Gm]3tËטO’Ò5æ§zÄíZƒZËHi’Ò¶Åxù„€9MQ_Ę2Á°2ÑôlÞªRªžAõœÔP^úœ#ÙíjsÓi¤‘[áÃr9oê:@Ù}ç3’ÜB.ÀÚ4h|†IWÍõèœÇùˆ>BŸðaxng8J}NÀH~:8Ðîó‚2:V³b2DÌÔ r‰Oç³/iTqí»Ž¾³â¡RÎ\Û5r!Š÷҆`ݺw‰=!52VõØtIš«öª©±iã…âO4þîtï¹–÷Ìߪ Û;Òvˆ ¨ì…ÎÖOæ_¾~Ènf‹˜lCf6rIS;áj÷  f B’Ø0„S0©Ú8°“è6ý5›,ï6«»Í„’€hÃ`3¨‚h9ç{¾Ðð—àÏïßÇž=›fëë|¶‚“ wÁ»_.qodAƈy·ˆî0çF,ñ-$Òžk¹mÊ÷Aéæà¤u6ñÅÀùžhßH=ˆ#ŸÓù‰X}¢ži:[Ž- 3º2Gª„õ!$Ú2.ŒK^“ÁÆíE©°ÊÌ«.lPl&*i ³­kºX¤ù`þôj¹š|H¯ÝÝ\KÇR,ì¾zeFc2 ÜŠ †‚’#ÂNkJË¡Ði¡Ù¶Ü6#|_’B´[g6UM¤ÂRh½ ’-v·ŒôÆ‚e$ÉX³&ðÚ[K›ÈòtÝ!Ä\oŽòHá–KŽà`Фµ:ÒÉ{ÌW úÂ]Ú)†Ýº3æ¶I–84Æ9Ð,|ÀÉSmZ[òûïÉ#<”5NÑ'Ë.&ìÚÉBJМ(ÌæëŒ^¤R>¹zQÁg˜'ðä4½_¤·TœÖîl€ñ÷ü!½–„'(.&á¿Æ”ë»<¸·ÀâÞƒ¢* ;®5w\EiŸ ©û¤†²Fì@G‚²F¬~nPsê_Ë/Œ½VQõ¯‚«tðÎZí5q¯‰{M\SÕ$;Ò“ì¸!ÉŽ ’·J²v…b»D²c3ÉŽã#Ùš{PÓxäº Â?ƽ)ïP_UwWªêê-ZjÕ‹ë•…~J‹‰ê侓Øg Ùv­ îOQ8L0‹Z¤õ‚Åãæ.U îi¢‚&ìT‰¢‘OmIŽzEuÛ‘Ú¼hÑ~«òbmjFºM¡\›q4µqùiÜ*âªSŽÆÛK9ª*¤'V°ÈPòX;ÓkR“.«I>és›Ì¹M8úT¼¥2+‘Ø:™-‚’–Šd6Ëe;®î­iQX3¾Zh±òìhZŸ1ŸÒ{KWU²¶äÁNT‡*”­%ˆ.aG¡¯DÅÙ£7¼íh‡¢£ƒê¨¥„&ž£–  óØº hËÛVÝäDߤ² HÅÙ\gF×ÕSZ¨ß’œ6'ô á†U{í œ¥åkœ¶Z{Ü­?E—Æíx²éF_†é}Éý*ÞzÔ¹+GKôuçàÓ:@åã»-À$—MZðÈÿø&&¶‰Síës%œíþÅ ft÷e«÷œ.ínÕbâ7Ô’¥b^Ó—éˆF§Í<\»ÜadæWXs?®Ü50žºÁ˜†Û{ðe §7Q•D³¾Ùgu‚*’x}]dÉÀÍYºÔ`ë×ԕ íå~¥ü˜·~úŠì ¡-Û¼Bh@'ºê¨â€:v= ŽëáÑ.{1¶ÓixhˆÄUM‰¢A˜n‡SM²fõát,-Ç5§úš]¥ïÀ=^áV+\ÅmýW¸ýýÎÜÙï¢ÂÕá±› 7<4z…›•öXáö×våZC‘#P™úp"§>X¤"ÐÜd‡ë¹Xi—î l ÙÕù&#}¾‰ÅÌŽIí’ÕÞ‘¬v¼j¿Y(DœzÈ ±©¥ÜÙb Œñ. r*s­¢ÐÂ-t½L ûu˜#0oý0—ïfÅzû’ -Þ?÷¼ …†ïâñZ‡Œn¯ÃCS>^³±®ì€dQ¤¬î# ‹³v'*Äïö¢Nw[ëNpÎíÍÀÓÀf`áÍ‹ÞüR-­Ó€–¢ø}1µ½ahi¢?ǽ}ØÛ‡Q˜&½}Á&ö!|ÊÕG¨ÆÚÕØ5BÔôÓG¨Æµ"TcÇÕ©Ö„W˜Ð§®&ôi=<žî” íbvp&´•å,WìR›Ï§uCU§‚‘yZÃLÕPÓLõªúϘBU§aBU‘GOújKÕ–"‹òHGv‡(O”§=Qvš(yR©ŒzŽÊQO+ºüÃH¡Õ|16ñ…Õ Ô3Ûr‡&Ê_<Cà7Jt¶™üœ‚˜!glýÊýrµc×1mG¥Îi{ròuëÞ"¾wšéZdàVEè2vtL°»u'xFÛ‘ð›½'²Êüu¸ôDpˆRsí ,îö±øDžq"”Qߺ¨oßÞ!HØ}k‡ºuÙ[dûcòkÍÒÁl£©î¸'¤_ÆÁv(_ÈÎxõæRlF‚o A~ÒpÂz¦òìü3Ë2Z‰-ùñó:/ƒÖOv†BÖ;ŸÏÀÞ¼J7é )µ‰£¡™9´ÊøþÃ(J~~óþü"Û|Yæ¿®‹Ì¦Òä3ø ¹T‹!IREûÔ°$8èa‰[­§3Jo-K>c‚ŠÌ¤Ž=å(1îQva º)æ¡?ñT%üÚŠWn'º´dá"´ƒè Ñ(é`Q‰‡BAT‘—·L¥|ĨުVƒÅ€9„%I:HT@~ aë&“Årñ¯,_N&1 ŠF"àÃr9¯q­á™Q{Çß<ìÍX¼F¥)WF‡»mÁÖ<ᛉP(C¥d}T~ Î+f#º+r„ƒq0œ§gß*öÅXÚCÞ%€ïãzï8×γÅ3­i >‡±9_#<î![c¸cçj~Æœà…If‰˜F‹óõZ`é›l³žÏ®³¸ùÚÌšÓÙG%Q­ryÍ¡Ù<8!Á*êW OiïÅx½&­„·œX&¡ºAó²’x+h*Ðê®È;ѹT5´µ¶VFËaÊ8¦-s[ÖÖ²–\¥-ÕU‘­Üöp@¤òÒGmDª¯€¸!£f“ß³¾WB-æÚÍÊ4ç4`š—ú„Cv\ÂKYÞm&Ë“<]ÜdÉá$«Ü¸7‹iö íà Ͼ|J7ƒ¡jtúŸ°Ý²™OPÏàÉõ×Hò¶í"\³] Zߥ·oÚ´oê›$ëÞ$)!¢7IlLÂz“ÄÁ$1!2~“ÄÆ’Pèœ=²(äUéô0U=:©Ó›Ê©syŸæAGÊ‚¸˜þªƒô†EoXô†Å®̨P¾n%³ÉU‹FcHE6økÊËvªk8쥲,E]•·µkÑœ–jt4´zËÕ;|,œ+ù±tœ•K´ÔÛ0i¡€I=1°|¡ûSÿåà‹Ùͦ,ƒP¡ÚÉÜzýž&Ú§ ÃÆŒ}nŒõr­êzT{S:RÞC H£*Z3^PsNÿ±ÓÓŠ: [_“áiÓ͹œˆ´ÃÀ`é“”ú ^A{ÄãÑûÚl|m&„õ¾6_› ‘±úÚÜÜœ®éƒwƒw¯³Mv»Óù8ur¸ÚIº}ñ^=©CÚ”` W¦–ÊT‡¯Xu©³ DU*Ü£î•@ƒÛ&ÝQ?Þ_BC€›ŸT{¾örõL'Õ·s¡CqŸcÏUDèTÄ¿™ö¡L!{d EŸ 3ìq"«‰e¤~LÖ—Y ÂPŽJ¶}=`/•Á\ØUUÔ8бcl `ë; ×Jåµ>Ãu¯Â\pD…±#H4Y_ãrÖWmIí÷ÁÞ©Ø­¤¯íÂKd|“œ/Qä1Ûk\®q¶S­0™¢¾~Áé½ö[m³ôÖJo­lçÀ]G%œìÉ9¹ýÈY/vûPØþ…¶&vÂ][»eáЋ]Ïb×ÓÕ†qLWFa®6°^éJcG/ŠB%Å©ëé¦ë2s*2¬õ—º‰Íö/¸lò†FTéìlÅ¡²Ù Á0=—ž¢²kš .ä¢6‡»—Hf^1×ÆË½ nŸXХĂ(sÏ’âË=³É[™¬V†BûG•îž?ÀA'òaØT´Þ¼ïÍûz¶e95¨7ï[6ï˲/vóž­8”yÏ ¶’å]gçSB#ó^Ž#Œvм·¶±IœÞÞ^ð_­ªT°-¦»¡}šWôÓ(AÕX|ª¥H¾#B¾ãc³Ú”ÚSb—(âJt9v¦KAÄb ­YîUÒTé6.Œª_­Ôbõz|:éø4îO-ŸÊ#Nǧn–Ñj„Mt#ßu‡,ªÕ(—U}^¶©–ÕÍ­oÿäŒm÷Ï8güésÝJ8#‚ÑÒ!|Ëàžk—RF.”²ýrTaøkÝß[±&k©;Œ“U\QËŠ;7óJ¬–«˜½»^6Š÷=“‘¸w-/!ÌÑä ³¤´åe{*K“tµÊÓ˜Š‹rÌ?Y<4’j½NÞ³=MS ÀG'È!(0~B0>ªésq4¢Çë!ÐÍÃhð|øÀ°w±ZÀù%&´á‚Zd_¤ƒ9F¶*JëUUy&/þ@!?,”1 Œd\â@½![-èpñúïJUCÛÉ,é0´‹J!ˆí]™ÚÔ–7svGs!ý$)]HZq!Ýíö‡Zß•ðå£Iý.š·¡zî¹?ñe€¿ ~½¤SÞÊ>neŸ˜%¢ãîÇ‘ìvµ¹ù4ÒȽña¹œ7v] íóCíC€„±ý‰¸;<´GC$3Ÿa’W ïóåíŽ9¢õˆŽÎ¨ðå€ÑÎeEóqz}8áH{ǬèèyÕ‰K3˜SŒÈ¦$] <£~I£ TŽ¥Jðëˆ/â~O=qôNúáüYÛ­yíÔÈvñÙñ''šÃð»Ú\nÅ×+3æùµŒV°Ÿp@…; G­ºì|Ènf‹˜%x@Skv²WcK !qïL- uŒR˜XY„Å0‰Û¸H°Ãí6ý5›,ï6«»Í„’ˆh]aÍ’¸9+ìûÑ4—àÏïßÇž=›fëë|¶‚“ WÊ»_.B±äØ.0ÝÖ5 *2>$îžíUlŸï³ÚÏ3À‰ëlâMäû©ÿó®ùv,€Å-ö×ð/öÑ&È»aäÛ° º% ®çYšï¬,¨ÇÒ'{ÇÓê蘚ò2&Ôí8ÎnÀÂÙNí,³@y„\°¿ä0Ý1'ÛdLcjª=ÌîˉÐïV$Sä%<¨Ê’âhEÍÝu³ø>¯˜¹QzBi¡s—&ѳÕÊ0|‚¢$ôŽ6Nç'bù”f–yð´O¶FÌ¥è"*‰¦IAÒ–ápá|òBà„KnwJ…7PF©}áb›QÉ ™ï›&7v"k1€Ù°Z®&Òë_wÖb¨§ó)ZöNÝ3À£5²ÅnÇÎcAIÔæ”jÓ¡ºq¡[½•6¶eÑ’W‹Ë(Ü·Œ#|t\ª*&V˜0íWÓáÉ튟ފq,&Y1bî ^ë`{É7Yž®w@´1¯¦£dSx<“#8˜"·²Žœ – gÀmÜS¹ˆaN,S1¥3„ÉÍ ìuÞ3AAt§°Ø®…êðÓµPc^-¢ÒqÍ“ëØèÆ5‘é–Œi8¶Ž}[DZ•(“ŠDÍV‹ tøªO¯Ú«6E­ƒ}Sm}ŃݩxÐÕ¦Cf̪+#±uÕÖ'ùïd’G¯Ì!8‘s,Âõ4×%i>ë2ílÖüÖP¯Nã°Ê:·Nä°X kÆ·dbw%å/;LzÍ’*ÜFn+©b¶XŠÜźF‘²\+0´zäj­ê&³½>£DwFÛÕº :|÷…àé– /ÚËÊ 1£u˜ˆñͰÕ7ÿ%Ã"í¯þ»Ùböx»Úb‚‡|ìl¼Æc¼.õ±èR/L·bâSyŒSïöø}±{3ÎÖŽCŽ{k®·æzk®·æ¼[sLˆ*I#HkI.&y¡ £MH7 $1ûêT- ÆDøžÖ´€OÝdéiMdžú²€O}XÀ§Cb˜¸¾rÍ+øÇév‚Nx]ž‚NÿSÐé4LЩK‘¾^e½ ŽFj¤Ó´C¤†§èÓž¢w¢yª {ŽÊaO+jýÃH·:¦ªÜŸ±-U½DkæÒ„AyDÅ „ ‰ÃÁŽrâ–ÛXAëV@Yþ9ë®;o'ºaÁ-ØÓ èúè|Uf‡ªSz(—ɈÄJºµ›å×é*½žmîc–l/š»Óôž)EäÞÝ5e€GßÔé)c 5_~Ÿ/o©œ¥V˜E„ÒãN³y¶ÉtÕãv‹m­™P”XP7¿zs)¶'Á”*DDg-àE¢¡Â«;ALÁ£|žÝÌÖ`í ¹-Å–>ùy—ÁV =‡qš‹ìËù|6ëUºI~©Q­ƒÃ²Œþ?Ì6Äù§t±Èæë"Ÿ#¨$‚Ó™dPñû°$XŽˆÑÆ­Ð“i¡ôn1}Ù %{Â)£8„\ƒ“¨hˆ|ߎ9Q†ÔQpÛ_Kd¯ë*U(wz(Å‘ÎX‰ò‹y+p –æ#)QÛx:6°]šLËÅ¿²|9™ÄÆõøùÃr9¯uPaf÷™•¶.¿6±ú+¹î§‘GyBÖ‘–p,Ðà\âAQSˆc¿p’ž K\ˆÑ²,H í*ÿúí&óͳŎñžzð¦n2eûÀ—ÐÙÒ̘¦òcË~1ï7Ùf=Ÿ]gñ1¦Ž·¦³³<[\› Ì_pè& Np€Š˜žð”6 >Ì F i91…¡´A£QÄúRcl≃<Š£¶*ŠÈh°½@¢%†Ì¡D-§º†õ,Ï…UIÕæÚÉ«¶Äœ9µÚs©Õ˜Ã¸Øä÷¬ŸŒº$©$ª0p9}”–oÏAƃ^Â/ï6“åÇIž.n²äp’UîË›Å4û g!%øÂã³/ŸÒÍ`¨}¶ Ï¦¶63ü 3hŒ3xrj9‹ËV^k¶íTYèÍ æEMë`½·ÖÁº·*¬†zë .æâ´Ì ^¡öHчHO3©ÝÀêcT»î&iŠ/Ë9ø}jmî<Ú²wo_½ûî/ñ݈·Õô.Å÷ú¾×÷½¾Kß3]/½X!kñu)…š¨rVDRò·ö–øn7ø'w«Nww»ÁímËM2_à¶ÐG¤+f! ø>ª ˜Õ°ðÖɱo’ÅÝFŠÉŽÂµÆ!ÑÄFjDÕ6+K—ÐÝ}U´=)2öÇ,…dF¸ç"ûR„ƒŠdÔS³ùê8B3·¿ÙßæÍþJ9°Žq¡•Sÿ¥Œ‹ÙÍæF±xY×ìMÝÞeøž‚a3ÆM7Ãz‰v×ÉÍŽ‡®Ü(WBáçRyaH :ËÒÚ>¶|Ît©¼(Ÿ³2­Üo™sÛ¬‰>weO‚KÅ^ï[p‰ƒ¼w69c¨w6ÕÅ\LÎ&[/§ú ’¯ @êl“ÝîP*‡Gå°˜‹j ÂUs‰Pí{­çŠ ˜”žƒè–¤L*\í…wÝüþ¸…÷÷—Pcss’»çÂ×^nëèdr{éôr6ý¾ õä(„ú¿™ò¡7âÔ'a2DŸL…Ãí n‰ ¤áLF—¹P¡…ÍÛÞKñ½‹™Û»¤0jeƒ©—ô ש.TWM¯ÙZ©böÀi¶î A 3ó[O —S‚F)Ac×” ê¼-²m “‹Î¦FŸ†Œ^…GŠS-2еé²eVTdË곸»ƒ¾ö³¸­q®Ì¡'™-×*r!±éÍéÐætY¨EmN³åú7§y‰U²zÝp°Çë›Ó²#}ÔysÚ¦%deî¿T1T©ìS4ìúT¡ÞtoܦéÎgà‰D9"D9>6³¦$¡R„D1U¢¹±Í ¢SŸsGI‡¤Û¸o§:ׄ/±èõ|rÓùdÜŸOBœOÊ© Nç“îTîi„>D#•O,ꞸVå©>uÚåéÎþ¶þĦógœ#üô¹n%œÂgsßR:°Z$Š‘ Ql¹öM¨òZw@nT7¦ÑÌîXZ¤Ú’9ܳÁé}µ\ÅvZÒ@­Q4Ꙁ¯Ýâì z >¥ÝÓú@ ÛótµÊÓØd#nÀW<4’j·XÞ˜}‰|h£>d«h=!h9;€\|ièñ¸²u¢|?£f¾ì@3‰a"nĸu®—Eö…·¯ÉA«%±W¯ÌÃ3aÍ î7ªF0@³¦ñ­ßB¿xý‹wå¦Úê¶S½JÚ­ÂâB·_z'ÑÚ„eŽÚÖïÛž$¥û¶O+îÛºåÛ«õŽˆ”fÍ‚·p›6ðò swe›‰sSc|VÓÕxËòHyéôD¸tzb–[Ž#8ïÙíjs›íÞèúÇ7:©#œìþYƒcŸóÜá]+óÇg˜„ÕÜzšÃÑÄŽæˆFÂö3‡A³â+ £ƒÝcp˜Ýç9e”,gÉlˆ¬ ¼†©Aä6?Ìo_Òèüц÷UY]ð)A4ï‹G ÁÚR3¶¿“£v^'þœAÃÖ°ËÈå²n‚C>Wíè!ct€Ý\*…¡°;jÕûU ãCv3[Ä&jƒ˜63°EWšY6_»oÚ`0c—Ī!ü‚IÖÆA€]I·é¯Ùdy·YÝm&”D››E•„sÈY=ÇØG†&¸þxÿ†<öìÙ4[_糜fx,¸Þýr„‹# ÙEÌÃEm‡98¦ð™È¿X{îå¸7ß%œg€§ÖÙÄ#ç{¢ó˜ÕqÞ¶>.ÑPÄœ½/ŠÙ3_ï…†ÎãUÑy»:ºC}=ÏÒ|§Xº"$ì>ƒb0£àPʘ˜ü¶à'ºëe;²Sôe ò)þ’Ãl´œìˆ&[¥‘^¸ûü#‚Ûå@™Hý6Šq O€áh …Z]4¥ø&¯&i/* h¡ë‹*ß®¥Z|‘zG,?§ó±B]s7lö[f6tŽb‰€hoé»00y!L>·¥{ù(ÏÏæ^~±èF¾Ì¾uÒÏ¢Í.ó­²WËÕäCzýëNiëZ—âa÷.ƒ4*›•ÑáÌV0” ‘¶³Rb•= M·Õ¾Âéû’XB ‚åTE~ Û¡å ?:ÄØÞKÒ›Öe}$óAÌ»Àël)ñ"ËÓuçsÐ9Ê%…ó.9‚ƒ)àêH©ñb!` ÷j_ä6 qfÌ”“ìsh¢"’ÀYx‹IµUŠ\òûïÉ#<”5VÑ'«FüÚJEJÒœP£fôÒ–ðÉÕ‹Jþ8Ãì8§ªéý"½¥¢µÁ€gŒÃçé%(åVØùtm¸ù*ÊÿÔ|vO#xu¦8YGÚ<9¨Mõ/(ʆÖQ¿º’¡!Ô²Y/ï|]Ñ^;÷Ú¹×Î µ³¾ž«ŽlÇ Év\í¸E²µ-ÿÚ5²›ÉvÙÖÞ‡F%× ¤(Û[–Ü>õ•vw¦Ò®Þĥ澸`Yú§´Â¨N8ÉÀ@PhkКàù•ˆÃä´(Kk]EX<‡îTýàž(*‰ÂEVeq½!iëhr*Í+ªÜNåEKö]ŽkÔ*¤ÛÕǵK[—ŸÌ­ ®*ui¼ÍÔ¥êJ{©sÝK‹|¨  <'S©³©Ôá™>§Ê"§*Â"—H‹¥Âeó„4kßG³Ò„ì;0ZŸ»žÒëC]¼T²=ä¡NTÖ:5p” ˆ„d¶»Ð}¡Â/*òvT%жª“‡–ˆN•p*,Eë’-S†Å©É¢OFe—ŒŠc¬Ú^‹®a¤°L߆7þj`gY“‡·,»`‡â¬ ¿£…îƒq·þeÒt“@·ª•±½Ù—L¬àøã½ÔÁ7 +–ƒK‰gbfKÙ§2ÛÄ&ã¢îøƒ0¶ûWH0˜QÞÕ´Ðk¶÷91ùû:o+$÷2}š$Q³ë~\øjdt…Y wÇ¢äÕén¢+çåp×Ìí½Å¶ø{Þãý߯´Ts用.Áé³íKpÆ,ȺÚëðKC{z’#¾"Ë®½;ι&ÑëßzGqízçõNùºc—¯c×;:¼Å¦w¸ËëÛÕ;}õÎ$QAÖÊÐò‰Z¶ˆåÒ4HëÔä\,Þ²S¹É[õ:œo•ákзXšSv­dÛv"½¯Ùw˜ŸH[OávÛчÛg‹5 ²îWAÙâÉÅõ2x«ç˜ÐÀ1ýìב‡ÀÅ‘g'¯€ëÜßoù2­÷°¼Á1Tz,ÇPè3ÝF–´{Ú_G¶²ƒ:ãµ·ƒgïØÁd:Ád*¼ÃcÑ;\LÅħò§Þ­*ñûbö&”• …þ÷–ToIE£À{K*’(,)&•QŽzŒµQ£‰¼ÐlÒG=Æ5£ÌÎ9Us÷˜ÍSgsóÔMžÖÁÛissó´™¹y:$Æ‚•)½œn!6‚å)6òŸ1ÅFNÃÄFb÷×÷µD*k‰t+² N" <ÙžödÛu²åi¥27*Çâ¬ó#‰ê8§rgƶ¼cµHõâì8H›ã!-N‡×ï;NG4…ZÖÂÏ×V¨Z–κâÛê~ ˆí}¹)KÁ•[ 3ÛNäÙ\H·sö:]¥×³Í}lr)Èåºb#Ý­£8Ûýûu Ò(ïØYÞŸc$®f¯ïóå-•O";cUVÄÌüñß4›g›LYªûÜgÍQ2¶ÅOBˆóÕ›K±)l+A…âÆ«Bƒ„WD…gÜ<»™­Á’2Z‡-ùñóJ/ƒVOvÆ.²/çóØWé&4§7q<47‡VßTV—ûábvýë:h*á<[¯õ\nò8}âėƾMWløãsOÓ^Ã) äJ©¬ ÄØN¼H¸™`Y@Xè"ŒÍE†w‰µZ)æüªõ¡ÞðØï× X°Ï‹»ù ðc–g‹ë ®¥U›Å[‰¯ÒY^<„IÆØ´Tô’ˆ$–³B&©÷Q°s4[]’HGäLÇ­ÓÓqDé„.Ë52?VöjL²G#*,ù…>ÅÈx±“CjbqCêt²HICˆA0 ö ^^ô¡˜/e)íõ&wÀR€!,H¢yìUTL&‹åâ_Y¾œLâ”äÀ‡år^ÇóPFNÏä"“ó¨iÀç5¼NÜ  ’·y0¤àäÐ;6à”¢[Qa§Û 8CÏÀ*Ƙé¹Wæ^‚—î³.!ýnòí<[ì$ÛjÇo×sµÌÕ-ñ2u5;cŽhÎÍ-‡ØÜdpT¸•« Œùkvù’žÊäWmÁ»·¯Þ}÷—ú={Ô+ß®²)YdM'%'CØVyÏYØiR (¢“<†úpÛ€}’d6ž_®ÁŽQŒÒŒð"—Á¨«^¿J¸ •ÜYrÓò]4A¨ª—^ËÁÜ:@D žâÙä÷¬9M¥oY’Ãä°ZûÒ¹yYñçË&\{ý /`y·™,?Nòtq“%‡“¬’ß,¦Ùod ð…Çg_>¥›ÁîÇ»„ +Ë Bî`<8!ù"92kFÇÜ4(£× M4h UÈpÞ«BµÌ+Ô«ÂúªÐ€ÅnªÂ¶2©Âj­VHÔ8µšåµvú´-Ø­^3ÕÓL5½¹LQô÷JJ%(r¢óþtLMiñØEÕ0eõäèÆ§rÕÒïgRa œûQ«€ž0IËÛÈ«sÏ:äðÓDîG8‰èÀRH…bÛ+e"|¥·¿°$¼:ñÑíÃž× ¼†1Ôs›Èm+]ç7Bþmr<ö gN5½íù­œgzÛ}vôß&·MàžmÒÙbÝûØ·åÉà÷ wg¨«†"bòŽy3Ìhì¢K£Eˆû5Q»Çž‹þFR+7’xL÷Öbɲ›7“öJwëv.Õ 6„‡ˆë^|(œ;»)@$&Û12™¬iR_ÐR {pè­qÊ]÷9ÖæCîºÏ±öpÆ5`±›Gܶ*Ÿp«´eyê|²íNÆWÜ0Ír¶ >l3çÁKª¶3õtN¬MÍ+4–¿½ÞêõV¯·‚xf+ûë).Ƙ‹‰5o°gƒe¯˜jÁl.36®\y°ö Q>2AÒ^BA—¬ù²Þ7˜9àk4;ÿå¸O©w3°<5¯9©yÍ8LóÖ<͹ H™ep~©Æ^©=ú íâ!DìL7ìRj„Áëå”6¡Ü'ÌdÑj¢ÜfBh1að)šL蛳Ôï)Ôo‹r>Uëž§Ê ®žÛöŽ{Ún5R^u£f#jõÊKl#NÑ\ÄëøÇnf†{g‚Üt=]oâtÄ‘­ˆ1ÔGD“™`%¢ãr­|EBþ­$,–ªl·é{«Ç|lé7.ˆÜW;6Ǩ}©\’±¶A6ï”gQ}ÃÚ›ÌóÖÂLœOïD²°‰J19óN\y>ÊÅ®7nÁuxù„M”)”õ¥`å=Ѫ ¯ô¾œÞ—“þýŽÒדßf“ßæ$Œßæ)@8l*ìé)sbv4(ÏÎOKggùGiGO"…#Eå@©€«ƒ3ZFz´´í;(ÖÀg¾5·òpÈéájMQ×Ý®uñÛ® aÍm„–þð/þ1R¢+Í"]g±®»ûø Tå´¡°ƒìho>jiÃ1zn¹á$bfµgSÄÑ•É^Š9JN5â˜z]<4’j£77‡ì>ûZÉæ3qùãGê8!1jÛ+¡ß—¦áÆ,8õ.Xg‹i FA <¯š—:´#67G¢Õ6óÚ«PÿÝÌqJõPö½3ÕÀüBXëí/‘¹0Râ’ÌÄô"l†‰ÝƽŒ]V·é¯Ùdy·YÝmŠ›v‚Õ… 7b;äL³c„nÕÅ¿gϦÙú:Ÿ­àLÃcÁ½üî— ÿüŸ-¦=÷»úJÓž÷%O @IÌœɼç{Žïó=Tüyr]\šn òÞPH<~ ß‚ P¢»XeÂÞ>%Bo”åAìfAÞº]ÐYp=ÏÒHK÷4®lðÐóµÈ×)16ågLµmûÐnÀzÙVí Ï@Q„¼®¿äðFM¿qÍú¬¯[÷Ì(2£ˆœˆŠ e£ŸÆÌSŽVQàÝQg‹/ó [‘oêD&íÔf°:úRZ¡º7Iê(‹p“ú¨¯ÒÁˆP‘É¡¢Ú.úª%üu±^I ¤†ÒÔ¥ —aPjŠ»´UU£­óz¢® q½¼[DzÓ¶W1hsz£<Õ"ÔDg@wLÑh°ØEEÓ(&Ec`Â"·×EÆcO÷J@2'1¢ku¤®( Sd´ÖQRýÁf‡6Æ|VômqíÞè;D„ೈ[hKö†Éï¿'ðPÖˆEŸ®ŠÐÇ€gVA¡b:ÉæëŒ^ÍW>¹zaÃØg˜/'PÞOïé-•µÍÆ<`LúÏR(L¢wðרãv}—}¸Ð<ˆqïFqýr]QEÔ©¹h~¸ˆ¿Œ-”¿ð®–,Ôaú%‹ë(=åŠËÚ°/TÜëÄ^'ö:1ˆNÌM5–uÄ;nH¼ã‚x«k{B—CãnïØL¼ã¨ˆ·ÉnÔ3èF…AÿoŪëË!ïq9d½JsDY&§´4¯N,;IeÀ@Íh3Ñšà¦zRÃ䬘äXÄY<˜9•oÞ=2Š¡ª¶˜0²çõ´{¾¶ák;,YU ÷†§0e_¸\´fâ/YŽÖ ð¶¤\ÂYÞF¦ÛéDS©s~ÖZeÍ>Îb½»Ó霋ƒ˜»nMûRf"róa :“j¡F_3-Z€Ä"£ÉP_IݹWuÇ|ù%Ë'–w½z‹T½q;Ôk9•pãÔ+»ºÊΈÅ.ê¼ö²P}¼˜í5`Tð^¹ì5`ÄÛ¡^ªD ^ÖÕ€F,vQ¶…äÅl¯ãЀøÕr¿šˆ”_;ÅHDt¦‚@i¯Þ\Š×ÛCèO©šRǦI)¬Øñì&Ïnfk°ä†ÌƒaK¬ü¼€ôÀË`c…¥“†¹E@XœÏg`ƒ^¥›t°€Ëm‚¼;Tv׺üa9}³ø¸ ZlÄÉT¥Î†Í륭³8>S˜5ÚR”4\¥:„(²qÕs ^t ‰Í…‹‰l)mSÉBŠŸŸT.±v³À 7‹Å2j è ®h&(ý4— ‡ XGjJò+I î§6ºª2©ÃlÊb§´I‚¥TÞÂ’¤¡~nužŠ<*sOÊB‹Ìä½J+a×£ Öœ¸BŸâËÐÛ ‘=¸HÒË:á¡ÜxÔ ò†éòa¾0cÔ|÷«†¤K:_XH õ sc²X.þ•åà_1ñþVšÚ©²Ÿ,Ë# ×Ö¨jaË»¨}ŽSyzVÓ˜PAÉÅm÷´ãÐçè9ñY #ûʆú®ñ !ã2à<[ìÿ©†nØJRÆÕ¾r&>6ÆÔ³$&ìFÙrI†lX>8P»&Sªùê3t³`ÆJJïðÍ#¥ vèÆ‘’½G¢;ÄÓ[?¥bprSñEƒH:œèÑ \®Dš2kà!úš$ÅÒS¾½£og 0ÂÅéJ‘q”l²Û•5ÑHïòý!¹Øõ“~Wl-žåïQ«Ô ‘ÈÞw¦9 ”Ö&-Öq™k±k†š'2Áî+0¿ÏêBÀC¯4\”†uS!€Ùbí1à¤y…VÙ¢sà&ÛÌŒ]Ð8ÓÙGBºuÔÎj“ÃÀÁÐH¡y²ëå4«¯{*©°¡^bÛ³ßj©@C$Þ F6$ÈÛ £0ªœ ¡©°ƒ_vÀy¡&†ìäµÄ]\=¨‡LrŠn+&=0,lòûB§Wùv ¹Tíß)$+ÜV@«×ŸðKË»Ídùq’§‹›,9œd•³˜f¿µ9€/<>ûò)Ý †lt•øÖuà1Èm¢«á}¿Âæi/ÊšN{÷U`÷Õt¿}WÓÞqåè¸Ra¬cG0ì̉C벚nÕ_5­¯Ó¼×aµÁò>kŠ‚^¸h-Ö:¦<ñóZŠåö5ƒâÒG˜V3žîdˆW2BµfZþ¾¥Ü+ö=L/UPRßh ÷ä[¿áƒ%NyZ¡º'[J©¼'·Ê3vOÛÓhÜ-oˆB¾8)1$L×»O\U—Ÿ{Ej·Ðnr‡\;¡rå¥ízW†4SwíÆRižW­OÌbÎqgqè©ú(¦"è'aŠ ?2ûš««´)¤z°òHìö ºì²l¸§´ôòS›Ë•Ôzw,œ\”¢²´ª¢th†ŠÒMD“ªÑUÀ+*ün«ž/¿ºFõ|Ë)ÊÙ¦â¾¦å ¶Ï%½sy]¶eà ²¹Éé³Ýëû™1ŽA$"+¥eؤ…?>ôYRTê;Ã_!¯kÀQö“óäÑ1žË!êŽðFÆõÖ@ú¶¸Ýo"²pYp°ÁÇšüþ{òePô vHCCEÞXK—¢ðwGXõäêE»žan›@‰<½_¤·TŒÖîl€‘÷ü!½g'(îZï*þúñÙ $Š»èÍ@}ù9Ú ¨¾ê,Šñt{¥0ø…´{õÕ“>©~nPïè_Ë/Œk)*ñû‘»3j0ôç¨×c½‹QŒöz,=†ä—’XGzb7$ÖqA¬ãöˆu¼sÄ:6ë82b­¹nFר0ºàã-Y^žnÙŸÆtË~æ–=ÓWº@^qyÿ¤ty¿Èú¡÷õ+ç,Ï*]\×dj—®®Ó²ªûûÝD¿Þ>§gËMÒé8'Çzñ Z䟒˜<‚å)ÑI©h…™NÆ=ì"Ø!¨E#Ÿ(Ú2’Th²a(EÍ‚¥dÖj»Šˆ¸b¿uD°Åc™ÈØp<º}¾Æ9®ž¦fU’³¸"µNœo æepKö9ÒƒàÛAG¾¼QJ—Bæ¾’—Òá÷1ëo¾ü’å“Ë»^åD¦r¸ÙgÍã¡W@Õ Èˆ¯Né¡àRG¼HíµR-­t·ZõZ)J­ÄíÌ>k% ½VªÖJF|uJ+‡$VâEj¯•êÅgÿy—ÎqÆ^+9k%¸}ˆõ~Éaúœô*å:Ú¶tµ¢ž´·³û¬Õx4ôZÍ¢<’ _ÒjÁ! ¤Õx‘ÜL«ÑÌ ØøWúÍe¶JçvÀž>~zìGú‘}œ¾|òq–¯7DkÖÓ› ŸD ú:ÃO›ÃîÙh˜-Ö@rÅo/ð]ÞvÀbÀ¥í›ÚxóöÙ$ è­jk@‡*×ÞŽ[6‚áhh{O–,"g5F@yY]3ˆ@ó­ìá›6 ŸuIïpÍíQûâŽgªÎe[×¾í´BU _½¹„X›ÉØØº6+uä yË€«O>»É³›Ù¬·!K eØ#?ï ,ð2ØRañdoá NÏç3°1¯ÒM:D~â$hAªå=ø£ºGâùå&Ÿ-n‚Ö<'¹Ïx¦RËX_õTŠá™Ž­Ó;–ŒÓ@ò”:&˜ÞT™vÍ冈Ð÷ÈlË„±åB­Û,òJä©)碤5¹Ë+ýe00-/X“WBc*²+‹öK ª™¤afe8ã¦$i4{W.ÔƒÀ­ÍSÝ'奃² "ó#Ùc¯¨J¸õn7Õ¦«àþè.FRA î6Rµ¼PîùpÍÝé$k‡W:[¤æ5ÄXÐïÂ:$†MYÏ ?™,–‹eùr2‰‡ç·Ó°T’=dUúZÜZ» }%Ï¢¾¥åéXI\B¹s%ó¶ÞÏ´@9œ£g@{É}ôN±!ßîñÝ<[ì Û)F~Ö°°„¨½äG y\ì¨eDLÏMø°íÆtý04/Û‘•ÜÄ|R§B£놊 UŽŸQ ø[>_b`è¯GàÐ }’ Rõ‚—k° o4ú ÞåŠHˆxëàõ’p5Bó>+ã¸xR Ä"·*†)PLKo DR'œ£á‚:¤q òœ\y‰“D†TœÑC[*Ô³›t¶XÇdVlW–Õ<æGÕ½pz1ç[̙ѻMag{ã$O…Üâë&ÛÌ6ÙmôÒq:ûHauD$Ø=8°™MŒØ3Ùõršy¹§ã e,Ûš=±¢8ð1‚!òóçt>a´E%($1nðËØ!/ÔÄ•ˆ”ØŠ«júÉHñèiÜg†ƒM~Oà­>,²¨òÀ\S¸£€H¯?áw–w›Éò#¾+N²Jl¿YL³ßHè}_x|öåSº ÙèZ‰M5§€ "¦òp>íOæ NæÓ=>–Oû3y€3¹ «1ȧ[=Ogëë4ïEW}ÑE0¸·â‹Âß‹0ß"L‹ÙÅ•#í‹2EpÈnlùÕËÒ“t‚¢V²æ^eb*v7Äv³{2ö0•ÃE\I )[$ >>Ã4Y@êðá«€é»p”=d8vdüfÃiˆ¨#LѽžgiDCÛ©y!B¿‡\„áÞ²œÖãÁ$Ø~$iý%]ÅCùº7c(¯fËX¼zÈÝÛ~û·¢Ê ù@°¹Ч™‘kaj½Nš÷§%ÑJä0„-z†jÝ!®ØA6fÉÛ¬(6'om-Né¡Mü™µÐÞW­i eOLÎ #×”Iøj°fß×—}n+ÕDb(SÔñ‚Ú†ªä’[s·³£2¸3‚;£á!ýŽgÑåÝ"dýã^/Xé´ {«0ôQx˜:§4¸ëšv †I;Øx±”ìU‡ :>d7³E<ªÃРAO¶g"–öÐ݉áÞ¾CF´1Ímš¥ Ÿèzf1›<¦J!‘2pQ dŸØ7‚ åÜbÚ³.Ý |çÕožŽZg/\œï«ÎãTÄy«š¸DJñ²õŽ«d¿L½Ÿº9Q9ç-jçî°3~kçÂY}7+Ãfêt{V]¦È†h)¢³m=ÌfÌ…@ß×vàUCD1* Î5ô‹C7oñPÖèDŸŠË¶a"q¬rQª%›¯3zýNôäê…™OÏ0›M žÞ/Ò[*;ëŽv6À˜+×xüÂûK©øëÇg7 îr û7zo‚+^ì<Öê»Ê¢äN·W|_H«7X½¨ÊÇÆ5þ…±ü¸–j¿¹«,£ÎBŽzÍÕk®¸dg¯¹âÐ\Hl) u¤'ÔqCB„:nPÇ»E¨c3¡Ž##ÔzØw2±F…‰ÿoÉÎòtUþ4¦«òã0W噚êÎ5p½=HíaY²"8Nþ¡®N²•0,Ú-´&¸k…Î0y °¹eìH×ä5>¬ÒEyšc£*ÐA1Öþb@3„™*窇sEYÎÇÝÃyÏ—f¾´ÃO%†F>1´]©°dÃKŠB7É\ÕvéqÅ^‹`ãÆ.±ÑhtëüŒr\9GÍB"g1…Y;—õÞ zËy¼à&ìmß_…rKvW#­k¹îA¡H«/B!á×<™½ Iw‘§ÐÏ—_²|òay×k£­k#n/öV)ñ8èu“›n2â®k*ª `,4/{…º[­z…‰Ââöboƒ^a¹),#°ÚÆBañò±WX(¬ìŸwé·•ë–‚€Xñ—¶Î‰è[¥³\ÓEÐÎY‹ú:4ÒwÜVî­¾ãqÐë;Ç:J&ÜuMßµŒ…¾ãÅk#}GSO€à_é7—Ùè£Û{úøé±íèC¦qŠôÉÇY¾ÞuZO¡V~)àë >myä¶Äl±º$r3‚ë‚ØYC×»oj/àíÚ[S€ß[ nV‚mŽí#0‚Cba‘©6 þöÞ®¹m뼟Oáä"+çqïF¢z.ܳÞÚéôü7Só$½›®ÎÍþKÅØŒ£jYÒRrÜžéþîK¼H< òDMU¦mK$pp^~çõwŒ p=åoBp@q[ÈÅ…ëmp‹ŽØ*³¯ªî8Ø*÷sBeûx¦ HüüöÝÇŒ¥=[¼*)¶xµKû|ö0óη÷ir¿=eËí( tP>ßû2ã©ìËÙJ‹ç'KúO2éÿq·ÍŽåm|Ž>8O~]@çêüiT1¿–47>”Ì·ìor-µ¬g¿¬i‘ê +t4ÄEYz\ØùBkñ÷S-çž…ê1F· C …Êë…i)ÅáÛ(*Å×5S\Ôç|IˆÆRmÞ*d"6·Æ·¸¯5[Äf#/¥bWd£â¦¬8¢ÍfØÿ;I› 6äÂAa&/§â^ÛŠj‹ÙÔp¥êÅSdb[ICŽ•ÂÛ÷}„ùÉ;‚VQeÒÇ7:NÑã¼;J¹Û%û‰‰úáÝ®n¸®Rl"Éö‰Q"M²Èø¹£(ö|S¨@ôûä|Úmo|2©«»í›fÂK£ `_° •yäÙI|‹w«â3Éíá.Y©?ÉŸŠ5ˆíø'ÕNM½Ó*‡:?JÉ+žÆHaÕLÂÆQ¸Õóñ|Ö¯ñnSp`žÑ"ìª"û²yøÚH™jSaÈNþ‘$PÞo) yÔnÅi Ù.jM8åTœ„‹:Ž‘âœ>óm !k-dµ‚%*B>å¨"4Ù#o¿²×Ï›ÃVtñj“4Ê»ý]ò;Ou.Ⱦ»yúŸ—ª§óTè¦8 ÈÄdªú ŽÂWÖš²ÏÐÖ©8E¯—‚\áW´ƒ§¹Â‚S€fX`"P€- ‡˜,»Â&ÌÈÂ{˜)h²·~n@moíhöÕµ]áªKs;vP«³äòï£nâé¿Q0ôÁÐC?UC_yKEËë±[„ ÊÂm¢'Å©’DÛ4Tl¯m+¶×­Oi 8%ãV+ä|ƒÜ õÝ-ñ䲂'¯ìN,_Ï*+§×RåôÚŒ[-ŸÐß:ý=¦ÑÙk?£³Ûèµ™.yóÿWŒC–MrœOÞ%|S «_9qµ>Ƶü/ØÛWõ·Þ_®0JÖ?µ˜(+2Á:0v&0œFÔù4ÀkT¯Í‚E•CÛåÝ〬ÜD§9È -Ù, Ô¾~N1õ¸ç(?BVÖÔ…ÓʰD¨R™G6©<ê™e“„‡ “-B©%á0™`Þ¿` BÉQ)£éöœ{Däë¿>Jseu<š"ãbµîkŒK…å¸tXÔ„²±êRÀ[M#¡ƒ¦c*0Ò­U¼š)$±‡Ib{C‰®2É"Í£2Éœ¯ŠN†–l2âKÐðÏ>º >Ó1£|iòœÑb½‹×¾'ˆ ¶Ü«WŸˆíb×õfˆ]¬Ö=ÄV Û=ŠÑ™Éè´«‘õÕè6ÄdÛ÷Ày(BБ¥ôÐAs‹tßМí8ÿ¬éÖV¡®rkë¸J°ÜÞÚÿŽ\•û¬ÄrŸ| CTñ¨Ü«‘ÖØ8rÅÖ˜\±(¸b>\±zɆ•+6¢‘DÈgØÒÊÉHÀ@ËyCÍ6dÜЈ¸_»öFË”ÌÁÓ÷™¯lÎ|Ø™=¾|ý“Î×ï4ï¦Ó›íâÚQ?u4×!çw<±…¼Üò&-ípÍ[F®É_ñFöˆÂmWd†ôžaä8¿¾ oòÆcî&>“ý6iÆËH›MÓ_Óéñƒ*A 0JÏ$ÝÎ7‹B#ÀR+5ˆã±>S@je2…útăFùPÅ¢úØ WBJ¯ò¹Â£ñ&e¨Is}sh%ÅpV-¢@ú'€”ú>y\îòõ¤ÙÛÕ$]‹K~©P‡ÆÒŽì Ù÷5KZ¨±÷Þÿ÷?}rÞû¯8辋îj&jQÝ2ЙƒÔ(»ˆGÐç¼¼¨õ9¿i°%vMjC,Q¥[½ÛÆÃïê9 Ö¢›¢1—ˆ1£¢¹ z`m¤4BKÉ-[˜1ýì|“äáx~Ææšt 4|>vB ”$“&°]"*Ó-9ÁKØ•ðßÝ0V‹>õûÉÓd§ŸrˆWŸ$î&%T:Ïe(»ïÈS&/pt“(å (i”© ‚ÆxA5žÁö+lO1ºP¹áû–µòCµ²º^Gì*Ï$°F·Š"¬&ÆËdš.9MW‘«ž 6•u Á65AaÑ)Ñ»Èsæ/èέ¥íƒj.ÍÅÞš Xœl‘+`¢è á3ÇJösr¿ÝcÓ²^ Í6;!"( %×ä! Û%MÉÑ ư =Ä¿%›ÃãùøxÞä, c‡Ùæ•€v®XTŒ¾àcöïÏÏïøÇ®¯ï’Ómº=’×\^I„ŸÞûa„9H¼\¦§+¾h²‡5á%¬D·Ýt>æ7M2‰:%'RœÎç˜ qÚ·%®q^±ž‹Iv+Ôs°Í)^ãœökÇ#η»$N'%ÏöÂIi0yéd»D!ž¹T2æë?0tŸ-·8I1?Ñ'4„ø)%m)?MAJ‹&ÑpòÂ#ïvÌ1™÷!&q¡¯q8‹fTml¤üMÑ@**[T ÐÃe:Š‚ºž†kˆijÊ!ô£,3ù-Þ-åémQ®×òºbeLÒhÇÏ·r @6¢’`#½ü ^ÊÝ„“¨ÍE U|¹åaÒ‰UÙmS^†¶ẕ±>Ž›Ïñío“²Óöö6'ÃäMm±QTPµàÂþÑjö¢=Þá2_ãSK7äåÌŒæ3©á›E!oªéJ%hèw´’Ž.Ð%=nÏSªà¹¶‚­o1LqE’ƧÑ)¥"g©“±º‹×äaŠú¶6ÊCZXÌ “£š‰.c{E¡ÊŒ…pTN€ù+ÊPÙÞ¡á‹7Ú ¸‹?þ¸xÁ&*ý rCІ¼P˜ó³ “Ý)É;±ûÞüò·Fá¸a²¸!®ÔÝó>~ÈÕj‡Þ, øKÞØÄ^Q¶6q5Î~Íâ*·išQdÁ¿%mõ1”£^ Ÿô¤í”•5, ºµ5ã8škêÆòÉÈ£Õ!ª~!r: Õ‡=6ä©Oq f9˜å`–;™åHÍ´+=ÓF™6*™6êi¡shÇÆ´‘™i#dLÛúZcIáVCòOeP†É½Ó™Ü«‡¶9Ì—W\Õüq>°T§ü­t±…dèÙÐ5‘3r«//^d-'žB§ËÞç´æ¦hd ‰‰´rI¤ÁÉd3 X¶¸cLWìzü/3¨M$‡Íã…=K;‚W|™Ýà]EyR4dyRó¨>y˜ žÉálNÇ%PÊ(uz%TB5TB±ÝåŸÂ;ŠÓLÅ1Íáìo'qmg÷º·+È¥ž€á笡îí»œoòH¸K9{µ‚ºªOZªü”\ (/²àƤðZ¤[,œR߈²iŠû#T.—r+˜\®¦}* 2øÖÑž¬ù‘¥þ‘ÆëFüs%Ew‰¨¸J×ûÕæ2ð[6€×‰%à-·OëéB‘ÇÓW”ÅßÖ®Î."(ˆ=“R±r¿(òÒcñ ô“'Ô÷~êþPÑcPh;GîÍî&(¨ÿ%³êgljÞ÷íQ­Ûïd²M¾'ˆíeÛ-ä”3‡ÚžËÄÀ0±6×öš+¡^çék³(·›§ˆˆá—ÐY4íu‚Qc’OCàÐâg.ì=ºký@§ª¬ýuÕPXÔw÷»tÅ`L¼Žè¬ê„ù–Q8d˜Zutºî´F:§uÕà´F¶NkÔ‚ÐrGTk›á Wá®r{Cë5mVMqg³ÃIîfÔÂaÕ?¡C[þhš|‚Ùm4»ŠÞÿ©›Ý0`\Fgvu„¥Ùíc3z³›–SækvC+ÄtZ!ÊŠ‚ÆB‰eµPP¸W3C RyÜÒ´: £usqÊJ_œx³M |¹¡ž-ÙuÉ ×¥ŽJG Oë§td»?ex|üŠeâjÅW‘6qÙ&®|¢@}â*j™¸Š,Wk-œŽàôÚN¯[r=%8ír3wpˆ¢«ã¿ÔPzÝ6ƒµ–àæº`Õ?¡ `u”ÁúSkí'ƒ…>«æ65Îm”ÿ©8ïù‘+×+GÏ•"¯4&DWõ„(ˆ1ÿ4²h³`D&Á­@ýfxhң⮥JÙò]§J¹Ñnb>Ëܦÿ÷öœuÍø.I¿%c‰Âþ’*Bì™´ëç»E¢BV¤ª&ÌÐUªBÅ"U ñ UÝÆÇøv{~Ʀ“¼t®–ç`_,q]#ÙäÛV‹¢l]¶¤ nhKåºI–efÄÊ4¡;ácaÕ¹ñ‹Xœ*DJ˜¤œîÛwå{²}ˆWuã(,v¹[ú7A…‚!>lšÜoOÙŠ;J]”÷Ä÷¾Ìø(ûrv¬Òâùù’¤ÉûäéÇÝ6;œ·ñ9^tç6ùyôÝU«äþ³qåÏÏÿ¿Äg=ç.9TúÄ•½~ˆeÐGxM¡ñ[ÜÁ^’¦ƒ~© 8%”öЍ‹Lièr§ÝUFe+0Q=¯ZN"Ù½`j i­éúY¹YßÕ˜Õ4ÿBÇyåœ]õ'8Ñ,—&dÜÞAŸ-£ä;IáTX²¦…èÏÇx+($ºLQ=õrq½ ¬Š.ÚJw¦Ò|M_åã …µ:rU”aèºÎãï§J nèÔv´ü³£oWGE˜ŽÒ±Ž’Ò=C§«”¬rIh™=IÊßʉä\Њ²3­”-&Ò’*JDÔΕÈf³?ìÿ¤‡Í¯é¤!>»6ñ 5‘‚ø«Å_$Q' Ð"æa©C¤^” #›J}„¼V‘PÎô ‘Î…¼%·I¸…‚dë$›Óg*bÍbÌ2½Kö“iÃ:f ê$ 2¯“yFÜ"v&).d½ç$‡t÷É9sB0˼QlKž1\[`\cöûcr×m.oEÇÇæ¼ˆbbÚ¦$²èÛcþW¼×&@©©,Úh”ÚÁz ÚV\»Dáœ>÷obßmryñ b«J-OMÊ…UQÞÉóíW¶ˆÃãysø²Iãý}rñj“4Êæ»ý]ò;?ŒùÂw7O_ãóâ²xºÖ æŒ AóR‰©²çËÚç…@jêiVé%¡‚ìn Ô³ìo[& ±t¥ÖÅiéFpµ‘pò_ãÓ&;³`ÁºX°–‘dÉ ñƒÆÌ¤~s"¡Œ-Мié9^SÖ×–êfÌ:ë^p„Ñdì:$ЩŒH'¼ªSÆ¢ºBûZË BZB­(m9@¥Æ(Ù 7¨8(3%qžH Í˜A RÈ(äP-‡œ:ÓD.}Ë"ñƒ( o‚$ê«n¦"ˆL"ú–à 9Ãs¼ÝŸB`øŠx!ŒbŽb ”B¦FE1“s¼¡”^÷å ž"©ã™ÇKB‡]l_^"ÅÞÔF`¦Üé% ]<½n/6+¨•>ÕŠLó X !¥)«–ŠèMP¹l6§¼€Ñë Ù8Ô-=èS¨:‡9ЧPuîÐ6PsÌîsÛª{Ïw¹®s­½æqU»Õ·ìçZ¦ÁÌ ¼¯ ûšåÍœëÔÜ`ƒ²hîî× v-Ø5`6v ÎÃ^{ %˜òÞ#ˆGÏ îwÆmVëÖºñ7àÓ…™#ê,ðtGf÷7uÀnŽn(Zcº¡(òsCQqc õ]0*IeW5T†.Ön‰¡?`S~ˆŠ`Û;^ Ó|5ÉR5Iãµ$õ+I¤ëHÂVŠ[IôWõ´¿@*Oy<®pjp2-nrêûzõÊ;ÝR£3ò¢ ·†Šiœ¿ãÊŸØ_F#:>ÝmoÏxƒxj8¥BîKÀ9u9ë-«8¹PôRÆ©œÞÞo4°pT‡«+DÂÉ€í0=À0«!4xMCc®¸8ë¿ðÑý×"&ÔÓÛ„ˆÓ²Ù¹2…š–¶¡&WWÛMˆ*õ² .@Ê"ÓnÚÐÃ;¹[ ”Ÿ¥ðY¶-éŸÐBO; ­0…Š–~BEoòHŽ­'UÚê³–æ¸F¯±7€_Þ´ J4ïJ»QÅlö6Ò˜M3yVzòô³×ç%V‘ýÞ|Ōݣ,?±&]ÂÉÃÑÓ½“ÃGÌu§ä !uÈåžJËÅìæïn˜H ØNÆDÕ¨]Mk'Ï ’¬–dJä‚l#ÂTVPŽa?=eF­7=ɲŒ½üЪú¡>n¡¯=T²U¡¾ìÁJ}(K~(«!"!úYÙˆ¹jP}"uuÚ{FW«ìZæ|í\ù´ã&V²¾ÈQÁÐJvçàsr¿Ýãµþp\ÞµÖÆQú§;F|ZœC8.€L áoB{ˆK6‡Çóññ\ö>JØÁ?û½ Þ%¼ªóúú.9ݦÛ#y×å•üþðé½Ýìï‚fh«Ùß½ ‰Ôd¤Á®óPÓ élCšd‚z*ÛÝ;ª‡4 ƒ†HÇÒA°C1ë‹™‚×Ú"  ½®œHÀcÒ·»$F<¼©“¢h#ð”AâÕψƒLäsIgœ[uqp•%¢ªh4øSJ:_ò$ûúØnöX"uSµ˜ÊDšP>W4ˆU_4Ôé L‹ ¬m½üuÑÐ+ªs-٦ߑkÉ0K¶fÑ?¡ËM{+d‘äÀB6Ûð¤$BXØîò¿Žbr†ŽãYÓφbà ó<ÜMb4‚Šî禩åàº&ôÚn{Ä]ÑÁIŒ‘Ñ{¦$B ÇGh’4Ô¯IêgC&“dãŠ1ÅìÀ™ëHÑ"|MylºÔSÍÉÃÕ¿m Zp–fä,kéo˶hÒaùŠ2Z¶O@†…wŽªLÕÅ\¼`˜þôKF&ú£wª¸ß€’œPü"Ù’|´‚bû›_þø&¯bîž÷ñC®»>õfÁhZböžÒ¼rûÄ~Í"~·if=Ï‹¼ÇTÜæÎ¥l‹=5N¼‘íFl¾ØÁoVC\Ê cM¼˜0ðÇ#Oÿ…¨ú…ÁÐìºí 㲃 4XÐÞ-h*Œñ–™y¥gæ¨#3G%3G}2³ÕÀìñ2sdfæ3w;—¶ppUÂAòO4& Ó¶g>m[_sx/o³ª­ã|â³Na[éëb IiÓ¥k"ëAm]^¼ 3²ZL —<«ùàÓd(,ãÛå˜0¸=H:PÒatj¤ÔÊ%¥pÐÊnT¾ŒwÆ1$Ÿ®ÙËÈ9†¶ìRlNŸž¯Ÿ§šì‹ïn=ÖîËsÔè«G:4YIFrL!7gòD)…Ùæò¿Ž¢hDMÆñÖŒô²@#Õ³îŠAÆÔé¾ewxJÒÍçÃc0…#0…Âi‹hRå"¡‚aìjÔ¯}ìs[3)ªâ`-QZËGÒܬåH¬¥pZÁZšô»H¨`-»ZK#5Çk-ûÜÀZŠª8XK<Ö’}U}§2CÙÏø˜AF5˜Bâ¼·ï>Êc|Ø¥:½™¤Úmc>‹l¤qÙÛû4¹ßž²…w*º(‹ï}™±böåì¥åóÓ&uS™"ùq·Íêm|Ž1¬¼º`á0ª§ô'ä†8ö–_ùË|¨^!%_äéx8Þ¯Â{ ÛîNO‰B”\m0JíN·l™ÒdvWAÊ Á´æþ/ÍŒýeãJ»ÜŽémýf%Zã_Íl33jîÐ,?²0_¸æùöLú›o™ˆÒÊ/%ª¦nJÎúu}Ýs\ÓŒBöû~­«È&žª©Ç< "¬ÖÑReÍO]Ãò÷Se 7ÉZªû–#a÷b&º·À¨"g¶©¿ô¬’/Õõå¿ÿœB–cs«a …š­&QÒšúhVÁq›ýaÿï$=l6˜ÖP7\j‰ôL¿zF$}7UÓuH @áÐÛ4êE>… Ð߰éüR¨r.WsSC¢TUÜÍY=Iò® n ê†Q*èš¾u §û„ —¹i™]²Ÿ°’qqŽÝo VÒ<¨«¾Õ#;vmÒSLj{USý_s\=¿ûäœyš¸Õ•ƒ¶ü¦ÍfȬÿ;¾Ÿ–É¥-ÂoÙNШ:Zº¸Öˆ ‚,¨Ú\?ÓIÛ Y?4*ÔËÎé3§ˆ)_ÕYi^^¼Á‚ÒBÒHlÁîõŠ&²øìÅ·_ÙrçÍáË&÷÷ÉÅ«MÒ¨+Þíï’ßù)/Ⱦ»yúŸ—ÅÓ+@‚E—¿dH¢!¬i³x-¢ œÕM ~ΞÐK¯è¥¶(Ž+`‹a°Ey[¸ÃªÎ[ ¤‚ [€li_ÐÙþz¹ãH¬ö×ø´ÉŽ.Xìž,vËœÂ€ó“ Æ{ãi¨u´æ[K×Ù˜nt¨›mû´cne܇óM( C2r$Ö;£é ³éî”Ù¬®Ñ¾_I¯•ì×TRš£spKV²D“Q‰SæKPç)=øØ— îâÎ(¾_çTŸŒÈs¹FèIÀ#ȼ]ÿÇCùþ›?&$ñLè†ø 9ûs¼ÝŸBm„Q9ñøBhn˜¼špèTÒh#sf²Î&<‡“ .bt’á ¡5BôÐÁ=D·Hùä{ÖM¼“[’ëxªÝÜ4fô× úK¦}Ð`D'®Ã*Ò=Y-¶Ùœòro¯sÆBHÄqiñ)´- 9…¶%UgAH…züð¨[ë¸Çk~ë_ÎÖ¬ºy¸ÔÊ–=?rf¶ùŸ"]þýÊÞÒ[˜zúï*ü`ðƒÁ¿ƒÏ¨aý¶œí¿(ð-ÑÎâÍÕD÷50ld˰QW†¼•hùF³‚Cƒö-puàf@¬Wö\-~?[+òs‘ô¹È ü¶|Sg˜.ÀsvÙ·ŽoN|\QöË[òÅäÞôõÿÌèËÎë !þò·¶[R¸ùñkrûÅ‚U8GÞ’=üéâÿ(ÞµùW²¿?e߸¸fþ¹ |±ÝR÷€þÇß."zÇ:ûoò¤LR¶Ûÿú¯œ¡è‚·[²â|%ÿã§_6ï~ùé¿0Ýn "ëe‹ùß/VùrÞ|û¡øï”Þ'/ªiúŠ7ÿóÊÅ@ ö·ÊöÚèÏi–¢צ &ûßë×—‹âyz‹=ƒÖäÄ>žãsB¯²/Mx½|I⢔YÊðßHoj|—ê2ûêUöÍ‘^ŵöòeöâ±GáØQ»áVÅXP ²"ÀšT«²gÇ¥Šs†¬2faOèW?&gjÿþûDn€úé÷ÛÍûÃùÝC¦Ñ"Iî˜q|ù)=d[Ü?>|NÒ‹L]R$‘ᔺœ¨=dNóîß%w_÷·ÄØ^ü/¦õÿ/ÿëÿ»IW÷2Sö‡L×Þ%?þo?þ×]ÓÃù@ÞsÊÞ’\ 4Gp®¯EÛäó_¢ZÍ•7Hö)æÐÞØ…øt·½=cáak` ©ù~£TœêèTmÛ¸ÜõÒ'`¸{«çà};!T_¥=GW"…ûŽÄj ÷8r5ˆ-ª™hÂÄ¿[Ý'Ä.ÇçÈ!Ô1®_ˆä.ë‘Ü7 ‘Ü¥m$×í5{æÙ2cûÜ —|eßCW b~@¸\hl”¡Ò¥*]¶ÊêŸÐÚx9 ²®0Y—~‚¬oòHa#F­„OªO\šãwUg¬ˆá½\’ú¦]¨ º7E¤R¡lØaˆPZ’}¥'{ßñ7Õ*ýÄݲ?˜/{µ|–íçA6±{D+y8žQϤÄq/%SˆbõÅbDG:ø±Òö ±ü^œïn˜Ô!½Ç‹À§Éj7Ù·—x‘§ÝÒ¯n¡4G¯Z¬” •[Ä—nž2XƒX¯4>˲E¬üЪú¡U£žòÐ,FèºÄQ6„ò“q+õq/ùq¯¦3ÓŸõÊî¬!¥ìê³n®ÞŽé•|ÖtÙô8릦×ý¸òlÉ®¬!l‘›9bF }bžLÙçä~»ÇlË:adÒŽN9éSJªhRÕ1µAÍy}ö“ ØL!àæ~M#:F[Æ!3×LB!é"~ˆK6‡Çóññ\Ž{ 2CÛŽ%ᕽ¯èI©fU\_ß%§Ût{$‹º¼’r@>½÷©é’ý]ÐsÃê¹ì‚–ë9ò˜‘¿Ž#²4\W —0׿€Ó$S7§r6’#e—T7€¾KÇëRܸ®&øµ_xxt_@zýk¾q@½3ÖŸÖ»Ý%1êY­Ô^{ DéTP¿*ˆÊU“•ábí÷Ùâ‹›¬Ìj ŠÇf ˆE:› 7úÕ2ñ§UË" =ø,Ôm&mðLñZâå7ÉïA“¢YÅë1m:Ã\ s¦û3íf3]JUÉ Â ¡*i$%=:ÜÉv™ÿuDC,5ôœÍøJdû 7uå 4²b0q±¢Æ;¼Àõ¸#v}{xÜ£ž¬¹okNY XóA¢H”ôH½ÀÑÚt UgcÓ‘íßdÓ­â ÌVËïÆò‹þ<ê .z¨ø£, ê›ÉÈã=Cm`BpÍÇhÌ‘ºæÆŽ!úÛrì™®ñŠ2r¶_@ú—ÏQÙõ‹?þ¸xÁ&4ýé—ŒPôGlÞ{qi"="rBÉî”äãÉÔÚüò7çªŠê™ 1žwÏûø!7E½½þfÁµDtlA%ºáöžýšenÓ ¼œù ‘pdŒrÔÊ©yL¦l‡cóe•}änÅ 3ª!0èç]‘G¢ÿBTýB„æ­:œ WgP@M5Ô jRáÂEYøVzá‹: _T _Ô¿ðù¹+_)|‘Yø"¤Â×c´ö(V¥GAþ‰v+ÂM]á¦.E]k—¨z¿&÷9eÂUÍVœßꤳ\V†«ØÀB²^”Eèš« ©g//^Å­¯"“ÃV—ŽÆy üÀísA…A…ÁÚHÒ•K’ŽŒ¨mî”ç˜n¤+÷3“œá^OE ­#gŸ¡ßå~;G³ÙânÍẇÖS¢œ¥Èb¦5C¤/(åÑe/Ø&󿎨²RMÎÙVâÚ> W‚Z£ &‡oáa¬ÅHê:w‡§$Ý|>< €ˆž7ˆ`‰+Xb¤êlÐ J*@Šh°V™Vy$Æ2`•€UXEà€U†À*â¬â «©:¬‚’ ¬"¬€U¦ŒUØWM· £ƒ)ýÌÕfæƒ%Î~ûî£<’͇½Ö:S] áÒñ©â^´í}šÜoOÙú; /]TLÄ÷¾ÌX=ûrväÒ&øÙ“*äLmý¸Ûfö6>NjɄ¼-Já«§ÿ§Q!“[äÿûG?Z8nþ'[­x-.î¥BrQ¾ç’L¾,¶±ö•B¤ÜøJC'óVôÑûŸ>9ŸÉÕÿÉm @»!ì]qºNìœæ ú4ņ FIy q(¿0œ!øï§a*œâR£f¶òp÷˜Y†_©z/½·ð3Ø; kTð­ò—51ΣgÂ*Ý2¯,­þ~ªàì #¶CÜ\Xiö&Åâò/}…”Ô{†aT%CØàSå4“®Õ§I(ÈC;®8ý>>lh§U!1±ylƒ½%'ËÉÞ!-§Ÿ©ÏÒ‰m6ûÃþßIzØl0j…NòþùpصU×$Y Ñœ„YÜv{yn1½ÐFªÉ7ȰÈâz–“FÑ)eœ‰#o”Ëäq¾D•¼*È©ANæ%¤|Ïã–PÎÙãÏ]²Ÿ têßmL±Bx)ùæ%»lËXE·Ih¿w–YðÜU_r{ŸœO»ím‚Sxõòw·ý²L ã|–™ÕW,F’e¾ y@v0ßâݪøLr{¸KVêOEò§¢Fuc;|L½×z–S íMÛ(0Ÿ`¦eOsÌF È qý ¶äÅ!¿Æ»MÁ›yyadØ—-(ſБVÊʈ$ †Ê–¬RÁJáfQP¥Z WŒ†‘–†‘- £®4TNìiEè# UÎé3§€Œj¥µa´`ÉâúT "TÙƒo¿²×ϛ×Mïï“‹W›¤ñœÞíï’ßyeЂ|á»›§¯ñyq©z:¯Ú'yƒX{¤~ƒ£à[+µ:@pîT¨×‹ÙDñ Q:¡‹S@" ºè@«€.`èÂDC¼è¢ (lÉŒ@‚Ÿ ˆMæÚϽ+£0×í nöõµ]çŒK‹Ï¾vÐ…£òï£ Á%У€VXaÖX¡À µ¯6êeÞÕê»B¯ѬâTH¢˜š´Ö¶MZë®Ç¶[î‡lÅB³WnÍ…†«puY«Wí¢hbÖz>WÙBµ–Z¨Öfhlù„ÎÚÑ(ñï1_û%Þ~¯.ï27ÿÅøcÙ–Çù°[ÂAÕéªú÷•£GësMËÿ‚½}U;àýå `³U›c½VEvXv;$rq àeª—gϯÊiñ2ÐLÖî¥ÓŒ`% —l·_?©˜Ñ;È:4Ÿ±6“y+‡˜áPÇ3Ë$YyòóM’ 4¯´ /XàËDCl/xÔA°!!9æ69–‘v{N&WÊâÐäÚS°ÑTÛLv·¯ÃXòÍ[ÙžTØL¥•š¯è¢Xj𠊾[?~EÿóóGbç…÷ò™Ò¯tPé´w¿­ êÎ…ùš€róhLÀŠHé ·<Áž¥?™o¿…“£ªæ+2R¹Ã¶ÐçuY"Û¨'û¨ŠŸ¥²Ÿv]üÔLLëz¹2g3iºˆ(x¨qëË;)Ò¬By§`š€äðbš b°2©¨^&µj(“Šlˤ Õm:ÒÃb|£ª’f«\…·-’ÒAåQ3 z*‹›"©¸)2Ë'8>( øÖ]Üb5 Ø#`>Ýb[Õ¿œ‰W;H®*¨Ù€šzjH5k‘dêYÍÖ5AP³îÕ¬£ZÿS­ÿÊO­ÿjTÅÝô‹²:‰YA7 N»¡¹.šŠúc}•ü¸Ù•¼%õ•Ý Øê¼‹Eû(ó.µ™‡ÚmQUʆÍAåt5C†4K¿ÚoÄ·›ÒøøÓøX+¹,Rüx*¹šªd‰²®èΫÀ¶}¦žïL–8ï]¦˜n ëå7¦÷Óë o0½X´˜.j³’¶}„Òï Ó«!ÿÕD`:+ó49 ¸ V>ª6. Y3d( Â˜ÄÄêX$8‡v ĪE™YWœY£«&ˆl*œBT6%«³'FVœ(©QÆ“-f‡V,OíÛÎNæowIœNNè[Ë/%Çœ˜mç‚ËØr°hÖ}¶îâŒ&'D÷Ðhè§”Tÿ¥üt´?ì¢DÐ9É—¼ññ§ eÉ€˜Ö…©Hà:š€¶³¶òwES«(RóD÷,éë{›4"¦ø)Óгìí·x·”Çs´Õ}T=KdâH[#yrš« ²#í¼ç_ð[(œMm­¯„Mx(˜Îv¨ xÛB?ÔU|~ŒÿñpÜ|Žo›œÝom½sŠÌÉp{F‡ þ g#Úñ%@Ch1϶´–îg0¿â¾o4"©?Ub‘AfOéHïHÓËS8"׫°5.-XIÒø4RV-5˜"ðxñšcebÅ Á+ÊhÙ6ño>7FUŽxñÇ/Ø£Àô¥?Y\œ£¡4\ƒæì.(ÐdwJò†=6¿ü =7L\7Ä£»{Þǹ"îôÈ›£çÉ›ÞØKʶ7®úÙ¯Y èö1M3º,ø·¤ ŽãLÊ1@…—|2vJË#67LϼŒD¤ÕÈ®½¨[WØg#–XÿÅØÜ6¦[72×I‡ØôMÖ –=Xö`Ù=Yvýlc+GY9*Y9ê•áƒÇÈÊ‘™•#œ¬ÜáL:Tážrœt@ªŠ3 ó§'5Z—sB^tÕ>Äù|]‰°²Å’™ ÇC×DŽÉµ¦¼¼x‘mµÐl9][öu'7W;0€A`DˆvF&„j1¦Z6Ê#PMî~45³¹Í‡ }ža4´øJ»ÁÐúò®hØò.ȜȸÅ\W@ݘ—I΋ÎLUgêÄR¨=³ª=C9ÂD@Ló[Ýñs#®äSm¸[ìÙ½É aÓ˜Þ ’©>p©òrФ¼â„ëÒÂ/î7iÀøåÌN›÷¢¸6DåÛ(w„Ì·îXCÁ÷Äö|†ê»iÞèfšÆ{i\gþCw)¬b±îá=ûåŠÞùÇ:PÀ÷Î4GQ$ÜÖÒ ƒ]$Å{”æZüËwÆGBØÒ¨#†–Fc…)åɨ…KÙ±YÔž†ðÚDƒ?uõ'#ɟ䢡n±ï>÷‘µ±‹åÏb)Úïgd±Bþ¨›ðÇb±t4Äh±„,V(gŸT9{™xnL¸/« w@~;/=µ,Oå!@“«ŒêêrP5¨à°¸5ά<¢"g¶r÷e\;,D€?±§B„íþ”±àT¦è ìÙèÕ[êk㨹ºV|÷h\« Б:̰Úᇠr|uDÀäøIMs7zÄ¡Ý Q,älƒ¨¤ðtd¿Ö8àWÏŽäxv ¾Ê¯«ÏX;GhòïËEÀÁ˜£ÿF“L†ÜüL†ðPJLV(LeîfÅr7‘6wc¾øz€_úÜMÔ:wS ¥µZö#®`×- ìÚNg®ÛÓpí®»BØõ%‡PäZ¤DþY–ãaKs”ãùSŽgí'Ç3†lC˜H˜H3ÎÌHÅ ¶ÈŒˆL¼L< &ù¦1³¸ªgALú§‘]urÔx6\’@ËT/ÏFž4™F‘8³Žl4ó,8EØ×[ûN^f¬˜¤ß’qÅØ¦r}¡üüz¢ó£ &á¬TÓCñ¤PðGuG“Ö‘?sYS)¯9Vê=(£P…)T?ÕEpÎQÐÚ‡>Ëߢâ&áo½`Õ–-Õ—Ì ­˜ü݈åÙ_Vr=‹lO.5EžÇÙ¤Ôl)Ù;¤U¬l‚ÜáÈ6›ýaÿï$=l6X•B'qÿ|8ìÚxjÍH–Å]wç.þH¨É 7Š°Èæ&¦“œ½ã@Þ)» ”Ï|8 Ò‘·AÕ *£Ï¬¤”oy "ʹ{Äò¹KöOý :†Ýêô›•ø²c–Þf¹e\ï@l{ŽÇIqŸœO»ím‚W~M"x·ýò%I“ý­yªKã—,®)Î|ò€†´¡ô)m)¼Ÿ>Är·õ¢‰Ä.‰©(°’‹|7)¢Õh P…TÉÌ‚;{Ëg‚IeÎgÙ6¯iÖ B~SU-‘°—’l0 Í5Ùv$l¨Íåœ>÷¨¨'Úh-¨ìZ\o°#¢•=üö+[Äáñ¼9|Ù¤ñþ>¹xµIëÝþ.ù•?],Ⱦ»yúŸ—ª§o÷¶w›âŒ oø•Ôôßà(×Z»ö®;çÙÏ`…€W<â•¶0ã`Æ)À (Ì0‘*À Ì0‘7ÌhF ‹2#¤à¡Ïl¯=·íÁ^·¼1kð³hº4ûBw>=ÊÿzûáïÿD×§‡ õ`€!†Ñ†,(¾ ÐˬYLcf ÞgƵ«Ø¯x`íëÙ }…ºõöMêàÓ3w©[3~se©OÄN_ý6oJÄCy0ÛJ¾÷`*[S £¥´Tó…K½ÀAѷ¢ÿùù#1ó»ùté×NZ­tº»ÿæ†ZoÃl@¹wTFà?EÔôçDž—à'OŠÒŸ sߡԨ*úŠ€T†¼ú¼.Hdõœ`Eó³T÷“.›Ÿ¢¡éTI§ºŠÆ`¯„Û}U¿µ 锦iN½S0P0jx1P…1xõTT¯žZ5TOE¶ÕS€Ú7õ¡á¾ñO ·S®ÁÛ×Né Ž£ª©…@•5O‘Tó™åº ´m<í–²…üðG²½â_ÎÄ·í;glHCM? 5‚µH5õ®`ëŠ (X§ ÖQÙ„©ìå§ì¿¸Žw4…Þô‹²*‰Yq7 f[_ˆ\JE²¾`~|tì¿`N|eߢrïb½~ª½KEæ©€[Ô”²QëV6]M‹¡…¸c+Ë2­W¸ Ø~¼jHácOá#¬ã²Hïãªãj®¨Üi_ Ð?˜WAmû<}±7Yê|–t˜`º-R¬Þ˜ÞL¯ë:Ü0½X¯˜.*²жˆ%ÖïÓ«þÕ¤`:+óì8 ¸)V>ª6@ O/d(œBš¸DèX$51¸b©¢Ì®+ήÑU3@6•Ka)–’UY#KN”Ô(ãÉVCE+6(¢=Rå<õ0ñÓ©´ÆäEÁòêÕ«3¬ ñyêDGÃÎV.§ãfãXrjös!“œÆwàý{¼ ‰cUÖo~ЭD ½"ßÒÒúä• ‡ =,ɧ[~Ò¹åN† u^E»‡X`\ãœ%Á£íC8ŽXcÞn1ì”g»–‰7£+ ÉnQyÎÓAD,âü Ãù‘uF|<&û;¬j5\yŠ–ZU?Ôó<vR³+àÛF¥¬øá+è¼ät^µ RÙÿèÇÛÎ&êgˆO­ºÇ§XįI}s %'ðûí“' Üs—¯GUÙnȵ¼ð— -Ñh`³çdO1,n¡>†ÁF¼ÿé“s3©d€!ªçj¶‰®ÐÉïž¹>T¹K™‹€óà­ÕË‹Zkõ›†Öj»µ«P©ûUá4M÷±ÎáB;´õÔ|¯9kwÖ\lŽD)û‹—RñÒ¬ï,Ÿ`ë>$Çó3Vï¡SÐáóá°ëR Ä™QPí·»šð×¹J!§z P¯/©nøî†1¸ZIü#=fÿþüüŽìúú.9ݦÛ#yÕå•èøðé½AGœÎÄ.æe~qBŽ1­(‹8aå àUOçiÊÓ$“ºS²q$ëéÜlz:£žaÕkœ…YøçhÞ]‹þ¼ì|ŠßЧý[ú1 ýí.‰ÓIJ}ñ¥Ô˜‘ü²ý¢à\ncκÏ]œÏ$Eƒè ý”’À”¡ì§›U”(:#ñ’÷=•<¡,Óº0W œGsжöVþ¶hluD:Öèáþ%eÑc³HÄ4?åúq–Áýï–òàŽ.¸Ús d±>&´a’g§¹¾ ÛÑ‚°‘qþEˆÂ©ÔF?Ð Kèè‡òpéЇª„w)ùC_ÍçÇÍçøö·IÚÿ66<'ÈŒÌw±e”¹àÐ!0rö$¢m_6…ónK{9ìäìfW¡Ã·J"U£©J8Ò÷\*…lšÓôˆÄjU‘È5+l‹¡ŠV’4>ZÑEKý¥ˆ<^¼&ST¶Ñfž’ér6ÞìtÛ5*Õg,O¬xÄ!xE-Û% ÎÇɨê/þøãâ{˜¼ô'Øu:BÛhМÓšìNIÞ½§Øýæ—¿Dç†Ië†8uwÏûø!WÅz³`ýá/y{MÙÇÕ?û5‹Ý>¦iFÿ–´ÉJ9 ¨ð“O =Ӳ݈ͭÓs®% 5Ê{1êúéÈ£9ÖA1U·ýÖMÔõe× û|FïóÌ{0ïÞÌ»~ö±Ž‘£ŽŒ•ŒõÉÈ6c’ÇÊÈ‘™‘#tŒÜéP:âT᎞rÖt«ÕC ã©'7žZ–sOB^xÕ@Äùð]°2Å’ GD×DŽÊ½®¼¼x‘m¶ß ¿-;»“¼8Ä!02FH;# RÙ±–­ò8XÓ5û]ÍŒ.„üðÒðgÇF‹/¶­,òІ.ò‚ÍŽŒ[ {Tyká¡üLS¦N1…*4›*4¤S]›(ˆm¤«»z>pÚbäE}ò ‡;XÁ>Þ›ü˜ÑŒî­@™ê³–*o LÊ P¸&-|éö“Œ_ÎðqYó6WЍ\åfº6ÍV@Pð-²=Ÿžú΀_¼±¦ñ¾š¯YƒûÐ]+¯Ó¬g¿^À1;ÿBcŠÅ}4€ŠŸ§ör+Íãé+ê*u¯~ÇÈê‡5»ºµrçãInc¹jÂ@;l®IјPh¥¡j{¿dæñŒU'⿯‹’oF}>l¿¨Ûs–Ѧ— ‰«€F;ºŸ5‰íà—ì™5ðuÆc”kCO ^±Ž3Ïóíà9Ë>B¸×yòzMŠåsuÃm#]í0Øa’¯å£L1Ój`¾yT®FG…°4:kN)WF­üËÈŽÍ¢VD´)W48—Qwç2’œKn(J{l~ekK0ZÞŒ–¢/>F+tç½;FKGD¬FKu0°Ñ %î“+q/óÑ™øe5H{çå¨ð¢ñTž 4ɪñÁˆ®.ƒÕ] !˳«y®Àåq=³Eû(àŠØqi‚ÍSû(MØîOÿMk¾ÉvZ@¯S/cÍÔ¿â›Gå_MsF€ŽÒaHÀC¼œ pJçWGlÎo‘älêT¯@…8´ªÃ‘Õ(£ÏvÈJŠUG–@lˆ•ÁíHn—0¬|ñºúŒµs¬&ÿ¾\”ÁPý7 Ø,`3ä( `3Œ§Rb³BY*Ó8+–Ɖ´iÆ¿à„éÓ8Q‡4N˜ÖjÁ¸‚]·B²k;¹nEĵ$»îŽd×—nÀluÖùg=D‡­ÊQÂç{L ŸµŸ„ÏXrab hbÍ3%OØ"S"òñ:ðñ”øXdœÆd㪞lqéŸF~Õ‰RãéD6ÂZ¨z@‘Ò$Åí£KD² øHDr€áW‹Œa¿ïî5§™qb’~KÆr›ÀmG„ô³kÎ÷*ª„®¢RM",%•B Uñ@]Ñ·ñ1¾ÝžŸ±ê/oí“å©tëžÌ 8£Êb˨»(-º# !PKà?ÒÃC®Ëd©g†°Ì ºÑ»d—œõŒ²é(XàjäZܤ´îÛwå«¡}`¨ì?[}3&(#âp§É=ù9í(#t!PŽßû2ã­ìËÙKËçgM2%ï“§wÛì˜ÞÆçxáŽåçÒ5ô­þO£Êùûã—m÷É©,”ð¡rî’ÿï1ÉX‰¿­¦n¿¬i‘׃ +t„”á§Â¨Z‹¿Ÿê 8ÏÔ(ìP‹QºelÂßQçŸü½ …úNaÊJqú6ŠJñuÝŒåA_ªÑ‡Ð¤NN2šÏÉ…¢Èä8“š-b³‘—R10²uqƒ0Š#Úlö‡ý¿“ô°Ù`“øN²üùpص÷*ÂL_PÅͶ•Õ˜.±ä8 ò)r±Ž¯$د‡úäM2Ч¬äæ ä'ïX•@F•9ˆßé8e3ï(o—ì'&wê‡wŒyU)6™dÅ(’&ad ÝQ{Žw D¿OΧÝö6Á'”:¹ºÛ~ù’¤ÉþV9?ö‹ë3G‚< !'}J[_î´Í¯²ÓzHIÓ×±Hª¨dOÝhu“°s¾µ*Xð`o9@ ”iÀfA&/¤UEÌáz©cNYËÜ‚pêjf(á)Îésq‰4;ÓN­`Œâz‘šì™·_Ù{çÍáË&÷÷ÉÅ«MÒx*ïöwÉï¬2èbA¾ðÝÍÓ×ø¼¸T=}»Ïv¾½ÛÇyï¤ÊÅøGA,{]Ùg„ëT£×é[øÀíÁi¶Èà˜AKÂáD&Û®0 3²ñêÊL×OS:jƒÛ‹Æ¬CÍ"èÒ` åôÌ>üë퇿ÿ]‹9ÔÈ»k3¦>˜ú`êQšúÂÌÛªZÖ¸Ô*`À»¸ª{笗:ûO¡¿M×-ݾ_xNÊži«½ò;K!ÞÄù‚l³y/"q³Áã[öÎ’>˜ÌXkW4L,õz½Ý²œ·Þþùù#±ÕÂ;yk¹ôk'9:uÜcõüµêhæ£ÐË-£Pèÿ)/8¿ñ`>?x¢þdÊ £AUiW„ 2‚»ÐÏua!ë¯çͼÖiÏRwO±R{Jæ¢] ˜êþƒ¹.oóU·Õ.RvR˜ÊNÁ̘hàÅÌJ ¨^ ´j¨Šl++¶tô†DÐFQ4À¹:nS¤C$]+€fFTÖïDRýNdÆ!–OèŠWÐÕ¹#po[9§jìPC@ žœSe¾œ‰{ÙoJ'èΩ™H¦fÝi‘éQwÖ¥<èN‡ºÓQáy„©ð|å§ð¼¸yt%Çô‹²êˆY™1 zXW[EE]¬¾d{Lôë¿dJteÅ<š²ãbµî«ŽK•帘XÔ…²¹êRÑ[M)¡C§c*8Ò­U¸]5¤´‡Ji{T‰®RÉ"é£RÉœ+¯ÊN˜lÒãKÐxÐ>1º AÛ'· €!  ¿š¦¾ø†âÀz‰JßÞÁw]ñaßÅj݃oQeÕ0²Ý èÙ’.¼v_‚Cl¹} ³—ª|ÂÒZ †p„¯ÑÁw‹´àð]¬Â“yrÅy2ÒàÕŒÏ2n{£á5›n;ß…BuU+œÉË º]«àúUAÝp… •%Y›s¹²LY1{BéPñž!*‚T^š÷A’N]­5&W+ ®–W«^®aåji@Q'úö´r3ß0ÝÅrüP³ ™>4¦#îß›®¼Q@2o¼ÑÅÝú;ü•Íá;ÉÇ—WÒyõݦàtzµý€@[;¨Žß:$þއ#¶(ƒ—ËࢥnƒËÈ5ý›àÈ&QøåŠôÞ‘ œç·¼aÈà,öÉ€åKç˜D7ë•p/.)Äü•>ãã1ÙßaS$Àè£*dhÐ<å‡VÕõ:¡„Ñ|.‰¾[j‰Ÿ´‚¬KNÖU«°—M‘~Üž\Ðè!8âµòñò½.ÿ‚],ª·L\;Ò¨–: U„S½Çš2›$8Ü«ìIo·«xº—üR¡âŒu#Ùôfx¡&{ÿSÞÿôɹqVœtß5}5 JWè×wËAdRã÷"N=H?õò¢ÖOý¦¡ŸÚ®¯Bm^%ºt«§ YÚïê9 ÐÝt¹ÙÍÕC+$eSñRj*^š—åì¼äáx~Ææ|tŠb|>vâ”$ÓT°m"*.U9ÂKصôßÝ0V ?½ŸždÀ,Ƶ–VnÈË¡ÍçRGÂw‹BàT“šJÜÐï˜&] ­IzèžÍTr™[ßb˜:‹$O£ÓJEXÎR))Bv¯ÉÃÅnmT”‡±˜!&G5eÆ6‹B—«â*Èœ€óW”£²½BĆÓ‹?þ¸xÁ&*ý r+‹†¼P•˜3´ “Ý)É›³ûÞüò·Fé¸a¸!îÔÝó>~Èõj‡Þ, øKÞéÄ^Qö:q=Î~Í‚+·išQdÁ¿%mõ1”ƒe ¿ô¤mw•U,MÖU5ë8š‹êÖòÉÈ£ÕA1òµáÕ{õayò3aƒ]v9ØåNvY?ŠWÇ´QG¦J¦mž|ëŒZÐ9·ccÚÈÌ´2¦m} ­Á¤p•"ù' ˆ²‚(ÃÐà ÖƒÛèËK®ªþ8”ªÓþVÊ¿ØÀB²ôpèšÈ!¹Õ‡—/²–ãu¡‘eÿsb£W4rŒD ±¿Îˆ48™lfË6w S‡éŠ]Ïf&µ‰ä°ù¿°giGþŠ/³ô«¨RІ¬RLÕ‹Å進&/³×D)‹¢ÔÉ–PÕ\…tü¦™nc™½ÙÏ.bgƒ7»—Ê]A.ÌëœFqxþáÆO°Gù&€ª”óV+ªú¤¥Ê Éa›òz n ŸDº£ÁÃ(g5Šè°iŠÛ(T•r+¨ª¦*0ø¾ÒžÏ àõ5ßcÒx‹Iƒ®œèn!WéÚo ¿ZÀüöYc{ðŠÓ“ åôa=]QòxúвÈÛÚ™Õ¨´‚ìs) +7Œ? ã–ÅÆâìô¹w.OÑwP¨FGŒÏ’à/™¹>cÓá¾/›jÝD'“mú=l›(Ûg!Çœù”Ð6[&®"†÷×f‡}á—ÜytäuBLc’[CƒR±3_öݰ5‹ž@ ‡)œ§nM„ås•Äm0]51Ø9o£G;¯a¾gÞ¦FD]†nD4Ö¤RÖ‹Zy°‘KE-H-n»¯Íõ±ïÉó¼®e;ù®‘ä»rãD¸Ì:ÿ¦)ýì­Ï~4=;Á¦ZØTE[ÿämjhîWsÿlªŽt£³©¾7âÞ¦ #ÆcSCׄºʪ€Æ¢‡eµèP|×C{Ry:ÒÄš#6 t¾¹Ò°›ªõ @CÙ:[²ëú®U•‚@ŸÖO-ÈvÊmüs…<9a¶zuÉ<M`¬1/ïï…÷f¬W©¤DÆ26AGß07¡ßtç眀áÖí~tµï¸s¨‹$²~2AŠÄÅh‚Eñ€{=ÏiíFL‡Ã8)ìÙ ¾µgÄWÆé#9N¯‚šëê3ÖÎA¡üûrp€ôß(Á±qœC  -¨Ì>­Xö)ÒfŸlðÿ‚?ħÏ>E-³O|Y«E;âsÝ ,¯í4áºéÖ®Áòz °ìj#ltËëKm ¹:¾K”×ýç¡Ø2塾ǔ‡ZûÉCáO„9Is’0&q*NµEGdÏu`Ïñ³§È,éÍU=½ âÌ?<Ú@ÿ(! •¨W’M²SܲÄ'[¾ëÄ'7ãMLh™©ôÿÞ¾ûéÇ öbBF×u:L¿G«Ü*Š‘xmš©Ò'æ§­Ó(Å`c%D±›Ç\ DÒgŒÏ",¡!Ù8'KxÞLìg´ÓxgKÜ%»äœ¨¦Õ¡Ðäýš C3Râøí»ò¥Û>Tluç(Ô+[}ˆ1(” qÈÓä~{ÊVÜQ è2 Ì'¾÷eÆHÙ—³c•ÏÏ—¤wÞ'O?î¶Ùá¼Ïñ»ɤ/ÈZ¥÷ŸFeòë¯Ïév_Ö\øP'ß²¿‘HÒ¯?²·Õô‰ê—5]‘#@aŽ&c(#Sim?Õ5pv©ÑØ¡¶b„ûEþ±ÎKü÷+Õþfý€^ðdt0u§â'}§ú¾nà†’w. éØSH‚(Kå¢V¤†œMÖÍV±ÙÈk©Ø(Ù@¹A$Å)m6ûÃþßIzØlðé‘Nâóá°kQ«}­"Mkñ©×Z´˜»c¡‡˜¤^” ™Y¥øWêI˜b7Õ)=Jåñôð°!k’‹()—’^tyGPuÀ褿…ôsÒVô¹HL[îwÉ~rbßñÀÄ’²nʃ7莺ƒQ§ê0* &O}é ^Y ×I²ò-Ïzã>9ŸvÛÛ£òè,ÿwÛ/ÊMtšéSo\_K¦Úµ—xåúŠAãßT·ºÅÑÖc.Íc(®  m+Jö  #ç)CäÜžD!rÞkäÜtÓŽœCq‚a • Ž*2šnÏÉÃ<«." #íT‡å|¦Ý¬0§a€Öš6"€›¡ŠÊŒ¥©2ÁµlIÅnˆ~~þHà‡ðV>Kúµ“&xÙ@"iݯy­:í`ɺôiâ²dÿ)r/¸LðÌ#?[x%ýÉpQŒ UkUÔÊåL…½© 4Y½l`d]w³´Y¡ïP¡0-»‹AyÅסûªónŽ>)-uˆF·ªãöÚD/öºpèW 8«r£zU*7²­Êm¬×q„Ó°÷¤Šr§@1n%[ÕäêÐ,ºjÜ%'”µ´‘TK™1¬åºb]„]šbL­:j˜bˆØbK›³œI¥ßôsÐÈ!YŒH#£K¢‘-Â}jäºîÙ¡FvÔ°ajX[ùiX+®ö›cgý¢¬ŒbÖMhÒµ«Ôe[Ñ­¢oõšõôßê=Eeëšî¢bµš‹J­êº€ Ü $*vÙøviv©&–x×GQ?ÚySâͬ¡¢‡»á ¢ÇÇÝè*T-j~\ ?– UGÅGUMác«:¢¥ÛËRútÞ*®Ä_ÒÃÃBœ -^û¾»%8hÁAØA«m|Z]cvЊÕzpÐD­ZóŽ,ŸàÜÅc6²‹›VÍ^­æä¦9EHö¥00€NÞ½C—ßGçØYäþ§åØé.»‡*kJA_œehE—Ï©”ºug5™+mM&dµCTPþe:õŽBkL¡(„ƨWÊY…f=ýµÓˆ´BH$¡Ôû„³^ëY±³fÂþãSVœ  Eß|¶²á³a¨z‹ t4ds=»m¦Å\ûݯÖ5 ÇÃ_0±S¶Kú²½ÙDß®EÊò˜[ˆ³Áãl„jHâkŠt½Á‡&‚D^8úü·Çôw|<&û;|úÆuŠ¡ ÚÛL(B¹’P5%è)v(¡î«¥ÂâäC¢³†ŒD¯ê‘èeC$ze‰6% t'á<÷€*j×\÷ ñgƒÅäÖ€š»Å˜WÜXY‡WRðvÕ"ü«È4î“'Á3åQ¾ìc»ÂákqÍ/¦BUÙ(YÝìºE-Ô'9A`ïúä|˜‚{z¯à¯a(„qÌ–d¾T{^ ó8LDé8¡eÝ„¿i0áv}«j0%\Çâùl±çåsAŒjW%«ýšhT—3QÅJ³¾”Ìú²0Ð?ÁÎgNŽçg|.s§ÝçÃa×)¶F‰¢kÖÎ*£ªö¤R—®¸lÒM¬Óäò»&jõôð°!“ƒa”í¼¸HiÅÄdµ³ßÈÊMºFÓÉS‚À[ <%Ry‡J:*ƒ 3«Ä½Y“_aŠæÎLO°ŒK—ªº÷zu!tˆO·Õ„xH¢Ób’C>§%?§:ÏAH6Õó ¡kõ!C¸‘_ɇDWJ‰i5ÂÈ>ôìtÕ\=Ù³ þ.rcA”24&ìØ |Nî·{|¡üûø´½§\ò)%ñú*l·Ùù’?d?uA„”ÚZF7<£A.¿L† ¡'§|ˆK6‡Çóññ¼ÉK†‚ MºãÚWª¼bñdº")??¿ã»¾¾KN·éöHÖsy%ÅŸ>|zïCý ,­˜¨ò)+&‚ê±?á)”¨)"=Aí´P;i€= “L“Lœ’# ”üÓN ¥¸PŠÕ¯J Ph…0Q+u„¥HQÑxTÑí.‰Ó‰é"{Ý@©”ƒµr`tC¢r¥ÀXºÿðê}¶ÞâT&&RóÞµ¶¯‹=—Èd×Zveú</Ë,jˆm }ñZAâKȯ„¢Œ±ûõp5´¢"Üï°À6/+‚(Óg²zoñn)س,P꩎¼XÓtÄ/CáºìD;wÍFËð/¸¬™îtfµIk´fÜ餵’?茵ªÎÒ[bSÍóŒ*šã®ãá¸ùßþ61ÈeˆrB0Ô¦­Ÿ‘™/SðvÿîLö¢çúnúkWHØÙÌ[\¹Rbg÷­@e] g %Ç¡ìÐ>¬Ù­ôØÿ¨Ü¯õ;'WGç ÛzÈæ~8n²É5ylÇ‹aŠò’4>!Ö²~K\,¯"d~ñš~È-To¾Y°Óûá/yÓ8[KÙ6ÎM'û5 ŠÞ>¦iv þ-‰\Óà€rôe‚9é‡ºÈæ6–nÕCÆŸ;i‰ðfΞ ‹÷×D’þ Qõ ‘ÓÛbÐA-#Ö ÷ÑÄW@\qÕW¤¬•^°¢Ž‚•‚õ'XÎïË ‚™+B&Xþ9 ½+³îC"¤ þL[&\n.7Jµ×˜èý¥Üo•iPµŒq~»‰Î8ZÙÆb É@ÒÓ¦k"§>r¿¼x‘Q¤¼%zÓ  w;~ì‹a´l¤æÊ%5ÇCO›+Ždä2†ËèŠ_kć³ÃÞäø­Ý/ ×owM¢œ8E9q×gj/ô*;¼ÎC~kYÛ¬,nV§»C‰sï%Î<2aû¸1_Þa>âIÞÜpËqíÚÕöWÝm âª;Ãl·Éò㿳ÄQ4'ÂÍYù‰æ¼É avå0Ä^}ÒRå‡çÊJyý+7Ü…W.ÝýÚà—ZQt>š6¡¸SURPneÚ!…&Ê)6å”ÁÁž™ÀpPKÿ6^ûÛóRz/¯¾}`q•Î=`ö»ÐsåŸÖ™|»kxU땇z/¶{O_‘öãùs»Gpfq.¡Š¼m“`AA$uM3tÈ!‡1I·íÆëÎyѼZX‚¾=íܬYœç— šñÙJ4wÜ·ž“!S84Å[Û;F7¤“œ²ØåÅ+ð¨!&¯5½ãð†û×yu”Y+µ»%0Ÿ² 8ÚÝúÐ VOTÕ¨'ŒDÓħÓöáÜu·ùü•—ÀBÙ|åj"IÑÄÕ=ö kéÇ$mɘ$ôZuÒœˆH‚˜f™è(3½Y&C†‚¢z(hÕ ŠlCAQ‹SvÞ°*„j×Üf)‚@ÐÎoa M¿Ks(’‚8Q‹0þ Æ­!즰 lR  °)Œ€s›æ3nΰIwÊÓ†M¨v­‡Mi9“0À¦FØšvCÓ®¾¢±,¿k¬;\VëU~y«´Ã5•+‡W¤§g ëÊAõ(`m6=•ÿq M•lÉÎkJ¹Ip…Îß‹¬°s»?eîãìG´°ñ×Có0?Ƶ!TÒ)T‰ˆ$T’NpœŸŽÂažŸÃ7ãžç7 ”XpÎñ0ý§Cµëz<¬¨Â:éáU€i\L³çG@tljCôø¤ÃE˜‹×!¥_#/žÌÚ³'Sæk#9_[›U¾öèìÈ¿/_ wN Þ ý7 >JðQ‚|”à£>J¡ò••+V)i+%"ÛJ >ƒ¾R"ò]) ^)±®{†Qƒg¸¶õ ×-Ny=KÏp]sx)x†P‡°:½£W¸n[3±–¢u —Jÿ„6.•£š‰ï1ÕL¬ýÔLÌ0ëK»,=®B‚J4Í¢@™u™ 2íEFdÓÆ²ŸU½ì$¥ÃÀ¬‘©­Q½6ìjŠ€Ä}#+bËw^ÄñŽ3FöU—3Ê­`­VÊÄ(I¿%øn#ù6×§7·;õ0†ŽŸKB×¾k‰ÒIœYÛ’š4Óë[ÚD¨–‹a£Ðø¸ñíöüŒOÉ;P¨<2ûÚÅëuÃ4!k%YéD!è BÀÔ²ýôðk[Yé0S_–ˆ¸~€T ØŸ‚胥´B†éȨT#ôöÝÇŸÞ{–Ú*)‘ ›2Ò¾ôoX ÍEb ir¿=eKî([tP~ßû2ãÍìËÙÁJ‹ç'LÒÄï“§wÛìxÞÆçx‘ƒåÒÝçT=À?Íx‡=éT–öùTz?²·nÔh=é—5–O&Vé)œ…U+4(?Õˆp¬QÙƒNå”Ë-rQñ—~Jm³vZOb6jOz€nî¡ò¼/åÄkN¸–{Íe¤Èº:» )[Höi9{%+GÞN~T›Íþ°ÿw’6Œ  “h>v­œqf!·â~Û‹n/"ÀäTÄUdj=“In‰Þ!ï“ÊW>Üá È;‚HªD’Qf&òÈ7;naä¼JÉg©Ð'ZL>53ÒºÍòúànnp;) Ï<âm§`~šèàÅü®À`UHCÝy ¢9,7Ž"¤aöÈõsÛ$`qP}4£$Ò Nõpe9>¯¸•C«ÆQDáסµUïË™ø£ýf‹‚* ) é¥€Q¥ižžUi]èƒ*u¨J•ÄG˜JâW~Jâ‹[·GQ M¿(+˜•?ªšuåºuaTTëê‹ÉÇEÁþ‹É¡dWVó£)‡.V룺T\JœE­(¯.ÆÕäJØ:®"'ýj…kæìÇv†d9Æd9ºš(‹D:žš¨¦¼,<Ö÷þa¹ 4ÛçÃùÎdóWàv€ÛpÜW/k p»¸]×m˜áv±Zp[T\5Dlû+ÄÞnWc韛Àmæå9i˜w?âª|Tm –Þ¿PŠÀ½£¤âÐà^,õ“ÙsÅÙ3ºj‚º¦$ H²Êªñ^dÅ{’ªd\ØbteźÄC4ªœïs%º0kL.L\O.L½ÂÊ…×¢N4ìjåj† `‚‹å˜¡fÿ2eh\ÇÜ¿§Êpõ7V—üæÝJPðÍ+ò-MÈ«?ÎXÙpư£|ü9Ó'3ÝyøMÇ÷·y±f ¾h{ÿx8bôð=ÝJ×)¿u-mWÒ‘}¢ñu=%cˆÄù•t!ïRj†øxLöw•4–·òË+?´ª~¨×¹#ì|f”^çF£ø+¨»äÔ]µ ÙäèÇí ÄbG«®±#…3+g®ƒääx¡›}ò$rîžõ¦ ÛM«¸ýR¡ ŒföŒì Úe-ÔĤ‰þýOŸœ>Å‘÷_kV³9t€Nt×ÌôAæ&5Ú-‚¾ƒ5 //jMÂoš„íºÔ6I¢M× ›hö½~ÎÍBsowõÓt³4kÞÕ\-@K);e—R§ìÒ¬Í,Ÿ`÷“‡ãù#Úï ø|8ì:¹ú”,³pöÙN±Þ>¿ 'y ½^þ»ÆÎje@ï™'Ï“o™§¼âõŽy’›œˆé!?KFv ¶‘§ÌBéFÑÊXò(“q…,zDir³@—ùºi‹3¶4,Ì„qƒ(‹¢œÎÍ<§I&a§dãDªÓùØé»¡Nû·Ô5^Â+æó2Ùn…|.¶;Åm¼Ó¾­÷xÄûv—ÄéääÛ^T)f!«l§h„5—Qƈý™î³§29A ú…†%?¥¤,.åÇ¢-“ébí$JÎB”ä? 'ËÄ`.LÕ7ŸÑŒ® •¿+PEÍšz¸EGQØÛô 1YN¹…~˜eE¿Å»¥<2¢=*öZX¬ImìãÙ^®ÈV´£l¤™ÁSažpµá´â6| ¦iö´ÿ–´Aä‡Qœ)<Ú“±—W¶ ±¹¥w®•"‘FvÓAÝtÂ>y4³ú/(&¬¶±Ëºéª~ìµÑ`Ïak0ÛÁl³íÌlëçßê˜7êȼQɼQÌ –;FæÌÌ!cÞ‡Ñ s w¬”³†ð+ 'žÔpb=úÍ=yÑUSç£XuÖÀÊXH]9&׺ñòâE¶Õrˆ/tô²ì¬Nnèrà gÀˆ#ìŒLe3ÊX¶¿cbLWì~|13¯Íd‡Î†>Ï0>X|¥Ýð`E¡T4l¡dê`Üb ( ËËÈçå[Êú-u¢'TqÁª¸PÎþ4SÓàO7upàˆ‹áÄ3 7`‚=´7ù$h¢ìZ&Õ'-Uˆ>?Êë,¸¾,ð½t—EV/'@Š«iŠ+"TΉr+Èœ“¦­*€$øþΞOM}óÀ¯Ý;ÒxëHƒ·«Äqè.ëW阳_. ¸›¼¡ |«HÃãðáþ‰Þoy<}E[»íÍcÕ˜¶âˆfTùUîyid  h†É¥(Jô Í3Lýë—ÌØ1j=Ü·*Q²Í¢»…ím“)ÈÞÁ[Q™8¸rÒ•ÚÏõ´B¤¨·üΦ9­#z—ôzÝp oœy…÷(‡™YuÇA=”È‹‡h»+Ÿ£¨¥mëÄèêiÁÎxAe„ÙÕÈòm£ñn0µîéhƒ¡uÏXI¹0jáFvŒµ ¼ ÏàF]]ÀHr¹h(öë­Y{d­Áy0GŠò9˜£ÐI>ÎNrôæHG<ŒæHhÇÔ…ïIx—yÝÆ|ö²šÏ¤óÒLhÑt*ϧ™\Õô`äV—€*A…€ÅÙTýV ïÊ~Ù’Ý—pµë0Á¢ïÿvʸm*s^vpl;Û{uw¼w³3VšoÄ·Æ7šb?»ŽÆ¡¡}ˆž`§ìhÇà²êvÉe-‰æÎêŠñCk5 ',lƒ“¤¨qdªÖ8@UfŽä0s ©Ê¯«ÏX;Ç]òïËEÀ!cÑ£€´ÒBgÛÒÂt%Ò*”¢2‰²bI”H›D±Tü >A•>‰µN¢h­óˆ+Ñu Dº¶Ó‹ëÄ[»@¤ë®ˆt}ÉAˆVgüÖý'[Øš%[¾Ç”lYûI¶Œ!úf¦f¦Œ,SQñb-2"÷®÷Nƒ{E†iLñ­ê)>wþiäS5žM!Ð2ÕË ’&å'nYú-ß}úf.çêúzkoYÄŒë’ô[2®°Øèo³!$ŸQÓo¾c4ñdUˆjâ`(C*訚ˆéè½ñíöüŒQKyj ,O£KO`N¸Yô›EÛîú+^-kÿH¹¾’¥›¸2çNï’]rNT“°¦!Š`áªbHÑ’Ò§oß}”¯åõ!lÕÍ£±èlaô1þÍS¡rˆ[œ&÷ÛS¶æŽA—åAñ½/3~ʾœ­´x~Æ$Wñ>yb ~Ÿã…®“ŸIß/P¶Jò?Ívþ#Áé©,Aðª\ØÛLÊEüÄeMo¼æ¸JX¥#4  æ£ÐSüýTïÀy¦Feš‹½CÅCÅ_úµÍZj*‘Zi*ñºQÊó¾¬$\8ኄK.#EªÅÙüÍl!Ù;¤åôpï{qT›Íþ°ÿw’6Œ  “h>v­¼‚8³[q¿íE· ž09Õq™ZÏdü×C~ò>ðS¾ò÷…ƒ ï"©IF™™È#ß츅‘óòH%q—ì'(ˆºÇw ‚Uè61e{Å*¥MòÉ8¼³xöÈŸœO»ím‚SNõ¢v·ýò%I“ý­yòHÃW,.“ͼò€†tœô)mU¸ŸF»|¯õª´î‘TTÉ7¾Ûðê,aóhÜtUаàÆþ²„0"™S…¡µMšä_Hª ”%âõS£ #ž¹RÙ†x õÊÄcä8§ÏÅÕê©’PÍÔ‡k×[Ȉe¾ýÊ^xkãí"^ùý@ÌÁ~ã’ô>y"A-.MeUìÚŒt-ŸÐ‡®ü>»òAjÛãLÞÒ^ÇîÇò–ÿ{»ŸŽa¹!×®¿=ðw>0Häâ@ÀË„uŽ£céWmÂM¹³%óFãWàOšúÊû\‡æ“@Èeß‚^ž^2BÑ̼’Vå‘Ï0i%l>ĪÚ)ĪbU&âa‹UÁÂÉ*GɪŒ¦Ûsò0¹º‡öÔãLÅ9ø› ƒÓò]CØ‚FØì •*¯¨Xêg ʼe÷~eþóóGbÄ…÷ònzé×NZ‹tºßBÿkÕ ÍJÍ—»F£æÿSÄ1_pÎãù~ðD$ýÉ4D‡ª*¯ˆCe x¡³ëbCÖ_ÏÈõQJ>K…>Ñbò©™‘Öuhª»G –H¸ÎWíX»€ÛIixæo;óÓD/æ§p«BŠêUH«†*¤È¶ ©±jLGsX nEHÃì‘ëç¶5H:Àâ úhF!IeíP$ÕEf˜bù„®pe9>¯¸•C«ÆQDáסµUïË™ø£ýf‹‚* ) é¥€Q¥ižžUi]èƒ*u¨J•ÄG˜JâW~Jâ‹{SGQ M¿(+˜•?ªšuåºuaTTëê‹ÉÇEÁþ‹É¡dWVó£)‡.V룺T\JœE­(¯.ÆÕäJØ:®"'ýj…{díÇv†d9Æd9ºš(‹D:žš¨¦|åR?ÛŒ{ÿ°\šíóá|g²Œù+ p;Àm8î«—µ¸ÝÜ®ë6Ìp»X­¸-*®"¶}„bo ·«±÷ÕDà6óòœ4ÌÆ»qU>ª6Ð Kï_(E àÞQRqhp/–úÉì¹âì]5A]S †$YeÕx/²â=IU2.l1º²b]â!šUÎ÷¹’N]˜5&& .Œ'¦^ aåÂŒk Q' vµr5Ã0ÁÅrÌP³ ™24®cîßSe¸ú«K~óƒn%(øæù–&äÕg¬l8cØQ>þœé“Ιî<ü¦ãûÛ<ŒX 3€_´½Ç<1zøžn¥ë”ߺ‰6‹+éÈ>Ñøºž’1DâüJºw)5C|<&û;ŒÊË[y‰å•ZU?ÔëÜv>3J¯ó £QHüÀÔ]rê®ZlrôãöƒGâ ±£Uר‹Â™•3×Arr¼ÐÍ>y9wÏzS…í¦U\‹‹~©Ð F3{Föí²jâÒDÿþ§OÎ ŸâÈû¯5«Ùº@'ºkfú s“íAßÁš„—µ&á7 MÂv]j›$Ѧë…Í4û^?çf¡¹·»úiºYš5ïj®–F ¥”²K©SviÖf–O°ƒûÉÃñüŒíw |>v\}J–Y8ûl§XoŸ_“¼„^/ÿÝ cgµ2 ÷Ì“çÉ·ÌS^ñzÇ<ÉÎMNÄôŸ%#»ÛÈSf!€t£hå,y”É ‚ǸB=ž¶ö+|O1ÊP·ñªâ°Ħ­g™¢ÛU\ª;Òí%‚¥&,4~%z&yÎü =ÙtÛUr»lë`[Á,^¶È3Q€¯{ £ùœÜo÷µ¯'è³ÍNŠˆM'äC‰6 èÃvŠIƒrÔÃE‡±/$´À‚QñoÉæðx>>ž79+Ȉ‡&½PÑ‹·ÑW|ÌþýùùÿØõõ]rºM·Gò¢Ë+) ñáÓ{"49ˆY Ë|Ý´Å[šNf¸A”EQNçfžÓ„ì;Ù8‘êt>v:Ån¨Óþ-u—ðŠù¼L¶[!Ÿ‹íNqï´oë=ñ¾Ý%q:9ù¶UJ‡YÈ*Û)aÍe”1bÿA¦ûlÁÅ©LNˆ~¡aÉO))‹Kù±hËdºX;‰’³%yÇãÏÂɲ1˜ SõÀg4£kgCåïŠTQs£f†nÑQö6ýBL–Sn¡fYÑoñn)Œhн–kc’Gûx¶—k²í(iæ_ðT˜'œFmø­8„ (”ލÊrÛB8ÔUnŽMúñpÜ|Žo›œ5··É9)faŽ‹Í¢·Göo³ç‚øb7 y³˜€ZÚÀ!ïxf”ŸQE ß0éS :*¡E¿SŽt´·UéÑ…Åh£ ºk=ØÃ{$i|©š*¢|–ZJ¼xM¦¨Ãk£³¼$¦ÅÌ49²é7¶_4êÍX²WÁñÊ¿¢¬•ízæƒJTuzüqñ‚= LXúäZ ‰áZ2çlAI&»S’w)v¾ùåoA¹a’¹!NØÝó>~È•m§GÞ,!øKÞÀÅ^R¶pqõÎ~Í"4·išÑeÁ¿%mùa”g ödìå•­Blnék%†H¤‘ÝtP7°ÏFͬþ Š «mì²nºª{m4ØsÂÌv0ÛÁl;3Ûúù·:æ:2oT2oÔó‡厑y#3óFȘ·ÃatœÂ+å¬á<Åà É'5œX~s@^tÕÄù(V5°2Å’E ÇC×DŽÉµn¼¼x‘mµâ ½,;«“º8À0"Æ;#BÙŒ2–íï†Ó»_ÌÌk3Ù¡³„¡Ï3Œ_i7„­ºy4-Œ>Æ¿y*Tq‹Óä~{ÊÖÜQ"è2 <(¾÷eÆOÙ—³£•ÏϘä*Þ'O?î¶Ù½Ïñ ×ÉϤï([%ùŸf;ÿ?&é69•%^• yÛ³I·¸¬i×U kt„”!¢ÂxZŠ¿Ÿj8ÇÔhìCoQ©(ÿC?€ ¶UK-%œ+%%|_7$@yÖ—•T £Z‘iÉ…£È±8¼™­#{‡´š.|/Îi³ÙöÿNÒÃfƒOò;ÉôçÃa× À+H3wÛZf»`øfÉ%'j–S‘›µì%á}=Æ'o“>å(ø^8òŽ ŠuQdt™…ò­ŽX9SwÉ~r¨yz×PW…h³N¶SœÂÙ –Œ³»Jeϱ/ô÷Éù´ÛÞ&ÅS+awÛ/_’4ÙߚNJ˜¿aqQlæh4¤Ú¤Oi+¾ý4Ññ­Ö >J²v¸íCRK%Çøn°C§§„­#qÁU‰¿‚ûËýÁHdNê¥Õ6 h{!¨*:–H×OÝ1Œtæêc Ò5” 7‘Žãœ}†m\µÐGM˜W0Nq½#ŒˆOöØÛ¯ì݇Çóæðe“ÆûûäâÕ&i<›wû»äwVõs± _øîæék|^\ªž¾Ýg»ßÞmŠC¼áWRÑb|ƒ£€W µÙg8ìTœc?íýl 8 Luì³C §€š‚‰D)´&V¤Ð`ê&bF&ßG±™ÁüzîÇj~Û@Ô˜õYÄ ]Úo¡œ܇½ýð÷âk Ú|­áÁòË,?BË_Xýê7›4.ëURYŒÆpopâSl”;°éì?…†6]t‡FhØI™Û¡A†‰ß X* ñÎÈdŸÍ›±ÊKŽv.ö;’WæÇJV‹n‹Ü&g›Ì1U{˜YkñnÈʯi¤ha>@•°¡÷É Vq1*‹W×f@kù„öÀ74Ï÷Ù<ÐÖç–:v?;·ü/ØÛý´õÊ]³Æ@ëpMè ª6J Kk^¨& 8ÞA¢pX/ÖéÉŒ¹âŒ]5àZS‚""YUÕØ.²a;IA2´Y1'ñ­z*/ÇûG§ÎÊ“³gÅ‹³R/k°rVÆ4¨ý {Z¹£¢b9å§Ù … ùÓ÷ï2ý•¿ùA·Áð<óŠ|KÓê-V6l1ì(oóIç1wœ@Óíå-ž…§ú<‚ÇÙÞ¥?Žø\x?׸uÊV]‹›Ánd—HÜY/ÉÂ÷q~‡[È£çÉþŸJÆèV>btå‡VÕõ:úƒÍl2ä|»H´?le—œ²+ûÐMœ~ÜžZà›!*´êbÁ5£>æzGÎo÷”Ù'OææîW_ê¯ÝȈkqÍ/*Àl$³GdÐ-j¡¦üíìïúäÜÎ)N»÷ê°š•¡Ë´…;f£2©1mƤiwyQkÚ}ÓдkW©¯6A]:Þb<@G®çås6Úm»ªœ†Û–Y;­æºåÁ“²su)u®.Í Ìò v€>y8žŸñáùN.>½á¾‹O‰2/žíç=ì rŠ—À›Ö¿»a|¬ÖôÊuò8ùÂuÊ&^¯['鵉ɖÕ³Tb×èyÊ n©ÜA%Ž2·AàCÈ"ÇóÍ~…î)F³6=AUÈ5‚x!ôl¢Mt³#Š5uE´½¥ÔD†¤Dß#Ot¿`á$›Ö_ûAFNWm>+X…À¹2&Jïu¯‘±‚Ÿ“ûíŸÆõs¶Ù)yé„r(ÅfsØ>ñhMŽp¸Ì0¾…„ XŒé!þ-ÙÏÇÇó&gÞ0„ÔÌ;¯tÅ"hô ³~~Ç?v}}—œnÓ푼çòJŠ1|øôÞ‡(£Ìí!ä2ß6e1Æ•f“…˜plaA„ÓY™ã4É$ë”lœHs:»œâ6Ìiï–¹ÆFxÅ{F&Ú­pÏÃV§˜uÚ³µXßî’8˜\ÛË(¥Â „”퉔æÂÉX°ÿðÑ}¶ÞâH&&D¯Ð`ã§”T°¥üLtµ-]ì›DÆȼߑçÒd€XÈ…¡`F`0𑵲™òWEƒ©(“Q²A×Î(êôú5!fº)ŸÐϲ¼æ·x·”g4´F¿^«öŠ¥1‰£­u<]ËuÙ‰¶ýßFŠùüÔÐ gQkø§µ †ÿòaûDÚò 1pà¾P&®|p•Æs= %@A-µ3ië†F$³†þ3”"gîÞ=Âa6 k@$òáúàÊç(Š^Û:)ºÂW°ó"^Fy`fÕ¬|ÓH¼L½t:Ê ßKg¬¤üÙûx‘OE-(.¿38xQG/’<®öJózë˜S›E0@Î ¢{ú(4s¯™»ÒQŸÚá5@¡{BØeJ¶1½¬f¢™ß¼€ZÖœÊCa&V×<±ÕéPq0¤°6›ÂÜ ÎCe.[²ó²®påæÁÏóœ›ßîOŸMbºÊ ŽŒmsy¯nï†rÆD3sø¦‘¸@Sl)×Q8ô”÷Þšëþ(€MåüRÝÞñø¥E:ÐØÝ\1õqho¢1…w-@‘ ŽlÔ€*CÇ‘:.áSùâuõkçKþ}¹8ž‚*úo`U€U˜ly€UhŽ¢„U…2T&EV,)i“"6ŠÁ#„Ò'E¢¶I‘ò¬ÕqÕ¹¶Ÿk;u¸nA¹µð¹î>×—51gu¤ùgÝî„­ÉQîä{L¹“µŸÜ þp~SÒ<¦d\™‡Š³j‘y9w8wœ+rKcºnUO×XóO#“ê„§ñh"°ø€V©^Hˆ4é;qçÈRylùÎSyÜþ7²(4óÖË+ûÊf얤ߒżF ¡÷lZoóý"‰ï «T“føÒA¡ðj‡xÆÚÛøßnÏÏø”“Ÿ.½ò(º4éåT›A£^±U¤ÍzÐ>¼‚ÑÕ2öôðk)Y¨™I+³jî„ð.Ù%çD5rj "–ª †“)) úöÝGùªZRVÝ: ΖEŸâß š†¸½ir¿=eKî( tPþßû2ã¥ìËÙÁJ‹ç'LÒï“§wÛìxÞÆçxá‚ãä'Ò· t­üO£Jùñ—4ÞŸv1aÃwû/‡ÍÿHίœëÍæñ1c¯çt»¿¿ª®‰y[»ät*>sqS ÑŸñ6-?D5zíqôªôV×¥_7Që¥B 1³Sýæõu•ÐâòÖîþ ¦-/é) ·Šg Êä†=§Îàô#dAågÎ5©£?“•¢ ª?î¬0>®,¯ïãc&€ïã‡dsJœOº©Ñ½Àõ¿äÆ??¹×ÜÕ±€ÂÄ-JÈÿzûáïÿôìþ›)ê2P ïh¼ao°¡~Ê@¼Pÿ¢Ø® Na¡ÜEñó%ꊼðž2ÒæR˜²/ ±|ÝÈ­öC·léWHZìâUIn4TJô~H%ZÆ2JÅyñêbQ;Cä"×§¨+Úâµûà[ݘÉiÇÑתÅêÁ½J. R¯m×ÙX§š,HøÓǬsyèÿ=ë>Û¨S+<)·ÁbKµ ¦çz*Õ•ý¸£KŽò;"‘Ÿº µ&¯.¨Å©IA6^¸é|Ò®?f6ýqwåâ†óQéé¦à€øÛHùÛ²G¤k AhìÕüi­ø“ïΔ|¯öÉÅ•Fq̾:Vô<ë|—[³²E­ìÐr¡ŽS¸\w=<?ÉH{’«†“ŒlORѯ¤Hµkc,'i½nnZäZ{’QÃI®mORÑ?¤Hµ‹d,'i½nnÎ…“,±]PeQyÚ%WÊ_Gê_kºZ á1ú'*?IŸ‹´Ÿ[KŸ[»‰pzZ‘=ýy÷˜Æ»qÃOñ·ßKx3ûÅ_D¨üOßkþ”‰ü_åÒÚ¿¶.­µ·òïuíÞß»ÃU8̘N †é¿kúï÷ãÆ|“C`±ŽX¸A±³UOëè;[õDà°Ž¸Á°³Uס0ü¿×žâºá¿·=Åï[žâ÷£–¿¶<¿Vö™-°Ö«ò×j¯ ´寕4÷Ü8Æwá·©ý=™Tð×qûtÊÏ}/}î{œ¾ŸåÊ[øˆ§¯ÿŠ3ï?¾wÞøØÝSG£DD_Œ}{8â–‚ŸòsŒ$Cîí¸]{Ýç)앨oÔV Ð\‰¿\qóóáˆA¯öS¤£Û¹û*¾Õ °—Þµ`!3+õÖy,‘!‘ÿ'×$%´D "'‚¤-”A f’áF Ž×®G ’¾™2Jx›ì‚bíªXE"ND±J[ Š¢XÍ$íX¯]¯X%}31ÅZmAY]]$¼.ºÚÙâ©(šv¿-Ów›öáK‡7T÷Jÿöj°Ž•)u«xèT¡Ê.]|¼=Ýc\·*å Iåe¶oÉ­oY#çpŒµÔb¬7 ki‹±®ØP³| ®¼,š³˜²Ž¶Ê>ÌZˬ¯„[KgV\z™ÑŽ+Á×R_ËðMÿ+\àW_TΩÀÕó@ô†->0±E¯ÁV+'E •¯ ˆ¤•Œ)¨øÈ9VàÈÛÃC¼ÝgÎêÿuØÝu&™Gà _sG¡ð …aw#Á^w`&–«Å ª‚ä†èßAõ–œ “ßT½Bµ¤ž¢×2˜óÔü[Èt˵ܼ³ŽÐ[wB‚ ­D²¤ý€^Û• d+”‹Qü©ï>Å#l@hP2ÎëDH®‰3‚¥\T5ôŸï>óªîò3pðCª ^·\–·)õË“ÍõÕêŸQ/±‡ð"Õ›#Ò^^! 8W¾Éù@D+½ € ¸ÕÈV€ÙÇŸ^Âzä©Ï>–†ßßþ>7 °å]\ñØg€á":Exu±Fc𽄱dž³%Z<ßçà 6 š€õíD˜¢à$Ý`ïuèÁ ì8l,Qaî¦ä1Ž©äqÞOÉãÜ :Á螪4qÖ¬yÎÚ,äT~9‘rù¿·D²ÇŒ FR9© F‚¿Ç¾<äîyxEŠrKÐâŠÒÖÕŽæs¥BRBZ݇sC[Scì+4ªWßW‰Fi«t²Ú<†.ÒÔÐÇQŽYi|{/ÓÔáÕì8©Þ•e¡Fùºµ•šš¦Pª©÷rÒ–.cYª!FŸ¢®^Ó.(Q¾)wRå·d£R3©×lô\æ¼hs¹ÝÌc^¯~[¹Wª‡t;K¡ºcÝi 5(4V’ÀY䫺»ÇÉBßoe4Äb”ŒãÆ6¼i¯ÆA‰j³uP¿-Só þv@û (yQÃj.-Dr?¿¾\o÷ÅÛͳߊO®^]wÎnŠ£¿À#U€ˆFì«Çâ$ ³?å íOQ–¿Ð×l÷§(ÄW³QdUËSêå)zéÕêÓ½ä<üªäýÅ×ånñeñ—â·§«/«Ã~±çV¶#âÁ‡"!ŠÊðéç»ÎÛßûër·Z‚ s£Ñj_°¼þÓv³þö=—¢8¯ÑJ˜¾”0£$²ïí7†uËÿG~¯¢?œN;anƯ7ËYÿ÷aµÞ;7Óð®Ýü.x‹:G ?yV g®¼Gߩ׷PyG„bAÜ!ô>Ýø?ª×ãÕáAÈ4{8˜â¦. ¾<œƒ©ŽÅ‹âðòk¦¼ÛìW_6Åõh ’ç•Iæ?ncœ»$F|-L5yquµ`{³Û¼LÈ‘¶Ùzóo‚±ã•êEŸÏè­y˜4%%Ϋ÷ ì¬!”'t'¶E˜&Þû)¡Ïg ×õzrsʈ!æt›ÞN(œ’«Õ¬¬ÆÙ·‰ßÇ»’¨‚­ðÛ 9EiRÎà“Œ˜;…Y–s"Ï ÷Út󪀨Äóu±ß/¿~mü¼Ý®Ñ˜Š±…–Ì1æ½Ðq£ª£c*ï¼Àc"ÕnWIQð ^i‰¾;¨eá¯Ø‹‰/’y6€µ1ÅØ6¦P-u1AT  ”"бQ@a‚BStøYº!!Ë«Q"Öwž&ùrLx=•5Ô5”…ÔI`5pObjà‡kàöÕÛ\§zÚšÇa‘!ÿU<³r –ddàm›Á5dÀŒ<¾Æ†ŠÖðÐãjÀ¶n¦Vi:qž x§Ö_kÑÔÌàõn·½¹= Ëu@8 ÈsÀ¥å88ºÁoÀ<`·áɧ^¢ƒÊ(Âi@2ŠJKFÝ £˜ƒ,£À#ºÛ÷•z$IÆóšaß$¿¨­r‡Yï,Ѩ6󨪉“œ•Ï:8 o£t(SVRœ¦¬[Íl@‘è&R÷ôRFÍ)9ôؼ DÜVÓ_ȬÕtÎ“Ž¼¦kÔiN}N?±fÒquo ¶Íì–SfÝRfDË6d~ÎÄÌOCÞ‡*s£¬™ :Ú'ͼ¢ã{Æ´ù"Ï—!X¤Ë°¯U5r¹ù[Í2®Ã£±Z|^–Zì/Ëý/Ý:ý7ìÚñ¯‚±uçSC%¡+û4®½Òìlíl»Z®K†·y·Ü»ïQW&6zíñåªÍj`-1ºU¦ÿ¡Ë€Ô…سßm©]îß>¤‡¬þë®Ø};¹‡ozï =a¢.`bL™û·úqUߨXï »`ø(›¢TÿÜ|ú“q‹ˆ¼ÜS¿ä|´ô¹'(yUï¯ÀM½†¤}1®5+ œ¨?á":ªYįŸÎ„\žÖnMšm&¥½ú©ôG±!õuñˆ%“Yu ¶œ[M,uÔ@X“G®Á–ÓG’^敟Ւ+7ªÜõ&(;§Z›š«¿<Ï.²µ±²6”hÃ38 n‰Ù§ÄìÔÑ$nËãrcãèÃlúµ?eæ/ÿÑf½ˆ‹ÔHcB$ë@IÆ(¸X¶ª”dfë£=h‡ m àèúæöîà÷ø™Ú›d?(?ZxžªïøOSN)ÿ¹î<E–+[x°o¹© àU)VÁÃ'ék*„_JªÊÄ:¿µ]âýÜyâ}ì-ñ>íßRÞÝœ—Ã.PoäŒè§»‡«ïV1ØTûö& oojûö¦-ÞÞ4¹·g 16³Ê¹°.ÍN½ÏÔE\u[ìÕOk.Ø¡jrˆ)V½+¯›r×M{ غCÔÁôt2ׯlçô¹òìZ{p\vÝ¢Q˜ÙuË®[vÝú4þ±YyÖ»»Uv¿¬ÑM¹ÏÖȶ5¦µ¶4[Ñh4O¶¢Ž­h=ìKáÍ`;:l1‹é°Å´ŸÃÑŒô„›¿—R¶—ÕÉKñ¶ö!ÙÝÆƒ ,…'™Â…›QëO£œGQ=Óè½*Îó°˜èßð4¿áÞpóS'uO5z®úÉFÜ¥<îÄÒQÇiA𻞀ªl²à”T'¡î‹g¢ÌÎHÙß·í}ZÏ'*oýSéA(ª‡›éê ˜«h6°€Žâ•RPçj9°‹eÄk=¢nF¼êöêÑö_‡¹‰ªÒSÑ RŠä¶NÐo§ÍI.º'Hʉe噕§åÉö©K9/¸!jÌnˆ‚çÏÛ¨ÔÚÞu{…ªØ°“7B¡‹ñ>¨¬Z[¨VO•ƒ5‚–°FfÕ7PÕ×RàFÖóÄ¡”‡t+µv Cº‘cüéÕ3’螯Ê@Þßá6Žb‡Åõ("e¬a•Ò¦h|º2Åë\'XiMªiÅÔ¡~zã×JÄú‹]”oînä'«-z€ùÆîO°IõéTùéÌIÔÎݵt{&|nt¢½pÊ_8Õ^8ã/œµNØž<â?§¶?‘ĺބ—´§’à¿Óô=ò Ñ”r‡@·KE°¦½Z²Y ÁCOù=Ät'¯÷ù´„eš ëí…ÙÀ«M£ð:˜K§TzŽñ*ص¨å7H'.ÐÚýÄ6A_ÛŠ«§‡ØÛÊ¢&åé'bžž#Ì×O(¦T˜ *LµT˜ÚR¡ö4’ž âñžZ*L›©0¥T˜5RaЍ0ÓRafK…Y;*Ìl¨0k¦Â¬!ÁH ©ï~|þ™‚fCÏAN¥§JŽ#§2>÷1‰óèÎ_vû²Û—ݾìöe·/·Ï™Ãsd¾Ž§Òªµ¯ãÍ«‰éˆuO’½‘ìdo${#±{#.ìð‘™àIpœ`ߨÒTf#™d6’1ÉŽæáX,ƒ£^¸‹˜záfƒ<î°}Œ×\}´‘IŽGJÃã¤4ýIÓÝ&†KržXht3:ÏKÏÞZœ—2>iÏï¿éý³?Û@3QAcx¾üw›³æR͵åqs–Cg™C3‡Ús(ÿ› \S5\†ñ°é 3• íÀþ1ñŽo ø8hu®üh±e™g¸_õ¿h;œ;?Æé»Þ¬K[ö‡ÕMá:u(ïYF¶ö‰¢9—ÑvNˆ€:¼,ã¼w[ã‚pïdSüJ@ããMDUü§ûLäyÊ©v|[óî-¤íâíÇ7ÌAW×ËS_¯Öë>^QÅ@k ÿðŸ.o‹€©c'òÙ$B…gM¢€Uäàûä¿'êü6ŬǬ—}ÉÊ œ× Ƥ Þs1,e{Åäp€mxRI_6§+mv†iÃsI*(aXÊáãáõ–îE¨4æLd\ªt4¢ÐATzÎñ¶€ÊMšÄ ù`t(nn•™Ãê ”3<¯üœ~¾Éººu©8z­ý8ç(öéiÈë=Wà.›7ç!}¹ ²¯ûÒ;7Ëìžow7Kè·ôuÎÌ€¨÷t1+øO}.Dè`‰*SD_€q¿NV‰Á*ÓÔÜlŸºÛ§:ÚÇj¤œÂ,[*ó7ň:jĺ2Â)ÌØfÕùôyu‡ý¾ˆüž¶FtR'¿Æùq,’Xj¿Í‰õnMTGéá´ñm`Œunê\ÏŽ àIop}:çùôl´ðb.W{3P8w&;!Ù ÉNH¼Nȉ ì¸?.»%¾ÜGÍyÓ˜šó&ý4ç™´Œ‰  ãL™!ù˶Œæsý¢… ÍÏóµ0D‘"lÙûåîEB—/¿É®oÒjùK ž t×–Fùbe Û~Q»;C¸ cDMîת7=òªØ•tê³I‚eâS]¤Ù>rœkÖŒ6N#bdÐH(ntµeô¨ñ\Pû¯nßTO?„Ÿ¬‹ýžQÝèÃåz½ý´m¯ËGÅù~*èŒÞÅe ïFK—/Ÿ¾ta¸ÃŽÈ®'á+R é÷^ÉÛå—Kå@Q‘.UöåzU¾®§ËÃò„„ÅÃÊ61WÁ;2”Iø{­n/ ÛâòaDçJ½ºó|þ HOÎà!´ô8¸Ñ WÝ’<ÏZÏy¤5~avùÀÄ<°ò ¬<׬´©·á/HšH²Ùai-M¬Èð#éõÀ±•BÙê„%ù)ð„†1õ àGËý²Òe#N§åém'éͳÎO‚#È ïW> OI…ic–—ÐíP€6yeO_^É®­ë¢´Œ”…”(–U««ºìW¸Â®äR÷iǰ+^Á‹%VI²­¬xÚù-Üótýªum26,Œœ©ÎŒ¬RõøÅœžœÈÏ;…ZÿO?¬I¿‹ÉÙ4Ùe¡„¡aê^ž¨M{z–?¯Ý« x×¶îØœV3ä„<ù g~¼GŸ£×·P)mB± ~zŸnô±êõxõ/2ÍŠSÜTã˃ûŽÅ“ëëËíúîÆ½#ÜÀ˜ÍCxÚœ'ôWvÈW›lÉú½»!"^xݼò¸†ÛHøj¸îAn¬áž`¯*ÅÚð#h*Š¿ßþš”m‡-M_Ë?€~&î®J×ô4Ÿ£ãYm£8–nnZ€îEeR‘£Âø­F¦ÐÛšÝк^ÖQ®ŠÃe±^÷5‡©O¡ž\àÿ—dmÓð»KuÛ,ÇÆ›fãÖ›ì5YÐ&VŸÉÀ²Çdþî!h E|3\Œ-óîTKe±mÝúÚ%Û€¥¸GÖekÞBëЊêwدS@`h&<ô·ËvxTNœó¡S.¸ÆOuX‡Ûä4ew)»K±™Üì.µ»äÒrg£mo´dšÅ4’iêq$“js•ÁtyoUe\ó€Ý3Å?jïÓ厾üv}¾]ög L$½ô½|O­n¹xÏûP)úÖ¥à]`ã>4 sŸº‹ôO»ÀÑbþ"׋âΤøŽf¹ÍbÐ×íÍr7,ý¾1_hª·S>ù–àaÀZ¶iªÂØê•2:SÜ¿ˆ#UÀ Ú4¤Í )ük*ÔmL—‰c1‘ȱ5LŽ™@¾Ýº±ó#t@Vý¡›hÐqñÕ ÏkL‹.Tv0ºrL9-—à¡^‘«ë2ˆB%‡U¾Ø tëª`5.Cß„[ÓDŽ^óÖ£L5Ž^װ¼Ôöz)×Ël¯:f/_¥?p¯],ªk}ìE/èr],»@ˆ´Á›Å0Év-¹—ÚIz"vðpØ™cBÀ÷Iñ`ˆàIò5Ü£]l4ÿ¢kL,nnß’‹–a÷œE8IŽFaéÚ˜ ±Pè8Šˆ}âGÙÃ]Î;–<ýyõåÙæ°ûÖ['2óŒnG ™Õ„䞇ŽC2¹;ÉÜÔÃÑHÍërßs„ž!Œ™êv˜Ý¼•YÀÍ‚|ËþHð7ëmü*‚lp ®ÞÎ~Ó¸oçá±æ3ëÒòq¿:ù¸$¿ËhÅ/-™¯¹Ið1¯t”~€A©GmJã˜Ú”ÎûiS:#7à:´~®Ðà Þí\Õc½¾¬r/Zö¿˜ ¢èüQõù8E‹CXõXùn#!lÝHÂÜc>ç£Ó EwÇò{¼¢´î!?Ô ª?ßD4AF¶¸qIÌL‹×ñ-íM¾q6IoìC taµÍÍâöêîgôÉb_Bò3|™Ë,9>ôôç:ò:-±ó¶¨ï¤k-ZÞåfg0"ZåˆØª#£í'‹!2`8~YÌ(ÐŽTEGäËŽÃ+ /a‹è¿}à_K–>Ln8•ñ%ÊàãjðâOTòà8xæ)ݹ°ÃR5õòŽìöTäé­Pн¤Ó\Íás?®k8Ò:øI‹ŸJ–Ù€·½r¿çQ,Ý´ôuêýªäx˜VüX"t[”›å­ÐbÙ”ƒÑŪ|màÏågmJù ò:5Þl‚eÑÅÒFÔ4¬ð·%…}Ž{M„-“¼Yþ£Xlï·wô=+»ÑSçs¨_/o_¦`»B2£;ž|÷\6/Cõý§ÝêÜÿô!'Ô¥›Ûƒ8?Û\gaîK˜)qeÈ™áÛ,ÆXçVÎï`e™û„ó¥%G0SÅŸ’ª6°ƒÆ†Tl°'|¬º†L Äç® ×5½`×â¸Vܽ/öâ†;sÞžjy{ÒÀÛ.ûG9DêÇH†·­!ǯy¼ðèú ƒòa›;¦ÜuS7i Ë'µLwð3v£ö¤ºúL1'tþOö|²ç“–uÈžcÏÇ­<–œ½Ë%9elÙW6}((ñžJíSåbmÕ…jÀs™ ØûçT|òÌÐLЉžFäÐ=ÙŠΩ»X|ÁæÂñV !Nê¢éîx¿n™õŸJûe^:&¹ËßQÞ½z̓ʺS¬räÙ†HQÇ.á–£NÛv8 ‡þZÜjp»Å ‚ØÛÖÔ¥®© éÿx{ókðî½1¿zvîÊ—=˜hòÙ æÛñë<ìsdŸ#ûÙçˆØçèl…Èç\|ÎŇï„FZ³Ï–xÙãÌIøÁrŸ³Ç]Nâ&˜Œ¯p’ЧFILœ# ©­½éûݲîÿýrsˆ2ë~·Ù¯¾lÊw]¹?ùÍÂs@6¾zýƒÊÆS¬rd܆HQGÆ.áî…°(Å_„\C1ìä4VÀHÙÈÚˆ™·Ùúê½]]W$q_C1qÏbלÀçha–ȯ`ɉ|Ù)Š&‘_ãaB¿ÎyÉnKv[²Û’Ý–„Ý–ÎÖúˆ uNøç„øT/¯UûLüËjNüž bX² §–¬TH8©P{%æòyçûµ¦6`z¿Ž5‚«_¶»È«{¢®N€þ¨R€>„ZeƒaU ¼ràÝŽLq‡ÞN!w|CÕà1ü®£ƒ6šEú+dîìæ0Û«úüN˜ Bi´5¯EÑİŽ@!Ê••ë_-Aå:c5¡Ö½ÉŽMvl²c“›A96ìøQ™ð\eÈU†ˆòÊXËöZgPø¯¹ÒpaYk@!pÐjƒ"Ib½¢á¦âÀX/m»Âuu‹»v«=<ÝÞ•XGY{¸†  3þÐo­?t5æuªÆÀâ•CñvdŠ:w y÷P©!x-þb,‹õUÀÐ۸ڛ؅ƺ0Há ±p€àl.`ÄÍ  ¹P òs¢)(ýœ#,Ôû&Ù+É^IöJ²W’”WâÀ>•i΀\Ÿî%Z´ÏÄ¿Ê͉ÿs‚AÂÇ«!³üªtp‚Y~ 'Y~ÖD‰ùxâ'àj²ú&wé¸=÷îgü[d¹üŠ„y⿳M»„¤ƒÊèS¬rä܆HQÇÍ.áî5ï׋ÅÍòöy•„ã‘„^û=ýû}¸\¯·Ÿ–‡íîúýv¹ÚÑ‹ Äü­àÿü…ç5d£]…‚¨;\²«ŒR¼kjhÒû‚êÙ¹” ;YѬ#,*Ô9GÙ-ÊnQv‹²[”Ý";·¨³£pD>B®häŠFø<¶wUÞgéDö¿sá$3œ— Mðýr‚?ÁêL…„›UÌ•©•'+| ¦mvwk_­)nnßü'Œ2º¾eD>çpÆqxj±7‚Ý8æFLÓ-òÝìáæ§ØïF¬ÔÕ§ÖûÊm|`È òbÏW¸“–ÉŠ1¹2ËT½h,^¤«î…ÌwÁ‹çBxxÊo±‰+žç˜cÞ­,V—«ÛÑ¡&•¥¡ƒ” ‚L¯KKŒûMKt‹©âM!1ÆïiÌä!±³;ºU:æð¨ó['@–K'ùþ-z›‹%hÿuWì¾ÜÃ7½w ÜHÆç^+“¢ÄŠäþíŸ~Ü£«ë}a—Ãï}S”NÒ?7Ÿ¾Ç:j‹4ÃrO‰9í‰kvÃF|8Mé^‡é·¦áãnu(ö§(L„¸ðjâØDˆ[­&|ljûÚI ã_ËŒÂ# ¢2]`´2•˜1±¼bCÑÕô'Úš¾MÁöÕm=jú±¦/o&BÈÛŠmƒÞ4¼û¶øk©×NzÖþ! ç í.0VÓ5Z:ë笟“×Ï õF39*×Mc*×Mú)×£®ž¨«  œ«AAJVZW” }Þ*ùúÒUܵÒȈÏÖVÌ·zŒUƒú­¼W5ùØ¢šªŠî\½A[“•Üìk/¨·ƒP=±â‹©¯8ç±t\nAFø-$ðâéË«·ßôì7 èxriÐyÿ~‘ªý¯«/»âËj_BØ‘;!¦Ã>÷^ùúË/—¯ƒ}D“¦oŠ_/׫’úO—‡å‰–IøËà-Z‰Dü½Vp7ů‹Ë«ËàŸî>îLIt©3w>b~/ås>S×,¦,˜äIö2,"¬‘â &Æ–!؉$´Ù áÄ_ÄS‚´Q@€R*ã\Leà—“bA”§òi GxN(·dËw[¨@Óüh¹_Í\z$ëÍ{ ÌøæÙGFû¹ Gˆ¾ë‘ÝyêU抧i›ÕÌò¶†Kÿò¼Z/+ áß„©ã¾ΘaÏ–f±(A\¯‹dù1j[e®¤EìÝ{ O‰ˆwv¦fÓ˜d¶·Å´ŽNNkÚaÀ}MOP ¾ÖüNÜ9–L©ût²þtïØ]m?ýãÉõuvŽÜ¹­ðÎyï)ĵòHè³°?R¡åÎ!·ô釸x;Tw3T ãTïÚ‘‚Ö¼2¿ÞG…”²¦oÀXUÓ¯„÷;,‹«Õæùòfµvßeãª0vÏ»ý» ,¼2+q"(Ûø«@qÈ¿›±ì]I®ó ” ›3ñ$”Ë0}ÌgK¼Æ%Ú9­Žˆ‰W¨^“L/–TËÁûÕ¦’lêâø ­ –ž ÃJ餱ÔCX&”Ƣ̿ÃûU<Öt‹ÃËw_/BI=™½e!ñdvV`‰Gt‚ÄcL‚K<oã]âu%^9ÛF’v:ÛFt,i¡$ýEXIsüKB?iÿôE Qµ<¦X±áÿD~9F-’ÞŽ|äçWÅ&IAØ—·[›Å¡»40¤H](XT¼š1*”÷Y3I¿€”]õ^y©@’Uýñ>#!|~®ºDÈõð‰ž>%*YqZDJîêPdQÑc(2J ¸Wsª/g¹mæI<‘û—dEeµY,;”3D1‚ˆ„êu°¢áT,ðz‰2*zòü}ñÿîV;÷‡ö å‚~6Ÿ?« ±LKàó•Á³üÃHMPt‚ç'ðI½é‰"ÈÃU¼ÜœµÐÈ€:A%6`2#¸ÚèdN5ôîՉ⟦à¿h+øÎ³ê÷Ô”ÿ ¼Y“ú„“AtpÖe „!iòÝ@B7ƒó^ ì?½Ü|Þº×(tU — ð¨Ÿà_e§DĨˆ¥rHvÍIa¯“´Yª¶Þâ®tæ^Ó"22™Í´± ӣϦGS¥×^íI¨è»Àƒ£{K?3ºñ5« €ø4©îg¨›Q—<2$צG”ÑÕÜååôlVWêiÑ}°u3-¤ÑÐT©yžeíV¬Žü ql5¯Q»&ky”³«ÏÁÀŒÚ‰J-::™§Ööt*çUŸsóªÏë}Ë;Xõˆöiµ¹WUEü Ò)*®n¾ž¼v‹ÚÙîM˜ºüÜ—‚÷Œ2Ð,^nVî»ï¢ãa å>8¸÷PUBÂ;·’t ä)ñw»í§b¿O–gñ…Ö  ’gb‚‡w>fK:H³VØô‰‚矯6«ý/GÍòˆÉsF¬w v1 Åìa¬ô§¦²tÂRóti±¦Ñ´·HaUGúÖŸ},%¹òo÷Ro3z|š‘ºY­×«ÃêÆù¹SðÒ.¦mFûÌ+˜ôÙZ v ®­¨¸wÁáŒËÝÖý&pÓnS·Áên£' Ãg‡2ÀÝþÜ©dàÕê»ï?A€W+1äų‹—ž½Fz}µªª0“ ù·Qu œÅWTCöê+ª´áò¶W E}öwÀûå7TùÇ3\w[|­¾¨T¾´CtS–[|¥5¯†Gž—-Þl/oJmìFqé|Ü_tswós±•ªZ‘Òš³‡ j[òÂz»¼.®GŸï6Ÿ€ýQ÷¿ÿßÍ=Õ½RnKý ýËåwßnwÛÃÜ_Þ½˜3b}>t; ÄL|E0SÜwYStfcmâÈê¸Êáô\†$K6½Œ ?ºŒKŸ‰Î¥ô<÷Yâ(’ éTв0&ðO'Þ÷æóêIè†PXŽBÛIL¡í¸ŸÐvq”(´Õ…u¥>ŒŒ™ÀÁÂÈ+ƒ·hB6‘Ðôq™¤L[GaÛÛ!6›Q윶šùr®J°=øVÔ>—LàÙ¿[ÞíÝo‰‰†ó z ²‚Û#ï!>ðÌ|ÿ½8ûad@¹G$Üà™ ß{÷ƒwâaAˆ^‚ ˆàöÈ~ˆ<3Ø`,]È„X8½Ö‡qS2h'Èš,ô† j¹{M€ÃGlN¸[²›å '™¹«µñ‹T-ÖÆÒ¯Õ®¢x$!}.Õ&TW5EÄ.+U JaÖ“ë5/âB¹)ŽS¹T¯ŠÏ)¹%Nøœbž&£3ðÇÄé CÅÄê+¾,½ªt˜¼åL¨9‡o‚¬M ÀÔpX’†µ Å18©Òo–îÀ÷ÈÔÕô‘Šè­MŒx‚ÜM ÀÝtòËè¾^C†ªar2FØZŽnýãɃ¾xý*¯³3‰,N˜æH¹¯dsòþp=Ÿß,o™ÁÕ÷¿lwå¿à/ëb¿çfZ£átÌey«?£Ü.W;ö2èu¡ûŒ~„ÿÇç#`êœß5êîLŒ×­£m÷ €µ£uÑÃì Vê{w¦ê‘ó,ï;Ëã9%O/¥P|ÓèÑg@ЇøƒJ> ß    àïÂÿëy4œ%ÁÅ|†/=àûTQšdYêŽ0yS×–ÅõÞ÷šX»÷*IÈûÂX÷0c*3 ²°š¥±¨jHR-²7‚†»4íŠõY¡\ ©£upú=ÍlEòP¶<ÌñétIŸ³£2“’Ù9ñL´ºò`H{ ÏÍ–ÔÉv8);L^Û ìo…L¶»}Û]=©£2*>ím"$IÃÎVæ$ÛWÄ]O®†¸Ü^R4R‘&ŒÍ ÞUªI‡îÛHlþ% (#°ñl)UãîðªW?³îšÐ—6jW¾J#ï„•¯úéÑÍýnBYL0BðšÇFcÝ)ÏŒšjé,4ƒæûâfûÕ}ÇuuéD?öØ-QoF刕œŽ®õEOïCõ,úOWûåÏë0ôÖ =æ=´ù\ÏL˜Y`¦ ýrÿl€èý‡9 ª¢Aâ\Mñ°bhË>ûº4•p^T~é¼§l:f ˜zÓ²Ôqé¾u¹´Ì—Û››ÖòÒ[wl]®îSÛºÌ< ·.SÔܵ.W÷ôÙºìçQÎ’2Lë2}åŽ4¸î½ùm]¦h(tæ-«ræ;á[—+`—ëb¹¹»g0z(øÅÅÃ:¼{àäþ} *ž¹·Jò³läÑ»–¨ðü)6ÌÇÈÍùa°4ƒOX¾f¸*sƒ¡F khX·ûZþñðÑI©¸W©…Åv^)/„h‰ËB…†•ØFš:A ~¼ýKDC^d ØQ]5Ã>€Äø\ö­Ô}A>‡gjl7üÀ@Ä7qiƒ(„26;m@ܳ}yr}–Wé ƒñ¨å ƒÐëµdrº-¼‚‹g™0iÄcÉc2RÂEßœa¤ÉBšÉêÞ-~²_’#bê¹&Gq~Z¬¡õìk¦¹¾PNEƒ9ë%id"¿MLLƒw«kh"Lù ¦Î;žøÏ'öºJÐVø¥*Ú¡à¿“T5Á˳æB$0ÏÍ„TñMuëê¥4ÛMÕí‹d[oÍ^ˆŠ _Âæ~/\Ú«P¨ô”× ÂuªÅuj‹ë´%®S\§z\§|CzŒfflxÿLÓÞ§5Ûî7æ:5Û½ê Ç&æ6Úlh³¡°¡µ0>´;ãØìNÄC´ìE¶ÙR¥0ÓžTœ“pгZs´´:þ‡…:ÿ’U§CÕ©:7'm½i¡]Û6©\q†(šÐévFüÑzµ¸/öûÕ? $«Ÿxa*?ùú·ÙßK°Ñë8$ùWþ[«/hP¾ÐQx(e¢à€§”7ý{õ¬Å«bóåð úÆhŽô Ø_²ZAõøóhz:ºÿ îT2éjõÝw„_ À«€˜@òâÙ‡ÅËÏ^#‘_­N‰]ð"`þmT :gñk¤²¾"³m=VY ɇ>û;àíòú&ã3ì ,¾V7´º*¹«òÌx ‹¯Ôö’ÿJ 0²A8/Aƒïcð(b:å‡V,Ølj‡Á×Çßõ÷$É-™uë*:WâÁƒÓ“³Ó ñFz·¦ó؎ΓLgÎô' Á|ðX$ƒGRaR=ÞøEŸ«^4½·þ•Oó+핳?7‚0Q` †cî;Ssû5'V® ¼ÍUq€NÚëý—ÒyöÛ§Å›íáåMi•V\£ˆñÞÇpû7w7?»Qiò¡;VºeÄSÛCG`[²çz»¼.®GŸï6Ÿ€?8ú£…?~ÿ¿›{¨{¥Ÿ²-Ý”Ÿ×Åèò_.¿ûnt»Û¶àöûòæÅœ¹ næsâA ¡âCðžà?§í¾kÿ5ƒo_\Êz”gmœÆŸ¾=¹¾îáØôqvtqDR<‰1ÊÝ]väé¯Ç‹ß`¡gC Mȱ l§˜ú™úªùÚbê£ou$3Hqê£ ©£qØÿÔÇäH¢µ*a¦>F=æ±ïcePòes„V’ìW%ŸNªÜ;ø^·?aáÀa„uuQœŽÖû9G¢§s$Ë‹|áø©™ýݬrb„¥Ú‹\¯J\,t2z©bc]eH ×"U×s›‘ªS•¶ê¬sï)¼îoÅ©yÜknJJ˵žQ \¡0ˆ ˜b¡ÝåôÚtöž[ƒYC ¹ËìuÍ0IMrN1uu¨0{Š("Òì˜#Ú™ÑÕiÍh¤M|3܃¼4¬Dâ,?ƒ•±óRÚpKJNñá–.CE ¶ŒF¶¹Ô:îu‚&Ÿ8B– ±–SåwgUM­´ºçBj¯{ª ³2•ˆ­TP]<-*½9D–”tÊ—~Üz¬HÆQÎð×Ã1¾ÜÞ~óìËWMìhZE/§½x>Ùï¯mÛÜ1z?$VCÉ+…h…9¸åÌ¥¶ {cÂQ' N¸»ú>„„2C‹õþ—ÕçCùC_ Z$|OÕìZgi™¬âbPÈé ÚDšp ²œ£åÑ}¢à¶·ÅIýùÏVS6+k4n_Íš Om÷‡]±¼)_z'ü§§#²¬¹PºÈIØ“Ur„*Y=ì9.ÖPó¼zP¦»¹ˆËÏ‹:!‰f!ü®Õض Û…¾näuQÚ¨¿ž•]¯î û&æZåÔnT0°: V³ò ¨|lƒZÌ3|X+ÈÆ d4¢ rnx7Pœz  -Öû‚má"ú`t(nn•ï–^†¾Œù|•|ÖäjÑkIñºïï­U¼± iÏš7ˆæ ÞPk¯¨ºÍg?2õî»]L³ïv¤¤µïx&bß €—ïFÁÕønPDë}7|IöÝÚ*ޙ߭…æÍ¾Û04o¢¾§©j}7ÈÛGæ»]øU!Ÿ×Û¥­þ@ßÉ d ¾Üˆ5„¯Y} =2Ýñȯî¸ÞÞ:vÊ)kAjôv#VÀfýÙôXˆ£ÓÒ“˜NK“܈ßx»Ã¯  “šþ’œ‡½/‚cXËw°íN×"ÓJÁNï¦á‘€ügêòæYßT¶\(84*£DdïTž‡Êñpc ´åÓLåþ©<;*£x8™/ކÌ8pDçGásó¤•>w뎖4’·ŠbÊpáå›Ë÷Ïž—!‰0k„¤?ŸÆÛlÊ: 6†âpÏ&­1çðMð¤(ÜÏi:ÚÃõ¬ô¨âu4ÿ|·½A+{¹Ä|]?’h¾‡Ó¤¦ÿÞ¬~;ÆóZ-…A@½d“|,ù¨– q"=«åæeÍa-•vƒšÄ朖¹Þ‹ù0Ö+°‹béøëŠàÎvæNhÛUÃXwÒ2å/˜¶®Ìè†sñŸO:«÷JÁÓת×ÿ¤¤ët²ª· M¤šÞ)Ȳ¢=D¾I³ä+•$¦Â€p#4§Z4§¶hNÛ 95íXŸªºžhÇú´.:¡ÔÍ%ÿLÊ{>Um`Èû6Û®¬rkëkb|³ÙÍf7›ÝtÍn'+tTÈóÉùA$æ4¦#l4†i4ÚªÓãФŽÚg1µ#N¯1‚Z´Â:wßfr¤ä¥?iš8Vwœh£‹U'싞æÍ‹fnl~›¨@0‚C ˆÏ)Û[øÛDZjG„¿ãÆÆ^‹kpÊwöä2•Ûsê¿kù•¶ËvÐö7³Q­¿±%Á»Êß.ÿnÊ7â;V9xÅzŸÿÝ'–\ð\x+1òŸëJ›À­J’Bp«-H§ðßYzït×!<¬UÐõ¸ºH%šç.¦j—WúêrSÛÜEC¡¯¹ÈUÞ¸Øðˆ‰î™Z §ˆ5gZ֜ٲæÌö…ÌL«®³úªëŒŠá,̰5½Ð"{a‹ì…-²²4 Ñ Qœª`¯ÍBÐ"²25›Ø›¹ËJM¹œÒ´EVJë¬T˜â²#'1~·0”××Á»³qî²[—ݺìÖe·.»u¡Ý:ÏÑ8;žZ9;Á]›DZâÔŸ]“ìšd×ä(\“nÖúh u€•5†ÚIŽ«é} ïÙ°fÃê²+œ*è˜&(pšÓó¦ Ys†Øî¤[;ñNí¬ík»f]ŸpÔhü(¦Fã‹ãk4&ÿmlì}´˜`]ÓkˆÂô§ÈZŽë¦M¦Þn|¤ïº¹Ëz¢ï²6„ÀºÍ¸îÔR3ÏÍ2Ïež£ÿãk$üTÝgoßk¯©Y4ç;Ä؈ÅE‹,ôQŠ…ø»,E-ÑÑG XÆ€‰ ék–Zí ù16RòüŒ“³3'$ކfă0¤á!Œ§»Þ¥í L¿gr]Ûƒ:O>ÜG sªÄÇœµhC IîëŸö HºC—â¢{âÅ Œ„·¡ Ø(n•^ÄNA§óÒž)Ùý[äA,>” ý×]±ûvrßôÞ)p%g£SÆL{ÿöO?îÑÕÂFX#š’nŠRþsóé{,[ÄnË=%æx´ÿËv¨vÏþ¡ªÞNÔL1ÆL1á\¥J›Ô0…MY^nÉbQ¤’÷û<_@È ðt(­w…ë(™{©à ,–s*õQåq±FC}4Tu€¨¨õ•ÌE°]]½:š¹îÆ Nv§°‡›íN9&¦¢D ÏåzUÒ¢ôeïn†™y´ähpl-0Pd¼}UìÊ×vt¼Í &o³åm–bâmÈa¹;|xuu4œLN+ÐjeÂ.1ñðÇÝêP„™ëƒ¸ §_¯á¿Ñ&¢6ƒÁéݾû,Œ_¯·ŸèGø9)´OÃ7•x‚áàG™fÂË’˜% žl®¯Ê÷MZ o Ò  ä ú6ý…»šá®ôÅæBøîQMám0üC•ª”I€¸¥¤ÀIÛP˜ÝsOµg1/‡`kîªÆÛÜX Ÿ{rÂÒòtérÊ6Ñ$øËož}|ûÓó*ûû¼ŠzmÝâ.-5{›´-ëÛ¬iµ•œTÆkjàHÎ º‚vi:T+Í£›§ðvÓá>©Ã}r|îÍQ½ÒæMï`:Û%Ê ~uEÜ3âVŸu!,ýIÓÃ…ý٥צv>`¶èiÓ‚ÁíØ…´#ëI?D¤W62¡«Í~_,¯sV¢Ç¬è^À뛯)ñÔDáh3j앉‰ôSjdûÈH`·j±†äCéѾÛB"ÇödSüÊÈ&ï\#JÿzŸñ´O9{/ÀMrïÞB]»xûñ R±ç2^‡WÛOËõËw ÕZˆ l]n¡X'Xpa€7Ôª\Ƴcáå„»å)–C†j¢Y+p2G^f•˜¸÷ÅÍöP“´Óäò ú˜Ø¼â¤øøüå—ó Ïž}ÀÂ9ƒs‚LÎB€ÉQ†RÍê,3ÅTV/Ãû`|NÝXŒÍ!»fœÍ1Ž ç*z%[uÐ47‡,_ð87§ q1’T.afçÐ% ‡ª“†—.}uâÝ·Å_Kþ?éÅY»?éœédÉèq·•޵Ú9Oƒ-Zº×n0†ò§£û„™ ,ûÅçàGËýpÀíaGìôƒ“©{d|Ï™ñ=3¾K?N`}ìR# uGæô™C˜ÜˆÇ1ˆÏû)ŸG\ÆTõ$s.ÕõTµÚ´‘T¦Ã–* |«•TƒÔÿiž–uÉ+Y%ø¨MVÔ.¼Ã¢CFw¬ÁL2®óæ/ª":< Ùo@§ÁX* ¦lŽç(ÿªƒ:$Ra¹9œC4HÓ«ýQ8÷1©pŽeüc 玅ñC„suÒ*œû˜Ã¹‡s¼9h8Ç«îøÂ¹n¹µáÜG7ᜨr8Wα3ÉpΛ¿M8§Á¸Çpîc¨p®|v–f iN]˜N–½‹rÀÄLÎ˰ò™’d¾ð'™Y™¤’29's$L"#aB&çcž9†tLäÙ7ɘÚ\ŒƒTÌår½·ˆ‡ñûà‰\ñ³l,·4EvÌFˆf‡Y7ºã½ÆÁ`5¬’%âGzy\Ž&>l@[ŒWŠeÆR|ˆ<€ ¨ÉÐ漯0ôgÜ0ô‡ž÷íºÁ  âÁßH†ÿ¸†ë/fP5^•}:§¬¤9¹ÌÿÊ=nFϤÞ´¼ƒÍìa…iñ]q¦%‰ô Þ dSMAñœ*äȳ¼†0Ë‹üW3jEv+ö¾¬Zm:3Ù+ ›'µëvWL÷2œé¥Ž9£ŸíÅÝ1²çµçÊp¹¡ô­ös¾öÅáÃê¦Ø%”í6u¥æ"Ž ¦µà=xOtpRÅž½‰wË»}áúœO~¬PL)칑ò„gfüïͰ#ƒd‚ ÉBï‘%YÎðÌ”/÷à©ðñ)qe×A>é¹”?ºQ> ?E6˸ Û»Cå(²£¼ÅÚº,â„">æÍšÊÛžˆ©Ÿx5ŠAähòu8»H>ªFÊVö[Ç¥Ì,ù’uà8$¼­hÞ1‹çxŠœcŠŒ¹ÀñËC@’*gLÜ×ræzºˆÞ‚;ç0Q!B=ŸÐh /·Xï‹ B,ŸF‡âæVùn«+ÐËWQ5vi€o’Ïš–%ÓkI .–i±2å4–Þû S›}w·ÿ姻ϟÃTfmv…’­,S»zÅÎùæP²ëeÊ_0u^êå?§ëüJë“·¬¨Ã')iÿ ™£]6ª§€rá(ç/R*$·vT¶»Õ£•(3È’u@„êT‹êÔÕ©=ªS“E@SQºhÊwdâçœpÛ©O«’8øgjxj1ö¨‚©ó\m?²µØæ6ªÙDeã”S6NZ{` ÛQ?Å,¦~Ši?ý1—ú¥B» ±ª:ÿQXgU€ÞXpoQãÇjÂo•_rB,jü싞æÑ‹fÖƒÂD‚,j@LxNÓWÂÞ<¦}Ç“ʘ°&ó!b‡0_gû­¶'/ŠÃKà×l–kp`Ü>©S»Õ”¢*ßÙvB¥L†4kx <¼Žl¥s£¸­ .cÊ€"8«ÌŒå£ltùîÛûâ€î<Ÿþ­X"¥!¤ßÙï–nÕ›í¦ Ê¥üõå›Ë÷ÏžŸà?;ü$Ζà Þw«C‘Å‹¥CÚòÅ"“€±Œ6| + ÿëåoÝ¿”·üe»ö|€5áJ™tÉ–áÕØU;¥ þ½uU*¤P_^î³¹2´:߆¦•ê”äYGLMi F‹©7 ´Í¥ÕƒÙ¹É8ݾË@ — íÅ í–ž{‹¯B0tšç’S?ð$L˜ÉF'`ºGwàåªüï›åMJÆÈ]æƒ Ÿ¦iª `ž¸LGíÈ\5¦ŠÌ!åD…ܾÇe8W¡xŸ]tAm]/O÷E-l— -IÚ/[™é~Àdycè„å ç ËÜ ¨%Žhï"YÝàf,ŠÅ ¬®Pnl01ÜMÀmꕜåì¿l÷‡£uòi:ôÑ:sÅé„áýdAZ’tleæ¨=qâuÂ\ëTºb¨ŽÀÕa¹ƒÇºò@qæbÚ±8S!ž¦@Á©C¹)¦ Ì{°ï EF·äjÏùZ@À÷JŒ&îí33ûÓ·C±Ol=\!ž ¿ràǤ‡)7E§‡Sdô6z8e¾𭇛¸·w= Z7Å&!u§Š1î r­ˆAt ™°Uœ:9=¦o­–Óåq‡ ʹž“ûÔÏO¾~–!Ìd¢JË.Ãv˜_oïÀ17{]Ï({LÈd³º Þ}$-æu¨«úÊËšõ•Cæfº–¨eC,WÓ¤ˆ!jše†îÛ8Ìν¶àòzÃó˜—NV®µ°ëd=K¹©;gÌôñ2¼£1“˜ÆdŒû“qñôÅ~…R“Žð«†D$¼]….àè}½ŠÂÕl\¯f…´ã0Fi_à鼆«éU-'”7‚§e³WïÀ«‡”LÜ­G8§_¯Á=¤cAŠØ³g•Çñ¹ö¬ÀgQwêÜ#Ƙé³{?l÷ž×lÙ¿wìßó^gÔ>Õ‰‡‡±‹u`Wÿ}q³=ï¶»”Öm"_t,«RÌÓ4Ò ü1•T†Š© ZBöjûi¹>FN¯O“Ñ)ø1ñ9å¦ÈØü9<]掎¯£cé«,]qeà䣩(0ÃYH/Ïxe'È.j1VeKše!óª@iÒg {kº\o÷j 8rzAƒ^ZáNV¨ôG3°Hƒ®tRäÉfÁ–ÙX!áð¡å;¥t¿¥»ÉÊb–š¾TĈ!˜0§ß‡š~çuÌÐïÀvùÉ»ó¾Y¤wdÇ\;Ò’!U.Á ¬}r½º}BÖPö1º$f¨s“žÁäÀ1ÕGbR}Ö†rZMêÆó@Ú—{UJ'JáêÕÖüNN×+Ðð9ZÀ®f튇jØÚûö7ÛÍOëò‡ÕæËË· q·%;sh&ÈÓ<üž?üÆ»ºz•Wvӹݹ™¾ÅÜ“¶½ ÀÐ%»1üJàÒ•„ô’ÄWVòà:K ¹Ú{áG‰°˜' 5§†±ªê=@z¤ƒÿ²Ü§¹Ô¯›AâÑNÐ0 Df ®ŠÉP]®‹å.M–·äqÓ¹\BÁkaD`Ïšùj¿~¹VŠÆÏëÕþ—#JЈˆ'È· ‘ég‰·¢ÒÐÛͦüðå¦8UÃìðñIÅãn ü ¡x‡éäüçã®ÂH»Z˜×ÁÅ-ðßqJbÉ¡r<1L=Ún"©Éàö ¥‡0¸}Ü0¸}b;¸}ÒŽ"“8'·;k3ft»h;ˆ#Ä<†¨•óÜ']mˆrTû„Õ>©·5–wèf“<7OÅìjkJš,I¶!Ù†XèŸÈÕñÑDj ΢l›©ø;VÞvÔ¬9©Ys’›5ulè=›P––~š6U®ccï&KçI¦³Hgéal( Ÿ7.ŸGâ”NOÎNmž¬z¦éÛUvæRd¢èÑe îÚªË ðºŠÁ¡Ñ·š¯jÛá‹oòüi˜\"àÔ*lÿL¤¼â”÷ÈÊOf\Ÿï€øøÂÝq8ü÷ ÿ÷‰xé"7I"ËÿÝ™xï þï­#O]r“ÿ|¢ù|ªù|6êœ$•ò¤ÏŸ*’¤ðß üw ÿ%è'—˜Ïé@=Êb¬[×ê¢î øJÒd$Çɉɉ-’MYP’b6Q…äD‹äÄ2%¾D|s¸*{³¼ñ<Ù’M×Ñ4—qº®ü Ê¼tH·Ñ@¥!_6×-Ù#J2&2fæy–±Ú¶àÔZ]žel›g©ÝçÐ@"i|ù–> ÇrÊä]ØE¼&Q¦YL¦)ó c.2n‘IÑßÁr!S@…Ùm0±*WÖjZŒD‚tÉ8„\©¼ÑýšN<»Õ¤)‰~仺ðC~kƒ`qT;¢Ô«vD&7ÛÅ¡¡jG°õX¶Ób+íˆ7Wî*QgÊwŒ#µQUï1ð8ìÏÿéÛ¡Ø'äT dßG0—OÓ% àÇ´Á‘rSí±™öa•” \)Ž®\ðN—É!ô±ñ8d¥˜XgÝ’¨hÉÍŠ ò2…Ýç¬ÏŠ'<»OWûOÃçGËY’ß#WrÌá™1ÚÞÞ¥´¢Ü’'1‚ ²#Ü#'nðÌ„ï‹åõÓåaé— §àpœð þm ³ÈEUE-z÷Ÿï>ó=èËõzû‰~„Ÿe~м•ÄT~&1ù©Ë’¤%žl®¯Ê×L²T€%Pç d lRVuE0=ÄŒd.d T+©€Ø¦$@K›·Blî9s¥G[L]!ðšWXZi«Jƒ°$<µÉbÁv)¬ðßß<ûøö§ÿ u¯¿ý}ˆ\¯|[ÜÅRQ¿ZmrŸAŸ¡U²í¹«À˜2‘68XßCP)‡A¶<Û,^a Ïx‰Ç3Á°I@Àcô$°ˆÿÓqp¨€h‚,*bà7×’Iÿ²Ü'È wÐ%Ì«,ô‘m7b™©ëùOÇé¬O¿ׯ—¿ }õœˆi‚ü-¡àQKŒâYƒ¶DD¡p@:lÝ2™ù±ëwé–qR jú#$O<«Jñ8š)5(»˜Òaž‰a³V 1"]«åb¬«T)*•º´Ý Õœ ‰kIVùf€C.4†_´/ØÉÂ[Û¸£µøe$nUdrâÙ’>‘¦Ÿƒ-'¡#é–oÂTÕ4—YÓ„*ÉuæÁ·&˜èò"9Ow4¢`CûõÏ¢€1(Öû¢Kۃѡ¸¹Ur@ubq5CûûÀ7ÉgMþ&½–ÌÑ£Éí9Ú: Àz‚Zy—¼ÛBl'›âWŒ Ÿ¿AÏC¹Ï$rN•Ü‹ÌÂ[¨Üo?¾a$ß¿}𼌫“7ÓZ­[iõ¬Ïû9Ê^+‚G'~ŽÎOb8?îgàüyÄŽÃcMõ®4RV5Ýy1î CÏ”xVÙÿÆq¾òØÞÖWña oøÇô6é!ôRN‘msúÕ6ƒvË»ƒ›Âןމy‰ˆ}š^ˆ„ELž‡Ä`ƒô6Þ¿qXæP·HÏ”“>.9ÑÓ†HQ&wºjBGÄz¸I^?²ÄFg=ìÎM’Dê(Ä)'bœˆÑêΜ|q˜|ÑFñ&\D»'Y$½b’X‘Un×dÊ»bsí½3·“s€/lí`ŒÓtðü€òjÝño†júØÁ9Aű;¶‹Ý±í._ ÒRép7–õg—oß@Ð;±:Á?M^¯ ±RFx 5œ_1Y<¬Šõ%îµËë5#ï{PÜ•$2éeï®ìgÂë–NLÚ|>\bkæ°8³.¥’9}n©·îÎË]Q>ùªüqÏm§ÝÞuèÃa •ãá÷3WyN‘㞘&ø\®·ûÙÚ–,Sdc|Ÿ‡¥w«+ ò ²+ }´ë*+æªÑÆU†áý4çO_IÒ’dXa+3Çs»–8‘Ãv ó²nŸu¥+9Žú雫WÛí?înäZÀã?€÷6ÕÒ.+_ &4LV?R Ž&éRƒ².åB˜Õ<åR±7“rjXÑP9Ô+•@ÉØ»Û¿&'tKËP”ŒàÃ%d¦‰)SÆ%/ß}½8FÆø&ÈÅòÈ…Љ©¯B05ÄÉÎeƒ_ \c¤!=íÊN&\{h±½×ÅÔ‹€­Ù)¨ª}A P÷*ýäùûâÿÝ­vÞw¡Ìó“ëë]é¦V0¤Wñ®@OY®)G~Õc-gpTÜj‡©¹\­¨$ÐOÖëí¯w+ß=/`*ßÅtqh“”f²)Õít@Û9Ös‘ŽÉ*Ÿþ¯Õ‘5Â6kèájíl=DEQ±ó}žò µ>²Ò. ]ê6äRIåΡ™E.Œz©ÉZ‹`®þ±ºÅ3s càõ0ôJVÍ hUXS‹¸ó膕®®Í‹Òµ*=°—›ÏÛêíÔ'µÜ¥)ÄÓïOÄËÝOSoY±bRƒä$>]Å$—ömˆiiß-ÌriÇ,¾â™yŒ™yŸ\¬ôE³k3|}W³«{y¿T¥Êtþî¤O×°X +QÕX Å…%l •54š9ò5k³L««1ws`~T(ö{¿Öü¶,¼Ø¶»å—¢2»'ò_Øï¬‹ »Ï„5ÚÓÊÜUËÀÇ3pSú‰U¥Í(gÁZr¥§ÌĻ̜›zþs+1íì°«À.Røðß üwš’¯ Uv…¡‰(/Mäq•hi"h|%¹ÖQJÐÕ—Øø?âHYYëJ£4Sr·Ä²‰p¢)¬€¬¦4é×Ïê4†™¥DÕyÍ4%ö"Ö¦co ¼íæJÌþIy –hGŒð… \UrÓ ÐîœÞ¿Å“Z@×Ý»o'÷ðMï‚Ñ gqŒÅð6b÷oÿôã^I2#Æ|·)ŠëÑ?7Ÿ¾Çöq‹tÿrO_Út´ù®z5ÔÝ©hŠhÆêbV›tÎÌNçÌÚŠÎL³oH¡efÚ´)úæ¶™ùdÁ’æz´£:˜Sð㬛—é8ózùÈyv ƒNÊ (§ÙþTAݬŒŠ•âapXØøéÛ¡ðÌßÜÍ`¨C?q"Í¡BõÖÚÕ(å’­#0(xÈÿá ˆÄ óæ%¦Ox¨Ì¼S×UÐC÷¿®¾ìŠ/`Þ®£,@Lµ.ûÜ{%K”_._/ùˆ:S¥w¹^•ïL×>‘^È_oÈÐI,Yü^«&6ů‹Ë+ºU­·iÁLò‚J+»´•V «Œ£ Ä’YΪ­5â¬Þ—·²Äk¯tÞÎÅaP|0ϸW”2îg ÷sÛPP¡$ÔšµQè„{ cÆwš UW²ÓÔKÕµKUo†r©©Tuå—šŽi™YXâŠì¼ìpmÆW íKèš÷·"N±3œ× §`D*û‘:ìaÍ^W~ð*üh¹_oªä-âI …úPaÆê›g_DÊ(œsù÷ó|ýŒ\Yr?ùØÂFµ5K¶fÇy©·.Ù®d»’´]q¢q³²U*[Gs±§1ÍÅžô3[9'ZÈ®óŠrIÆB¾|ðàô¤JŸ[Ž‚&ÿU<³ÒK2ðBU\0˜ýûhÍ¡f´ÖT7Ž€f 99JBÒŸ4®2|îX~®Á“é³UO7{‘ÊYÞôÆa§z‹0·æÍÜc>甡`>VE!îz“SëqßHÏëôµ#§˜µ¨Uº—·³.2º¦Îì\´£J†Þr?}yÅo£è#k«BÌÀ?dß„iþ–û—Æ•\ÍЬžyQÀx„ÍòÆýy/_¬Ü}Ÿ†"}ðyïµ.v¬mYÆÓ38,pûOcŠ{SÆ5·O .è }“EGA‘!ˆN…KZ¢S1eÔ¢ÓÛäËdEÇñ(Ø ¢c1ä2&щtZ¬@ÜwÛ]ºbS%Û´T)1ix—”&á€lW#0QÃI,ÏôÒm%°¯澄¢m‹¡š C óM=KîA¬úÕž;J¾Ü_]½JV2ZTQa‚ .dÆG½\ Þ‹dƇ@Èþæù‹@”C¥H‹8Ì,i‰±jÖ{0¢zcÍrDy5: sG9¹•:í~'vW­Ïä á‘Àh cŠÅ7!£?Зu;0*U3´=c(,¤®R…RÄTj˂īT=Å¢W©A¯U©•ª¸J¡à”ºJíeÿZP•Ú²PuÄ*5¥mý^«R»©M gèB¤|VÈH•:?5Ô^¡2Ì(ÓuLŠ4øù32¸=ƒÃh(…†z¥Ÿ`åW|=!jò G´+Þö¤ ¼®1%„¨ TŸ%=P|–TÀ Z x¡9±ú*ò G´©S÷¤üŽÖ7£ƒûÍaPú‚*€(*ê©ïÓÑt8š¡m=~€þÁÑoã’úÌ0NªàõîG‡•Jž¡Xž¦Ö·úéaýºãn7¸bõ8UŒ{n²³nTìHf‹92>¶'[lu†au*㬇kôp;–ÇŽUªÇpì˜ÚçÉc´¤?E3yLVˆ~øvûùcÜmÀô0^7ÚL!ky«³ÈtzÜ‘-X]š|Íq˜¡d*'¸sv¼ÎÀûMfíU oÅ8e.|/ÜŒ2Q%ŸV1“û¼ð+è¦Øõ•fCçóš^fRƒŸp1ô9Cu5“Ò¼‡¤0!^÷|0¹“A*¸¢„"œ;Cáܹ6œ³Q1ø šp®‚¸Q¹h#¹óúH.­vç&ªD×äìà¥ÔÚ¬Êý’¦ É_=ŽbÞWÙM!%~i7…œù¥*çÈh‡’f«³Û|/y¤}Š!x§¸Ò(9Ïòš¥.fÈ>ËÛÝšÔ“lF²IÔŒtÖ¯YµêTë¸ÕÚ¨Dõcj:kDµB«ž¯UŸÃÝfÅR3h-+åÖØöV„R›ö¥°¡5Æz[‹hè¢]ZûªT”†È·*ùõ"õ~÷P˜ÑÀñšªJè ~àúdUbL4½ÜË®ºPÂߦ¼9´$³ñŠ:¹fyfÈãQ-«c‘^˜M~K•’šÃÐ íʺó òf*JŽäGRI‚W»Ÿ>Z¾GàÝm–_ú8ÏÞ½m_û\ôžBCU-ü3ñPMwCuØÛz¬S‚÷ùÖ¨1(fªÇŽÚj^£ßér6Œ#ÆvŒÿZøI,<‹Oëby$L­Â¼žîßS`„‰çØÈc”Âà²|úæîö(Ùã>F&¸eeÂL¡˜þ,¯éom©_«;ØP:{¾üeꤡdò´cíqT?åÿ>mÕóŸë²ôù—û’Z&áK’L_¼b*>üw’¶x3‘p„L }Æd‹°õ¢?Øåî ÕÀ}’#ö2pß]qö¾¶Yš¿Ï÷#OhlªÌ‚MâS-âS[ħŸǦÚâØT<ÅÔî)1×ôÉš¾¸lü3u–‰ ÈÚ3ÆÎzÏ¢‡u²ýx½;®œ…®N•O½ì do {ÝÍc¶Œ•è•]æçÏbšŸ?íg~¾rb:²Ô_‘6Å*T.Θ¦%™ž~|£¶Üs†•¬åêÚ膪өñ†ª7;€óÕÙw?Íï>ÂwÏþ¬aEV&OTÁÀB¡†Ã’ 5SþÙçÄ1ñ_‹Hûáÿì çsÆÙ,S¶¾‰ýX1S6µÆ“¡v/Kö¤*ÿȦdC/‹©ðMċ܇™íJL§ÁE“¯ ¡$#ò¤:Ǥ öÝt\R©¤Õ™†R6-kF¤–RrÆ•†àÿƒè5Âè"|t9Vª÷¬Xï]õÑMÔoyŒßò„u,Ä¿]›¨^ÞúíŠ'V„Y&j² «1=&|Á=Ä—2ÙƒLÝœ­Š 穵Uî¬QŸ-Íö$[’lI²%©±$š3°ÒÌë$ÓaÊŒ‘§DÄgƒ|ÈY‚9ë’©Ë ˆ6ºûêÆLyJy- `«éýZ&Sc4²MUŠ †ˆ÷@ª!w•"ŠXe"’lFë;tN¡#3ñä¸c…¦Y ª¤ö·¢œÐOeŠèESñ"-Ž-§ÿ+ÒNèµ ´¯#—HÀ@¹ytd’}naoØXÁØ5‚tÒ5¡„“Ž<îóMXõ)È1Áä˜²ä¨ & ±é†„—·¥ˆØImŒD”©’(ô ˜.bo$Ú‚ƒK†bºµa_¤ÿe!zÇ"‚¤]+Ç"ÑòRk»olö³ÁÏ?ülð› ~kÿMGkÓ•¡Ú»“-N¶8Ùâ(,N±vÍ ÜG_±b¢õU¯,y.W¹#{‚Å*!WqD=õ™/t`56QÆd-mÏ´éÅÊwiöá#$\\±!»>¤Úú)v»S˯w.Úþe¹þ´‡‘îvñg Åä J bxFÅ6D´]³Y(Š‹ÊU"Ë51ÆKl·Ç9N >q€ˆ$y(TÿæÓo›åÍêÓU±.¯ÄÒ¢ŒçÅ”ìÏ~‚tV784·˜%Ö8ú¿qÛsÃ<Â_¿©Ð**mÒûh¯Œg`9-YT{ €Ø™í)€ÊŒmÖ†T#7”PŽÜ ˜0ãcLzRØði6>/^ß”â¬-Å€Bb‡ ‚–½2QˆQ ŠŸÑ1¡ÇÀë}QÁ‹­ÌƒÑ¡¸¹Uª€ê ¶Ýüo‰Zt€o² ü阒)SB¯%a3q$ÜN–ý9á|ˆàÝ8&>„'Ÿ!ü‰nËŸm~¶ùÙæw¶ù ;]ë ÃdEsú £…ÎåÁ>Å’Öp¦Q]õBï  ¹w¬œ`PO;S[^*iú„[šE5 Wõ5ÙRSû°ú½¹úò˜Á}:Êž\_ƒBÇ;ôÁx$2`‡(«’™]›8™c™¹Êá£ü†ó¼¢íøT4SÔRÈy¯§–BRפ¦]Ó*É5¢™\ŸÉ¨h&:FEFEOl3~Íñ‘–BR«~ds¢ÝŽU"3$šÄpDµÃÈM9Ù$–S&ý&ÜlâI}Ìgy‡6±áóÕâúÓ·÷ÅÍöP¼ÛîzØëmŸÂ#3þCî÷î8°_4G*R肽œŒ3¦Œ*§œú®ÌÇÑ©ïbó¾8õ])ñKm㾓A、µ("¯¶Ÿ–묹xr7[¯ÆW4LÆà—-Y+KVGÁ„ì™S4쬣³mKÚ¶½€Ýš›mhsÖi„¾°ã„ BŠA ¨‰bÊFùµÆ!'ÖŒÙY N€7ïaÈXT »w?¬nŠí]p篓´Tç…œˆ G—¡ˆT"Ô,=<‡ÖH¬âsb[><ÈÑUdr$Ï Ó!Ó:î : GB-šZDÈ.˜fª¸=IKœIrõ^¾‡#¤ÅBž\_ïBëú#/ .Êå¨; …Âã•«´¤“ûC+ÕauN¬#P0¡U =ðnáœà/Eáž`:O‰Ä㌠×l²‡Ž¢–@`6û ˜{‘Ézáê×å-RQ/¯ ­êª;,¦ 9"TÁô>kÈÙz/îÅ î.]ölZÒɽg£šCDvˆID $­jÔ¶4ƒˆUÛµ+±x ºŒz …5þ83ow4SÿRL;,ýŸCÛN„rov),Jl"‹·…‰‚ÆÛ<¼(?};û÷Åò:´qˆ¨ XÑd(Å@ŠP"…@Ê•Q „w«¿/‹%Ë ¤‡à”’öŒR†ž?½*hxi|‡û`ëÝÍò–9áôpÿËvw@Myëb¿ç?I½zð÷ÛåjÇ^_ºîæÇÈñÎçÏ y>ÎZZ­çh:vhá›Lù›$± ƒòÖ@7s0F“Æy¾±†=œnl ‡¤†ÜR•|Z@áGŸ%‚>ÐPqàïP×®ÇØªŽºR¶Í“âÔíž4â=~ŠhcYo¦‹–+Û!+Œ RS­Â˜Ú*Œæý,u/P\m¢·Ê’™Š¤Æ¢C•2åꃌKóÐ;º•äùÓ¿,÷ÙIËNšÎIkßVøl„Õë³UfŸ­žÙgëî³é©‰‡âÝg‹ž"Ùgkûýûlšòã0¹pþ @5÷¿®¾ìŠ/`Ûy×¾Œiʘ}î½’‹Ê/—¬Â¡€yPüMñëåzU¾ä§ËÃò¤Æ–ÃoðWÃ;3”]æßkáMñëâÞðqíàî^r~ ÄŠ¿¬’asØ÷~æÝ:NÁáfýš¬²ýì&þäÒÙä7Ï>:Ÿï„Ž!}Ó$ò©}.*=Æ2ª!Š›zŽñë~úòJ>îÚGסÚè¡×½-Co½îœçNÏÊŸûʈGJËÊ«úZnîJFÔceØIâ´é×>bß©§Î4î. ¨W”j=<² Ùk¸¢¯ ½N]ôÀס•‚@hÆ?ÐÆŠ Ñͱéú¥4¾&ø X+„UÛ_•së•Û_éÜú8bO+ÔÅè³´9ÌDs?ñ$ÕÔUTI®VÔ´¿¼ÅDU E ƒ£›ç[Ô};+½û'®ü~†¥›‘Œì`d#;v†{›M-÷Æ‹¶0«MjµÎ¾üðoI–`µô ¬”GŒu^ê¿òßZ­xc‚VÏW÷½h –pÛ8øÏ~ôïÕ³¯ŠÍ—Ã/è£9²é`[3ØwL<^|?=Ý¿w*%jµúî;ÂùàÕ @L yñìÃâå‡g¯‘Y[­N‰°±«Ï«Š×ªÕçµ «_Ë5è¼n_’ýçDV”’tvŠoe°<ÂýçÜöqÿR¹x\½lœå„iæ„È9ýYL!F0°P¨á°æÉ35O²ORóge@àm®àPËíîõþK©áŸýöiñf{xySê:`˜‹kääÜû¸Ææîæçb7*)4Ó¥¹&|Õë¶dÚõvy]\>ßm>aôÇTþø=³–þݶ4?¯‹Ñå¿\~÷Ýèv·=lÁcöåCŠ9·¿^ïØÎçŒÅlûCâ(<Ó>]ÞÜŒÍΟÕZ‰‰—j >®Ë¶Õz*TàÂÁ9›×?çãêæb\ç8y΢ª)ÍU°ÈY´3äߟký{›èAòï9ZUÚì\›6ÏD1n<(\“_‘KïÜSï½0­`dçI¬®<ȳ ¾Ë@÷j†ñZÆî[£iN*’»Í~õeSNÔ°µ$]ÐXMÄ” ˜¾_×yŒuZ¹B…¬Kš'²ÎÕ..Vu‰¬sÛDVgͯŒ„TaP\ÓxTnà ¼\Ű¾…MÝ‚;P£0†ŽS–¤ËŽqXB’iÈÀ[6£i\ ŸGa,¼íŠò¦ÇÓ«/„>ÞR) üNÀ¬Îb¿Á­ûò·eùøÅþ°Ý-¿t>²üö;ëbÃ6ˆ²ñ8=U"xüà3pkñó~§,3LÌĻ̥ÔÕ©þó©ˆýT‹·s kiÏÇÀ§ÎôFïC-4è™k ˉˆj±³›Õ,Š’‡±Í¦t’ÖŒˆR¯£—z‚³¬4¸aÎ$ܲœ‡Aô œaQRîL›£šØæ¨T³,Li'Ím pr™ŸÑˆÂºdçM8Ÿ8án v±Þ¤Tå?Š›[íË'±“Àÿpòýø2ùL™ ™ÐT½–xßX(PX4ºUFS¼UòÔ Ðúe8uÿö!íù¯»b÷íä¾é½SЛÆðÇ^ waCwÿöO?î•$3b?À}›¢´„ÿÜ|úÛÐ-² Ë=}iÓÑþå»{BàŽM•Õ)£«„ªXyç *hf§‚fÄhV›WT¨ž™’ûįaœ ÆÚ¤,˜2»VpÈd'ˆ¹{‚.ø‘}ã?zÞ»L¨^†¦`½ü‡í_‹Ýêó·««W!ÜKõ£®Ç‰z\¿¦'ŸÓlþ&BÞB,„Büçw¬ˆÝù~¡_Jçw˜Í¶¢¦Q[1#ç±“Š² ×öêÕ»¢Ø=/±¬{jI&òrìCÌy=%\g¡¼)G56þƒÊjÀ¾Æ=Qó_ßA¨0b ½ÿ¾ýÔ»»ý¡¸ ’éºJÙÑ“2}·¤7Ï œS¸/¨ˆ°+©‘ÆV—±sãâV‚_D”ïoi¦É§CdóšDïâ**ç¨_Lj¥•x"Þz(NS‰6ÄùÉz}Y*  ÊN´\Z­‡_ ´\Gºô•=Ž7ý®ê³ƒsO}µÖYÐ@T9Îæî:<³UÚú-IŸ¡Rq쾈@ t šZŽšŸk)r°ÔVŠÇIhöq]´Äó\M äs ¦¨ ÞýçËl­mbIµ˜C€É[B%úýA iaí_ YÃôQ‘MOX_´Ö00Y|¶îÙ¦Ô ™ëVÖŽÐ-}kWa’+­¨uÉÑ!ص)´J ¸Èø¾¸ÙŠ—ï’s• þ){ Q–+‹£xX.ñiS 糥À½{ZÃÞ»ÛHæFucy¸ç¡ã¾,zÎÎõ27õ·ÒÇß›ª49OÏ §‘Ø7ïFuë_ž×SI,bfë3[-ÏT¯Î qB‰fñ hÅ èñêk¦ Gë†|°!ÞDrHøƒI$õ9cgX]S;Ê©]¤ üÍÇðÓg k˜lâýÁ\ú,Gcí˜ÓL,Šÿ4Uü‰dmgümùƒOåß/ø¿_(âäG"(d4ðÝów{,>íþï?´Î!»:uÅ®;v¡ùü‘æóÇ<ÓÙ;ÆäsL6í‚ÿÎà¿ðßGðßÇN³—]Æ Ô½«â¸æµ“¥¿Ñ-æ fp˜`7$Xœê2%•x8*|Ž¥7ȱ¡dÒ,æosª}›“†·9µ}›ºÝ¼&4‘7ó¦ò6­!ÇŽ8\j6R–ú¦H?Í´úÉæþBû×$SVûfújߌ*ç _<Ÿp†Ð½Ð¢{a‹îEt/ F^ˆØV£ /HdüHm¯/°½~Ô&öÈÎV?ê@…Gæ9ÿGf °G” ëm4f‰Gˆ%kYâ±-K<î@ŒÇ: ­âÇZû\1ÉcJŠ”ñ¡ÿƒýlÑÿ¡ú?èW±”„û"î4삈ÿ ,™âÄ'íGW–&êÑOðÏøçøç1øç‡šªQ©µé4€I{Ý”»nÚ¢nÑýIR î§‹!¥óŠüAêùnygi€œÈ €œÈ €œˆómæ@Nä@NtJøŠƒsÜ=îa“SR!ð1»©Ä°bU¡jRsšƒÔ¤æ 5癃Ô¤æ µMê!2ËAY÷ ¬‡Í…Ñe ¸b‹¥ºÄLB¦,å`)K9XÊÁRœo3K9Xj–z r4Ð=˜+H$åàwpä[úñÙƒÏ|ö೟=ø8ßföà­=øÞœÚìÏv÷gg©û³qx°};¨íQk?4{ ÙÍhö@³çÛtàöá‘eg¬ƒ3Æ8aÀëÒ9]‹ý~õÏb=¥O¼»P~òõoçg/ øó ¼ëå¿¶ZñÎô—¿Ÿþ=ÑôƒÇ”7ý{õ°Å«bóåð úÆhŽÜ¾ÏÛÝèdµ‚^ üáÏ£NG÷ïãŸÁJ®\­¾ûŽ„xµH^<û°xùáÙk䯬V§„a¼˜MÉ €;¶øŠ´ ò¿"½„•‘°œñ]à£Ïþ,qùšY‘dÍüâku@¬«’— ¸¼›ê²ÅWªÈ%t~z{%@€‰ðM žK$\†@ñdVÃçËçY~ðàô¤ZznôdÕ3Mž:©{ªÑsÕO®äÐ,êAbY˜½óïú½Ò¤"#Î2#fFT1"ÿ›†öÐ(B@¦2¹-@`yV’•tLuÒÁ?ËFV.²¬dYIFVÄß5`6ÕL•1\"dzج$y¢—dñ‰m%ûQ–ì,ÙY²H¶Jlj`EèB-BôDE,êà¶ÒIã:$SË–zœµTÖRYK¹–R}f néél ¥Lï&Ø­tìy½ŽU=½½ûCÖ»Yïf½›õ®â©è]õ§M¼ñ¸fK¨Õp7Ane3Κl††>-IU²ƒ‚Í ¨úzÈ>ûíÓâÍöðòæv]€Òhq*®÷>î¶›/£ÍÝÍÏÅn´Ý¡BéösUCÝÃZÕ¶”õvy]\>ßm> îèýñûÿÝ܃€ÝÞm÷ûÕÏëbtù/—ß}7ºÝm[ðˆ}ù€bÎ\È·BÍçLµïšx(ÔS¥ß|X2ÖCzü!;îëa5û4Èó½=µßõw÷^î nŠ‹îPÆÏÚŸŸ¬×émô"GX¦ìö™ïB†ßí·GâÓònãÜ¥ Ýüm€sn´4¢Jî³4¥T m–n—»,+/ÆÀ¸{-;OmÙÙ¬}R‰«Øƒ¨<2™˜ ™RQÂà£Ý¡ÎÁ(±Á¨NvK§`ª“ÝÕ1• µnŸaÝ~Ñf –Í wxyk"ˆÇÛk¦`]¨uº8ë‚2Á#½>Ç qâ‘–!l‚á/´¦…8¬vRó#­.¯XD?´:ð j%öâœjý¦&iHµ°©É`Bu Am3ò2ð8êîmÆÛ‡i—Ð¥^"¸ã ×R ǜϒ¶‹ºr¼•ã­oåx+Ç[9ÞÊñÖÑÇ[®ãŽ# 9ZXÓ1ä\p[Ìàzf²ihƒ‚ä  9(ÈAÁÑ]á#ô‚ÚRã§äádp³š½Óìfï4{§Ù;= ïÔv„þWB;xÿ+&—+­ ¶užSö™²Ï”}¦ì3«ÏÔÙ8B"¡1øW>AkÛonú³ÑÏF?ýlôÍfœ7XÁc2€ŽFÿÓäñÇýLŸäaFñ3jštÂúzÊA'Íìòäùˆß?ûsã8©‰z8ÑHv€M»Aôlæ2Ï¡Ïlé‰-ùß4ÀTó«â˜JÏ6Yä¡ôYp²ààÿÕl`Ø™õ(@ãauíÇÖ³§ òÔú,úµØgÑOIôåO ˜º¢êEÝ$M‹)šò¤Ê.íÙ¹ y ½ŠšYÕ`ŸXV`vÐÙ*0ÕgMï?î÷ì°Ò€óí#˜J\RÂåPbPh>ër±ƒÇõõ§÷uv37r2.øýrsü`¶3‚¶$0-PÕÜ™f‹à'Âót`uóL«¦U]ã* £ ‘öÞÝ‚Ð0éæ`Z`„nŽó†nޱm7‡Yß‹š`bãKŒíŽ Çzéç0›Ñõæ¨i’BsŽ#ÈÓhÉU#;ØsLjt혽š G:|KMŒ£™v¬F¿¿qǼŸ)´(`N”í‰.g!ËIØúVÙÆ.Ç1×£8Ö^×½²û“ÚvM2QpЙËÁ£àã yS i…®"׳æ˜5Ǭ9fämæ˜5Ǭ9fÍ1«£‰ÑB·µõµ[í1jK>>‹-ìr^uŠ®r\•ãªWå¸*’·™ãªW帪ÛÌí~ƒ‰GôGüí(Žˆ9Fåþ;qó[zùÙ¿Ïþ}öï³ÉÛÌþ}öï͆–÷æÅf¶76èäôölHŸµoŸÔ…ïiízf§3;ÙéÌNg$o3;†¾÷á‡e¬7,èäy¬G§Ë•OåÀw²p²Ó”¦ì4e§)’·étf¾c'"ûîý‡<¸Hƒû›ÕëÕ5ÎåŠe0^Ó„/Î/î”þãxÙìÏ bšÈÏ¥Äc$æÁ<‰ÓF.Žsþ~–’,% Ϋµë7Ãû¸ÇèR¸œ£Óòâ÷>'é;y`q|g‡·ss+'3õŸ¬×qÕ'½·öðØTB1¼è»™&HZw'|ëî„ûn]k/`&>O1ßí‚¿Û…ø´E„C[yŸ¢w7"òyazo ûÙÈ~Àñúîìb6‰¬IŒpˆfW#hkãºÛ2SS–X6bÙˆýÁjdb½FÏÊ|íp¢áã˜&>êg¢á8)Ï@7{=ÅÑgýPˆöQûØŽÜÎìq6{œβµó8ãp2ûv"-œE;_1{‰ÙKLÑžf/1{‰ÙKTx‰Ý}§ì6Õ¸MŽFdþÓˆÌÇýŒÈÌsûìG»ÈögÙßœ—fì'zì !ÐÍøÐO÷ã“<°/sbŸœÈÿ¦¡F5 gª›…c8‡ìª ~ý+Aòf­G¨nªðÈõ¢®ÃîNE÷Ó òØ+%¼äÚw[øà-À–ûxõ¥7E¼9“[0׿{ YxñæÙG†¬]U…N ÜÏ×l”»x|¸r¢ï½üû”ÿ»n˜ˆûæ÷®âšâe‰wß ?`J`[KšèX·ÐÊj\îµØöר^)+¡˜„ûÕbÓ¢=µE[Ѱ^‹¶Øð­:-7q­NËMí³ºÕ·/µMßýð8S²Cà~~šc‡À£àÊÆw·å ¦<ñlijšïjã²yc^œ£3L³˜Î0Mû9ÃtÞoßZelÚµ¬q]+ª´žÔ¬¢êÍ›Dãq·å5¼aMÓxs?fÏgóò;ïðÎÙŸ›š!û]¿ÞÀ}ÚNâØÙÐ;õ¯‡ùœØPº^'ud ­Uê­6·²ïÊB~…Â?pWz/BÕúp.ªA¦¡ãœÇÒQáGé>}yõö㛞#H³xaÙç®ç‚Hꂞ+}j§U]¦I¤KhÅíi‹yŒ §«Ú·óÍü3®—¶ zO|J#FØP+ŽÅ¨é°‚=ýª±¸l;•[Î~Z6!û®¤êù öÆlµ±nöøÒd¼è¶¤a ÌzèùÔ#ß6Õr,¹÷p4´Ô!Ìيݼmjð©e0jž”LÅ©ŒoxŽdJ[kÓq6ý^ø Öh‹ùG"æR.n,åâˆB€Y¸1EWHEâRš¿Y5ØŠùGU5MJ:VÕ´ç`ÕÐ"Î X.^MH%âèoDj ŽâpTb@›'¤V¦6ºU5èºYB ñäÐCO–&“`k˜»|= 3s1¤Lv!ûYíÃ…Œßi åvðýì\¿ìôe§/;}ÙéËN_|NŸo訡~– ºw„‚»=}{5í½Sç%»-ÙmÉnKv[’p[ºÙñ£2áýlEìbÂýkW¹µåm6¼Ùäf“{T&×PmGÝ^ÐÏÎ/K}êF…ڪȶª°Nf˜u`…E³~ˆK5¼/–Ÿ~)®_/ûéîóçÎãR¢íýÔá›h3„†'i&ü,±‡?<ã‚ÿ JyçX Œ¥luÝOæ6Åå*ª‡d]‹X "üŠK@kˆ]d¯Æ°qѪ¼dÉV^òØ21Å„ BbjܘšØ&¦j"†rˆAC4¹)—0cÝ¥X#HÕ,Œm”Ù(M´Ó¼1pÂ¥‹&-Nú;´9YP¾à‡ù·(ƒûÐ=Å¿¢Ø!OÈ\3G0¡Ø€Jуè ðeä“!L÷1$Buä‡(wë)«*Á'?¨Ïhµ³rä(Ñ”¿ _½¢n,!9)¤‚ÈA8ÔöQþâPúG=MLÔ§g|Ïêú4·ªÁŠäø‰—ÉŠ¸‹mÊó'ÒxEzþdJñœé_8Îßxí5Õ¢,5›2VÉ á”ßÑÔtJS7 —ì¯ë4Rç*@Óiç*&7*6Ô&'(»?ÙýÉîOv†áþt´ýÇdö4ªæÊiå`8%ƒl¨³¡Î†ÚQYàèëަA_Ä4 z–ä4èÊœ`mÙe´ÚA9‹d&tGL{>°Á{žD::¿÷ïýY´JKσ¡u)ЖáYvœevÌìØÌŽüoÄ©æ§OÕpBÆÃ¦ƒÎH\´³ÔùgÄ6Y]@¦õtu2•W3ÿ¹a‚:`·‡l «ûí:ÝÁ~»òÀ^ˆQnRþhÌ•&Êž‹b’œHÒž‚ #m¦Il¼I¹´”'œ8>\¡ÌxÄyî°>á!Ÿ>T$<ôç°Ie"ʃØÊ„”á¡… }FÑ—áµc:0¤¶-C*ÉÈmµ¥i†ˆ‹:L'ÒCŒè22pÞMYÿƒaYf. Ñ©¥~ãr âpW«À«7qzr"<áçî)“©³öoŠ_ßmásA7>üh¹_þ(= ’µç= t?žÌ]Sú„¤û_W_vÅ m]'¡B(LY’}î½’¹Ê/—lÂÁŽùåCùJK¢]®Wå«~º<,OT,HhË\oÉÐ ^ ü½VilŠ_—/ßã8×ÕÛJõœðžB– Ó2Ï:-¿Å<ÜV·Ä¯âÝ[H×Å›gr-z5è슧·S©t–Š^GOKè:ÒÞºWöôåÕÛozVé2RÍ*y¦úœù §Òéñ§s¥8_­ @8kpónúÜ¡NÕ¢' - ~v§`ÁÝ<èVñ%ôжìVÌ>Êh²*éžûNå9Üsîîy½[ÞÁNØ5óŒcjæ9ï§™çŒÜ€Ë€É¶KH}nN‚žé’ ]ÎúÊ:_{Æ×wî­­õÉ ðåùcýŸ1»$qhqré¸T¡VoA¢“i€(´¦×ØÃÐ!j›FèêpÁNyBq.åü÷ÍòÆ3Kª§ udÛÝnÊÛo繜.hC|Þ{’TÂÁk›{ÉGü4'¾!?=À¼”ÆüT‹Z]¡i£ö–›·´„X ùrÿ¾øÒ[jAÕ’Ó@㦗ì‰`O%¥U­L%òxݪú†ë¾P•••Õ”•½ [†Ÿ¯>o³ÿbè¿b Ê¥£± £Æ°_<óxF׋aWVYÃPY-¤yØ‚üj“1¦ŽLI«Aù1Ÿtt‚h#öb”öëÄ”<^†ª¾áº0Teee5ee/ÈÖa0>%û/†þ Ö ˆP:JÁ¸»0j ûõaÀ3׉aàp½Fqe•5 •ÕBš‡-ÈôL¡ûŒµÓ%x‡ÆhªD|®MÓkVþc2azæ¾6Ë ¼Š!Ñ8 þN-ŸœpÄ#Ã…ÑáG>‚Ë13¬*˜$4û¨¿ÇYxó›;:¦v4oÓ\¼q?sñ”íÜmUÁâ`ÚJgiçÝÅ:²O5×Á‰žw‘vzMä¿ ªò«NúÜDªpn­–* ìK⤡rLà­.ÈŽ³%‘¥—±È+\ê.¯¹Þ]§¿ˆ^`¹E:`c9ûX®iÚDÜî Ùè¡ÅrþF8h]^p<¾XŽª‚cŠåôÓ²ðZÇr€±£cêË 7–cuV²±;ä&Çrãֹͱ\WFË•@vŽå€¥°ˆå—×\ÙËAËÙ1–£Ó&r,gË5Þ‰Û4›1´XÎß<­Ë Æbüÿì½{s·±7ü>Åý¡²’‡Ü ]Åäõ)™’E׈´]Ú“#zËä.Ã]Jvžãïþ.3`€`—Æ,ΩRäÕîLw£/¿n4ðr¹ÚìS.§E“Œ×8—CŠ N©S.7Þ\ŽõYÑærìį”ËYÌCXp›r¹¡2œËDÎåP¤0Èå$_oùfg.‡#çÀ\®½“r9ó\®kl8¨7gl¹œ¿á^JÈ‹fÁËåjW°O¹œz.W2^ã\)68¥N¹Üxs9ÖgE›Ë±ãS.g1aÁmÊå†Êp.W98—C‘ —“|½å›¹Žœs9fYJæÌ“¹Î¡Œ°¡æ€°±¥s*a/•/¡cüÁ>et-3 “›çtX¹á)vÊêÆ›ÕqŽ+Ú´Ž›ò:‹9 tSb7Xˆ€3;DåàÔÇ ƒÜNöý¶¯vfw$†LïêáŒ)»3Ïîº&Õ††zÃÇ–ÛùÿªD¿hŠ$¼Ì®vû”Ø©'·&ã5NëbƒSê”Ô7©c}V´9; ;¥t³ܦŒn¨ 't‘ƒó9) Ò9É×[¾Ù™ÌáÈ90—cfÔ¦dÎ<™ëÛ jŽ[:çq¶öâaºð:ÆìSF×2Å:Y°yN‡•žb§¬n¼Y縢Më¸+R^g1'á€nJì pf‡¨œÚáxaÛɾßöÕÎìŽÄÐAéÝw“~¯`¢ä¿@ÿsAELS¼2á›u]U‚þ©-Ë+ÓÀÿ…Yï4ÿ|:UVù!–?—â?§q_”B¸Šåž[ÔfZ7;Êè9›Uð'&³ »ìÎl›¦Ì¤¹•ÅIrù)á~¦ä~fÊýÌû™N*?S§ò3Y¶Cå_Ùv©úc64ù|!V<]lÕVÏåÂf8H ‚ÈAO'9zÿh©Ö4‡Tkš¹©5ÁN°‘%ûɯù¸jT£˜í£ë¿uÖF¦Ík¼º~¹ìõk(-‘ÔÏ„P,Á䬕w'–JAC]<Ñ|ÀaÏ*È‹_WÛÝÖYê¦a;ÂM-J8°M-B¨M­—ùîÁ€ø4{óéÓr×_µ)ãêvIyå–«5%¨M¯oŠÃë5úÄ­^?»XÝÆ¨Ø;Dö0ÍÆ¬Ç©Ú„tHº)R(w‘õ}Øà÷ äï`¡ËÇ+;y(ù—ÇŒÖr¥äßÉGËï±~/ßÿøŽ½ey»¿&ò6^y ÎDÞŽ×DÎö×DÎâ5‘3p&r6^ùþÕó äau5Ð> ¾ã´D8$Û(èÑ· ¼n2ÃÀÿ ¶ üÏ>Íâe”fq=Ø,^Æj/™ÅK³¸V™Åu»Y\{5 ®Žêiß¿es?@Õ”èj,ÛóÚuTûóÖÈmnÐË÷¨iEW¾I=æýiʸ ê)¤ êãt¢¹áéa!Ü(¹³qJ¨¸sZî)©ÛÀé7$}å}vBù #¸!ÜéöP\A\ÃF·GoK§ÆQî]Gp­-ȼä<…ð‘†pqk?Ò.`Aœ’70ŠW[èê0^~Å^g7ÈárÇÛáÑ…rÝ r0±ÜÁZÁœlÖ›Dsß›/À1`ã|_T¼¨€_ð`¦o8. íG­À€|Ç2x»/È ­ (:d ÛØ"X ¼MÈ`2x›ÁÈ‘ÁÛ‘ ƒ·À‘Á[;Èà­2xkœí 2hk~Œè¶C‚A¶ÖBg  Cg ŒœœGgvÁ™28³Œ ê.p¸¸ÀeÏwt @¯  $°C® @ýèျ.uàXÉ.!ñ"ö°O¼8€ VðP@AÝp €Õ´"ô {ñÿeñßåá–èâ¿Þq0ñß¹Zñÿåðøïî8ðøÿ2ÅÿQÇÿ—£ˆÿ/AÇÿ—6âÿËÎøÿÒjüµþ´ñø‘WÅMu°@}¶ñõþS|ézñ¥ÒÑß’£ˆð„%z¥€b*ñÓ2É+"祑:?m9ál2ÞÝtÄñ¾Ø¾óg›1Y˜öNb\,‹‰Ô!4_AO_‹‡‹/Ö.;1ÅÈaìqZN„  ¥àCN"žó Ïñ"œX0ì°6a;”pÍ6‡[fdB!Ô4Ë·® £Á,R.)>™ék9MD$Í5h4®¬l]˜¶¥ó¦J˜wÜó¦¦0O !äRi\ãY"–´xWCø{käü9¹¶¦tùè•rxäðÆš)‡n¦=ð‘ú ýb‹ýwØ24š˜‹×4bBŠ)Œ!˜»Ê1{ɳÍÝo Gàh"Gà˜…äsµ¤ÔçZ",—óç£Wî+gbKBàæ¼R4HÑ` ÑÀÜUŽÙKrû8p[ñîÚèÛ0„­sí}Vl\鯹dÄ.ÝfÚ¿»”ñÔL7Òf:aÃ=Òf:!Ük¦#Ô l¦+7º[þÍR³Ç0õ¹uªf-Ñ} µ2ÍÝê¸P…æŽ La‰Ø&¢ˆ+›Kû)€j{w×i(Qï?õ]ñ“XG9ïð7õÛß…Œ¯ý"*´ûSDLÑ{‡Aïp‘"…Y¤°Tz™C*½ÌÜ”^¦€K/Ýå‘cUy¤ó]Í·I‹$\ï`£DRZ¾¬à#¬¿‚,ÙÍÌd7KJY ¶þ›äÝUŠEKÅO±§¬ž¦õÊr!ä¯ïZYIù“}¤á×>€/ãÔdÃT„µëÁë)†fºßÖþâÓA¯Ý·,Í4Þ¤²4°θ’pÍ6 %bcOÂS“ ²´Ç–SXÔmT©,m¿±5•¥·±¦ˆ˜"bŠˆÞÛn{‡‹)Ì"E*K§²´Ò*w &•¥ûÊ.•¥{ b=“;œÊÒ#XÆÊÒˆÚeiŒ ´ëŲokQ¿,­óëÞeéŸo7Wa† /¦Ðjª”D*äÔýJÏC3i$¿xO„bê½ eSO©žDCð\ÏBG>²R¹@ÄLÆ%x“IM\ÆÎøt”‘šJéÌo¶yEµÁ'“]~{']ÍêìèOô4™}‚~ÉFµ¶¤­þn)„¸:wŠØ;°‘ÙÚÈ:KO§BE'©9¤9×Y•QÓY)YY¢VUgL¾<ùòv_^¢WìÊÕLŸµËç óvŠ3HÅÆéÞÅW¢jÀ‘Ôå ) Ȳr.g‹¸æC„eÛ@õ DäЂv@DŒòâþ‚X]¨Ч¨pžç¿ø­%l>}2.%Ü å)âô”ïb †—‘Ô¢­$`â=ª%b £h!Kà‰ÖSÙBdr ý»"bÃZÙè!šŠ=DDyq‘x³—c³‚–_Ü^+ãf¬x°÷€—]” GxÝEEz¸ /*u¤Ãç¿­/÷F³ê.&;œÞb¤³ïïò5¤!ÑH{³{z¬ ®ZέLùDÿÔvÞ ~þœ}Ô¼7”SHà?Ÿ 5Éú¤ZNÉIüç,&;ÅŒ¤!£ZRÚíh‰ØL«ÿÝøæ·ý_ΞØþ_ÐÕÝýOn§«è®*ãs¹uΨuÎ{UÆç¦Ú87“Àܼ0>¡ˆmtR2‡ÕÅçl]|®UŸ÷ØãDܵ!GÌÇLÙe ˆYä„q Y ‘T9äH>äè[ö$¬Ø?iß#¬DvÅE# ¤PBÁB¹«Ü/iÿ¼t«—¤0{*T awÛÆmýnÊIß{\ÙÆ/r÷}õœ“ È5v}+ 7åkG3ùJOéJÏzÕŽf¦±d ”Õ¨ÍB„‘6:­ÔŽflíh¦U;šõ­YCóŽö¥æ㊕8’wоã@—ÁµõÅÞôO0VšìS»ë/4ݵԘ¿€Ô˜?O÷‚‰žIëV0È'ÊÿU @á/+ûç…¹íòå~­¶yÜ ?xD¼&¡p5ëÑLB £·ŒN5™hMÓМ¡ÁÚlŽB²Èàæ¤TjåmL ×ÈÐs‰çi‰Á,q‡ˆgZD‹ùû»”L1R‰e Ò\DùÀcl­‹‡ÔŠezÚr²Mõí/«¿¨óæÖ7õ=Y÷1Ï®üfÚ$ý¥…‹2Þ0U?ú§‡OB ÖÍÍæ’ÿÈG#U™® ØÎA«ùvfÁO™€)â¢,Dðl}u^,BYËCšAÜ; Ö ÷&…½¶r9÷bY,|]ÙûCUØkòN¾[°Ž˜© ˜Á;’äœÚíH¢¥ì³:ö*Þå_>l°ìЦÈÁ:ÿRÚ#_"ž™þÓc¦|*€Þ˜U°b2JE¬©÷ªŽµfxVÊ‹û"Z¼Ù\þ©!k//M¨V"òêpÍGª8è‹hÕÁ&ÅÍÊŒcË-<:¼M¡zë¾^© Fž½,Mlf“ÇŒ-R´a´èéH÷ɇz¾›&èÙ¼çK>ÏôÎìÒj õ«ÖT¥Í“‘NÑmº¬èGéØ"j‚éñn|P¤ÆêF°QT‘–nçjÇž¿Gj௼‡Ø,ÒÀŸšãÄãY|¥Ô¬žvô§×˜tçJ­Ÿ>ä¨ ¼ãiͺðaÏ`|šQ6p¯´ÊVသh,eüío?®n®.³û«ðÞqøÅÔª‘$÷nï¬4©º¹f’øõ» +É›®/¶JuÓ+ë¯bà;·uäïâm'TS/Ý[™£¾b|·õàëèêîáo2È®¾Ý\¹Ú*M «Çƒâ7ÀØý°Þ®®×ùUù®ž‹_#p—ÕÙîðÍ܉üŸ¢è]Äð#§{e ;Á›Ðʆɤ¦Di—N­”Lî:3ªßO&»üöNŠ<ªo°ØƒzA´”OÐ/ËϺö¢êï–µë¨PŒBè0Á‹-b#Ç, 1À„*¶ˆmC(¬ß?¤[,赺È!I¤R¾ey~ŽGp… = ¸¸Øa×.C Š)Š7Tp#4Ѐ´¬–¬û­€Ñ)@M›&öôµ”´ëH3Õ/[×_šŠq¦ß¼l_ÑnýYÓQÛ);³n²q!7ôWxõíA5Âë‚ó´^§lxj…×i[xU¸êª÷¡tÖ.¼²ÍVLg 9èN-ñ}GRïÉì>~v^3•3Šèxä$‰?Vä*»h¼}HW2ÈÓxääØõ³û}Sõû´fKvO”lîÌ@&YQ;°¥Gª-â$IVç–ßw}¿Ç`IÄõsÒ€ëõ0—ú:]7wÃàT¡ˆÔ4ÊPðOˆ±üÀ?$f—Ú¬qN,ª*‘J0ËDÖ¨5¬‘÷*Îù.IŽé9*1 “~ÅÅûgm $‘ Å€àÞÄêYaSoÐmxJÑ0s¯%çA§›Ü›=ܱ¶Õ ,wT©Á.R"íÔgjÓ(¯ˆRÉjÖ&ç¥u; ¤Óá2 ÕÿŠL„¯Õ Îrbb!rX5Š:°u(ù/[¾Ù³ø„ÆênîwÏv»xÎèÓ±U/Ðÿ Â{C†ùèpK»˜0ùÙ)Ä@Ó?™W°3›KåjA táT¼Ú>Ï·—ùú ¹»XT¾÷\[‘ãèôœ#Þ»¢—£m%ÊÍéé¶d¥ˆËh–߇"_ý a_A~8§ßnƒ‡c9ýG£×MLÜhŸÍ‰¤N%²IÁÊ>Ù‘ï^t æ6†}²›ûúëâ€M‡@ µ±M6/²Jr¹]ϽÒlKÊüŽÁÅ ¶·ŒÎñGÑPÄãi×+d'Å ÒSBèBIÅAdƒÂ÷WˆÒNíê6ÛÕG½ù¡B+Ö›ªG$E8íÔòÚüÆjŽî¡-Ö¼ïëØÝÒë¢6zdϽ®³Ÿ³õuþÜ÷Å©&ÊK|ÕÐ’±h² {GŸ_(E5³°GpôUO¥( Ö;í¬Qé¤/K5ÎqÔ8yì’ª›:ÕMâHXˆÏKXc¯±†x30®\–rN5ËT³”¼M^÷ÑGªVÆP­ë]ðë””â¡ÊÒÇY©Mj>¬gUòmö‹ÿš¤81®Ñ[Ÿ׳—™‚z*®ñ@ú’¡H½=rUpžEë Û)En´]/J)¡P‡Ûá–|âš){ªŒ¡#?ÐjÌ|ø›p‡< :»Â»ûäèÇáè{Xóø 9svÎ=ä1pÑGx<ØlI1‚yœR9,1--]Ì$ëùš¿èÚûìÇ箂qŒ?eˆz$9’ÊÖ‡)évê½C[bº·_V×÷ùõj[á"Å$èâ"ö½ ðRü¸G85‹B‹Puv³*üy¶Ëk&gxñ÷øïàç1RÂ_aîÆþ½UÏÖù—åÙÛ|»Í®=Ï´ìMKBËwTÿ ½,»‘ƒTŽø Õ2¹m µV“Ãâ­•Ö!ÕÂÆ>lpÒŒ#þ(Û.Qq­xeéœøq;ô5ÔH?¼Ç·|÷âGáÜ=ù¦øÿrÍ(4í¢ì¡øòöŽ˜¸nÝv™Š­¯?×sz3Y¯î\îrgÔåÎ9—[ÆÄ.¯;7óºsÓµš ¼¿UòÎ9ÞyÇkF+ÅMß[Ãê~çâ,4erÀzúަkQ‰H×õÓ‘hüù<|†1ºë`%Ðx;ÄÀÖΉ ‡±](6áׄ_~Mø5á×øÕ=úI(ÇÊ™‡C9CáŒñ²ÁØD M(I $’P Äj<wü^gÏ.˜¥¶´¤¶´¹›¶´£ò\““t3Thr‚Üà&íè°ÖàÖ}õ/ ‘ÜüÛ%ºyˆÛ“ãaý>6Ù˪ƒs¦9¤“vÒ‚¡Áù:v‘çi‘Á,r‡Øg ±×{3GÌ£µÞ/§ [Ѥ7°³ªåP'K{ïÎYúûÓÓ ‘´ŸÚl~¿ó 8lËO»2vŸ?ìq=ZƒKíz™ïP˨»N­¬¼§FéV.„ªD„ÈïuÖH¥krª ÀùU9"ýÝ)s¹†·åT+§ºŠ[ twŽð"ær(¬l-Ýþ.†*Å÷âßÙÍ6„pß1¬‘±G´%u3ßÇ´ya.“…5(Ê„{2:] ¦½‚85Œìt—`å^0ª:âÔMÑ2¹Ô65Öq*øÅò&1…7¤ŽGü÷î)G>¯+eyv³YA àœd¯ˆ…¹S$<èûÄñ{C…D€:C+ÔšúÂòêqâ=Œ<sú̺3+pè»|÷esÿK|yÏ«g”öþ'Ø$‚ˆ9û)Y—±‹Òžÿ”zgmÇ©~5/tË&sÔd8S'$H=F\p.š_¬àà¼z@:†â#´ ¦zY}Ö»ìo¤¡—1Ü`Á–œ4/ÖºíÄYò¬˜Ã,å \”-—£=ÂRe³`Éó\×p&R‰µŠ«•œ#©œ©ER ÎsD•Y†ëhª’I#˜–J¬HËï«‚(5Ðp1ôçla-¨¶?‹'E=ýc'^ˆŽÈ‰TÌ^Ü,žæo8 yeu:ÒN§s.îFœMz¡fÝN:GÇ-ocJÒH'5Ž»ît²A¬:æŽ7·Z‘ã<T3ÞÜÞfë«ø²€òô½•Â1BÌ©@ÉB¸l ‡Ð‘”×fÿ‡MÌçAMÆD”~A7¢ˆãº¹) 4"B:üù"ZB7fÄ ÕYcÚ[ä¦Äd’çaÎÿ`ãMá²Ûm´µô¬â"Œ˜áå zøA>J›èÌ øTÀ6tŽ/(L懘ñgdà cS³‚.ÂŒæœN£9}•¸Åˆ~@§ª[ uEòQ›#*Av;ÖÛÕõ:¿Â.4+ïV?é»bî§…nÕ7°ç—›«|ªüâŒÿâ¬&Ïùî{çßû÷-ˆjè˜ï=EW•2ÐŒ±pJËR#–ççxŽuÈH‰d’ 0ýA/iˆ¾ÕÞêòß'ué•Ãyœ®sPqTiz»¦D 3¥f¦RŒŒÖ‘‚8ˆ¹U ³n)̤­­‘xÑ5éŠY˾¯Õìðéöï*ëíÓízoãAÆýo—ïM^7y]#¯kìo`»KÝ@sHÝ@³Ô ÔRÐì?ɯåÿJÆxʼRVŽóDFb22³œ*Ùu­»:‚~›¤^¿·þ› Ó& ZãJëé¢Óq[òrƒ¹!ûÔÕV:ÕÊBvÕ‹Öþ=6Ò>eÿ£Ï7ÀU=Ûܘ$à6Pª®ô­®à¥W‰…°”·Hö±Ø¢EøŠ &,–² ëñÕÓÇT{izæä““OöPŠ©Q>(e´‹2©PÑ‘2w¤©|ÌKÕŠ=­VðÉnT% LºÅºñÀC‹ͧX«L$dꙎ“&4Ú*Œà8.=ç]Ø–Þºäh×çÐ_V…½¿ªÚ¦¶S’4¢†ynî›Æè•Ôbpã•á:g¯˜²¦pöjÚÑÒ<3min«fª$Ö1á54[ ™z¹–vfRG•½RTV»;šg\?ò¬=°>Á¸r±ºï2¾]At¡5vÎ[! Ä|Ú Óì¬Uµ]G­°¢ÙšÜDßêzÜg(㨄šÅ<˜…1¬Xs¼scóò<˜¥2Ÿ£Yä"!U©ÄÁ‡³X 7Sg©,U5 »ááG´\d×AN‹Š÷ÕeÈv~!‚¨>¢?XÀ¯×¢3â#U³ñ™+Ð݆ü@öñ–-½DókÛŠ9æ›Y˜ç˜_›‚× /•‰EÅkëF} ô*Ã~m­Ê¸üÈøø°‡PÙÚ·*„¹w£Lx†ú…Q C©Tb‚;ÊÅYcƃÞfr0&3ªL7߀O‡8æblåµ8^¸›w¢kŽxëÎÌAï›kV ®k¶FqÓ5Ǹã(•èýF;·î6ª£§åÝGI¼s´K9üMføbCäïášöJáFžþTl¤¦½6akÚ+I‚Û´'x™¯¼êí”Þ ùó}”n­þ–ÎKÍ —š¦!6j7—fØT?¶~4¬\;…;T’:üôOåIôúÔ®qèÁäBëÌr›·øK‘£{´ÒYÃ×VÏ'ÿû¿ÍRG%©DÍã÷ž’¯_ìã;4— ¢R¥¬P=¡EEÆ_'ü’b1Í0û¤Ï¶Ë³‹âÕùŽ~ºçÈ·Ð0ÕI´˜¿ÉIˆKŸ…õanÆÒyñöÛg/ž¿:ööÛBáž]¼ÿ8y¶ý«¸°ßØ»—{°Óþ*´Ï0¢ˆÖ¼8ò-™÷̨͋ç$„y ë£o^ü-š÷`çæuvqö!Zãbˆ·dZÌ£6,–fÅ­Œ¾Q±?³hRÌcÔß Ú¢5(†xKÅ<1jƒbùaPÜÊèû3‹Å<Ö¹A½Ý\åÑC¼%ƒbžµA±|„0(neô Šý™EƒbëÜ ÐåßÑC¼%ƒbžµA±|„0(neô Šý™EƒbëÞ 6»Õe¼1Š#ß–Q±ÏŒÛ¬8N‚¿>¦ÅýЦq±vo^…°ïW—ñÚG¿-ã·…ñ¬11a‰ lŒÿ¥M#ãžìÜÊ^ÇŒ _[G…¯G‚ _F…¯û¡Â×nPák¨°Ð´xw…â-óĨ Šå#„Aq+£oPìÏ,óXçõ‡U¼ÅoÉ ˜'FmP,! Š[}ƒbfÑ ˜Ç:7¨‹ü×x Š!ÞV×RýĨ Šå#HÇ»2ýJÌÏlv+ÕuoP›»ˆë,õ¶LŠydÜ6Å2Ĩ¸Å1°*öw6ÍŠy®S»Z.·»ûå2>s²plŽò­å”ôû7˜†ú`k‘*àrËå}~·¿ N˜XÃ)AUœj4'g6ªe‰NõõY`Ô¶6ã_|x¥¼,büûß9Öo‘!oÚ]Ïõ8–*²ÕÃ<•m¿¬®ïóëÕ¶ q –b2tõ†}ï£BŠKÇ?©c(íìfU,Àól—¨5…ÿ~&#-QŒ¿·‡)î°‡>°nËÂ1—Ê¢Ç_G.…<,™|ËÑ'aLÅM·½óëb8ë@XTåÄéK¸‚X!Å’x*Õßâ×!ÎŽîr‰Å»?Z¯â•y„×UsŠsBgáÛ–Ñk~hz<ÞAó›1ò=ö¼Q¦GV³Gî,3Î/ò_íCaá weÿ³ÝsG©4,¹„–SãN ¬œ—nÀ¯‰aÞ(,¨2o”¾„Í‘‚ÊyqžÃ0”èrF©­fŒaÍì¼§™Y1°hòEM™ÁË]Þž+"G3ÆLÑíà +s}N›„¶eŠ¢›Æ™"Ϧ«)4Þ2E¯«æ)gŠ.Æ:µ-£×LÑtÒ“ƒæ7Säy왢L¬fŠÌˆžBû>æw7¿Y·~n(Qeû¨" –ÿÓfsÓ+A”Á’PN@r‚Ze|t›<»†‰!·†Š´­ÊáÁì5ejX*^KjˆžÂç…xµ$…¬]ÕN|Ùĺ‰DÑ›…~ÅıY´ÈZ +FW•³ˆ®J"‘ŸÕI8£Ò¯p+9Üœ¢©hI ^eÄ ÙûYq9ñÕÂ@ÖS‘ȶŠïq=„eÏÍQoµo+å÷WAìOàU/ž× ˆÙH^ËÊoíƒu×±W>šÚcµîÁLRE9ÁëÜ~Ùƒ[™º0P6pŠ×ƒ%ãWNªuF%lt›:»† ·ˆÊOò&ÁC**¿c…xÜ$¢Kïšâ³šÝ…3¨ó>eÁ”¢Iît„/·sBukj‡<Ê3;—WX¸àT$²-³ã}1ÎìXöÜL²÷–Ùy[)‡pÏ8³³„zñ¼fvfwCXŽN~3;ÖYÇžÙ5µÇjfÇŒôG¹úÏ­ý#ðì-•± w„ö „­#òªkÜ }1¢q4žY ÓKÁÙ…T_ Þ|“ßŃ”áaàôZ—á·®œŠD¶ÞÞ0XaÙssKˆ7°âm¥ú/c°âàšåâùéavï»ý–çñŒ¿Ž¬4µÇ*Xa®KA¡íýÍúĺ¹swÄTæ.Ü®ÈEaÉ (¯¥qX¬t›=»"†…[L%d‘¼€,¥úA-¢0 óK&‰b &R²ÞDJõk"ç L$ºÝ¹­îà„3°ó¾fÁ´¢ÙÅѼg”·îæ”^fŒ;:.¯ê´p“æ©Hd[‘„÷ϸH²gïÞ,Ö½y+’x[)‡Ð¸HbÿêTõây-’˜Ý¥j9Rù-’°N;ö"IS{ìIØk/È®û¬í]¼4t(“†-7 ¾`Ô H•ò¢aùÜš˜¦ü‚ªAÙK@ŸÐâÅéꌖ¡¡Ä— ʤh7 jfú§µ„µa`ñ¤ƒz2˜ :"¼5í©-·wÌ[¹þ´Ihk>(¸i’rlÚË yGç/+ô¹jN‘¢ynÈéX0?ä˜ ÀO”è‘ÝL‘»»%g›+@¸¶¾öûì-¸€‡õvu½Î¯Ê_˜gŒR©Øò ÜÃ}€Y97΀_Ó¬QXZEÚÈ.šz#)“EbmÉ"Ë.ÏÏ—Å3ùl’S g-ƒ<έi âžÕ ƒDS%8ˆgÕ¬Äò»vn=¡9âÕÁÇ ‡xöŒ] ççñî?zH$S&«˜è5ßiƒþ3wÓeøZº_öÚú~Ùê¹R–œÃë•Ï&57ݾ€]C,ôZ¹‡ÆÖÏ%/`¿×zª†ÎŠôйDWCWJÑj=œ±06 fMÝ@fð*é.‰o­¦3Ngd5u1b}̳ífH)‰1 Ê xBu2úo±#άF€:z×#•¼À£ k„·" ê`FŽ2œ´AEˆ1,v EšíKñ¼þ@ÁÅ„6‹Ø±…õ¾À È¢‡Qí1®ˆ¥Ð Ù­˜b´½€Œ,ݺÍ!;à̃ڶ¿y‡Œ÷¾Yö¬m|s.ÍÛ®··•rˆû´Qž„i /Ü67˘÷åww›u×±om7µÇê¾vÁÁŽÉ •ʘ·0ÖÎ}<Ë“JÂ’ `ží’Ê9é¶yv= 3=n)•™žäÀ+ɬ(ÝU’ Ì#ºlO*A«ù^8ã2©$s«9ܬ¢Éø4å/çsEø>V’…ˆä¤d!ưXIŠ04‹^ñ¼J²àbB›EìØÂz%9(²èaT{Œ+b©$»!{?+ÉŒ,ݺÍ!•dæAm•dÞ!ãJ2ËžµJ2çÒ¼U’½­”CÜg\IfWÞÈ WIfó üV’Yw{%¹©=V+ÉÿxXy¨$3oa¬û4x–'•„%À<Û$•sÒmóìzfzÜR*3=É €W’YQº«$˜GtÙžT‚Vó½pÆeRIæVs¸YE“ñiÊ ^ÎçŠð}¬$ ÉIÉ,BŒa±’ah½ã x•dÁÅ„6‹Ø±…õJrPdÑèöWÄRIvCö~V’Yºu›C*É̃Ú*ɼCÆ•d–=k•dÎ¥y«${[)‡¸Ï¸’Ì®¼®’Ì2æ=@ù­$³î:öJrS{¬V’Q˜qã1ï`lû4xŽ'‘ƒ%ógžìŽÊøè¶vv- sŸçÉdaË 0ÏöJ¥¬h˜=»"¦Ù·šêtOò 6ßà +ác…yÂFâKúd2´›ö´°óžföâÉýô$0ûsDx{þ‡ÌÈÀf\rR<‹mX,+š5°ðX^mYt5Áí#~¤a½¾hô°®ýƱ™Ýн§UfF˜Žè :3ó¤ÖB3ï›I¥™eÑ^©™ónþjÍþÖË% 4/7³ àý,8³¬Xžkά÷޾èÜT!«Uç·›«‡›üÅzwÿÛòîò‡ü~‹4l›ÛǺ̛Ëç>- Ÿˆ‘†ËR¨½ðný´Ÿ>M¹Ïnn6—ÓN?b+el 3oñ€…ÕqýŸ–÷ËR–¸3DÙœeÚ›5\Œ"ò‘i¾Øðô{nŽ«V'îe…Àê¾"—M^&æpLƒ:eÁI Î E™› Ëòðq µeWãdPgyhñLYK™ÂÅØ1.ÜEǰíÖœ†´ú1jëôã 7ú±ìYëóã¬Á[›Ÿ·•rèø´½š„i®,\‡˘wæ·½uç±w÷5µÇfsék^Ý–ÊÂÆ]ÛõÃz»º^çW¤¢‹Êa²Ogƒ-óʸÙO<ÖéòÜk>g7Óêkùåæ*Ÿ*¿8ã¿8_1/Uš9@Cÿi!ù'ÓôŽÿ\UŸ)>gD‡½w…ýßi­<\²ˆÿœâ?gøÏ¹ê2 ézHSç(øÅJÙhÍû‡ìfYjÜòü|Y<¥,|#%•qNaÀ;ý÷brÇZE]Öžü¡ªks§ð8úæ â¤² vî§„û™’û™)÷33îg&ÜϺ¹ŸžÑš×"ÎhÍ:ÎhÍMës3ÉÌ¡̲J, 6Ìi,ý5[(×lÞ±f Ó5[˜­Ù"¦53&–BfÍØ“Y$èÑ#Yö ‡ýïH!Û}*=^7—¼°wŽ ‘ÒšÙIÏÞ͹³wså÷Ü÷Ý{]ÞdvÀÌ "¥«_ÒRœ%cpÓàCdõñ{zL3Q‰kŸ#_—I–ýè”/Áp¾“M¥¦ÒTJKuë/MÅ/yi¥¤h÷˜?±÷çû¼¨<Ûà 㘠cÚ#]²ÐÓ)ÆùweÒ$ï…“&’60Gâ©AfzGàm»ƒçùöò~…¥æÝ'D7éC"´¸]ˈ? Ÿ|„ê¡%"€C=Üе õ`}ÈÈf{Py¾ …›†M +COï6{»Xß“›{iŒtLgƒÉñ¿ÁŠ6«øç3ƒÁ¨rYÞlåEl9¼ ЬÌг`MiôAví£Šý“Ç-Âj[ÿ ze÷¥,Xˆ±ïβ•ëû²ß}H;³{¸3K—ÝÂÞ,}Ò˜vgK–öuVÉÿžìÐ*ùO{´jÙÀÜ¥µGnäû´JAÀÜ©µGnë^mÉnm †@ì×RbÒŽmµcë «VZPÕZ/‚ìÛò˜j(v’+’×½[}DUI^RU?¾ƒK)AµÝï>œe77?e—¿„PÖ’] êO  ”ÊÊêVM¥õÎK5r^¼©:¡ÞÎÑ¿*Ób$èþ ¦Åì£RjÙ‰?f÷ƒ1FO{¸G±—žøÐa½øTÿ=rQ„ÂçÙ†ÓBé8¢EÞSÏBÿiu·=Ðñ,ɲ[_¦nWy³AIËéé ☾օA&d)ªn²„®Zž­ªÜPý«jl¥ 6kl¢Rê礕Ì9éQGNzlêòUu¶’­îP "'µG.Uü^µ„°mí‚×ma™Üf“…¬vé½^©dP¬WJ½iwáRî„™ fw(”ÖJŽå%Ruñ<¥U‹c®jq¬üÞð˜áo2îLPGQ\Ä—[:¬øð’uÅ'Ÿÿ9ÿW±2D‰ ý…ÿÕjŇ;å–g?ç‹oÅð…Þ2ÁÃ8¶“ÿ®Þµ|“¯¯w?“_LN Šø´¹Ÿ¬VTà¿üu2;œ<~LÿŽžTïjõÕW¥•a‚W+DqIÉËËW/Þ’À»ZU“ÓèÀK4Šë¨|•u €%¢ÄtÊž4;d²µåç¿È27Þ­cšþõ´Š(u;:¤>~ù¹Ê÷HÏ £ÍqŽU‡€åçÚ·v¿éXõ¦Îw5ß6aþ&ywé)ñ{§ÿ"ãöª‡i½±tËò·w¯×±¸^üCçÊÊ‚ñO‹´;æ·ÛëÂ’^üz¹|·Ù½º-t ùÞüŠªG?Þo ç¶~¸ý©HÛ …Åž¸ðÈ¥“Þb5Þ©úÍ&»Ê¯&ŸhÂ>ù#Kïÿü?ëG˜šG…ym ëúé&ŸœýŸ³¯¾šÜÝovôÜmñÔü”ù"‹žëœ¤ë ‚G~ÚøoY0@Oe³#“ù‚;²œú± 42…šùÀ`x ûá’ æ{Öƒ&®$o°MN~¼¦[9ŒåÍn¹ ¡¥Üw »ðœÆùi³¹¡r5,úò´=ü؃1N,úÚoØ”'·c:rô[¥Í‘Ó9¶­‚‘Óaó˜ &óÓIX¿>|»äfm§‹¸uœ 2'Ôy,¨IÙY¹¹Ëï³]þÚøNkë>n¶DÏæ;-±ñ:¹¨¸”çùÃÝÝæ~·E° ¤¿lT §f§—Úºý»LVª‘;NŽÏîSÖjç³½NS*ßÓ^·i4ܵÔm ½gÔγ««äoúÎçe%¹o)¹ð–“€q(JÎ}ù’rý4EO[í‚#¨i»ØÐ–#ŸÐ°÷cÖ”ySÖ?ôdŽN[˜WT*ššZ{D´öX©µ&ÖJ ÖZ ÅÚ¦Û®ÀÇ ,œxª¿)Ñ&¬åêà×q¼Éa|™ïÞe·AB`àÓ~‚lWؼ¯’~ÿ%ùI?, È!¿¦|Èv?ï· Äl˜~øf€ ¬¸<þ•5Ø?Ä(Ì‚‡¶ €ÇÁ›&òãê—Õ‡ìzÏAS)…˜£â¾eTJÖ, ¹oÿ–ßÜ]ä¿:¹&Ó`%³yp|À7NÁšÉß²-"4: é¹u*á=f›(Yf{.Œ†Ûm)({ƒÚÕœLqØÒáa¨%§Äl”ƒpa¡¹(ífA•OÙ!nvYñž¿eë+ræñûm~þ÷ÕdzwùîËæþ—åýòßKLòŒ7²ê~¦¼¼¬T:Kò?eųBm~Z2F¶"?ÐÄl“, “mõíHûk}l‰Zh³‰ Zd$ŽË¶¤pÛ#ÑQdyOÀ¹ñ¶Ê@"tÃ?Ë×-!pçùœµ NÆ.cl“†Ú*‹Ù%2›k»DÃ-¶=t‰r v‰–Hnu‰ØeŒØ%Þ6Ù3ººu#ˆƒì·Ýº‡~2²û7œQÞê5Ç|#Ñê1{Na >b·Ùc#~}¦ZJ ¦E²[½eåFFì*C7YÄì.Ÿ5Û2"v™Ïú5gì¡Ûl—h×i™ôV÷ɹ–»PÚá~|¨Ú‹âf‹Ìè°'þIàÓžçbOÄîÓ¼ÇÁ™O܆³ñ~м…{Ñ¥ »yÒæ¡Æ©ÎúMv6ÌÝþXZ×ýºvÚb¦É@u T¢´!ÖҨŤQ‹S7£e‰Ñ}&•ÂRù¸{¤ûY91ñ1ú…bÒQ¿ŠÜ@Á6×Ô˜+ø»„Ù)lfËÿUÌnÄ/+‡F Ã;G7–3›c5eܘµY?5ÔÄF ±Ã72n÷ wÍ|#Kx¸Æ^Yo.…(ÒQ!Ù.¤æZ#FÔÆ ÁVJvn0ñØÍ+[ ·¡h,„z¦Kew¢P3†å÷-Ë[ÍòxC›ÎeýÎ;ž~]ÏcáÔ%ß“œ3 ã+vË õ=Å­4̧õµ1C÷Nè?Í$ÿdêKøÏ›„›²`ÝN±&WÑÀ÷8ˆχ+¢Ûu‘ÊîN‹r›»+úë6S®Û´cÝf¦ë&¹¦]û``¯›1¹ÔKïúUžZ*^­Ø$“_O£¸™Ætü›îæ˜ô{3î{³ö¸ëèM}ãxÂ=Œn‡áW}SÜMq¦ÿ¶wùo¿Ž:PbßÎÓ>Üå|ÏÅ÷ ]òÍ6Vwî²tÞo¶¿Òí~ßTý>­ûÏ:o=“ÖQßzÆÒ;|ó ùÆŽûÌÉ_ôPÿ@w“­â)öÛÀ+ûÃßuqøÙæö6[_¹¬øÑW ¾œ>§ãZðêmÕu¨ô«—ƒÓgz¼œ_(_W„“zu•ÄT°û:”4¼vv{…6Ia@|ð\ZÏ]È2A1ñÓºX~0W—zK½üçªËÍçœpÚÆû÷ìå¥4+ÅøÏþsûæ%—ñÜanâ¬q9›?«®§|Wa¿]¥‡á—Óuò.Û[ÞÅàš7ü}î–· 7ÁîÛÁ#Zýc\g|:A©×æÓ­Ö²¼-e¹\~’54à';ìZè°ì*r K²¶}—0Wº„Y‡K˜›Š`ÞCóè\‚1Å4¬öÚ9Y(WoÞ±z ÓÕ[ôX½Et«gL1…?Òú[;š•àŽŸâ]äËä[)sùÇ ßØXZ ;æ tÇÊï͹ïÍ•ß[pß[ô(ú£h@.0õ“ œ9-¶š Rîòû¿N¶»"’”•„¿ˆÞLÞ¿)þ¿êó:{ 1»¹¸ÏÖÛ› × ø¦åWæ¦y‚4G¨¿0Ÿ'k,i¼t®ÀõöóKùvz0qÄBbðËÅ1º½º0éÏR“¾À®~ù©„´á~ün¹ã/·vµ5×+‡¨ ® ßN&5¹{Õµ÷Ö'RžßlóŠXÙ· ÷±Ëoï”É’äûlæDµiËô¶ÈÞ¶•V·ÌØ–^ç¦Tçf£ë>¼îs³u·’3š¯û<к÷'Â+ÃuŸKÆW÷ËXÚH%M`ß™CMc†§ÃÓ„™Ó½.U<¤~(ìU`Þ>[JµhwTÛ·ÌA"#¸vÿtÈ?SÜÚtV)IË0ý6oÔ|9ñH£Ø'´Ô¡t©Ciá¦Céè°J–˜>Õ¹ÐÊ¡už^£ùæH­:6ŽÎ«B‚Ö±ù¹O’V›#U«Í°&"QzÇ éi'±GUæ3¼×H$kÚ\T)Þ­ièÝÔAɬ%Z´È©ÑÒ¼©¼%ªnŠRµG±z¹«—²6;-m•7Ú‘mÙ!)'HKSE’´v7](¯d½fm-{ƒµûÝóöwk¾]õ~-S‘v„²¦!þF_¡ÀÌÖºrÅvsé}­ÑŒX¶ £æmyA©5Õ',B÷0SPÈVÿZßvPe<à>”Á«®a(ˆkéÄüÞ³hoÊi|ì7B…Næ¯)ËÑèõ“Þû¶F¬ðŸó²Å] = ûüÜ•âI3WðŸ ?¬ŒËÈs=õÐuŽxêtÀ•ðÎWg;‘u ÈšüM$‘rÖÀ^ÄÂu7çÈ·¹½¹{Sp¬jwÑ% {gߤ¢hc™îi1ö7Ü!1ý Æh©ˆÀޱCmýH©ÀޱCmÖ%Raº Ì=+ rÏʉòž•Ó{VN Wã¤×Ý*ˆÝ»UN$çÈìºr/êDöÞSSÐONtv¿„h®<.„{À¹äK㼡¿q(žÇœÔ˜ßú¸C ˜¨9q(87Àæ •'TžPyBå •'Tî•»¤ ‹:Ä¢–ŽÔ éHý‰›#õÒ“¹ªßJ¦õ>oó”.…D@ÎèŠð$Åup—ÍA­œÃeÍä$™‰bE’™€5ñ¿%4•…FLÏ¢ …Záñ”ðÖF[§+®â‘½%†ÃõcCÖ?'ƺ©ÊOiâü”Ë»ÎÅ?•Vb›Õm¾Óü0;ÓfÂ#:+UŠг}BÜu)Þ{„êú—…þ fJà»7H«VIÝ 'è¡qfÜk?PÝŒ|Uá@9øWÏöšw,çÃÚîÖ¸;ÅN/0˃'…‡Y î†ý"1.Áþé›Ò 3ߨ)¿4pÂæÖT¹¹™K ôÇîJ6€:ýM«îA)•†‡hÝ;Qø ÉÞIÃ[”Êa®Ûþ‚¼˜ñå‘ú B~ìn‚rÔKê¼z•@¢T_]çP~_å¨añ ߯Qù`¬©.Ï¥åT×—­Râ=j©—T1¼+äûõ› )?ÛÊ~*»ÊωWUïÔO›ÍMóæL4#Ò–ô@Åf$”OFBhŽã$l›t@žƒµJpÖ8Kõì€Lî¤{hx $º>}:9@ÆÿäÉáã»§õñ·<ä÷¿<¢}„þ™…åÖ•YVêTßýé›-ù¶p““Öº£e_çùÕä?ëË?Sylˆ¿È¶µôf“íÛ|»Í®óêÚ¨?ˆ='È¡–€zbù™à§Ø#¶ŒI@âg$`oÅH€yl¸VÂo7› Ó lÔ3&œòLG •(ñþr¹Ý`µjvaÕùOó?¬ŠÇ½Ù\¯œ Ù¬Õ"û‘êwƒ°šÞP*°:ÿìêvŸu³¿Î6Àèd»Ÿ÷UÛïQ+:f ¬Žcý«Þß­nòí>ëx%€¨½æ"¬¶×êQå߯‘AÞçhåÛ[ÖÅûÏ7—uËàÝ­Ýkæh6ä-nqF±wÀshKœ;¨@•ÒýÍ*ZBi”âK› p¿ŠU‚Õù•Wàvòõ7ƒ*ÃnlM;6ƒf¦›A’äÚ‚jœ&‡³+d›rêÈ¥p…¢.’È&ˆtoÄͮȌÛÓ˜õØQ?Á<8Ç™Ï.òÛ»›l— ãU¼Dìú÷sñ몄ö§¨ô÷B¼W{2,%ÊŸâ½¶D@ûéu"}¤aÞqŒŸË-qF-q.ÜhHãH›)ÎÍLQ2¿FÿÆh˜*È©lqҵɥZv¹aÅ©5ÎÛ·ß|ÒÓp Ë|Ü`í´’…èj‘œüŽÌ Ýö¬ªÒ²P#¨°´q—З©€ 1'Ä› ,TsË…vu¦-Ìío¥æÙÕÕùÃO²ëm ŠÛ^·Eè˯–ÅŠRC&ôáK^±Å÷ ýÒ°ïþ(`-ߨÏ2lx=>a‘ñM®µ],B¸²*$v¤ôÞ6T´ÉLŒp5™œ‹›LjB¹(íÊY"ú’ã Ì—ŠÞišT ø¯±A›:y¤OÐÏËϺºúëï–gÊHÀø¼,Äyʳ›<»§8¹ÞÒ±JŽÙHû2x<²äµÅ»²¾Ìw‘ªêµKÙö*‘C¤ZÌrཱིˆ_ŒÃÉc¦×¨C¹Í‡cð¹P‰MÚ!ùçìæfs™é|}·ØîjzqûS~u•_¥ ÔýÚ@m®ûˆ6R%Ì¥’ž¶d ÕòìR=ö"žž´ÀVï‘ᆫŽn¼Z%ÛÞ¬çìûFìû5nü9ÛÆv‚Ã8›bX4›b9ð\`õ$À쥛íno´´â5^5­Y霣ªPÔWÏž¯¶EYÿœ~€]ƒáhUVäûފšFyÏöJsÏÆ ¶gAuö †Â¢$;ÈÄq®fyP~†0%—Ülò1ßõ)JÍ¥uÔ"/€Ê‚¬X¨*ù›5Ü)ÙHr¢íóÈ%åµ:auöPækè¥QŠMtœ™£{œ¸ÄY“Û£á }›5wrH;™dRë)JþÇD8®œÔÓ”–¬v7®ñÍÇüzµÝÝgˆØÓ§ÙOçÒOfµ®÷PùÏ’-§÷¢c×Q¹ËŠÿœGéÔ8þ¼ökö™|l}d2R8?#“§“í‡l»ç%Gä¤ß­.±)Ž™uq̽‰c>Ù¾ºB7†X”Çܺ<Þ䱘l?æÙÍ»ì¶eÂx{âÁafÎ8Ù!Ä*n±•|{¿É®ÐË `'ßr‰£Zä9FÍG Ä®qçÝ-ž¥6Ò'ðêg?gëùýíj»-ä4 àGPPg*ä?›ÿÊd ˆf!ÿÀ†Žã ú/ÜŸQü× ÷__[.ŒÔ_š‰_’$oi#ÅÔÎnÕ?ç—›«¼N¤0 ÅNø/œ4¾ð5ÿ…¯ƒgYüç Åç5#&©çÕEîH¾ðŸ üçI|ž_ähi ٮϺR§XE%ì]H7˜v]‰x$±²=“ fJ3ã ‰d&Ì‘Á¶NQ-É´ö‰vJ¦ÑeÉHFÕ_8sÝ_h“jAºÖ³:“mÖ0Š(õÕ,Ú)•FË%Ž—ÁºDíЛ)ÛC àZC«èI$»-8X¢ÈAsÜÇ(ÔÊVŠüÎ`­è†¬ÖBàÑYyý}ò‡*æ€!ŽƒßTŒTp€á÷­â0‡9>Qr|bÊñÉ ŽOŽ ŽODŽiÏmÅH…o$ŸŽ¿Vrüµ)Ç_âøkŽ¿Vsüµ°u!‚ö.f¤Ù™u†l«óS¤PèôÇ×6Ï7©ü–`¡.,Äê2:dH¸C–àÂØÛ"œB ×pZǃ½²¿†P+Sðl„hGAÑ…%ì{zAB^AËrra€,Ì &u| 1"Œ˜ b‹("Ä=ˆ~ða,eºâÉ—yªÓ%¬¨‰‰¾Œ-R¶áÅ•:•4ö¶T§HfØñ 1•0€a±AdÆŠÆTLÛÆcãÄQ°ÃĆÆc …E€ÂÆ Â a° 5;…4@í†Ó:B¼\Lh±MÁâ>bEOP1–ÚÝóüsªÞ%Üh´Óûyœõ»Š1@è1dO-½­á©E–Y!w<ÈL-`àl ¡±â35ÛöwW?ÇTÏ£ä†Æh ™EÌÆ Ì á²Àx y€¬ëÙ v”(2.™0d»4`BÈýDÞd,U¾â/K|h¬Q9ï{N¾ÁÜѼhKSÀ˹ÞsA60geïß<ÿíß9ô™F~+G~cµõ¤oÂ! `²à¨˜jcΰ‰²h`®V”á¡R 9Œ1«1ÆœÇåÔäÁs%Æ0Áôæ+#â*éŒä¹ˆ0êÑÈ„|Bf÷îv÷8p–ÿ}ˆï„ )϶…Ö.éWJÌUüð|µ©¦5äÒTÔVÈ¥‡¸JéQJ'"»›67JkL1%Í¡* h°µ‚ÉÑͳVði{Œ5вj1A÷Ü*ƒ‘¿Ùøj$0*¯wù—N•{•ßä»ë\{‚`ø„‰Dè<"e){ÐÍFŸ<@Ê‚ÅåÂYLê¸Òœ(²œ=LrRŽÓ. à)Î>d8{’àøÉoä›û•ß|̾D³WÂæ7sé§5¸öœÙ0­6bâÒ’ÓDÖnSêÊèúm*Æå!÷%ÔòØË­ µ8€áö„aw}PË|ÔÎ:@íÜÔ¶B|µt-"p€­E¢iÔdÀm|‰‰Z€“‹D7”ÒVPN]µ—ZÎí‹nç6;DÁÃßÔ-‡Ë "‡ÈcEÈrÐâ»R ëï6¨œÍ'0o$øX>AùviÀGò~€|[y:ùÁ@>ˆg`¸ <·ÀpSLß}zú¢øËÇ|GWÂÙò°–ƒ´QX_à•’Œ×úÉäŽzS²¢¥0‹rx{€âÉ“ÃÇw"-/ òþñßÿvðˆ>ôQÁéÑ!ã§9±1^š*Úã»?}³%ßþ}’ßls37ŽäºÎó«ÉÖ—¦:¼!j—mkN'Û7«uþˆÒõ;•Ñ<Æ *¥<ä\Þ6 ¹¯úî~s»,DxÀíî!™~s@¾|èäòÄùv›]‡Hùé›û¸ ­¬=¼O¡ÆïZJF ¦Ç”¾¶ Ëvv¬’H#å,ÕZ侄aÄ«#ÑÙ‹¨·±qܱ15Ý‹è:K¥”Q½ÀÙŽ°J6µPéŽãB¤[ ×½Å0å úÓ[ê'ºÉï׿¬7_’·ìå-‹Üi6ùI¾³¿¨»PÔ·yÒ¦—­C-þòn³ 3Æ7ZGZ -rZó‘§¹ˆ;L›Tw@Nê=Æì Ï.Î>$÷h–•"‹ß9b.’k4lÇh‰æ®LùŒÑ:Å<¬váö”™· Þq»»:=ý\}ÓÅg¦Q¼õ M«ÜÅC,Æþ@ÈÄ ,R|À†O:œ¿ï‹Éÿ¾bÆ‚YH¡~BHäÈ.“x͆A‹¹_hÑrz×õ]}4"Âå1Ü8ÑXâûô­\ Þ&U9$çnõ3ýÊÆ™¾ŒÐ;¥ù–nÆðp@qÞŠ~óÊe*žŠ!úä,k æ¡¡êþ&I1i69Î-"GÝC£Ã¦á›LÏL²x`¢~{*n™·Ñ¢¸ÅòUú>‚Ñ&)h ^ܲFr;ÐLÅ-¹¡¸ˆÁ¶â>Sq«^¦TÜÚ³â’þˆŠ[˜È0ÄgqK. Å­Á¤Ž¼¸%—àâ–%‚Sq«S¦c(nù欭¸…aP*n…,n½ZÜz­,n…¢ îN¥RŒ¼Ëõu5¦×þkL­bi`§×jLÖHVã½×ÊSíã_‹é¿†¶}˜þ5ðt» ïoü{Kf]ÿ¾qɫ֭¯‘Ý–—Ç:ûýuÊλ„2;Lêȳs¹|gç–nfçlí“·ºµº¹Ù¸~“»Y»òg9ב魳úçalM‹Hª»õÇz•¬\2€g¼["8kðþÚ´Xábº»n}`øt÷áo2é߬ÖHÙýãô }C(?X°G¥yU¢ä* í ­6Á¬R Ø]#Ùatªa,` ¦ˆ–þà°?DZ¸",óv0^°¯«G–åªËchôéùô+š¬Zu‚VHVûCÎ|EXÖÁ„*Â"€a%wpz¾W3h_4Z‰Q4DcF :HßEN¹0@9“jTäd«—àîµ”‹Ø¥–ˆ¤NVïFK>`µ\¥ |¾5àˆæíQct†È1:Ë ÔÄÐè £·Š¥ááYµ¬‘¬ŽJœù*0:ë`BatD\ŒÎ¶D¸8l …Ü£;v€ÖtDÇ0;P®oÌ/HÌ?˜Ôñ`~¹(€aþDa~ÂEL·ØË%ø {Kg-ü8_}nñŽóáw—÷CL¯ÖŸW»Ps!´šK£šó`c÷›?dyFQ줬$èÓ.àDZFðG?¨BéëTIpg§5’3YogwC =-iú U@àòÛ‡OÅÊï 8¦—ìììf…Tc޶tsÑF¬%lA Ü>{×tĬÍÉê.ïh3¬_`ã«‚¡#”f©€¸Á` ‹D·T8¨¯çjZá\¾:wôQ±^G‡Ì.3·øÌ3 ïþôÍ–|û÷I~³ÍÍ6¡‘v¬óüjòŸõåŸitÝ’mkÎ'[$çG”®ßÿPíË.äê=§ê½àÔ›Fꮾˆ…™Š·ŽnÑRq0J‰(ÚÛ$ ݈vŠšê^a(ªî‹¾`—`H¶×Î}èj›û dž#-ï«­äÚ \Gt@Â\¬zbW\ÕJh5ÕP`µ˜ibX åÃýêsð6?¬©ý@¿ý ¹j£h@°€`•õv \C.pNŒ*Ü Ek4«1õ1±€!‰6!ZQWÃÀ6$Ô´ëõKѶw´Q³_ƒ©iµ¤7Σx¤Q6š†?k$»°ÐþjJS߯?©˜#oø“ó5,úžD¦'x – W‡É r§°á'4XÃ_«të`›ûÜîr¶\îÝ.§d™G´Í)㪗ï†Ív›[;röìá‡QݲßɃçéà=²©õ=²™·=²™rÌè5͆.›W©i)‹8ÌK¯¡Ëù köiÏT¯‰ ]ó¾`¦ÙÐ%må»+²•Kæ„Ë+ý×`[¯Æ€EÑLH$‘P@¤O ‚[Ö$‹þfsâÖ­è¢ ºÞþTÊ,uòñ9v–OiCc´%ÀÜ{òúç«mðÖÅ7öEckŽ#W[†‘@ºË(Oþ~›ß̾Àü º7Ü5 ¼!DEùPÉ…'­‚ÚŽ­£¶©7Ô6€ÚJÛ¸;BIK›În}Ì8v›f fýž·™»¤oÙÅN6–Ôgž]œ}ø˜ßÝl×A$ì÷%=Ú` ª'eŢ7í–O³"ÉCP¿j—ö–’*kýý¼lÇA÷µP’ÛZP÷ª89b›Šç(eÇ®³ã‹â?ò˜ïñ&OúV j·v‹§$3` x\ø7A_sÑÀF½qÞ°n‚¹Îaî¨n· ÜÆnaãÚg—HPá-÷þ1c[ŽÑ [ž¨ø–£Ò'ÂíO,òvåZ%]tËï‡uy÷í"ÞuŠw‰Gƒx); ó&Ìæ¥Þ4ê½È݅üÌÛÇŒx6G€wYn ¢]†FŸX·U4 ¸ÈjPœkl5Æå,½Âe]P|ûvbXâ>ÛB£A¶ˆ—k¬ Ö"'Ó¾ÛoÌáZîýcƵ£#@¶wàië/ÍÄ/Íz»c¨ç?ŸYußR.AûøÏY¼^¬ûöZ’W æH¨æ§&+GôxÅfBÀ-ˆk[±™ÙŠÍú­Ø¬«T­Ø,ÜŠiJ·,šbçNWl68K›YÏÒæÞ²´ùÀ-”2j3Yþs ] l2Ýêi/eL·…6ùôƒÜª!¨·…Z']ßÚt_3¸šH 9Ü﯌èBQ†¨®×÷‹JÀ2®Á¤¦}?û,Ðo=EYFBïžv[Ƅޛü@ !Aл†x ¢wë¤;DïM÷½×DAïiÆâŒ2ˆy&eZâ– &u\;1*QÜ‹DjÚñ³ÓÌå îǰ—çËÞn?ÎlNrä¹œÈ Ô°ÏÐè³&Ø*šæ@ZFûƒÖ­‘­Fœ¥÷Û{a]ÀÜ ‘ˆ®x‡‘¸íñ¶K±£ÙsA¼@õ±¾7\¤²–W £3mµøÙjAnô>KBåöXƃÊEn FŒ¨¼S40Q¹U²¡rÑUDåˆD8¨¶ž;O½åÎÓÉöÍj-;vdب‰WËW«f»†4{!‰cÖ³i…ÜLݼIý×¾imàÖ>•EŽ’°»Sì^KxÀa'¡vM¹@…ì6hvˆ×߬4BAêZ~ŠK‹/LH:’6ð"ðÜÇË|÷üÍÿžc(ö·l}U<ÏÜ œòœSóÍð)ñþ€UòJò•vS’ëô»üˇ ~jdÄeÛ%Zû»Ý}©ÕfBÿƋѮ¾xØv¸\bZŽ¢Š˜F1F;) ©iÞH:`;å­œép"oÜË#Mœ=N›äP½;ÔAŘB"GÎ 2Ú©Tæ†KòYбCmÿ"ŒÜµ /³ã[] JÆ"§§òyËívõŸ|¹C‚ºäJñÉçÎþU°C–ù‰ô/ü¯V+Þ»`§²<û9¿ü»Ñe ·Dÿ4ùïê]Ë7ùúz÷3ùÅä”8ÝO›ûÉÁj…}0þË_'…Æ=~LÿŽžT,ójõÕW¥b‚W+DqIÉËËW/Þ?·Zþ…ÑbBÌÿ3©yÝåg‚fˆWþLpÑ‘´ªÀX9~õÑ¿ÐÑ´â‚—nâ¤åçêHNç…rä8ï¯aÔòsN:^z\¼ôHáXÊ7v¾³ùÖJõZã,Ñ,¼låƒ~çªÑŠ™Çº•¤KlõäÉáAUr$Þ£nñV~ÿà<ßagK®µ|ñëåòÝf÷ê¶°ä;ó+â‰ýx¿)Àáúáö§ü~Rö¤…G-ì›Þ¦ùÍ&»Ê¯&Ÿ֗ȳOþÈÓùÇ?ÿÏú¦çQá6…Oø©ˆŠgÿç쫯&w÷›Ý=U¬òSæ‹Lå”z*¯¶YôÀÅ·Y'zdâ'¿ßæ÷)åî‘üb‡ˆ˜‡”t›‰rÖm‰b“´û‘=Í»Q°{Ø&/Úß‹ ÆîG)É“š ²/µF³‰7¥eOý)ý[ÚìWÉßb÷«”‹äWMÙ¯Z£Ùį’—&¿h‹è ³Aô°Þ®®×ùUù¤ähý:Zãí"¬>^7‹´ÑìлE6ÈUoQëUl±Ö$u¹Ü;;=nù¸åùy³³\ÇI”þ´—´¯{IÔë8ÙI"rÚLr+aØûIäo6¶”¨ÏÒÞU*¿Ï»è!ÛJÅß‚]q:¦ì]r›hœ¸Òï ¢qæðÚwuÂJã­‘m˜ÉS³ÉüË » à_©L°ZY³ò§M Ä{\¤d@Û) ·up¤v‡“ÇÂ;³ê,I©i-&UºMΪÊçsðÄ]†Fé[]ÑgÅÌ1‚hïqÛb t¨=R«þjïZëŸg»ìù*@û¤@…µ”<À¥ÊŒÏ®®ð8ó€;ÇøýUêyPþ·‘áÀ< S 7ê\´bÐWkDÄu‰ÃÞ‡ZÍ¢ÈÚ{äë:KJ"l¤mNJ€-Óï>v¥¬ªOdõ®zt·E’¡Û2X˜È`Ñ-ƒ…áVljҎv|bjÇ'}äsŸ“LV÷‡ŠŸJ÷8fèÄ9úc!ÿ‰“M·…1S~ï„ûÞIÍ’áo‚ö§#Eûðp}(ð>¤›bô„Î:Oè<’¨žÐyBç–йtç Æ ‡g`×,zØå `¹ÆMýñ‘>c°´îµZ´­•Ej*ô,^zþ^ή‰u¢¼änðò*!«ºÙ;¾Wpž 9ìS6#æÿCï¬úWØydÿSñóÛt:ÁÕé„R¸QŸN¨˜H§ÚÅáñtBIÀÓ ‚C 1Ðm£6’ó؃ÞÊFŒE’3ÝÑ•¿ÛDZóiÚ[Úzð¶õÐH Ò8§Ö˜³*g/)œ³Wž¬#g¯¿×Ì¿û¥¹ß¯oVë_D7š2Ü¡ •‘kÔ8•å#å¹ñ˜ê²– /Ûýnµnô…ìUš[.eµzfcsjORI2j?Rs‘^SÍxmÒÜ–òV¸ ô}µw1É{‹ôÃkÊCñGÙïoo-}¡<‹¬nNüm~½ZcªÜp6hÐØù—Õ5ÖÆ ~îòû¿N¶»«ÓÓmÎÄŧø£›|»ec%ù4»¹Ù\f»Í=ûO“oNO±f,WŲ£->3Çu§ñF:ÂŒåØ?Vwu,ø`q£$F·†ÝÈHHµÑÉHÝY÷uÓj3c*ª9ëgnåIù¯†L¼¦Àœ ÃË‚QãQ8ÿ!ý­VÓJcã ÃFÊ„%6¶Jt[.\£¶»±GFÜ£½Qhà¦Ë¸GŒÛ¾~kgQ©\KG8›=õ¿9éq¤"Ž´¡€cX‹§Á}ºŒ¬ªJG£‘ÕwiõÑ”™o6ª>”t1ÿ¸ß1¹%—n©p¤N‰a˜Kbt79¤±8$ÔÚ§G2v «‘ú–ƒ-íÖï¶òoùÍÝÙæö6[_]Oyn#UU ÏÚ*(L…¥ïØbW|@‰èS „¹ÁP 6êj àÍqo•’ø‰¤Ì‘æ]¥XÕ4F½µrú¿ÈNByCoV±G´z{„µfÍäÒýH^k§iƱ×Ó=Èðôýýö Ë&Wáˆ?«ïòb?]˜¹ß–½úOsõ?-$ÿù}¬2¯?ŠY=ÇØv…Œ¼+”]!«D7w…ñò–©·9j𡢉»;Hãѵf¨Ëoóé@áÕk“¸­|óòÓò~ùoZ§(•Áç=sJ6î/“s5ìÞ¹¹ÒfÆ07•BûfJ1ˆ·šEa ÆDÓðÚ05\(×pÞ±† Ó5l¿¬V)ñºÚ(ÖИh †º[¾9+ÛáFçÍä—êÍ廹vW²k-ýÞœûÞ\ù½÷½…}tG CøÓȾC,ÇEÀ]¸³ºe~»½ i® ©?õ4XIŒV¸¨Wˆc._ý]ýùàÕŸ›­¾­BŽùêÏí~ê)1\ý9ã¿Ù]W^æTÍ%´¹À }ù©ÄðÒün¹ãÕÒŽ­&6ã¼çdR3Ei7׈!ÊO~³Í+tÑê“É.¿½“ª›þ#ˆ.ª¹9t«ù ztùY×þfýÝÁÙ×A›­áïÌ4¾3êsã:tgiÀÙ ¤g‹}p¦1ÊìHÝrn”™äL†Ñ,³YLÒv>ËL>¾®“ù©„y­Ú«ËHÖÕ‹™L/JÍhÓyÒØ5¤[H3µ4ß+³®vNåÚYë§Ž¦.’¦&Mí¯©Ýïž·¿[óíª÷ëÚŠt–&o#üß“å˜Yކ…iy웃Hɬ%6MD¤gÞ G»ôqÂ’æv,)ÔäÚšŸÁ£k™LUv¬²ûG|¥à©bøiã{Íñ·N^díÁ=ÔR iÿGÍ Qÿ™ÁóÛ`Ó'`Lô´q¡ÅŽî3l¤­Pc Ý µJ´t+Tq©E{ yÜU_4ÂtÏÝ*7סҒ!Ã’ÇàdY>¼NÁ‹Í×¶ ¬³µKu›·åÌëP9ÚuDއ)s›Ñ Tþ[AïM¾ç¾z0椵ƒæ9I@¸ÀºgÛtkÃaÞËì#"&`f†¼¢‚Ïíëd›4cv´FiÆél[ÜáÚ¥½éty/ËÎG5ñ´ÜÔÔ8i€±‚~'«\`r~†s„›¦â}”p“„t¬nƒä1èÍzéΫÚg56`Ó…«½ú@ÕìÅ« ’ïb7½ŠÞ6°Ä!öÞS}S°û1¿^mw÷¿E‘{V‚Ne¬G›9ü 1—• 8E‚5Òú<ûœï©Ž³¬Gªã nc"š®Ú¸àô –ê¿Ý„T}Õ«Á;¬£®cqŒ¤V­^Y&[{·€s0û¸YP$ ï~€¶AÀ~* ›ÍÐyrn˜=#þ~Q¡¿óê‹ùåæ*ŸwÂ@cuñºŽf¢.á&¹|á€õõ¶èm:yý•›)WnÚ±r3Ó•k£DcÖ ð•3¦—ºufå*K¥ “D× õ‚¼±ÌËßøúÓ%  Úªy¿OþP :‘¡ŠxÁïTÏ|xŠù€ôoXy)µ½ÚÊ,©²›ù²‘6Æ–0¾4K÷ñHªBD`ÓF[ô¶í[ªÚ7^¶ä!- G¹²\ÎQ>$¦Ì¿eÛýõ¨Ž“n#w§„ƒäN[Ï5IEÖÚ¢·» DåT‰SÙdžçù ¼†²õÃÎý~eÇŒïïPÝïr“¯Æ6Ii“ÄD8`ݳ-z›î¹²CIÀ”´Ì”m&×øÐ˜.‰¸› m˜©Û؀Ɔ~çþ^ÂÇ0ûóÑáùfÀH¡"…ІŠNtÜþÍÛßBÈ[JÆé骰ûl·¹äF‰0£ö£”…äH¤Ö“Z#¸Í•fõ(CC/ÊO1Ü~Y–x›ý’/7»»‡Ý²´JÞÉ’Kl÷1ãzŸb²É#ÑMÆ~{E¿vzz•o/ïWwèÁä&ïå‡÷ØO.ßÿø.§ý"ŒÏt¨×Š«=å$éÙÞ>=lÃJ‰îDfŽvÏ›_¯Ö{n@T‘šPI}(#*5h¯Íˆ-½Lý“DR¤hšLŠ“'èaSñGSO$SÆÔ.§ra“>Ef&6‹ý/nA¼†)oþžNþ÷'ÿE¥-5ü_ûø?—jšÊÏ”™[eŒ./þ*±oˆê/‘›»úmÝ–ŽÉèß¹ÔÉyhçÐD‚|ü§o®Ñ?ÜiÌî œ.Æ_ã I¶u¿#_9Rg8çó‘WÛétŸCêtŸíã¥ÅêhTÖIj—Vù=#·W1pÀù>¼0˜&´@CÝÄáä¿ ÖêkÍ1z<î0ºI¶ €RÈo¨¥{ª{K·þ[gÓÿTÖô¯Ñò_7åkŸ*áu N•„jðÇnð'±Ò ¡_úƒÖï6=]ÿ~ÿ³›<»ÙPU¶N¤SeÔ”ïRÍ­ñ°«M¥u>Uòà)£ª–LÒJsLZi¦ÊVš©i+MËN‹’o­K›i¦êf§7öé[[ð|¨™†¼GˆmŽüЉž¼%'î3«¶ÔmzFËy´¼è¼F0P¾ÚØþ¸‰í;‘}‰À5S6-‚&O ŒæK§Ñ‚ß+o7äÌ-šqü!+L=®h[õÏT‘ çm.Œ" ½,Æh×ÝL“ÇmÇ1+eëüò‰»8ýâ×»l}EÞíœOŒÒYyF rŒ¤ó”-)m»¤À¶Z&;ëqX%aϬK|0˜#/nFRÚ:R9é8î8X&÷Ü·•t×lr'ÍÉñzHl`útr€|Ä“'‡ïèÖ5jäøÇC~ÿÛÁ#úÐGx[šYd~Ošë-A¾çñÝŸ¾ÙÒ‚i/ z`!åu^$°ÿY_þ™ÊcCÜJ¶­¥7›l?æ;±/Ä÷kD¶§õÈÿ[I€-¦ìRûñ³¿„•›Q(‚T‰T(ìo?üV$ÿë¼,ÿùêÝÙÇßÐÔk∗©Of$}2 š$¤Ùpê•è-äúoH">SJª. ÓhR/’œ0ýõ7ѪËÒ=¸ ˹W1t‘¿˜ÿ°š™È<¢_ý¶*Zü RñÁ«õ§MÁ(ù'D†a3úÀf/…v¢s*ˆ/êÚTÉCÀæ‰â—Þ{'”l7оLS»›)ä ÎtW0Ãα ª 4Û£‹—?§­…¡ÔI|WDz>#·ØíŸe%jï%%°¥ ë„7‹Œ'c‰I šsq°æ‚Ëâoav¼#v—Tf±»Ê’ä&%ÙEÚ#ºÕ=–Žc¼®±Ð“mò‹~ ,v§ˆyHÑL<Ý¡%Š[}!ö#u„/C•Õ†µDJKN$¼äÊc±9¶—¦…1Ë-‘²ÕPU/U®¥Ç•Ù¸Ò —ç^®.inÖŠ"4†^U¢0m¬Öì~ )ƒ1 ÷Fh fˆ7Œ`ƒªýÁJh` €/ˆEhÆ¥°0fPjTKø~›ßÇfˆf+F€¯`êC©?YƒÖ„«–ÎøEüQ=©L øv)ô4^¼Ömá]¾û²¹ÿ%6sxõñŒRnÅ(è³âµ‹’P¦Á®G«”úfÍFê7;¶”³›š™¡ª­ yT¼6Bée"åJ´šU2kÖAžçØ2Þfëì:>Hu¾¹ü…’n'½ ÏŠ×@J‚¥ì‚´šI©qÖì„yµKcy¿~vu&ý è5³t:²þ’d*ußv`å9É·e‹vñ—ù®Ç ³\-ÂÎIÖ¼@˜m2•å0jY˜t·ïû¶È¢±Šá1/ Læ “¢A»½Cé¤&,Y1bât½¦Ìæý^ƒÄ?i? )ø•j(Yí§Å³Ž@öùÞ¯Ÿã=s8±$\Ô°Ne‚ºIˆc$‡vq‹ƒI5 Zþq7]ƒM8C’æ*·.þ9€?üÿÞá ¢r‰õ'²†Ék?¬·«ëuͶ?oîññî¹eoJ?¨î¡fº-…—Z:çöÍ­#yþóZú0žuÕܲKÐ<þsŸçæùä¼Y±P ï’‹MÞ!—†k¬ŒP×;V?`hXæ¶w¡vÚÑ;3m€m¹ï½SPâÍï`aíSN½-Ó[y6ºPè8lé —ççKì Ñ’ÍÈáØ¹òpìÜôpì|ÀšÍÎyçÝ8‹ä‚°àìñ±Ø9w,V £8ó‘¶ Ïž¢7ôížq¿³v<`øCÜðfs½Z?ÛíòÛ»°a»»:=Ý¡­P¼BA ÿóìa÷ó·Y‘cx0Ÿ…“*VБ§U+^` E]ç_nóÛRÇTQûÙúêý—µ:ñ*4o¹¬5ïbYiÞr‡ó±âWäM^Nlt U ìm†#^4m£‘ÿÉASð­ÆXãFt)Sá?;¿X¾{ñãòí‹·ï?þ¿•ƒêý¦2^i¥gœ#ƒ—Ÿ}Wü:¿ÂDB9ªæf2dK¶e+…ÒO•N¥ 0Š]–Ÿt ®À†³Mw¦ S>×*ÀÙœ]º›¹\Ù£X)Oe,ž|t”í “a´þ~ýËzóeн³/vÙ*UUS«Þ©=o\àWf‘\` h±SÖGç¶ÖÙ%—F,mD·ÖY~?µ v7«uÞ«U@p—Px2ßæÛmvd %yóXÛ¤b޼ä%ç «æš (}¾ú 4…ÓrIí X—eÂÕ‘¦²xó¶¹Ó‚Ûݽ 1Œ©0Ÿ»FÌõ—fâ—f½]³Õ³B£Î,?€\qXÔÜ*7™-51ÊL²÷’ï.Êrùä¦ðmõG;òavs³¹Dw¶³ÿ²k‹l33aêtÈ…)Vo*£Šg3×ñÌ ¹Ô=6¿ö tõgòÍsºr‡ó¥_m+BÎîî6÷»ü bD’$|±sæµ ¿2dï[Ï[ÈÙè&[ôÑôÃI™KÏ@6.kEñl£èÉ ìnŠ#ò››*²9|q¸ïž8=ŽÅÆ8Djw;vºL\âۻ˰.¦-»I-q83År”Âæ¦Ð»æ*‘|ÌÿýoC4Ü'xá§µ¾ZãÑ  k KhK&! ]IÅNˆŒ"tøµƒ!$µ€2Böƒ QõÒ“¿¼ÙdWü½¦¾ A—'ú±ô*¼y²Ñ/Òçœøè¥7í)QCýê…ø¦…7hÁ®‚4 NîƒÛaxœÂi¤à?çøÏE|€…ç1µ»öà†WÛ”g#hyí `xe›r=lEoôô ­:xq•4ðv-y¼æ«7 ¹ŸS¾àöàP„oÛE[˜yïÅ-$ÐS¹‡¶p½‡fXŠ›šq†À*dƒÛ ÖÛ O¼µžL¶üy»½îÕpÈ#m£nwœlàÉþódX;uÆ“¿|¿¾ –å0ߘJ¿Q%/LºÃ$/² "ªÞU.b'·hdÕZ¨*r´þ©'›õÏNÁÈn*— FÕ É ¦_Qz±ÙÔ)ζâç=@VÈÍT=@‚™ F03ëfî ÁÌ- ˜:ŽfU¿þ³m5@o/¹Ò% a>z³V]³ŠýsébK ³þý\üº¿ÝOU‰ÒR)òT¦%eÈøÃ ¬0„‚èóuè£M"2€M8ØIÔ¶bâ¡"ßÓm“àr£U²›µFê­åð[âÜœšÔñ×{®˜lKWió¨C)ét>’έCÒ…7HºI×Z@{RWÐÔÎíç£û,?oÊ~ºÉ‹k#ƒ²r&Æ<Å¡£2LÜù†|Z•aÿ MÔâ³jëæ^bÆoà9 '®í(Ä5˜ŠU™`T¹`åg’#`õ?µž³ t;„*Î7ÔjCbe +á¶%§ÈaõÊ55÷“§d?y¦ÜO6)6Ò R·¤ÕÚRžl)‹ûàôTï§û ÇQ¤HËè®Z#HʼÆr*0éåj%õþ"¼¢Ú`V£ÖŽ[™ÝÕX¿Í¯Wëw?Ħ×oËCÙ«bU†hwɤê]‘J¿+ýQ+8) ÞË/¯ô$çã¾ð˜±þö@îk4iþð«üòýïœÝ&øâ×Õv·}÷”fë¡íЦ)Q߃ӧ¢£ÏT1‘ƒ å¶#Ø"ÉY£¸®†á“® g‚ÔA^üj¹Ôÿ`«¤‰kx˜ž;-yß~Y]ß!d»|›¦V7ü³ï}T˜DñゎöI]ƒ-&犞g»ì@ærÊ@Ç| ?’‘ˆ˜ üÞiŠ(Y>}»\âß9Š6Û¾w0Ÿ²D>’xo¾ö[¼çÿò?íÝ!L(€w/~´ˆ²Wot·"ØZÂÍÚ"0j‹ õüÕ9Ö\m‘!ݘ½5 Ú[!j×þñØWÍBâ<Ž«ªjÅ@‡ôž÷HýuVî] b %=r¦¢ñúúÙ@ \ÙöØMÙÖ&­¦ÕYÄb¥•Ÿ 8¬œF6«2Ùåv»úO¾ÄwZ^òæV|òùŸÓœ8B+ðþW«oqØÐ–g?ç—¿`sí ½¥x ú§ÉWïZ¾É××»ŸÉ/&§Äg|ÚÜOV+ìBð_þ:)Ôóñcúwô¤B+V«¯¾*•¼Z!ŠKJ^¾¸X¾ºxñ–ØþjU]×Co*ˆ)ž_>€ÊºTQb:eOªìy±åç¿Tgöô7‚ >úW‘„*4戦^ËÏÕ¯‘hÏ Ÿã-÷:3[~®Ó.>ŽE>êMøJïðÏó¶õ·[tˆâů—Ëw›Ý«ÛB²Èxó+âýx¿)rõÃíOùý¤X6lÊ…I—V¾Å‹¹)ØF¤ùÕäÓÃú9–ÉYêþøçÿY?ÂÔ<*”lSèØOEZ{öξújrw¿ÙmÐsQ'A~Ê|±Ž§§5ZìúBÃæ‹°–x¤[ÞÙ"!9¼ß»Þñ7|Ðÿ4N†u×x*):¨ñl½yj.¼FÓÓä*oOg5Zä!¿[û€†ä~ìr'°4Gu%ÄÝÆfø]¾û²¹ÿ%ˆ?xõñŒ¾žñ 쇱úÊ@üî¡d¬‡¨µÅ¯ŸP ¦á*X}ÖuìoTn£4Ü`žƒƒ8ŽÎI}±9 Büþ‚òÖ]x×*7cïA 4Œƒx.ÏV¨#`­o•NäßvuÙ›1¿4Î Hn:Ü ËM¯'‡TÅK³Vûj¦ö" Þf,&±azÙ•T{†ö Z×é÷ùÇüçlûó>*vÅ|ÄÚ]ó^Åke‚§ç›ín½â>fM¯™ êµ>Óõ"±}¾Ú™Áºøwg÷‚VxAk½ÈIxÕÕ ¢þŸí¹òŸCóÏ`©ýY :ïnsg/ÌùæRh„!Ÿ„ßÔz(²!âÈwºEnÀîwSò¸áÝ)Yƒ Ñsƒîòqàq—ç)§ÂBv?›5sòAn}•ó˜QÉRòF†ò é’J{‡ê—>â£Ä÷¢4ˆS2¹‚Oz'Å€iÕ¶æéñŸw’îëëÞ7Ü»|^FH{÷~‡Þ\å ×<ÔcëóP‘¦ù™‡:l?dÛ­8 uˆ8¦ÖÅ1ó&ŽÙdûnuù‹MqD~ë+ÔåaQÑOÎnÞe·¹z~pp1— 4™+|{¿É®Ðëà '1ÞFRÉ*úô£æ$…^÷¡÷m¾Ýf×ú¾¤¶I+£–¬ûŒ³Ÿ³õ‡üþvµÝâ™ñ(~3òŸÍe² Dµc`3Ç¡¥rºû‘ý¯¯-P´nÈÓº/Sÿ9»YTÿŒ‡ê.xŸW|á„ÿÂIã _ó_ø:x&Å®ºÅüd°woä^‚jkÝ"Žÿ<‰1 ˆÜ‚-A!{öZê”L£ø„]ŽªùYQ"njЀT4“ÖI@ÖnÔMc,7#š0·Ú&›–®­f‚Ýšƒ•—ks´ÄÒ¸·ÇÑ0·çØ#8S]¢Caw‹NV‰lñL|CÊKÅQ VÅ7¹?œþ`Ðz‰÷r#B3ð3ücñÈûEÍò Ï2›8àa–O”,Ÿ˜²|2ŒåÉ­I –OD–)R®8© „åÂò×J–¿6eùëa,­Ãò×j–¿nßéþÞ3r)ë ¹+‘†¡?NÐ_Ï_¦ñæ/ëíêz]¤ q'2<)£q˜ÑL÷*£™¦ŒF_2)£QŠ&†ŒfÙ£Íh$bÑô%xpFSFáåù9ìF" 1»á CwšÃ#(ò‰ÆžïHXöšïLGï„OwR’“’—IÎ^å8°Rc ï0Ç1KqÂÜ2k™êQ'fqæe)-Ó“ ì¬,%ejIì_N¶)YàŒì@’|Åœ‘½¿‹xש̵`s­2AR¦X‘Ÿ*Ôg„§‚W ’™ û5RiìïT0ñÿPRGú¥¢€†ôû9Þ—àÎ7¤—²,âx)¢kÀ÷Ñ-ÚÂ<=êê±[xè–[l€m”x \ [{–If½y ¥£–ñàÊ+Õ’€‡*÷TÀ”½*ƒà0åó|“*‚ `ö˜XFˆ1 _ `fЪ Bû[T&‚Nìˆ@œBÐpÜ2£…r ¦£9‚‚ÆP#Dœ„‡s ÄÅâFŠá`A¸°•B¹<`Ö Ó:B¸ÚL`³M±æ>BÍ Hs•Ã6«Ë<•êì:‰wRÆ@!Ï ÅC•@ö·z¨’L@gÚA:•4 ºAtF ëT\;v¡†ˆY 윋ÎÍÁsaˈ À¬#'vŒÈ3*à™pg«0@ÂνDa@ç8ʉÏóÏ© ˜èÀmìÏc-)V¬Â¡A‹Šj‘ìoYQ-˜øÎ ½#‚xjy@Cy)è©ùv¾süy<%FÊLx°— ^”o¼À ݯ¨ ÌR£ rljG#ƒ£ vˆ(ÝS, ŠŽ£ðø1ûRüÈÂc…@TÊ\\>—~ºF/ø”Á¢xMß¿yþþÛ¿³ÿ´üSäx´ÔžÒŠ5Pˆ4hÉQ-0%Ç.€`Þ©åÑL­Á=²H©Ôq€:ÂJå“ïv÷ع—ÿ}ˆÃýžm‹U]Ò¯”ð¯øá!ùjγ‚ôÔâi (ÊFûAQZéÝô¹[Tcªi8-èþ ]rýU\(WqÞ±Š ÓUlǃjyˆ€0ŽU4¦šÂf•¶‚}²r*­Âû Š•~<×"SÝx—)0KiåWùM¾Ë±‚*¿·à¾·hÇÉŽÞÔw‡‡Ý lG¶Ç‹µaAí°Å_¥H`m;¾Ì šÄ åfÒ‰ -HYA‡8"H ‚äòºvÊ ÜçâË;aç-9 ›bË»_ç|_H£“D–5¤ka¯…ÕÙˆý6Ø´9 %ý܈d[ÀÛž@åm™¶òZÍi˜+ÛLš:èz¬ˆŽ¥—hÎŦúî̹a’ GX3wW0‡t÷©‚Ëñ]yª`ÔñM§]û-™½Nå.vs’ð)IJDR"Ò7Ùƒ<Vvã$¦]“´eÒ% ˆÓ>&L)_êôti/²¥}I–‚äJmûB)W¢»vAR%&é‘¥#-‰iBИ mL$t#¼anJ5^ä'“;æÈR–‚Â\ÊQùÒ„'Oßt·¼(üÇC~ÿÛÁ#úÐG³G‡Lå$Ç„OªaïþôÍ–|û÷I~³ÍÍâ+í:ϯ&ÿY_þ™*ï†è[¶­E:l߬Öù#J×ïèÞ¿>À6òU¾Ýf×aJ)ôÝ}„Vå#¡lÁ™”¬ÀÍã)…mé õþG•P r©àaû‡’«Næ+óyu#u70ýá»B6÷«Ë>‘'aT®‘g-z÷(°×Eò„zó”]òi–yÕç4-SÞR Œ]Ï ^ ¦+=/^ø°=ÛÜÞfë«”}v:GN^ÑûFž›”‘ºÏHKYë&¥¼}Âô!Åßât Ü7ËCø–ZŽÑ;†Ï^Eg/¨ZðÆ^ÐqÇ^ÐÔt/¨s³Y)¦zµ#dnj·:GLO#Ý-ì¥þ)WáŸöØ#P?¡‡¯}·Ù…þ9&WKÄ8OK9I޶—”€ûYkd›¹Yêdö×Ëž]œ}H>v(œ-„8‹ùHþµ‡Œ€{WKDBXäZöÔ³þãaµs€qµuúvwuzú¹xÓæ¾ê­|Š?Ìnn6—ûùä›âÿùùFöö~˜æÑ·Ì/rݣ߿·þTPec}ŒA3xoÉw½\0ÛèÓÚ²sÔl£×î3etŸvD÷™itoï­— ¨Ñµ(´[¢˜†Æ›fŒèt•'L5Ú~Y]_ÞÞÕSî=Ž3’ Ulä7ŽŸpõÅkYc4’0bĤ˜/³§-Ó#“LãqAg€œ)¿'šcU‡¿©¤ يļ_¸½ ¬ìÊ$‡PÖ^íKEX*ë{"è4V\ ¿õ‰¡Ò[ßS«dà5²°HÕ ÍjÄÊy p }fMè+/ÂÊhP›»qÍt‘ÎÌÒŽ`úöI˜1Ûö¾Ø†VcTÅ6Ì\4ã½Ø&—ÌbÛ`ZÇ^l“ r±ÍÅ©ØÖ-ÔQÛ|³fPlÈ)ÛàÛÐÊ=÷W¿?Û†ÛQŽ¤ØÆržz?dØ&)ø _l³Fs;bMÅ6#Á¢ØˆCƒbgS±M™¼_l«çßú»Ž¯ŒÔ¿oŒ¯Õšgùu|¯ÛªrñÞÅ÷:Õæ4ä³67˜Ö±×æä‚\›³D±9Ìå–7£–77›l2u¶³z&g»qƒ]ë4ày {Ó¢’ñ®iÀÑNÉ•‹ò”\Kgúî½6-Vz¿mO·>8| ëð7õÁû!+‘¯••ȸǽV”cÃ𠂯[%Ó@œ¯A­Ñ¬†É¯•ÁÖ({ÆØß7«5B!¼dUò‹{¤ÂŒÞ5–|Àu‹] ‹U¨Gï´æ,îà0BÕžK[:\^éPàº;0…`É•gž¯,µçŒÖf$›Í˜¸ÞÓ{¡U.˜…ÖÁ´ZÙ *¼‹»ä²€vq×*©óÕ»¸«5æµ\¡2 †,0ïþKy„ån$c¨ôšè—þöÞµÉmIþ>¿Bëž*wM¯KoDõlOT—ÝnÏúÖ.Ïtœ³;¡à”h[Ñ*©VRÙíyOÿ÷—¸‘  »n,‘™‰Ì'™‰¯ë~ššõÎM0jó½ìôHføpF")ö |‹HG¯ŒvÁÂB«<¨CX˜!¸¨ÝûþC-˜ûÖ´hÿ¡–´ýG *­ö„ “Vîva©U ç“RjÑ”º(µ 8¢81?ׄcŒŠ X•=ÝœNjêÈÝi"$Ÿ›TîýƒÚ¤r|¿IåyîpTö¶I­”L)˜àuÝoäã„f}$µÙ&•Ç!˜›ÔÛÏ룿#—FçÆw„’¬Ê@ Z”¸Ûû–R'˜›JÔZm+Í·*`ÎèDù3š)V›lW¨·±èmüñB´WÿáþC¶b×Ç,ZÔOwuµY#ˆ]&úµˆ‹V0×]÷Ú¿g"h­|ÎhÖ»muWŸe6ÃKoù`©”ó®ýå‡R]‘/¦@oÖ±¢ðXV rŸmWѽá^ÉJ ιR¶¢k5” \ÇÚŠâºUL ;Õ–4»w©ÔG…áPßn’¯/×Ût Û§ªŽëÛ4ÓœÎ&äùßâK ùK çNÚÓ@…¾ p>ŽŠËèèÍE××·%z î¾B,=~{²->å » G“;Z‘ ÏV/•bͳµ>A.âÑ£Ó‡wdÝ—ï3ò~¾O÷_OЇ>ÈVìñ)Wë–Ÿ«tPÿ÷ðîOßÈ·Ÿ¤›CjW Aú±MÓÕä_Û›o©kÝ’ Î'$ç”®ßÿ×jŸS_ NÝt]}na§äÕCjŒ´EžÃâ‰êr݆ª[O¤²Âç!Uø…i”[Ž|³c#ÑâfŒMQpˆAp é¦n[úËK;¨{1P5– ü85†©fR !JAª¯ Õ4„)G0àB•·ûõg-&Xb¬¦V^¬”ÁŒÁ ;°®ö×po Å-°Èœ£WDÄP#XYÀƒˆcKLÁf9Ýê5¢­Q¹IŠ3¿±­[âõQ®`øæ‘n ´`Ç»1Ôí*ÔX”Üà†àÛÆ°¶»°vhm fIx 7„…½^Þ E‰ñkñ+‘í€"XÊPŒac D KÁ zKÈôÇ  .’¸D,+r7šèì5ž­‘P)2-ÀoLë”v}\+½yd+âÜØöÕÁψÄÁ¶™`Õ"nbHCÚ BZ„iÐãÙ÷éoGŸÑ,÷þÁŲoƒˆdy~àÆ±•½F±•Ò)żÞû`Ñ­^#7]yl‚¹¾Þeïôžƒ^‰l¿R†bCØ BX nУXB¦Ï8V `p‘¬ÀÝ bY‘#¸Ñ¬@g¯ñl„J‘¡h~cZ§´ëãZÉèÍ#[¯àƶÝù™°2üÈIv@q-f'FµÝGµhðÝ6Ýİ6kÿ+ýjÒbLƒÐ""}†³ÜûÌr¼ "”åùÈrTöÆVJ§òzï7„uF·>|ŒÜ®R:¥Í¯÷~wqÎèÖïá#7ßÂñØAýÞòz}ó«»ZD'PÚiÁbhWˆx¸>Ä]‘Îõw7¼^ åc*È<^ß’T=x+PsÄEÛ<ŒûMâÝ&†âƒ»×$ÞiÒR<@ç@¾Ë${LÞîן½Ýc2öpœ  ÑxÎ\tí5×ËZ,Þ’ÒŠwŠçà 9gDÆ@Ü} .É6ø8\殣ð†×Jhî”n§A¸ŒM0cpÔ\*GI8—Ï;@×âK3ùK³Æ¬ ÞÅÏg­![ÊžÐåTDõøÏYˆÈ3²ûM´kå-¶oI©UlO­U¹ã5›In6#®jÍfvk6k¸f³’ƒB¨[³™Ç53¢”"·Ê‡bd§k6k½›9ßÍ{ÛÍ”F˜£æöcøÏ9ؘ"îÊ:(ˆ² ~W&ó×Å{)ŽÔIè®Ì)ÝnK#6ÁÜ•¡½£Ç;2cm„‰@Õ‘¾¯Ñ„½‡ª’´]TkZc¤»I·}dÆÛ>»ª” ë¶Ï2Gp݆ŸÛ> $ö¶Oç´ëýK£Û>Ëx3JG{ `Qz¬ž´­žhãþ°ë'1ú7•´è¿5­«¢èd±ŽÒŠÖXIé®’RÞµ®¥Ä½[·õ”aíÝÊÁuú~ön»wsN»ã½[¯`îÝÐÝjeã6¶òJ&ûÕV7pQ¶÷ŠRÐöUí%•îJ*—¡×SøݽLÕå/¢P<.É6øh\æ®—à¨ìÕYTJ§<––Ó{¿¾ÃÝzW"¹yí„Ç&˜Ñ7Ú%@оcÙ¤mÙDχ]3‰Q}½8 EõíX©D)ˆu’æ„Æ"IwEi¸BwcÝUG†´“ùëÝ}ìÆj¥t7æ”n§»1›`îÆÐžñõ.{§ðŒå&þUD(Cp¶÷¢ˆN"ÐvP­i¥‘îJ#¦¡WG™>#r‚AÅä%ù•—9ì6x:=øóW´þÄíþE4z󊉈W0£t´—¥Ç²IÛ²‰6î»r£S‰@‹þ[Ó:°ŠN«(­h…”î )å]àZJÜ»u[OÖÞ­Ì`§ïeïf !°{7ç´;Þ»•ñ æÞ _G·mƒØ¶áµÔŽp·ûܬi„mŸÖ†ÌmÑ4b€¶;kCfܘ™m̈ŒM·eÄ#Ãß‘a:½¶¶q j/Æ3ü6L`®'çÉì×£[ô†ñ ïÙÁ»¡ZïïEã6Ûs ˆt»µ¾M÷—÷ÇÝ_wk?³Ùò-Ö`Ð’iøp)p/ëbi·8Y-”òÈöª˜º€t@®…غ¸ ‰—«Õëôøe·ÿÕ ¾xwE_?æNßbÒéË1D Ýë J«äR&Î6ü¡©#Šõ€Ê#@ì&Àø'ïÒ£qÖ‚CqÈ-ÀOÓMzLAú›°£pA°ÁGá"7ј‹¦qGt7¢ÅLŒ`Fç×évõ~wµYg¢ò‚—\Ί1Aíbóê½Nbs~  ,õ¯mâ¹sçñÜ´·xn:9¼\oU–õS¼^½UP«•¤\¡$௔ê„ÞŠš*…<¡ªªõ-nCŽÈyB}V‡XHTÈ6øÐ\Åܽ‘tJá®ÿš¢Sºõ1ºeAQ…MÃôl 'F7‚N¨˜Éj Xˆ8‰1´·º :AŒsu„.à ¸8†b´e.°¡– ¢ÇYAÅÌ}¦ƒWÉÝåçìAÉ?7~P³y´Å$–å›—OßüðWP)Ës`Yb©çÐ,W»ã+ûß§IèÂ+Àå!“à’~…köC.úÒÁ§#­W (C7»íAHŸ©Qªõ”¶ÇÒè§vqð]}”YB¤éù§N°”‹Ã_§_2H`ʰÂ5,Ls5æZ>¡16¿Ã¯†ÌX˜8«ë¦ñÓ25å_Lov«låJX”Á¯D®"À·UèîŒø2´çæK—+£™ 2-Ã![W)5ù…ZÓ´Z,¹†…%L"n&ÈËW*w’sRïÍ(†«]Ù™‹2pöãz»"‡ãÈúÞaPºùç ¶…8ß`pŒ˜{b=có=U¢‚ëtœR]µ‘È­ëôäDÖ”SŠÈ Ùì*28|»Ãj…P”–>2J K‰;ü–²!†è—»D«¬ _¿Ø~Ø]\<#ÏA5rÿóßéÿdßEþ§®_ù þÿ¡Š¤ÿpæ5¸Ö<Õ?eæ5·Bª1 ùM Å—žÈ_z¢qQîÇ¿ˆŸÏ5Ÿ/4Ÿt6##lÜ ÕÖ“ÁÎñŸ üç“ðœ)ÇfÜÂ5\7ê”ê²5_Å™v§5«8³]Ū½]•ƒªg¿Ý,_ïŽ/n3£E. ]¯üà—ý.ƒòíýí?Óý$CìN3·Ê|ÅãÄ. ".ó,î·7ÈMþ¨$üßþÏö&ëAd» Çþ¹I'Wÿ~õÍ7“»ýî¸C/@®(½à¾X„íÈʾ¦ÁoÎØÿÆ¿æ~<6Gþw©ùAîXŠzýÜ ^¿0ª×%äëõÅ£çò“,‹öÐêñmêîJ%4*¼‡·£XŒ;ºfb‚»£sL÷ ïÕ[zwLw¹øNA_U3ŠUsëz³MQ½éº•ŠòšŠóÜ âܬün^qvX„¯J© _YsÖã5çEëšóÂy.çIo¹œ'–¹!’mZuÆ!a,8[%žg«DzlºØ@ çæˆQW9 9;ªqÈYôèª ÃaŽ£`knrÄyÇ“#\[¹;r¯ܸÝ)Õ±c[‡)]œÁ`¯vÕã¨ÆY¼MŽŸ€:Õ77K …p ±¸jN/#öî¨s®BqÖí ‰ÃÖ ºÓvHùÒmu2›psNy9åÖ& üæFaXzT†bšdŠ“;›Ç—BÉçXeŸºêÛ?W‡”óbgø£Œ†çÙ¾'Ÿ&›Íî&9îöü?eÿ/ŽÊVR­¢Â 6¦âææãL¸ í´nõ烶LœËe&÷÷yøF>Brç>;’Os¹ ÿTyý„ÛˆODmåF«<ŒøÕÆ›ŽlVVsó¢‘ wôœj€ÚÌ‘¥?h£l呬&Ç@o¦Ç@ «‚h¢^0Ñcxûuù÷ åNº˜½ªñ ÎOtáZÍÁ7…ðZر{HØ]Tþ1ÊQù Rù´›òÜ@:imv] û¢ÕÍÀZ‡VjVµ‚wÛqïW^쿊ŽrŸ%¬›(×7]ÛEΫM›öµÒÚÆ}oÍÚ2Éí¶K¸æÈyœ)ƒQ] xWT´hÏHzš~H2瓾’ÜŒ9UÁ‹aøÁ®nG›¦¨½—$G‘ïEÙÄ…2AQFíˆ×¯‡‚×Õðä™bZ"¦%ª6¼*'“°’ªm'è”G°“„g¾ÒÐÐ"Agõ£žç­²\Ÿk³NY.šìª§ÕÁÉN„GKˆ™šôÆOt½qkzãÎm{ã îÁìÕ÷ƒ‚iŒsK6UaG]q_hÍÄ*9õ6 ü¸ÆÓ䘨D¢íäaWÙ x~Öõ‰s¡ûî¼zaù„&'6ž®÷×.èúËú#†‘_²Þ¥{ºqûßûô>¥¿KÖÈŸ’%ȇÂ|ÿßÚ/ÈçO9 ¢BXÀ$pJ_ÇóòöëËõáˆ.È99yH6ÓìlËtR,pþfxÃÃöUdÛóoÜÏÓÛ»ã×ìuî³»ÝÝI&åo¾Y¶D_ž~/Žémñš³É­Çò‡ûõf……|òàpxpÆ?ïCON¿ýqvüö& ²÷èùŠoÒLûWì+§’¹ßܾÙ^®Vè@½—±=ù('p;¹Ó¾Ó >©ì1m´àî÷d †^No·×Š£”çÇfàïFûv„&Ú[ì…9ÓÖc(ðOÞ¥GÃA0; €œ;§8ìä?üyŠö—ðò ü’•èj%Í'´¦ÕÊ-h1Ã'78À«Í:“J¦kÛìß½`àÿ}}u½»ù5‡Á“âÕ¨Ê"¦¾ßÖ·™ë:|ÚíäL¡[­8‹/½¼êÊŽíKŠàôܾo 9…å¼h¨Ö׉Æ)¢×ˆ¦”¹ešbeþEйòZIÁ=Xîžt Â57)2€\^_/1Fö¯b-ëòGÔëoU”œ€x¢: ýmR3ޝ“„qûƒá®|¿Ù¾Ü}\o/G”Äô}Âmæ3EÍ:C¬Ëûã§’lý½eC4Q€Ùñò ~G&0Óóôh´šÛôËmz[4²¨=üåvõæËV¿g#,¹Ê½_æ*G;³_‘7õ3§N®rPe2j?Gw|4Jxt¢kÃÓ˜a;p¡kñJÿòúýòõ³_–¯ž½zóîÿäèÔøM̳iq\.;»³Ÿ§+L'ô+ ˜™æ¤\Â-É@J&¨Îæ´CB\x}‰)°)U¢y½fTëDSr™Ì:L3ªìû±-´%¼\oSã– 7&ˆ”¾J‡ä£Ÿ«éè»Õ¦ ”nðù15W ÐYh^ öÖ¿`(Ÿò1vjþºS®÷.¹±›µ7¨Q t§Cr÷Òy{º›¸øºëÀ¸øRéh–îîKÏÑ3·f yŽ@!³ç¸¹R.ÝÍ|N©c©ÌtG‰¡ 'éGŠÈù¿T˜˜ÙIÓ¨[A-M9Ó“ãŽÎ¿Í:÷oN襨Y^þXéúϪ½ï)Àn^r2¯ïïîvûcº‚é×Ôn K(éµg¿2ôN=Õº¨]OÉ^t”vâé2ÉP©ÆLXp+6Ñ_.ܨú÷°Oë½eÏŒe¹oÑZß­G}r]žÒ±VÔ¨ÆÑ¨—Ëä]ú¿÷éÁÏQjø9¯ú€ s1̰N 2ŒE7Äè„zȆ Æ W:úà‚üíå.Y! Þ¬ªœW„Xþè åsžôÑôJg³kƒâÕ ùM‹Þ"ñs]d´pш1 lÚ€ÿ9Ç.B nD.ckncIAnÎuMz2„öÜ¡@ŽÅ\“nˆÑ»úŽÃj˜•ƒ0¥Û­ÊÔÞZ Ój0ŸS0_U@䆪êx ;_´‘ÑB¨j«x‹Î«x¨¥qSÙß°ŠúšEë¦Ç…ó¦Ç'½5=>1¼ÏºØqˆñµÝEÖȨptÿ|[òmnþ¶ÝxÜÞO¸Ä)ûà”®¥}·kQm‚êFê6M*-ñ ²¤2o`“¤ä)½&Ike£º Ûq?&ý~«Æ¥ºÅiëQ­Lä(¶2hé¾õÈ ½‰®õH[f­Ã–™ó°eÞ[Ø2o¶ž3É{±ðŸ­ó¢Î[ŒÉøg´Ýðååñ]&YÌÜáÏ•_\tàð+–Åïçò×û+™ê’-Jå¨I:†%pÌ &’`ðÕ,}…UBÑÝ•èñ‰ r+#N¡—{«Ä9¹è”îrf‘Bµ:hÁÖ8· Jm²øëM×LUíÕZáÜ«šJ]zM(:oŠÎ‡¢‹ÞBÑ…u(ÊEv•Ù²GEºlðUûÒ•ìÞæ÷¹¸— ˜uþYq†3±Lô(ž¼Ú9Wb løÚùÇ®cß¹ªç vuÍq/á3޵¸Û«ŽIøžV¹œ<%åä™¶œl“u¤?h§p¥ ר¢<³¨(ל+,9LJ —KeíÓÛÝç”ü/˜«çðÒ |èˆÀ (×éµ4T-–ΪBª;*E[F’F€ã}ý¸>[ßÁ„É04Ç þ½2­É~œ­¿@ü¤ØÕfû'Ò¶n=QÚþ®ø=üLNZø+o¿.ÿžáº ò÷J4Þ¦_–W¯×7¿æw|»FbôpöyŽo†¼ÈÉÓ_ŒyBßpš}—¼íD­w™ØÞî°š£]*þ(9,|ß÷LïÄd.zúÛ7X‚h4gàn\¢¼çýÜ®ÝàÆìV«ù†[Nâ‘B½ïºàþ%×.iMJ7[W™¡ú®âþŒæMÆä§„üŽÀ6yé’Ø„³:Ë7¶qž?™Û†œŠ•~úâúÍ/¯;Ž@Vê­‡HÛ4ê$ßBÎ’VIFÂyõ®\Ï´[•t ˆ» ÝTÀPFF¦Œ;SEÇ*a¸©:ï&Så†J+›©v@üKúv?Ž ”3Ld‰:C\è-îÙ‡7¢eŸ|þïé?2žÉÚ?FòþNüÕz-Z6¢åÕ§4#¿F2ô–ìèŸ&Éßµ|™n??‘_L.à+æ×ôryô—?O25|øþ=)Óõú›o˜rb‚×kD1£äù³÷Ë"v½^ç—¨Ð;`2b²ç³PAë¶:DŽ˜HÕcr#AØ´ü¬¬\r©}ü³Éc•¢<¦éòsþS$Ôël œâªb¯.?±`%S™ƒ¢ÈhˇF笰îÑ£Ó“¼Äê’…s= ¹¹à/^§GŒF¯¨»ýÙo7Ë×»ã‹ÛL'¤+U~Ùï²€s{ûÏt?ÉãM†; ŠX wÙš¡†¿t5ùp¿½AÐ7ùcNÚ¿ýŸíLʃÌ6v™iüs“N®þýê›o&wûÝq‡Š*½é÷Eê™..èTÿOrX\ñM¿²ïñÀò¸>ÕŠý.=¤îG©ˆ49öœš'69º{ˆ*Ym€èÚÿuY.ñòõ«|êsömOÂÛfðMµ˜©1þ†ÓD}ŸÊL¨ïA™Í3DžÏ~W‰Þqo§Ô&¥Þ ‚¨Ï“éa»öÇõìîyzüiw8¾J!euØJØ—/Jlèƒyê­v¬m ¬Ø± ñÝ£Sj$¼&UTР‰}t=;)Ü3‘]ínowÛ«OÉÖ};^¥ªã¦‘ÏÙ/qÇ"`ò¨ÜIB>Wõܽxwõ:=~Ùíͪœº/ü÷z•îá›uá)V·ƒö»ž­›g¦O·oº#jý~‰Õ—}È7ØÑÏ»ï¯3’²ÍÌÆ4ûî¡ó•¶»ÂɬçòVW`\í98¦k$éRŸÆç^…ßh¦îk],ïÄŒZ上î–nwÞýñìï“MϞƺyœ$¼`÷Õ ½¹¯°¶ØUºÏvJry³-·«!C›ý¸û<>6ë×é‘:ŽžaUÚL{Øt¸,d,Êr,ô´m,6Þ\ÿUò(Teà¦é-VnS¡VÁ¨anÐeÔ…ÞÞ{wŒ«‰õÍ4aš~OÝ]aÅUZÁ ªÜÑ«/_0\d#cîÅ*“YD=#Ôò ö÷Œ%ø\\‰|† }¨â‘Ïù¨B>LÄ=SÁÀ…=GôV¢Æ…A‚Þåjõ6Ýßö zO°ÀÁÿ$ÓŒ©8ÁÆÇÙz^nÁ" £¿ÌŠ‚šÜäÉ ­ªvt‡M2‹þÀ–c*m¥Ùˆ~!×5âPž‰gàÁìËE.Ýerë]zí¾ÝS¹k÷Œþñؽ–ãNížÙ4»ž]Y$3²þTÊu˜í©ŒxHÝ©L@6§"â®Ö„£äXgÛj8â9\ÇÔ{Ðq$L]‡¯LªŽ›ÊQt¥ä?%‡À5à¨Ü‚ àý½™ 0NËw7aœ ˜ÑŒêúoUpÒ5žà!0¦Ë³i9péîŠäóä¡Þëa…jÜ=êP×=T¨(;_oLÛ­*Íý«;Ñ)˜úÞYˆºsEÆÀ´Ý¦¼Ø¿²c…‚©ëè¿#<>ÍØSÛsê!%¨rM‚—¡ºÚì¶}ÏCÉÿÕ²ÍÄñ,°`÷ì„z ‡ ¬Çº:O ‘B©Sƒ3g/ǃÛÓ™h<k&v ˜ VØ÷¹‡åòpÜ/—crÀ”å/£¼p!.WT“D;NÓ§‡].÷éÝè´˜ð¤SÒ}è1Õ8ŠL ýº ¢?ø‹ÎïªÀcPºº«ByM‚ù¡]œëϾA.Û»ÊLíÚ8-fHyYuEìßWu¹ˆ+¯é“†)!4›(_xí¥ÖA_$9 ä" G´&ª‹$ÀžŠ®à¼ÛãЪ«ïp‰q×ÓÝwœË|]õÛÑr(]íÎü²­[òö÷:W0._œÃºáÉù÷…k’¹D.ÁK2Çý]s‘ ¾b O-BÌÕLƒÁöè•Þ«"G=]¢Ô4:èÜ÷»rëmÝw¥÷Ž~;úíè·ÃôÛÝUôTtq]é²€t¥Ë¼›+]f~ï0!.ù3ñGÔ •Þ/ßsþdêÙoD­ð”=«† 2Iîo Qä“[ΰnæO3z%C}õës¥×Å_¥›]ø'þž{y©çq©á-µZ*’™©%“ïãlÉT“W£‹¥«žÊL«õÒËDˆðÆw¡_\÷"ùá3!`9C*sVä$Û<Æþj"vµ¢äÝlÔHD’Wjh€â¢Rcºí¹àùsT•QD;½Þ‚i¸… Ò6­Ò°×\•ÆÃ-˜+ÞurQeäØsª‹W9º{P¼âo¿ea.ßï¤Ìw4)[ <¨”9é†ziÙ÷¨ÐN¾ï‘$ë{ÌÈd{}Bvëäâñ(üTúO¹ò¶¼÷¦œàDgäÒ<ºé›¬´â_ë›,æ´o²Oó2í›lùÖ}“D ]f-+%PÊ[bžúî–lM¡>§*¬‘ªO²çÆHÂê×›MÏèÓgdˆÙ Ð º{óÀÇK”£gükæËÿvH÷µBU»ÆÐfW 2 Ö+æ ôà ½L¯¬‘ ¼ñ•® N´ó+ÙK7ÀRîû=Àøg ¸"dUçorµ÷ä“•ugʺÓnʺçªZŸªÖTSez¬©2MoV*JÈ)••TÍ)`&ëëªçººj£Bf½P•µ:¿U9‘Ζ¥¹%dŸ\ùeû !úòxLn>yÜ)Ó\k$û ¨›Î$Y»ƒàX’\$U£‡[ÎjeQNbQ­5NcÑï+YÅ›+æ‰u¦” aÀ‘sÉd£±ÖEÏœrzSÌA5‚V€Oð1´ËŽÁÜ:²q Ð0» ´e ÍÁItÖ|±i˜ý4U@×À|iÁc€¾”#¾G_Ê©EϾôÍö—O;E!þÓ™òÓâ$zÛý§™þŸæŠêúü»ñ63ßhâÅ3>ëÙì'±\e& µ*WÔ– Uæ«6Ó®Ú´fÕf¶«¦8NW)ù@ìU³¦–âv£U›kWmV³jsÛUSœá¯”Cé?èU³¦–úUEQ˜DêŠð™òã™úcÍÄFõcå÷fÂ÷fÚïÍ…ïÍ«C)ÏY„pÙ†ëÕn• DqÐ[{˜¬‚MÌç ÄXÉX2@Ã%‡—#&†â98 ²µ±†þò1…ÔßXL€œMN€¬€Èâ÷3ùë˜ïI/ä1˜âh9F"ÔZÈ(Ø:%¹ ·üÎSÔä)Õä™õäT›ù.UÛÑ*ÖK»¼Êáû3µ> TgBb³x·~'!ç×Ì} ×)õ\732×8Žè2¢Ë¦Ë0†ÈÁÀ¡£n9¤nY7ÝÛ´+\lm—Bí”°‘ŠW7±©†õ©šuØrÓ f5ÕÎ Óîö-F‡ùéR)hnÙ¥ÂÁhiÎ’AÛý¸q¿øj…Úod‹ƒÆ„].­îpsåtE‡€«ÔJÓ[ªó–U²§Y=Ìþ¯©®æØÍ5ÕæÛ¥r­0€ËÝÑ[.—ï¥ Æéþ€!mEÝU½C0¿hÜ´†i¹}Ð?ÁjØÚ­oGãÆ¥Øú¦þáB[°ÉFÿxƒ–c7ŽA/̾ô™sqÙ˜úœ.©S §YºÍmeÆì é3öNÔ§ Mïÿ:B^lHE•²[™‚γ57ÉF²/ëß8z³J7IMî”).̧Bb™#ôÁ)JþpAvܶjÙû?} ßþ}’n©Ý¾ w›¦«É¿¶7ßR­ÚK…H§“Cö«Ãéܘ!dd?­&4~Üí_'·}w‚p“ŒõpeÎ4W™k<½¿Ú¤Ée=CRyK/x P·9â{FÀlÙÕE%:`F¼4 l¸ì-åFXëÝyËX xù.½xÙ´ 6h¼dôG¼4 P¼tG¯1^2Ô^^á£nP ³Å9µf3l¡œP+–!ðCj#ˆ-d‹’\†cóõƒp¯J@á9%™‚r½;圊ÕPÔ¾mG‡øÚ¿É®Ÿù‡û‚ºáŠPܸãBb=ÀnÏ‚v=̹üO'õ ÍT­œÕðÉóD;îì'¯¸ÚÝo™Ãýö°þ¸MW KC²5`öC6 €»àB×T(iY…«bO[^_—«šw×õ-Pë§ÕZ`5a'Ä±ÛÆ‘„±ýª:7ŽŸ}a&~Áý¬×¶Û½k•͆ºå»nd¿®O¡ËV·ëõ@z 佯ÒõçÓ%ÐÈyʵ›“”é¶™‚–y›™©ô ™—7ˆÄÓ3™ißç1ÙÓ¥D¥Ù³mN¾=tòm1¾“o5¯Dg­kÚÄØ]ÝÉXn˜Œ7^v'ÝÅpúÒáúUêWÕèä áyÁòI‹c‚®rç6vuçMWwW×óꪄ­¤GùL)ò¢úa{$YMž‘úÍÔêÇs®WÅETŨŠÕªXCƼäÕ‹þ0‘C*ttÅTg¼YÔ›ˆŸ#û93-Oê{Cù\™âq‹Ÿ×}]|¸ü²3©èyVj(súøvO³ûuÓW›4Ùw‡ÌìÆpL8¹€§¾Ç¡¼fô<¯à:ÝúXpµY#ù²üüIþ•övrxÒTõ‹ùèÛгô @NK ’ÀªQ' Wg%«dQÊr3­5=vȾ/œ:,¢³7û¸V‚„¾Q×BB~¯–}ßP_šÉ_0W3áõÞD°ñ 6|ŸŠ()•ÇL}¯\õA ›á¸Uý+U)µƒP<¨>4«%¬EEÔ¹Ò«È@®â¬ÊeœH/©j^éÁ“Ä‘ƒ(\ªóW¥ ! _×Ü;šÁÝÀÉ¿æÕÓry>]è®l£ˆ]Áï,hn}‡F·EÈlúÅ3Ùa4Ìr=OoÓýíõ1¤$ËðÙ7è]È\˜õâˆ÷p¬öúW¦FÝ]¬`#´w±Åìn¶ÎOÉׯ‚c•K¬®'À?t •[°Ù1FoV¢º•Iµç«´|Ë;SD[ý½X/*®T#3:}FÌÏõ€—«Uƒ`@å,0ú=]Nâ´wIÞü Òîߥ·ÑîØ=•[°vÏèÝk9îÔî™}A³ûëôø*“Ömw_¶ý?»ýÑÂøÙ¥ŽÞ.&ã¥¬É Lx²{v;a¿—„W°-¿ò^Â’ñ÷Ê%oΪ¼½™£A›4TȶŒé•«9vnÁØ‚üï¥_Çx°¼õf’ Ùxùñ¹¡\€wFnR:;Ρ‚›óâžñö~w·¾‰€gxXV!Ca ‚ž±dàž+‚+€Ã ¡ïÍ—mß§hÂÆ?,°àAp‘ÐN<ÀáÐÕõ˜HPcÐÀøµÎõŠ‹ùõÎÔg—Íë9­•Ë/x˜ÄLxJpñ·Ç£Uí?ÙU!Sý«O}‰êªÎVè'ö4ýdBÉôC Œ ŸYȶ/ðƒ$[Á “Ó]( ø1ÔPéòþ¸Ã‡îÑ>F2ZùSÈ-dÀT±3ªº ‘œ— UÖç!Xz±ý”î× š`^vÁâAKãÁ!¸Å… kô€ ïÒ€(¡ÏÁM:Ž<Ϧe¥Ç‘NZò‘8&7ŸÒ•ŸO!z7NhÁº3ž‡ñø¯J®²ìUÞR}‚a÷<¦©OçT6Èhе.ˆWPÊéhòË Òä—i7“_ÎOQÎÚ(#PiØFh—F°ÿ–^ι´„MUAa3Æ„M1œcSŽÜjÙøš`’“Úz„Iø4XÝ—šŽ)AÝêÛL¡>¬?ÆxØäÌVÈñpÎèâa=×îÏ0‹ò_íÓ‰)öÀ46s^„!›ºÀÇh;aª¥ÐC3Œ`‘@áéúdñÇp7Æ”Á7ÅŒò7ÄLzVÂgÛaë á/@¤„÷¨Tz/tßüu·Þ¾ß¯ûn ìS y.TFüURPUÖ¨¦Èg€Ê)1ÐwÕ›‚>O¯Óã—Ýþ×€”óêÅ»+J5{qSÅ-øPi9â=ŒµVA7Ó’Ó/µf¿N¿¼ÝágkMxOK¤wÇ=q%¦¿‹÷Š‚vQ<Àje ×]”xÐxê=XCÕ`W^™ zû)Á„ÅöSž‘Ü‚M2úG8åYÍwÏSž±Ñé“…~À óÔo°\CÚ¦¸¸Ö€r Ë㈇t­S£ íöt­Ás2ƒi†—Ž2¾¯¹Ép6C¥¬äX›¬bݵÔB¥ Î z‡‰ØÛ7ˆ[ÝØ5=oØ “^zÞÈêî¶0¤L,ôÑäN%F jJ¢ôO3>¼#”-ßg`ôó}ºÿzò€>öÁ)"Ñ‘üÁ¶”¶ì8äÐŒAçÃS‚É5_GvQ|³I"½äêjwŸqоâúËú#žhðKÆË]ºÿsæñV·ÉqwgyoHöÈ3üo›ôp`¾|’l6»›ä¸c¿¾KÖ{ú ,Sá!“ïéÿ·Ùʲs7ÃÑiCé°Iûd›~éI_ÄȈPÞÏ›rñ—˜ŸÏž°\fïýjÑ$–ý”üz?ýGúIþþ÷ä£÷Óoà÷‹ÁÿO½ÃÛ7–o~yÝY% ï¡ù^KoÂÌý›Ï»ï/éÿV¶•â’ÛÚ´òAKík¼ãê5£ÜGu7r5yXQÛE Õ|ÿ¨ã|H!§ä¶©{ì\ÈøÿÛ[?;.0²çÒ†º]ÒJÃ$ÚïªåB é(!£9ö{ÈuÕÃñÜÃ¥)@ü]qJ`¶jqùIÿÞiLgçá¶ šÎß}˜®[ÝzÑ¿¶¬ï®H€¤ôü…!j¾ÕUžÔŸ¨`èÿ$p+T¶Iu˳ìC´›³». @X…ŠÎíBÃ*, t¸ò m‡öào.<¯ ˜ò˜U4™ïÞ¿g ¦ox½¾ù5$#(2%,Ir…XàS%¹àª²%Â4wò g0,Ó0íŠî5ÖÙºVç§±”lôðeýñââCf¤¢qvOn÷f Õ!™>ék æl‡k„|HM….U¸8²x’‘í.Ö {ju»ý0æW·]ÝWùÞ|²µŸjþ‹ƒbþè°u¿`9@•爦éœ&Rp/Ã+}ª·8€2(å¶œ;Ù›j3‚¤ØÏ}Îq’½ULa IßeçpUŸÆÍ|a7ª¨†² !pÄCƒþB“€ˆãÀ„þÿ6ÀòŒ°ç &„uùÙÏ*¿n–X î³ÇiПöèrü ÙXã4ÓuRÖ²æ—8ÐÊ<óeõ‚ä2ê)¦‘Zaƒ†xF¡Q;HƱ\Žûå2 Sh=ˆˆ² î3Ê{˜™šë¸¨&X·õêëiŠÈr¹OïF§Å„ç Õ˜’îC©¦ÀTdÖG’&wßÉѶaᢑ´÷o%…*ÍÄgOKË#Ì"nöéÇõáØº¹Ó`ª¢ü{dê–ý8SòI1—çuúåj³ÎàirLNÊJ‰¿(~ ?“þ 7Þü÷J@Ú¦_–W;tÐðÁ:?©†–àÓùæåÓ7?üµÚ…"êšwæ jÀqN-ùÄõ­ÒéO<Ñ—‡ >rßAa$û!7ÅIÍá¢à£(xÚ<,ƒÍaÂ"‚ë©Â3{È&DÑçd“ùíýmS³}Nº½I ÝÑJÕ'£ö; yžŒªÆ)C”øDzÞé#}Ð`P:z‡4'åõ³_$GA—>{I7‡Ô.C²Ý¦éjò¯íÍ·vÄ“C!ÐÙä€ò€Æ\Ê©cš+æ1Iø # <1ÖëdsLW?%‡OýìøOKˆ©Ú%p`jºÐÁj«¹Ý’´*çv‡²Å(1§ÑÉå ‡ùúMµëw^³~SÛõÓ•0Jèý¬I¦H¢Ú0â·]\p §Þ/ž)?v4WÝtƒ§üÞTøÞÔÍVÒòMîäýÎG„ß®bCœ&Ùhg§Ñ~ÂèœtÃÚ²Æ®Ž¤ócsü#Yu=W ã1ÁtýTs|é?éíæº°ïïd.–7ÿ69¸o\¬Þ+ƒ.#«q~5¿2L”Ó+Sú´¶‚ƒÞÌ-¬H¦B@@—WÄ1yC’ 2 P±ŽbŒ¶›Å%NâËÕêr³Ù}É¢»ÝÁ}ãßðQU`°Ð*±ÑCJ0,d­“PxuNv=ÆRP•€e|Èú.½ÈÚYE‹¬Y-åY“mŒ¬°ŒYñÉN='úéÐа`ެÌCÈŒ¥¬+jËè¬k㎖R£ë(@_°A€ÈEÌ^5Ð@À5ÕM³X"ÐŒ/*xîÑ]¯ò;U@-– n¯1^ü“Lýfù?ã«´gµEß­pTÜ·Á1.zFäf}_çÎû¾¦½õ}Mqß׫ÃG¹ñ+Woê}ÐeØ‹v¸Ñ ]I?S)ùí•ô3kE˜IŠ€h+ÝGèWagN¼)„c"N0Šœ%À:ÝD€=‡°­¶b¬e`Œ!Ñ€@œàð\o¯ÆƒåkÎ>¼Í2ûäóÏÿ‘qCÄÿÉç;ñWëµh£Ø4IU¨lyè-ÙÑ?Mþ’¿kù2Ý~<~"¿˜\@ú°ÛONÖkŒOø/žÌN'Ò¿£'e¿^ó S Lðz(f”<ö~ùâý³W-ÖëSÔ#z 1ÿ9™² ­_~&Ú@°í3Ù³=VZg øÕÿfö Õ¬ÇTË–ŸóŸ#)]ÑT>¤µ…y,?&Áþ[²PñYJÅDÿÃÞFÙ^¨LN®Už‰è^Lñy¿+„?‹Â7~ñ·’<¸Ð ¿z𽡯éwÜojøç_®z½Áê?V­~ñTQr”Ã?½NÃ3HÎÀëÙo7Ë×»ã‹ÛÌŒ^§+’xðË  ÜÞßþ3å #°CÌ#öFŽ]¶›]²ÊÜÀ‡ûí r“? ÿñÛÿÙ>Àä<È m—!Ú?7éäê߯¾ùfr·ßwèÁÈ_¤Ü'¬'—Á,‹ŒžaoA܄ъïò>à±Ì£¿wr§·«ÓÐ'D©¸ üH´š§P-¸§;©8*­I4\×mM·Ì®y? Mdÿ*ù5Eµ”-x{o3@HÍê Œ¾ÌU(fßå†OM¾¬ðÖFßÁ¦O®r¿ß¤?¹õv‡S(é-._“„`ž#¾Ÿ³ÞlÚH.|tCZ’¦QÁÕM¡åé2§Q²žÓŸÑú·—gµDKP'ô7 Gù¾)¤|ßy7ù¾sÀ)'E‚E”r,ªÌZèl*‰~G…-sG<ÔÔý{«$Ñåjõ:=~Ùí…Ô—Ñb\‘ÃÆ8]gÆÕ‹wWTh=6<‰>+ðN Ž‘ØBo! ]sNINJ-sTãF;^é]zÔW•€álÑ5̓U³—„¦e)%2€ô>Å`bàÉkæäl‡ŒÈEôFvâê\S]öIr[Å]SÆ×·]Ú"ôÝYÈ{ÄM8\¤÷y¦íg„޹ý†ÿ<’šŒ+­ŠeºYj?óÊl:µ”ÿ0¹Tc\øè±\æ(9ÒbOâzUdÔr®&D0ݼa¬¶Oͨ/QáÚÓšXêþããÍ\à,œÉöÒ'\ƒañS6CšµCNµC6èITä=Á·%4·Ì.sx+E³gEïaÝ…¬aöù]z›ñëg»@TiF â 6’¹ˆÁd½Hº'¹±&œ±êcÈÎ&5ü¸Þ*âÄѤöœ”.J¢ 'xâÀ{Íó¹¥¹*Ë'•YÔM?<èØäþFRpA.šCò„¯lüœýº¿QPƒÒ펒_Ìþ¿}““X˜]z9õÚôÚ-\ek_®Æ%{®¼5TAŒ -ߟ<ê*›öSr¸¾KnÒwûÌØ½L­Œ³Ýy0%÷šš&WuÄ]­jRËoïø¿šÛÈM·ysÛIþÁ©âså7Úî=ŠßÏ䯫úíæò—æµVlÛT'~>k‹Ü•€DÝuøÏYH Àx‰- ¦‚ºÉqG¯rƒ3S+ð”*ðL¼ÊcK ÛLrÂ_·])yŽSŽy%%ž©•˜}ŸªqÞ7W cF…1o Œ¹0æÖ˜ cn$ŒyUe˜R¡ë*DGÌÛúuÈûX1N1;«>Nè% €2ÏPïÇ£©ËoQù¬{‚ÝïZ×=3‰¯oÒXýŒÕO¢ êRžâþÖV@Ðw¹Îè6‡ª“À¨k£:¡ø©jb´gÄj)àj©6ˆ@Œb0â ¥³ŸŸ‹uÕuU…Š(z ±x æ`;"œµ×X{u\{•x¬À6”1ØœñâÇ:ìÕ è:¬Tµ ³K˜pU“¥AëÊlÝsšüºE•öÕnu¿UŸå>-Ò˜õ5Yþ‹Nò­\nUŸŠ­¨Õ_ZÈ_*>躠+~^×¼ÐËí¬‰6ik¼øÏy`»lÊSÜ_›‹îÎÚÅå=µùêÍ´«7­Y½™íêUeyu²(åwÁ¯ž5ÅÔµˆØhjqÌ©8 ı°Ç¢8ÆâX‰cQSœ tèÊÊIUýÁ?¼ÓTšò{3á{37)7Ë7Ù¥æ„`F‘¿a°ê; ¡m°&˜Œad #¡"1ŒŒad #ƒÆÆqS ™š‡L úEÔ!S‡ HmHƒ™Ì@s‡1˜‰ÁŒCïwÇí¨é ¤¤E7 H±9†½Íä}Sýûw¾Hhìy tumh‘rÆ [YxU\DUŒªX­ŠzkIœÛhH¤ŽL#›Ñ¶ñV¸Œ0Ó¾ Œd¥Æ­æ a¶Ol÷œvMbçxÄ>±ûÄjÆ„Ú*Oc5‘èäX‡ç°BÌ a GRòë}n øæ1D<ôUŸl-d®ÓªGÅÄ.².»È†5y.™1ÈŒAfHkƒÌ¾[ˇT1šjMÅ3ÿ fC™¯ãœçÄ8'¤5ìºå¬‰W½™Cg±ñ,˜~mCý°­Ø{ƒoø1ÓÀØ~µ1¶Ÿqÿgf6è@s5‹¬ˆÏÜö¡Ù>´õ£šv£½8 ÿ\ÉͧtÕoºÉ(…¤K5Lî\¨Ø¦É:†)¢,m;ò†òDxð)Ý_JZÕvÓ¨ßäÙoÊÐÙbn³è[ßùô´yºøÒTþ’®\ŸC5µf@‚ƒú.rÑC^”OxŠÂ8§Â˜6¨;Míġ̓ֈ£”SÔž¦F…'2ùœå¤DÃL´ƒÑß~]þ=³€“NáéúpÁÁ8ð’ F"DÔJ¤{”ŒÔPÝ=y@ú࿸֗[^Š6ïþôý|û÷Iº9¤vë–›¦«É¿¶7ßRyì$‡Bz³Éá]z|@Éb…®ÂmZºz®>ÓDؾ>#0,gŸ¬óöÈøkÜ=ùJô÷ÑßGïÎßǪY¬š¹©š)³óC­šÉ¯DÒ}¬Ì¢« ã:çÝbt‹Ñ-Ó-6t༅£ZÒR-i>ú‰Öõ9péu#8%$GÃz=zàÿ®(×䙄 !FØyúð+£I¾ü¸]ãAØbB¬ál?¥LzËš q>‚Ÿ,ŽœaŸjý³¦ÓsØe ¦—› ™YÖs­¥Õ00ӽʅšÓ§•XèaÏ¢»’¢ôœD¿\­~øzLïҤ繖÷ÛÃúã6 ÂüGÂú~Xñ€lÃ3âý•yI[!˜èÁ ò5â<([×åõõ­*û/ÛУEÖ¦m¶íôD!ï‹ËÊXÊN圡BqQ¬» ê¡ÌÆÞÿË~}<¦Û.@‚ 3xœ`|D¨¨”FÿhÁ¬Õ`d{†×ë›_Ç8’Á¨¨‚…F¼8ÔT0@g-¸£7)Y`ÐÄpÁf’‚RÇ$dÌ]n"î™ã•VÈÐÇXˆèg!¸èŽäJ d01T|±ÊÄAб¬B†@Â@@cÉÀ…?WW‚‡¡Bß»4Ù¼NnÓˆ~FèÇÄ2æ7/JÃ?9?øU®çwV5ºØðX¼ñQx9§ÔaxJ|ËãðÌk”na•|jiÂp›‡5=/Ÿ=ÿUæP×^ŽË³Ç ÙøMo %…\"øðtìñÐ`-çòA9ˆ°tL°D8•ÃdÁ GŽ>M·__f¨÷j×ó´@mœ“WÈ&γ1* ¯dܹóÖåǾ/W·ëžGjÙXR!Û4a`TÖ¬aÙ¹+ò硽uïjË’ÌB¶j™•QÙw-óxlÞÚüØ/ïîÒm ¬@“Èl IYUT˼ó8I¶6Ï¡ÒÛ}ÞÖè©ÐaõŒ—qš½–ûîìžYœ·êÒ§7ÛÍ׿¯“W»Õý¦çÌr –_’ZȦ_ffT¶oÀ~%Éêü¹ýí¶£,'5tøH\![{ÎCL†ØvÄ͵éŒCÍ{üu·Þ¾ß¯û¾ÇâIŽؘK/dp,˜ëq tsPƒC˜ÂýDC¯’ß Ñþ›Ø?^ÈæŸó0Vë×  sãÏÏí_ÿºÞ¾NnãNÈÌÚ™¸B¶öœ‡¸²ÜCš+wB9V u'”añëôøe·ÿ5ÆB c!&¿’gcÄ‘^}E¹!zÛq§"4„^†C‚Àʈa¡Z}@ƒ`˜~àáõîý>ùða}ƒ²Ã»ûž{l‚²Cˆ/cEˆzAt%ãô€ÏÓ#úïÕfæ:ô F@ ³ïÃquqñ9û‡Ý>Ó:BÿäÑþ8Ùlv7‰ø/“ï³ÿ”Ÿ·²ƒ •°( „†¶OvÏm 8æÖlÙN'ONbN©Iú[²žÃ—õÇ‹‹ûÝ­x$NEGߟ<âÐ96ÃËÍf$VhFøB!¥0ͣ߃õimˆS¾ŽM¨C Bÿí¿FÐÊ~ò ³ÇÄeü3‹œzFQdùë¼ V®Š“׬ ˜ {|·ÞͿ؎Ú „i" `MAÔ5˜öðz}ó«ŸùìZæÛZgVHÁ&<ý½™¶y-ßn:åmÑR7ÇVô<%ˆëäl'`QÆSÀkÄ¿K“M fmšÛaúâœzHǹ&5wÂúàÖÛÕO»CÏÇæ€„Œù0µ=§lð™+ÌøóéÕÕ¨ÕŸã?L àk¼–Á´ƒ·É!¤Yî 1¦æcÊÁª“QH:Oö7)#½UÏË \õÏ9ðaÒrœVÛB®p6Fö@NÕwl ×Éfœ±c>\ýÇÔƒvX¹`ºËÍf÷%ÅAYH¡>z|H 1‘ÃÈ›ôpà$W>¡ÌþÅÉ€^vašÀ¯-—±¦‘‹So»ãîíÈêÖj½^§ Äq©/G Ì^‹Ú¿“5¦7#(žmov+DÁÍBA˜V!ñÖ($uƒi^ïme¸Ý©Íþ^}l`ÆÐðX—Ö€‹Í¾jX…àÎUO[àåBU  Þ‹ª XÞˆêØ’3ôß·ÉñS@Êïv`b>LíÏ©åÊ0zšn¿¾Ü%«W»ñ?Çs€*ÏS èye‚ð/—«Ûõv4 Nù P¹åÀ›)$¥FÆvdc^{ô¾º'O昲ˊIé_eX‡7ºÆóL¨îùÀt]Ð'HŠ~yüôf»ùú÷u’ES÷›šÚi{‰óU¾Ì0½/«$åÏöÌèÜÓýáí>ý°þ- Õw—”á È€MΊ0Aƒ:ÃÓIö «OÉ63Ö4¤ÀÇá!IaÚD‰ °vQR:˜¶ñ6{ÅûôïÓíÍ×€ C¸«M K@˜F!²àÁ"øÅ¨jÑt­Âä+ݪ®CëØ6®7‰0 mTv™×&ù°íè|[ð{ý' “ÐÜÞ˜e4½·Óƒ””¾ü|¿>’a¡˜‡‹q”ë0 ‚i˜S#³,®Þ_½}—ÞmÖAm¥_9l‚.¦Êó xPûW†ýÏœž© áuúåí¿;[s"‚ä°DjrwÜ3S±W‹Âv=ìßÔ~µ»ßŽ2NâØÓ+à˜Ù x6 Ú¯g áÅᇌÝOÓMzLÇsôFd;@å—¦ö’VARxzô_»mH{ÅÆv€ÚÎS©¼k¼úÂ_éá]š„„éùhƒÆøã?+|΀ê^Ðîs×›/‚å 3Üò¢‡±ÿjö¾ÅÊwl¿ì×ÇcÒYLçÖAEª0òáÛÓµ°Ì䯻õöý>¬â´›jÎy€¦QÐ4cZ¨ðDé«ä7DëøÔŸ1 öç¤Uþ\§€ë>:ôëz;Â¥Û*?O=¤]r®IðvÉu/“íÇûäãØôœ±¦žçÔCÒó\“àéyæw^§Ç/»ý¯£ gï*;O=Ü &W.àqMF*W‰¥-ðü‡ipmBP4àv±\ŽÙŸÙC눲  0Ê U߉ҋj‚•\³\îÓ»Ñi1á9H5¦¤ûÐcª)0Ù¤UHÊŒ/Úùœý¾eçÅ»+ÊÄäQùþ_ñMý¸>[·rbLµïƒL²gª!PNu]©ø:ýBÆü=MŽÉIYéðÅ/árrÂ_yûuù÷ÌVQ\ù{5¢ÂÏt÷ïÉf½¢ÿÓ9²°ÃˆTKè óòé›þÚMkŸ–U .ûÍé¾;î'Â\"Ì–—‡ 9r¿@$ûá)ùjN´@ =cõˆA¹!û“‡rì $#êÉÌÞ|ŸbB1‰Ÿ!“íý­V¶ËI·7)"¡G⩪eäGÁ°Ø¦áEîí’þŸH?}T5+"yR Èì8Óp¦+Ü ‰I®F=Ë'Ûô‹Kü‚ÇýF!\}gØe ü€¶›Tš´¸"4ÕéòpXÿ+]‘¸oD¨Ê>ùüß³dü…yŒæ;ñWëµU¡–WŸÒ,åƒ ?è-ÙÑ?Mþ’¿kù2Ý~<~"¿˜\4ÿ°ÛONÖk îø/ždºûð!ý;zR¦,ëõ7ß0Ư׈bFÉógï—/Þ?{E@s½>ý޳BÌNr“@x¾üL-‚÷ŸIÈFã4Š÷ ØÀ¯~ü 9Ð/D- J¸åçüçHJh vŠ´‡‹ï–Ÿ‹¨©æ•çÙ+땎½´öµåçÊWí‰ná…cOú=ª´†ç²fQÞ£G§'O;–îãzéæHp1n“A‚Ï~»Y¾Þ_Üf†€P8]PðË5Òoïoÿ™yÅÌÊ0&gØÌàú€mo—‰|³KVéjòá~{ƒœÄä¡üö¶0A2XØe¨ðÏM:¹ú÷«o¾™ÜíwÇzô!{pzÁ}Qˆ{.ø4‹ÙÎä`Úò× dÏžÀƒíãZ<%ñ®RÝÄ«RDz^ö\.ʦäE™cGõ­|úâúÍ/¯;.lÕÇ—ü*˜F™Š¸„Äš¥<–ZpÉmg…5M®6»mÚYÌX‰õ0œUÌ>™9ÞŽáçfñë,ÿçôf·Jg÷kâçSk{#&íñÂÛ5üçÔ¥½u^Õ+ñÓ³qÞÈHÜV® šlærS¥ñXÆ )H Añ_fתu#¿³X9úƒ&k7“ä€è#Œ#¾'„qăªˆ’3@êÐú¿äD¿/=CSoN{ô îÓv<ˆ¿žyš®ù#æGÌ=æ›"¡?t”V›CJ«Í‚L«©ò\&×ô®Ö*½6‹× ¼ø›"×—Ç–˜ŒiFB‡üiF¯d+£~½áŠ+S~Å“ý&ÿJD»IÿaXU@ýnhjðCû\ÏYÑ!ú6ÉÀ3Ìœ_›>{­,:Èö©JÌX…¬–Ç©ª×üTmùñüFœ ‚jØçú4Ý\§ûÏ]œ+–Ws¸=pŒô¼}ca>§@^"z¼âÙ}X'„䉓üU;i‘ÃfÉóyGÉó¹˜<Ÿ;Ož‹ŸKŒÙ;09ÉÎ-²"ÕŽÿœ…jÂztúðî¬8CƒVŸ< }pŠvBÜK × LQâáÝŸ¾?oÿ>I7‡Ô®[Ix›fû€mo¾¥´#öš Î&ü“”0¶GÉ1C‘ÅŸ‘,þ\›ÅŸÛfñç-ôan’ËŸësùs)À#󢩧ãÞ|‚SùÃQB^Ýõ9,ºÒ-úÌù7t‹þ*:?רŸY¸³èÈ¢#‹Ž¬ Gfì 1ÝQ c©„1濾?£®"Æ(Ï® 'G6Wyv =äg*á#ÏÀÛ"Ÿ'·ÌÀ«‹<<¯1ó¨1Òþïµe£™ªldT8âÉPb¥¼š"ÿx%Ž 'e%ÞáåNÞW^[\ªùy»Óû]ɇ”6gòhY\bR<ž³¸ ”+œÉѶ|\Žþ@ˆTÉSé?=äbÖSµ[ 9|Úë/6ú»pØe¸’^n6d”̨jR2ï›T‰Oõ©’Jy©R½8 cM—Çcró©ƒ+ ûQk73ŽxA®ã3ž»ÜPïB$-„—á ¾ÙnÖÜtš‘1 ÂD(+Õ?xæA\X¶ÜÛì >ÝÈ¡„/èЬlÔaA´9Ö!ò½(ƒÉí·(S+¢ra†*ºqa†~_sFB4èÄß¹<ºs}¸‰àÒ¸ðÒ¾lEˆi$¥>PF0no@ó<=¢+Ðàž'ÉCÊé*ˆÀÃ{Æ…çÈž ¬ëÈǪçl4Xy®^'öÒÉ…†ýaqe1/9ôy‚Åì²Ãn-&Ÿ_;yX{Ž¥Ý=ˆºÎÑ¿ÅìjYK™ŸRH²:ÂË#e6vM¼Çƒ¿åK<а8ûWNhõ9ŽÏ6Õl1 ü–¶âgv= ùy!û·×Û•wk…q B#MiЭ¡‘ÿ ²6à™²˜ÿÆ\ù¶™ˆâ÷3ùëª1UsùKáMZ¼/§J1eñÞKÚ4ÄŒˆVT 3"î¨VfDfj%ŸR%Ÿ5h3·¹ß½ÙªÉ÷é{Ëgjå–zËóÁXsµHfT$ó"±‰¿ÞL$ò˜H½HæF"©I¨ÐäÍð}PNfHÂÏ ‰ñ†Ïy” ã^¢ `£*µñ@Œb$# 4w{cóxSh/È:½Ê#E_}Ñ}‘=ðŽ sg1÷Uz8$S_iM£Ì˜àŒ Î^oñ¥FÑï¾æ0Ìl¶„Ã}ßàëˆäDÛך£“ÐÚ781Õé Õ)é¤ë\gw+QÃ<À¨¡ç˜ ¦)£?þ<úó ýySçÝo-Àù-Gc²1z”èQ:ñ( à,rƛԌ;©sÛVlpÖc Ø´ºþJ±“äž—:éï! NÞb‘(9«D¦ÁÛ]Õš=)ù=€Áñ¤#¤F ¢Cl¢œÅ¾R“įNXÐ;KÑ„zÎA'Q7é„Òw+¡#ž{,Åñäc -EÚø F12ˆ‘AŒ ê[Šêàøü_<é¨5I២gŠži¼ž© c¯Óp{¼öÞHî}ØÝ7ã­O«Àxš-Æ« A«¥z`˜åj„«‚5 Z—¬ëžÓä×­ë¿dl.Øú/÷i‘­¯ùòßXt’·år´ú”nE-¸øÒBþRñA×cñ󂏿…äÒNœè—¶’Œÿœ¼7§ü޹ÉÞ\',è{sgt—÷ææ+9Ó®ä´f%g¶+YŸEÖI¤”Ed%­é¦I̲„P×I ³"øB-”9Ê¢PvBY4ÊÂX( #¡,jŠ"„]QDù1é@ðï4a§üÞLøÞÌMbÏòMM€B ¯¡aì;¼ §Õ±&@¡i MC hbhCÓš6ëÏl…Ŭm®F€u^ëõÔH14Š¡Qˆ5†F142èjÄ qà¨ë ¤¬E7-X±1Hîj¨ßTÿ¾Nº~¤¨6vý½ÒA·ôHn“SQ-£Zš¨¥žÀZç6$©#ÓÂ~´-q¼o#,¹j£\©±­mÜís]<­]CÝóôxõ)Ùüe±Œ2SºÓḺ¸øœýÃn²¦'Ùbá“Ífw“ðŸO¾ÏþÿQ¾}"0Í2]¨„FSL¡¦•r6¬²JDíœ “¦ûXûEÌv)'' ¢Néf8×êÒööðeýñââC¶¿·¶eªIøþä¿ v?ÓøÇõv…Þç?½Œ“I­-U— ¦Bmh–¢]2™ âeÎŒë4ÌVF‘ÉßÓÉÿûü\.»DÍ_ð{/È×ßg¢ÀÿvÚT¦š«6µúˆfä4ù¦"ݤÌÜQ¥?­±íÑÆì…owxQÑ{ñGÉa‰ì4{-ËÓIáhöDQ‘»Ã.QŒÓáÖž­AùK‰€Ã8I^pAU¿*Dºúå’îrõ«@^À5>^î.˜lRRñw ýr…åà "]ðÜ­ãÂ"*åA 9ãà…EÕÁQ×—iSB=¢Û¦þ0t©¿í‡RPeú¼ÚG„pÝîX¸Fï"¼ÄOË|ç,ÿbz³[¥PÇê©*ìF+O0b i\ÂLwT—ƒÌÜVéeÄÔ¤­SȰUZL~g¡ÇôÍ–Gî@Bî“?ä-G*¬ÏY¨ñ%£ž‘Ç„à¦=h©=h6Ö Mê²°Ám=ª‚0 2;à$ïÌâø¦VMÅßïÎñ=ï–@PaÛˆPÔÝ­¶ä¸Ø¢]Ëg%Ÿ’í¤ŽÏp–íú ¾)UÒ±ïjU>šn`é0•ÊrùÆKÜHÔn$´¢½‘pGuU¶Z®ÖŒuöé_wë-NÏûÏ;·ê„0EÇ %ó÷|ô ÌŠrʽA˜—loõ÷luO:ÊgÊJì1£‰+R‡ô(U¦7éáÀ%«±ì£ŽNê-ÍÙ¦Â9¼Y–I‘…ßf µ\fz÷žl…Ù'HäÃ\ïø9žõVž©ªìè˜ÓCq-0s¤~SÇRëxÆ+£Ú2– ˆj`e/P<õå e g2…Ón2…çàSTÚŒM9|-ålTI¹QåF]¸†n«å¸­6µê3Ï–“ë$ÓÆÅÌ&_rá ZŸjùù>ݯÓaœkA¼|UuŽÒpz²… .ð}&ǨÓ-fKip¾…éwæDüº2z9ã‚_8öü9»³S0øyƒØÖÜÄp‹pÈ@çÔ]Ò]•UgÖVü†€“M½Á‰ü’²QÁNÆ3éx ±`€wï☧ ä½…k!üRhA½Ê« Þà„9=ðc[‡U|½\ÅHÝy¤Î„: Ï™‰=/&Íó!èÉ6‹Ï“¼­È Æ%Ýõ…¸$ï“o°RÙMÆ_p†Øm{Ùõ" @›`vIÉBüí¢¶Háj—,~>oíjךÔlŸñŸóè¢ÿ©ÿ»‰®à;n¢ zí’îò&:weœb³;|æD—Z]^Øêò¢ñ-LnñYÈ\Ü⳨¹Å§qÊýÛ"æ ÚÆ­Ó°ãV‘j åšúx3Fš1Ò Ñ!ÇH3Fš1Ò´*×´‰½bØÕ6ìš…võ`»sX,Å0)†I!z“&¹“Ú8×É]<òÒÅ#‹±^QÜ÷ݸUWÓJ=0ñâno!.#}âçJb)˜¶¸”˜×€yÔÐPÏýLϽ!ê7[hßT­}75Ï™±î¶©˜k~5­Û£Ã‚€Ñ -rÔs,_[E»Ç9É”Lµ™››féÚHBÎ)[>¦ú–¾ûw"°MòyèÃnϺX ‚À-dz¶ÃZ؈€Ñ0ÌÍ'dÓ‰áBb5ZäRâbcT³/;/ïËjwdl/d‘UGÆ ïHv²ÇA¦f$ÁiÛ}ÉÕý~Ÿñî{¨˜@IøaÈŽ÷¡íFókJšXÜARö¿|[Œ³ÎͶô¼±£Š-&Ü+亩Å1éå¾nt{3žÛ~­Ù†õާÔyÑá¼™ ¶_šªð¶YBÕÉD‰ëÁåQ¯=§E¦j!S!MÏêb“* u³6éU¦ñºÈpªQ1¸‹GNº íh¢±ŸHo<ÕƒšÏ¡°//³—ù(ïÓ’y1¾sX?1YÐ?xæ‘íçÞïïÇtõc¡ þ31„:VüÚõq Ñn<¦<›Q±p3üUúZ2¬Êyþ‡´¸<ŽÌòߤ‡wŸœbÀ?ý—>Æû_®Vec²¢á$¶²(?«9‹é “9&‚ÇèŠ}BCIÎlVlþXMJØÿåÝ7]wÞ*_¯'”Í Ú]Z zÞ ì3âÛZÈê˜Ù ÖBgQ,zZ?gëüZ±}—D'g?L OU´à,o¥ {ûë瘇ÂJ2ÁdâyÜ×)­pJX·K}l‡ðo˜¡Zâ¢kMr¢=“BLX8‘"V\0ÄœÏ6nzè$h¸ºß‡4Ððª}Á…Ê!ü€1â9`¨?‰_%˜ÄÓ݆Ó/Ùÿ¸ü’| Ô0ܼ¢2Ü( >À µƒWe$̯M„ÞÎÃYÓ"c{£dëŽZ ]4ì`ëó.ÒFˆ»D*À"ãÂ[3p6Ÿi<‡½1%oÔ i¢ ×~‰™0bÂB á™Éu^ÿK}3Ë-6I§h½:J$; °‘20¥ZÛ=ÓORU' RŽ2×pÓeþƒŠ%µdoaæœn3/; ÛØÃº;eà5»Wä§ëÃÍHu™g=|u¸ñ§Ñ‚>ùI FºÂ¶Æ¤Ôë+µÌ¯Ó«’>yQê·÷(ðñzƬ 's?‰H±k¡¬ÄáµÛ¤@OÃpFtR¡Iy’7Z¿Ò­ØÚzƒæÝûžJÓl£ÛÞ£7ŽÞXã-Ð{eSO7£æF)Ìâ(å‹û¥ <Â*t3PA-Y {š°{ÓðúEžêÙàªwÚ-µr‚[ìA-zç±§6‹ísp O»“ñ)Bì"WVÎ̧ªT>Çøwâ뿾ü³æ“]Ôýì$Å»9Y‘*§!ÁíìcS|lŠ ÷F}æA­ªƒ´»ùªÆ3=­ª3ªzЧ#Šâ‡ç£’í)rt¤\åfl}ñe cÈCÆpWÕùñŠØ¬áú †ëÂâRaqÞMa1fàk2ð2£S£2ûL¼nVH¬¼ ³ò¢ÛÈ4\ïy\oPv^Ïí¬Jیޫ~³µÎiª»…ÖEý oÒ;M¡¹^ï|%VœÔåè¶Túm^ж}t›G5.X[>ÙE [yæ;Böгˆq˜KÌ'º8† /ý䜅!eã#\b¢±³‰0àjŒaœ‹c`¢7Þ¼åé1 ´Ä)2%¿ñ4Yk/¼iŒ×U¾:ŽZw0Mãa£o¾5úVõåãõHl¹]Ý>jG£nNŠ×»¸Q¹=ÂÄ XnKC«Za$¤pºòË•Q~óý&J«Í°«(ÝÑN½Ä.!¯’Y8œ’ŸÔŒà‚0M÷Z¼‡ÜÉÐ Po›r<‘2OCÀÆ0†€m¯#o* ¢%߈Ɖ`l÷ë•\c¨îPæÆç {œ>yÉuªÊAñfì×^M)Ä Ô¶P)uM{9ü4_ÑØ¥v—FÂCó8¤:ëÈ9HxW×îqL»{÷*dþÃÆg+Ÿãbla¨Éònš‚‡x÷^lŽ›ýØ2øD|ƒÎаÖuÔ7ðÅ`a][7«*-ñ>g¹ê'WÓ[çFl"ŽÁc cðƒGGAFlç0ðþñ6¾xùqp·tÕL,4«vÆšÌj2Ú-M¼o–ø^4ÓÊo¼/DÄ Iñ¾‘ÏqMºã–ŠÂmôZ<»Õ³Z‹·â›)Éú&3ô*Žñ-µžó+4 Ü¢ÌY7ØDH º$=Ç8ßj‘Î0º§^Ÿ`”Þ5Ò¡¾ ßÇú:8ì¥õ¸Ñ×F_}mÕx_Tö8àØn'Žøí¶¯·fë4„Î^Ÿ¸ncCkϰDKHav' ”[4öÍy³Üv›ôæ’zê1F0î·Zjôû:f ©éø•³8ô·Ë&]`ó8ö·ApÃÂư0†…c …ƒöƒ‡¶ BÛ`…« Õ=–ùñ9 XÐ*_ÀÑj †{¨,ö}Äà´EyRdêžúrXj¾ª±ÛcÝñ4YÍ#àŽ’38vŒD/½´Å˜`<Dî@f5Ž Ž£‚»¬¬<ÅaÁ VFQq\ð@Ç+Ûãáô ŠZ®wH#ƒyò] ¢™vcƒ+eóÓ6£ƒ«žäbxp¸Éõ8>8¶Ç~’ØO÷.ú3B[ÛQŽÍÅ]4Ç ‡P[÷GlPŽe (c@ÊN‚ŽØb ÄÃqÄ0ùqpƒGkf0šVIcguœŠmN3<k<íÕ¼b ‡ˆ:a©^À£†×²ñ®óqÃVOoù´–#‡m+êÍëâøàÛÏ÷éþëHOSr¼á0%ώϳ”¼Jy9Jù<=¾^ßüê®Ü?w» Ik9þÉçd3Íÿ9½Ù­ÒæÃ7óŒáÃ>#~¡í ŽV0^¬l… o{‹ÉW•†+O6K´ö,¥T@%ò; 9Ð4“„œFÖç“?ä‰ßC.­o(×X‡¿?ÉYÈ5KÿNžœ(äzJ„R„¦9ðã~w›xÂëÙK¾?¡:Ú Îx,Ôʶˆ |ˆÈÐZX tKq”ÈžAJdO»IdŸƒÏ+hw½2,–¶ºažv©ÈpäÎ;O§ ±Ij°Ý¾Å¡9Ê­=ìâ3w@‰u’0``‚à Œ„§ä?õ?)¾Ø|Ûœ=ër7Ým0¨t‡²Ç`ìÄmF•0|î4(Qà7"ìÄý† ."Pô¹ë`–€ÕĽÇHö2JÆíGWÛ9 †¾¡ôºÚ„0`±Û‡äéf+òb•‰ nD:Ùˆ`ÙeB˜‰›½(|nA0Ià7 <ØÄíG$"<ô·õ ÞZâ¶c$Û㦣«M‡ðBßr`j]m8 Øm7(LºÙl¼K“Íëä6 Üõ“÷·qúLáûýœÏ®¿ÆÛçš×ÜáwîïXoW?íÇÀ­ÃU`ÌľäœçÊ9B~¶Í6숂h1¼8·˜œ“€,&WFÈóóýúH‚× ¦}Få¾¥0F`‡_Lí F_×¥þÒžÍ"äk3®t¦ãºIçö8iEzz‘;ªíµ M|Ƶª/&b¦ f©Mõºa÷Ùh‘Ó¸xº#¼?¸ Bå _PN{Íu£úùhÁÓ°ÿtº"»8 ¤ 6ý—GN©üO?nv»Õ;tX&Ì&¿Õîoißã— "ü.¿‚Ï}~dqNëúý ¬èø#Ïþèâ÷pÚ“øÃý>Øó÷ÛÃúã6]MŸvû£+{ÁˆÁ^<[Œ¸Lf–CÔ²ÂtØC—××Kü\ÑŠ$Õè¡{€Ó¡Ð‘X ¡?r9F¤qì.û«à£÷†^«›!ÔÛì<Œ ©…ãBë‡ä®2ç… u {4 m»CÏ>VÂB;x~ &x7= œh଻вoõ‰±È !*j=x”"-ˆóõ†"YHô×Ýzû4Ý$_c . $ü8½`%¬0½ÐÉ¢t–48w,cðÞ¸¡IÜWH¥_\˜®Ï€þýþþp¼Ül®2ý=Ä©¡­€CåPÀCd €x›Z/ 7óB9ŒÞ'BøÙ(Jרw´ìf–­Ur gtŽaF§Öâ¬ÎNfujÃMÐ3;eªÌî,7ÃÓâWí®û~®G½Ü9]ûܼ{‰Ϲ8´Dµ8“8gá0p©BèÎÓm˜Ä·ÿõ"n”Ûo”31jŒø‰ÛcºÙg¯ò¿).à`”ûáÂŒ£·Þ#…ö­Ìqï;¦½/^qÛÛé¶—ƒØñf;Ýì"p±Úçb8t²Åq-$çìrw¾¯~ÞÔWûÜÓ꽺Ïíì_éá]š¬5Œ¼È¾A ‡ÿhi&¹D7’‚(-XùUL¡’†=Xè‘쿚V¬B;z1¨_öëã1ÝF›RefÅX Ѳ˜n†h\—«‡¥`Ü.«x€ÿŒ,/ÛA¤d†ädµVå#O[-mëc®°í<<”’¸‚E{Ëâ2*¼ûíaC‹ ]…#­|úÇfÝÞ`æÙowÉvE†”ø/ÉÔüî/cxÙ`†¼l4/aKª–èIŽIOJ#“ŠcÕ&‘'Ãj¤’íuoð§.)ðÚcu_×ü§3o(.~® .×=Ë8ÒäñŸÓõê#Ôÿž¯'ùÝ£É]±Ž×EaÓ³É ÂGNÞ‘ºüò}FËÏ÷éþëÉúЧ¨4Ï-¶°ÖÜRS\zx÷§ïäÛ¿OÒÍ!µÓ¤ Û4‹ôÿµ½ù–ÊcG '9Ò›MïÒã©s¡p|ÆÿxÁ3 ¹œù )Pǵ^xõökFyÔÅò6ùÍÀJÁð¿Ív&¯wÛô;úOÙÿ|ñúêݳOè?(z5Âñ­ŽšæšfÝ4Áo¼)µÛðn"ï¸a&•ÌI#77ÊÝvmË /ìY¶$ìâo%ï"?Sé^0IÓØ{˜b¡Ô„Ùé¢Ëœ&,žv']XìÊnü¥ÙÏØÿæÓ¼ck¹{*„À 挋žäy̧R+ä9Ib¸O/—ûô.ê>•BðÊOÙ€¡ýT³ «ÿóôxõ)ÙBÕÿÃquqñ9û‡Ý>beòè ˜l6»›„ÿ|ò}öÿí»z‰¼·”‚¦Rh¡ÒV_ÖÙþCf,¢‘”¿zí{0¦ëtŸ­ù@̉0£2(ö/ŽLŠI-|£Ê9bV¹>¶0,òŒ:-èÁ¸Ð†uĸðî[e[ô™“Yø¦•sÄ´rmlaZx­ktÀ­añL ÷éÇõ!EK›Â”˜ª(ÿÞ™še?ΔE R¤©^§_®6ël©Ÿ&ÇäD§ŒøëâWñc9™É=G¿WbÏ6ý²$ëàn¸2×™#ÐT Bàȅ䟦2>5ïBdÚØ´¨|Qˆ²²Uˆ …IU4g½T}\S=·­Š*p‰c§Š|×AKVlr™ªýÇ9õÓ†þæCR]½®b½Tô­tSc—1]Æ ³ÓŒjHêúæù™¾Õ'ƒµ·;üvTÄ%‡%²õl%˜w‹øMß¾Á·|ýìI⥊ã¹PqÙã.üPÜÙ˜§¸• x+5WƒÑŒ‚Ñœ#ê}êÐhn‡Fó&ë5—˜gŽQׂ5W‚RîN)*ÍY¸²PKeN¥²âUæƒëâÕ…\Mä²äòJ«B¼ºð¯ÚÑKcœòBa]ÉE}¼ªœ©¦ÎœHú…úïæg'2µøÛ‹Îò ŠñgåÚ¿©ML> ;&÷|wW·‰ŸÍÃç8ÇÀfàç8ÇÀY8wnŰªeX5‡Vu4Åö‹ðÄ€'<1àé¨éµG'ÞÒ‰/`8ñ¾/x‰ÑéF§ÛøÂ-CÐî{¾úC’·£ÃHO FZŒð0RÍ;јǚæ2öF·~èÚ-­N…$çžoUÑ…BÃ9ÝåKë×uª_W£#]¦¹Êç†,Îp…ºÎÛÜõ7]ßy\_ßë«’¶’Yæ3¥Ì‹òˆíyQ5yf 8S+ µ^Q£2Ö(c ó’o/ÊD ©ÐÑafSYð†Qo$žNUçÜ´=P]ìåƒ gòÖÙò÷µß×\lÆþ·T=+5¡¹}~ËÇYþ¼ñ±ó«MšìFúÃ<æE™Ï G+òô÷’Äd¹/^AÔy®îæä^§[ßCÈ5Ü }ö•wr(ÓÔ¸¡ZÛðsù`NaòÒ úÑýPzq”RáLwMO3²ï ‡‹)ZìÍ´zĆþOi×bC>¬Ù¾eÇ1Š/Íä/¹Ÿ‘j 7uxbÛNDϨÃw¸ˆ™RÌÔË«ÏÙŒK­ì|©’H©„ÂBõÙ¢Y-em*¨Îè¥Ð¦XG~tgUÞãìDzIUÛKN%N]F¡Så2()(ÉAÖu…N±ÏN‰Ü Ô¼zZ®æ·_tSâQ„²!ÌaÜ:Jr [DÐÆß<“GÓLØóôø:¹MƒÊ‚å=eyËRã+yïAfÆí~®ãÉ›ú*¯ãÁŠUÑ%Vsuû#¾Q¬õÅDl¡ßÙI• Óåuì"²Ëûã§’ƒ{<`æ ¡øÈ ðm¯‡L²éj™¹Ê?sÏþ~rLoïÈ¿×ùÑá6ÙþQg×Ó±×hÀ¥\¶é—Ûô¶Ô°s¹]½ù²Á‡wÖŸËeÁçû‚€e±?Î~IÞ¦í¯uq¿gIõUh‚º·–Êè!•Êåõ{tãòÕ³WoÞýŸ‚b~ñÿ)¡ k%mÕA@;ô´…´ýƒ¨Žaˆd8W0}#ýÛéñ„UºŸ¤›ì+ŒC^a{ ê¤xß_Šwÿé{L!ÚrådR‡r‚,{€ï˜ðòŸõ¶©Í5?‹ _î>®·/¶v~ÍæLãÕÿ}}u½»ùµ˜Q| žDaŠá8—«T"ãñ†wd"Èä ô1ÔTxÇ}º"< ÷¤­¡Hà·íŠp;43¢‹æŒÊ@ž6RÄ?†ƒFŠ“FŠê ÚÍI´#E„v$‡óõ¼¼AÊ€…ê)ÀþÛvXž6î4HöÝø¤ZŸÊæ§QÄ«¼0b¸:špÕ¤©D¨{!H9ë¶ŸÄL'Kñ»¾opHk¢í~!0®ì¸ã}LŹóN3IïÒ÷‡Ô§Ÿk>WÃW:¨ÿÆ­Kôo¼0¢ /S©¨€³1né.'c˜Çã½Íè•F[Ñž'«äÂ|ž‘ÓßvÑ|ÒK±™,ˆ• e?±(<·ïuQI||Uiµ,Üd©¦gIÞêÊcš<Í“ÛtBZ“½¡º¥I^v®«)G- M `}›_vûUÖ¾€•I|äÀš‹!kV[`ÍQ .°¢âRÆr„U=¬pýÍ ¨iR©" F@¥€J,ì´L)R©¡4ÛοÝaFÑ®”–`2Ù|V±(r(u t¯ïÒÛÝ1}ñ6l}ܺ·n}¡”õÈá5Cذ`+q5‡¨æAj—1ê ’ÔF§2ƒÄP'xTÂ3HrRˆUÅÑTY-Š”ú. ­ ü fµ%³ ÜÙñÍؘ̬ôçØÏÍ|"È_šù4¬ËÛ8Y6Îe¼ys!-Kó Ì& µ?u.sRï ´ó4'Î¥ùGaÝ)S+p] î).÷3˜¯žßÃ%µ²wªÄ=ʼnê8 Ë8ñhxš½›ÇG(¨MT^ëF£t¸—±?'…þå/(Þ®û-ÝgQgûf‰œ÷òé³—Ï2Jμ}ƒÝ)Š@óRÖÙ2ŽÀÓš`¾ .82>zóËkaðÔðÏ•°É2D“¥`†ªw»¬ ¼õ[Y…®»ÝÌ–Eêm++j¿—‘ÿ?{ïþÜÆ‘$ÿ~O?hI gŽ@ò~œYoÈ”,sOŽH[±··h- aà $Ï­ÿ÷¯«ºª»žÝUÝõÊŠ I ™Yù®¬ÌLÅ΃Yš1…³…Ž$êCÚáÅÙ ‚‹ùºCSub²¢º“P"©¼ÃTy^2y¼ª«Îqs;§¨”µÁÆ5 ïSòµò|²*EJ“$éÒƒÔ¥!ž%VçÑ0Ά7ï¦Û"Ç§Š T'½¼›D“‡‹ E?Œ%K”,!G‘dÒƲ1§Î·ÁíÐYߪÆ‘2H{sö˜$åÞ–v•,•–X++éWaA–W<Rл—ôÎ¥¹Âx\!ØÎ3[)Oob¸/ñq3¸”ÆÒÐhá½¼¼~ÿñåºGe3’t½©¤|(þëqQ*(| ïÝz·¸µµÁác»17ÌÅÖ'Œt#䈱WÒÂT®Ãv«-/»Ë,û&¯ÃÈ-+÷£ ]4ôZI‘…pS1414é€t£Çd£Õ†=‹Ã‡–Û×VªÝC×Vzªp[‰D¡¦†RCº!I!ZA‚qu‹ÛßêI¤Î•ä¯ëõ²Zeåo)9f\]Ü®çE‡®ÿÙòFi"BF­01ÊÊRsº¢PeÖk‡´a©f`…±* -¼ºOwtƒ>ö¬FÐU(Œïˆ:ø ¹ôûãü&3w̹¨fAK‹§cÖB]1Š,±1¤„PÆ“t«…oŠ\0ÇŸ…4~lg<üÈîpòZfw¬9œžÇ-QkÜ4nÑöqÐxâÿs¯'ÌkŽ'¯‰¨7ÍFãÁä]Óî%fç¬{ç#Îi@{8¯s~Ž• òI¥íÚ/l."U˜Â(sð·ùö·ƒµÉù¸í2Ä LÛ 9+Pû|9/Y|Z ®jˆ“÷ôãå~‡ðøŸà¯%à§|{‘?€MÁO¿G&0@Àý$ê‘2?…‚'Þ‡nŠT(þjèRŠòVYÿÅ×ü÷Cåý÷x™ŸÀ!Tî'X,<ö¿½]?®v+$ú …F°r@ñZp¢ðêÛ®X•qý¿­}ìôû–ûxÂ"T9 -81x—ßÛo‡'Þñ²>‚?T¦Gl»ÿü„ìðø!/ÃcBåxÌYa±ü% GŒÝ+¤#eu|lޏ),/eïºØ”ëx³°0!5lN§p”ái‚ä{šÅ‚cÿòÝ­‡Væ¾9¢/ÓWà‡ÊïOÇê¯n?¯ßÛm~w€ªž@>^¶'‘•ùI. N®Kî>X WH$B’ËÂKP‘¸˜[,ã!Ná ¹¢¯pÀnxË`ÚÚ£Wå Y =w†ì¬ã ™ÁÞX¼º¥ ”“d6`G|&)µ.åy_xÊl4Tb…ÈFÔ²Q»dk>AK€Äëûû|5ꌮýƒ¸e¢>WFâáô nµ¸Ïޤ‹á!¢¢N«~ùÏž<}8mšSýý±Øü~ü=ôÉÉiÓŽŠx„~EœõôáÏßo««™ÆwJäÔ]Åüè«Û¿ ¦]W|–o‚޶o«â‰¤6)k~Nä®Ö›]’x™ÄÔ‰^êI\’äû–|RîüH?8Mô¸½¸¹0?ëܦà{mÇÑÐ,ju@ ‘šqhS(Ø^FÎ¥­8ű§8~X?–„ž¿ÿô)²< v"¤Á4Ò¤€ãŽ€“8·Ý—Û»]~û¹ðà´û.@AˆGʯA&¨ Î -9}µÌÿ5¿ýíÅínñåÐvhXô£e@…€áµ°DáºØù–…Z…õßXÂÅÅqØ8ò€‚i¦@3 Ú.ЬäyIÝ\=î.?\¤´ªÜWôŠZØ )]£E`S5Æ–§i’ØÓM‰]õÛ‡üë¡*ž1¥k"Æ®D’ŽìA£5¥I°y}É…úlŒŽX ž†õ×: 5;@¯î‡RMU›@á«SÛ¾gõ–½w?ýuà¾@Eä}´£•YLæÜѤ65³Úzc™ãÀÉL%QÎ$$17IGé`®æ´ŽË!MÆÎ¥³šj饯5u9£¥>eÞgÆ5žŸDà6W¤nííÝÚÃîbÞñRлüL¢dðÚ™+¶1çog#óh)M;¸5±±[õìÙÉq]ÿjÂ·Š¯AÜ,¾ÑZ¬ÏÚy=«“{÷/ŸY•×y ºor@¸P¼ÊÇÕvq·*—=iˆwY‘6vïaªw ÙÇ©o)#çªUœíÛ³4®Ü¯DÒ+ñ*Ii"½Ë ¦Ò»¤ÞÙé[âÇÍ®¯gåi7“’\Ëî&¥4}ãñf*“RÔWŠf*•µN@™Jc0·f*kÝ·¯™J„`ŠÅ5G.™•Hœ WR$n— ¹‘xª‰Hé,Æí¼œÜÆá Éþ­‡ëèÊŠpûáV"\’sÙLá»˜Æ Wp4‘FÙ_wóízþ¸ Fe’ŸfÆ)ú*3 céÏÇúº—R¾ñ)µ Ž#T¾—¤vu ²Â53¯jÕW0“®à¸c3ÝÌz­`á jÃŒ4²ØX"+"6“§Â3ƒÖSx]F]—™±²šoêaÊaÏ B¡˜mrІºÍrŒ¡I°÷Å8˸}6v—‰n f“•Vmmr‘?¼ZLg\M8C:ËH1ê¬#…ˆÓö(±™ÚvJkj ƒÍ›Z¶ˆ\Þæ†Ð;‡xÄñr{“ß%Å;Tñ6DŒ\ñˆ$ÅÛªxÛ(°â5 öÅKèCT¼×Å®¤ÀõãÃÃz³ Eóâžf™=ŒÛet»³L¢¦¥(òïA^ŠÆ'%¦ú)X­mn^mׂ‰‰ìg7®úÙeÒ~v™£ú.›½ö²xHzÙel/;BK28†ó5~¬ HR}ú½š3û²x(V`ÈSúxV†Ó¯ïåKiµË/ÇÊ©ÙîæççÛ\U±Ç)üdYl·õGGßWæËåú6ß­7Ä7å?lL<Š1]Û¯‹»òâíCsìË•ÍÒXÖ\cÀ¬"Á[3¬ßåZï˜}ìžÔž],‹|„šw;ÄA†w¤=Â¥è8ð e'çý~?ù ” %Rß]Á‹Ú;©‘H­&}‚ f ‚,·üµºØÓóëR¿]ïmö F;R³^ƒï®q…¨•VÍ€¹©Ùª®©Ç”‹ÚÔ×H$S¯IŸ`M½A妿d_M=£=tvqÊ3Ê,©1µP½ç¡yýæÔ]Cµ»Æ(è®Â. œâš0¤ö½Ú[pno°Ý-0¤ƒ›[ÔC­Ëd£Úz7³xñ¸ûÌ訽4žÏHg ¾cãY³‡sãY®Âªü8º)ÆÚœY#)k6ð»Þƒ©9Ä9sÞ,î‹õ£‡êD·¬‰ÐŒ”11ôŽÙó†s¦|¹ØÞŠÒ$q”=)ó(Å*¾L{IµŧÇíþs+‡p¤,ËãáÇäœã£Þâös1›ûáñÓ§ýœX|#e] ǜ˱sƽ.vï·¿¥ÍCÕÍCD°¨÷1iëP<ÁX¾qˆ5Åžî–è½øšÿî^âC„cuˆO Žé“‚ýGæôRƒ€\±«Aˆƒ#5X¯Òp䡱Quhl,=4¦3þÝ 7«-„ÇÅàñq±1{\ J”¢z0ë×¼.vn`\˜ñkû{çùHr ½Ó† MíZùY|ÌZbž. ÓÕ¾Ø'øQ¾®§¡P9 ½- žF“×¼_ì¾®7¿y¬¼üp€¨]þcêCÖfÔ_uáR*×yØ_0¡/˜ô¶±²Óøô百Mf‚“Šž‚3úðg›6 P h~I‘†‰»¨bn†]U8ŸŸ”2Õ¡pä=Ôd¸Ž¾KI`æÜ{-ðT³ Õ‰Õ‰.ª“~¨NTPÈQ°>ztÛài~ðcâ%1E-3úz-‡fÊoO¹±If&™™dftÛ«pº×¿Ú‡¬vý ™î•1©Ë¤(“¢¢(%Úãâ0t°aÒÁ†É!Ž Ò ÊH %”Ƭ–ÖXÑ,­ƒî:4¿ †ÔÞe\‚tIý4¥Wâõ¿^•„ÓO›GËYb’X":– ï!  †Uîž^¢_ æT_gš Ÿj"Ê»9KHÎ7µÞ¨yOÿ#R¯EþN{Œ$þvé &¶pæupÆð~#Åm»Ž˜ßŒm<Ê"%ã[ñÕo±µÕƒ-/¿”_À~—øÑ|'ÌfA/L"…ȯHa<‰T¿…+C¼6éÃ<ÌI_ÕíôÓf}OwAÑÄ÷Ljlt *‘(%þz}ë±`°éà2ô¬x… #àÑnU‹Ñj´ÐUFx e‹E Jl]d’  "²/a(»;)»;JmkäšO©qÍ> *HÆøN·40N·Š§2ÓÝ× IŽüø¸\¾Ëï=t f9Ñá–Mÿ®«òñÚÌOÞe‹GYs–Ø€Â~¬øäÕ#+ŒveÅDaস[lwƒ@(TÙŽ|ï“’}Ê›KF `GqS.Yé^Tð¾Ìwù±ˆÉ°B\IЊÝKþ£U)¬Š¯µb\0¥"£a¥"öüi’†´‚zÃpÍ@ß­Z+$ APáÐâO—Õ«RùÖÆ½éŠËßC®ž½{õѸs]Z´*µHÁ@ôsÚ5€AÔÿ êååõûï,‹‹’DT”ׇêJšƒ®#!¿Û(ðÁ^²µ™" |]·–hFkþ„¿‡CçW€GÐ4 ›Dáµ °s~xÃE0í5¥ Æ‚ó¸š6âÎT™NgJCºÌgoJŒ¶Õ>€áñ©…V€îYU³ anõÔ‘S‹ýÃãZ[-½iY­¦€v´­—¶€˜ àGE/Ì 5DžȪ9>ªAµuB7Ô§õDX&ާr´·p<Õ½@5Ø8$QâòVwýŠpg㔾îŽE€a‰†Eê¡&q • 5Ç¡f¦jŠŽ¤*Ѓ=’N¬ih¤ÃD]êj… þTrªœªŒ0f=BNùô슭Vóá¹Df»Í»×Ûêýæ »?î;ÎY%»ÍÃãRKý½$zu;"æ[=‘1®A ̇ükÚêÐØê¨©ù^GƒGÚìèA£pw;L-ßîh”ǾîwTZ;C²ÿ:r/dÒŽÚ ]5:Ћ‡¡ÍŸRQŠo‹í6¿+úhEß=²’~ 7 ²¨GÄ(§€%QÎìµÇÒÖ/˜‡9ƒOœüOˆO'`ŽÔa+¸¹´›W-©ÂV^µ¦dž®¬*­„Ãi^y(m½Öï8”B› 3‰Â0غKb8µúvÅEhÇÓ%áZxóÒi@{ŸtC9?Gúª}Z:w5«lõ¿ÑxüýÑÆ\µýŽ!Ýö¬0Iar/*…+›»+`®ÔȾFÍŠm±»øœ¯Ì÷† q“#ñö`‚‡ÁšWÜÇ@¥îRÆ»‡Q„‹ÜšC’×#O¸öÛ¼rà ^°·›P„^²ÜŽm6¡¾’âR³ÓýýX蔣 ¥9ÕÐÔ™8•E)¥ÆT)C¨!¤œÛpóƒÌáÙA¨'sƒ•* Ì·ÅEþp†£­±¬pn0k.ñQª½-Ñ< ­q–E |$_£¸gÒËíM~÷j•—šÞË!à0r/plàF»-!!$#OÉP¨¨ ƒfÂ=Iд+ÜDa¸ù„ͦî,GdzŒ‚»NRH'³›Q™C¢ ¢ eàiŸÒÍ/Ipýøð°Þx9v(VÂ=æ.·¨ä §- W`?Ž´S¥{O:…«ÀMÎkpÿc¢q5>*šÐÆbƒ¤:?:|Ãs•o½”„á÷÷pôÍ"÷ñ1É0hS(h“`dùþ+VûºûºØ½Í¿½[Üþö¦XE—¸{\mw«bŽïг $C´9= Ç©Œ&&W¥%¦Y¯%æÅÏ›]_ÞQ”[C±€Ùi Q)70ùÀ‡ @®Íq 6%±·´u[ÓõšÝ¬W xã؉”J$è¹—AbâXúDýÕ±Ý7Xk%k™ˆÝ=Ö ×MÖU#aÈ­ƒ¥¸#ׯé*æªØÜƒ· UÍÀÕ)$!ã×+6‡¬[Ú aZ¿€oÚ• %¯ Môf»*kÆøÎEÀÇ÷ùCE¨S‰¶¯æ /‹í”›Œ ÿ~Èt\GÙóªéÉæŠhsPÑ á-¦ðË Õ8o¹h$L,ýú££J0g³ß¨4qžQðU—|Ñu»ê“ß›êo€/º/}Þü³2üµÙˆóhÂõnL_`FîØˆ¬OÓFÓîLgiB-›&ʬhŽCŽ‹LiŽ=‰D\s¸ „”4‡J äCs 0-¾ø§Þ/4Š@ĆTx AšÍÛŽh âµè˜(ý̾(Ä™0.ÑGæ qˆE[€h€ÍÈ·ù6¾ñɘB÷À1þ1‹Dƒ7‰h‚šÃúË€}ˆ–ý†w ócÅ] @æ2Z°–ÀWh8b@T}F)šõžÞ¼"ÀhÁŠÁ»b÷u½‰Ð ”C°2 ÕÃbŒ‚?™ ¥}Wó©í4âÕVw·~Ê·ïòûbû-:‰é™[>çQVF ¼‰HGšµa¯À2¬%`?ÿA;HÆG¸ÇÌù…€YsXx¼ÿâkþû»õnñé÷ƒdÿý˜%€À"`! X-@9¸½]?®v‡, $¢– ‘‚â¹ðdâÕ·]±šó+#–ƒ ’1K…GÀA1\xòp]lÊõÅRôc–‹€%`µÀäàu±ûy[lâ,À%ôÛÕ‹)ÔÜW›:RQ.Z¢ð{¤¢ß2vmj4¼môµšÊ9V–RáJƲž²–¶ïƒšÉ4¥Æ`ìËíËõz~Uâ^~m~Ût¾~†(ñwé(èÆ~NÊnh\%9ú$q G]6ôÒ.u:!º¡mW޹3¨ åºÕ|(7 -ìW',®iøãè;ÜÙšQ¯IÊ6ÅÝb[†6¹‚¡ÊVä{Ÿ”LQÞ\®<šV·aèÏÏ_U;­øûçG Ú´J¿­ <ˆtB?vB=¶ü~J?e¿Nÿ¼SÙéî}ПË¥N$Ÿ7ðÖï½ ÿ;§xO°fðçþœª¨ar˜\rg™Æ§S ӌ٭F&´r,¹˜—„1 o¼»&”n»Ä4¼ü>I­ã Õƒ‡Ùf•¶™HµÍDWÛL´—d¢2ÃvÂê˜f†í¤éÅ<¥±S› J†HN¥HNu‘œj#9e¬ÝÓ)‹iãI@t§ ºÏ…èN+tŸKÑ}®‹îsmtŸ³l+t}8ÜŸ³¸K\&HˆçlO¡ÆØŸ”à5÷B_¼Ñ'ÛÿSŽ'àÇüx.zô !ÿøê=tvgï^}d6böÛ°ºÕžKO°C½WHpˆ‰b;åèŠÅÕP=„›^^^¿ÿøÎò·R÷®^C}Õ ½æjG¯áº‘P0©©»†ŠÝ0(% ¯¯ßDȬ½N4æÆY×ú4¿Ÿjn?K¸•-¸>æ^Мó¬å;Å2<8bƒ<Ù¾ñžñ>A„ˆ%€Ä£ÔkÒ& $Ûµˆ„»É¬$¯è­õX„IÌ •ˆ+sG±=+gYF~X¬æ?­·1ÊÉðC4"BÄ-*5Å…9HÓ"+5ó…ÕO›$è‡"_Fü^ð’ò‘qK …‰O‰¡W©ÃÂP,i,éE>ÕÊA4’ð?¸¼ÚŸæÛnÇfvjJÄ-I Qž†ÿµ¾ÿáßpòÿyÝÆh>¥‡B·’GRRèÑåŒ8ºÍùR°ŠY!c 6š •ÂËûØú³=5Q h~^hHAš]ãqš;¥ÖààP«1gËŠ¹‹ ˬr °èé—(T³z|ˇØiÛ:`o"®£ZvÀæ=ŠÀŽi)¡Žhè°ý¸ÞÜoÖw óÕAö=¶ÞèGìÁH¸Íü‰º H·ÅšNïW½ÿüó¡Žß1æ¶O2ôîƒC 1ZWåã 1È4Æ)ù†}ˆ°chfÞ+T_AÏÇ3»©ÞÁL 0#¥Ò„q4ÍL—¸ØFëϘvÕ|(îYÑäú^åwŇâ¿ “åö|K‹"^ôûZ46ÉåèOª ³Ë·¹hͲ·{]W%V»Ëb6ƒ/9 I‰âOmÐù”§üžì4ø$ÝÛLë]“P÷ù`÷ŽúNŽþû¿éU¯ç1€æ_á{Ï›jrøÝIÏu–„XÒÐê"•Ä4¦@xšŠLj¨°ªÔæB²y®M\_SÖiÉ’ K6ì€lXO…{0º–б@©Êtêlۜ븥õVùÉ—ÿ˜ügI£ŠSÎåÿJßµXÐJ ê®ÙÅçâö7¨ÁX¥ÞR>|Uyü®Ù›bu·û\ÝQš}(ŸÖ›£ãÅêxøËߎ²“£§OÑïàI%,úfeðb Ƽ~u3»¼yõ¶R§‹E]¥ ¿!0ÿr4Æj~ö¥’éÊ.|©´ƒØ!"´*|õÙ‚dky½¿O(V¤/f_êGJ]—;Aê|ÿ¶šóºÍxÅXpÕðÓþ¨…–¥r–¨LQ¹û}cùûÞ(z§òÚž‰Ö¯.»Êµjƒ·^;h3ÞnïJôêÛíìÝzwy_J#Ðþż2(O>nÖ¥n^=ÞÿZlŽJQ‡¶ ´ ØLl¡X—K¿\çób~ôéqUÎý'Øÿô—ÿ»zzRê§u©ž~]GÿëâO:zجwkðømùð✸ðÏÏÍÉŽSô÷‰öà²(áL§(¬j‰‰§,»ó¢hŒnÄ%5 >Š¢k~ñP}]¢ùSQŠ©ùþ 1„5èG̽ì«9¹^±,ì˜{žSOpZh•bÐ T°ùMî¯?}šu6®¯ cQ“û wíT/G²ö¼g—{ ˜¶Ò2ôŒ©Å½YÕýùd¨úx/Ø t_’NbÔ-$vm£¨)-`Sw}öÕ(À¦C w7Ÿ­ä<ÆNûjd ¸œË,ܹRIyTuv\ÝÕŠ5[áEêôîJ/Ê_ê,=•²ô¤ƒ¥§º,=íM¤i¤,­ 7ò¶È£Ë;ªõÄßM­ät%sÂë¦ÔuÓ¹ßáoì¨zÚ‘ਆã’FqÚAŽLŽer,“c²NŽ¥9ÇÒ€;âÊïp5úªÛOì'X÷‚+f•ÚódÉ“%O–|Ï-ù0vx¶+ Âv™±R¾ŠN'Ùšdk$¶FQC¼k¨ˆòyHE”ÓÃ,¢ÄÿÞÕr˜ã*?À1:µv¸.N¯–’1O{UMé‰ÜáU2ñ³FY%¹Ü“´Üá,7ù»a6¥aÉxÜ¡hh ƒIƒ …uÛô;ºrš21d;CvÓbÒF eHdï× I¹;‹g—€x.„¯P2U <`èÕŸ29„S2«Î~Ù^'¯üØþQ¿sHþ‹ùÜgɳNk@‹Í½Žâ©—`Orà >é8l?2|Ö$Ôùtñk¡GÀY}“Pó9}œ"kl‹VK;ƒý‘ö¥a]é„•Ú~W.h#’©Ž¡cM½èóþ :ÉÈ UÀ–Ö8輹ŊšQ/ûݶ® _\?®bÓ4üŒ'EˆyÒxøoýOsVh{ŠùbS~sÈŽƒâLÆè=ˆ‘ä;ô¢RÀ^ƒA yA¢üjõrÀͪàŠÞ¿~t,{¼¨­Ä˜üt¢§ÙãD} ÑW:Ýß!¤z¹÷ïRƒšç¢2Áõe-ô`Ujë™®ÒŒ?Óuqs ΄O‡ª¯çDºžYÇzNt׳û S QسL­§6èÈH*–¬7n@K‚[ü±³ƒXÂë&Ôu“þÔð7éú]À`—?òû­q§‹p‘wc»›ŸŸßçÃߟþ‚_-‹í¶þîèûêÃ|¹\ßæ»õæoÕýùbÓ\ ~ÌÑ÷ð(Në/5>wyÿ*û>‘1±­Á±º*IUáY‡*éªÂv—ˆÀ¬Û H…‰­Çbwv„ÜÙ1U WòþlVÊÎ ^Êê“/%®7̇µÈ4ŸïÊð; cäÇì ðo cÍE+ý×Á§-ž·Ž¯Ù•kh].ÖÍt¥‡žÒN=¤\ÙN¼m2o Ô@:šqœY @UAYFØE¡§1:´¡3¢ ø¨‡« Bàç—î娚YÖÊ–ØÆ¼oƒQðÐ[¶f­e_;ÉA×|Š˜M1¸sŠ&}™ï¬ÍtÛ-îÑéÂÇ–Z,‰mÚ p„¬„Iÿ‡ÈX•tr+ ¡ÏX²ê™£cÒɬx”wtÔ€Xñ¢õȤ¸Úb¹-j?=;Ú÷BY«¯ ˆgž;ñg]žJs->(Q'‚ç aWI³<¡ƒãY*§SûwV‹h)7ß3¯¯p dS`:¤šØ†N`C:=²sûì¤V¾ÂcO,û2GžØÇÕ <á§pšïL¨Ø{ãSBEpzËÿ‰,¢ÓXX*RJ7Õâ<àLSùŒÅýzW\^Eèp›òn0 âvÃk,É‘ÊJÏÉþd…äÂpe%γֆΨO`#¢ ùaí@dájS|Z|K)½\ 4b‘ÄÊÈåöj½1kb ±8 ‚Þ¼€ÜàÆ {luQRã‡+Y²¡}€[êqéKF—¾dì½>úÿ8ƃk¼WÍk¤Òñ/•ã_Z\“h蜫H¬…\P)5®*¥2i¥T¦[)ÕZô/Ç“­–Ieò2©L“]Céç+§HÀ| ·ôðíN`ÊNC^ÑoåkáÄ¢¥†¾Ãß4Ìu2ߚƘëdÝI2å ñxÔžäê$W'"Û‘\WÇ”™<ŒüŒý‡d¿¢íµÂÛdq’Å9,‹c@ –6ÔoqR¿Å‰~‹u3²Abe-¾TÊi…¦‰OÁTãDRÙöëȼ–ÖMðÍ£ò͘éŸ=;9>;©û¼v¼‹[[¯FÚ¶sͱøþ! r–ˆL¹ùMðîڟΫž§§P ÔOSz%^ ñëUW™ë.J?Z¾Þ“´Þa­w7™aEÄoVå5AûW11ßym 10Ó¶2ÜŒór ã”õhª_z=«ç½ÍmCšÒæ_#Ù>Àü&^œýIqÖ¥˜S©Ÿ§”\a‡á=×)GÕiºƒ‘2ž¼Q jÓ.Ú¤§Ð%3”ÌК!3Šùàt²¡4è$¤4h–Ò ~Ó œÁO™Ð˜3cÊ -IP˜”€›ÉKÕÊ´_:IvûðŒÒOù6¥“̦“L À˲'‰¤ä¾wºïrZì»:èü‘OÓÉ£®“k’žù#£Mõ}E)Œñ:è´Q_«Óet’¹Iææ°Ì1|(ê7eˆR†H) œ!â {JíazˆË=D‘ÂPH Õ ´GVHv¯‘"#øä­ßœPS¶»ùùù}þPoãœþ‚_-‹í–Øâ©>Ì—Ëõm¾[oþVÝÿ/6ÍEpuêÇ}ÿõí $:æ²Þ}o0qî¿4«¥… f&µ4~®36Wkö¹ŒÙ~]ÜŸ*ÝgÚs桇Ÿ|)åy½a>$€&@ˆ¥îëð?7 |·~³#ƒzh…®[ÔoR¼ZŠ7`e”‘!Ed(O…”'ÛÉŒa;Ž£lå»(`=+ÒIJáóˆŸ;ƒgßjŸ"ܶÅÍ¡DË5°Ï÷l5á”úÛXD ³ÖžÃbñnÓ/äÇMIŽ¡'Ü­ScUÍý\{F2ò˜Ð‘ù„½cj`'L·¡#ýy²'}*9„yÅ=Òvðç$f·!˜6Ý”»SÈ(ðÖ›qÐ…p™˜çLjç3ÊÀ—îlV¹½7xM«k··ù|7Û¶È…N¹¼|À*³%#µJ „¢Ý ›åÅU…!^„;…$8kÒnWµ®º\Ë!M»MtÓnJm.e$`ûF soyîm¢©²¦R•5éPYS]•5B—i¼*Ktä?õl®S!«Û‚¨ÞšˆÛ‚N[ª *…IJT^ŒÁ¦ Sêºi{ÊÀÒ›z¦ (>¨r1%> Wݶ?>ÄïÖw»“Ãîäp'‡;9Ü{ípÛpÐ\zb¾›!RžSPMi%ž“_É”+4ÀåÑñx’¯“|äë$_ç°|æÿ`­~’Õ‡U-ÛbÇÔ¹t•ÎÅ/i«4m•&o&y3çÍ”j“qe€Ú$½˜ý!ÏÈ<®RŸÊ„=ìÌSÚê H妭ރÜêPèF’6‰S¨‘B`ì^ 5R¨®)ÔH›Ü1¤»§{í3¦íñ´=ž¼¼äå%//yyq{yi{ ¿c¨-ÃóÚ2Lí´eHé"ÔÐ Ñׯ´:;i^©Ð¤°Ç _¦ìµç$ßÄ6¶Ùf ☑¦i$tb$#‘¿w6œÉDýZMÿAüÞkè4³ÅÖsôtâï}¶¯‘r³°ã´.7O7'n¶ÅÍÝ‹7‘/ž$²÷ëÉ“¤·7‹j’®¤+ùBm/ZÞ23òæ¿o`…•Áæ(çÅd›æ°UóýS6C¨ÖlPíá¦6ì9&r¾he ,ÿ`è7žløôÞw‹í®Ø ܈†‰eÅ Ósò½OJËPÞ|rB§™‘6¸)Eî]ñõb¹(eúe¾ËÅæ^L_J^rõûì—Ò„vË´æ±WÅ×ÙÅMQêRÞäw?å«ùr0•øízþ}û„ŸK@~"ØqF{·Ÿ”ÏÁÅ·¨ÆD¿ZÃý°?Ê·3à'”æoXÐ^ÿl´€WïájÌÞ½úHìm›i]íix[ÓºCHrmì•¥ON C]å;×÷ååõûï,—/´ Ù]À Z%Õ"ѽT9C³½6Š¡¤Œ5JçšUÿÿ%Hê/™Ê$²^)~:~ªyª¶¹hÌ^Ä}P0õJ諉à+_‡f{ωUMmLcùܬH‡X/xjÅ×³Ò ‹›hŽÇb+ÛVú¢3LHRò¤G3®x¨xY˸Â~e,–àFj«e…ëukÖ¶é™Ú¶qGm[¦[Û&ªqÒ#[üã¿ÀÍ2üÈ2Unê+;‘®lÖ±²Ý•ëQ†­"meµáGÞ·²( wô ÌÃhëÉéÑ1ð3ž=;yúpÚD¹,6¿?A}rR›Ä²S«N,:rrž>üùûmuõGÅr[èq`ŠUQÌþ±ºý ¢Çºò'òmC½éÑöýãîáq÷A†SxMHYM3ÎñèbìaVµoÂ’¸Lüñä´ëtjÿñÆUã–I¯›P×MÚÝqKoèÞ—$÷>¹÷zî}ùÁA¹÷ßäÞë¹÷BšEàÞƒûÝ{!Á"rïÍÀ¿î½2¹÷fàOîý0÷x˜É½÷äÞ_~JÞ}òîõ¼ûËOåÜ—è&ß^Ï·‘,×~ØèÙ‹è‘coü}ôëE„‰È­7~òê‡yõ¥c™œzON=”§Xýú·bÇÞœ ß\Äu«wײ¿gÞZUS®»µöayå®É1×­©R-ß|(ä=Ýó~æ~lÜÜgÎÌ}v´­hÍ[û‰˜×3ÄëŠ×±‡¬^ª‰3 »ë´0Ô¯?2 ë ¾•zƒÏOáy=ð‘å¿1´ˆïÙöŒÂR àYÝÙ·WŽÜPnhÕ²ˆ¨±ŸV‘–Å[;·ò2øÖš+‰žoæÄ z˜Êq•ú½ôYŒ®ñƒ*èÁN©8[A.hhìõp æ ³'SÄ êåX FPÝ®WF×®o æ4 ‚¨bˆ˜\Üwh[ÝhT9œ<S’Š!ËŒ³ ‘ÆÉ›€¨'„=wŸU¤[x½gmžsg±;\)q‹N±û@©Á@{o²t|]ì^moó‡8î!¨×A>Z¬óóWR=òo¼¾¤HdËËp®1i¬ô5§fÛîvýÙ8ð…Ûœò=ÍÛB­[Caf‹Ø’ž¶BNj9¹°“^l¯ÛN¼ç`*¼”3—í'-§B¼Rº'u³ï­¨ŽÐdäTL$[L:Ô]Þt™èÖ¤íõFÃE ¿S-$n{ÑÑÈNÑ‘ †HrS.¾4é#o†Ü®Ê14"mÒˆ´‰iµT‘mùZðŸ)¬ÏNüTãôN«Â5NWTƒß'ìSÏ%*jÌ©žõ¨ý!DÐõ¨æ·Î¦ücQS~…FøMgzQ;|Ù¬ƒNNËf‰hE–ºxÉÚûëð¨t˜Fhíüexônç/xÖù¹PaSY3¶C}Õ¶~@6¸/T­T£O<³5I²H¹ª?å[°3`+…?$dÄý±º;³åc:[.K`[)áØJ-mð\ísJôvÖK-È‰ŽªœèXšÕ9îƒnN!6,LŽå©Ñ \ Õ¼éX±þÉpÕC«jq‚‘RS IØP¡E ˆYHâØa€hnn›µÀQU%*ÅãxˆÐÄ)¡Þˆõ:"§ðAQÚ ã"ÏÍÚ7ê0Ô»Å\üñ.¿·wb¤‡gíÉ]÷7æ€Øy÷1*ÜÂ/ªÑ£bp…5–Áç‹kߪ§}=_ÂÐóÃúëåj^| Iש9 \õrAÔ­aå„0¥÷WA×zWÒ¢¬¹¿R>Ò{‚HN-V›‘LÝ)¢D@œ1ª…ÞÊèru¢ ”+¢V`È ¡ö.‡Dâæ]w4åä:ÖÍXH†mé´Âj›6Åc,‹ÚË"‰š’¨„Ú;Q#q ]ÔH†KÔJûãbY\­· °f!‰Û~:×$µ÷×Á¦°ô.½18Ùí³îhSJÀ¿³ÍïEyWGƒ¬ÏN®b-²¯´ÃvgoûLW±ùUö’§úœzûn®»Ö†-²õ:¼m úŸ?h£ÒÞ ÙëAÛ…¬Ù˜8zª&k˜‘[d oePâ†ßôýñ3w"ª—m&¨…ºMÙ·×B/y¯DЀlQ©eU4|,‹+†Áðü@k“w"šrNŠÒ¹·9§×ƒ·†\H%Ì<© e¤y© ò‹õãjΉ£ÒG³‚I´§‚Xáæ=}Ôˆ %Vs¶ˆUµÞ´4!p,GöZ{;—¡Þ'LG‡€¬{*w:}­ËÜ€³m´¼škÙo¦}åOùÿé½|buçy*Rí£0cÔ’gb!IÅüj¼í‚K¡»xÜ$™S’¹ŠRû(r³ð%1kÔ˜´…X²0\ˆ[}à=­a@Èy—âàKd„²S±Ð©Ô€B—/D¢Õà9”{^¨ô¶z­³¥´©nÑý|\‹F”M×Ý+ͨ;V7pÓ!c'Ü ÂŸ‡×?ZecM¤¹Õ¸%ŒãÙ ›†]K-Y´dÑT-š®n?Xµn¨ýÐ$¤öC™öCuÞqÝÖµ»åçFt6Ü!IŸ%ÒËHßüæ©£®öÚKšÐ†Ñx¶³M—j,ê1«Ò‚Iö~LB|÷eø%Ï8#igžõôaßízÜÃA!ÈðRümlYU”vÕßZìJÄŸÂXS5´4°óK/³x£W=ÞI㳎xg¤ït óP}Ç7¦áEì$Œgäb*ŒlÌÏÕПŠ5¢â—QHþ„ÞÊ`lZÀú¸m)Å|VQ0÷{FQK‰"XjuuÒYÍEcö"¿[Ù"µÔ?¡ÅU6ô&ªÿð _×c‡º%_…G8­à|ôE<¤Ù:%éa nÆb~!~  ]YO­{qº®ƒ˜\z«3ŽXãöÔfM’¶ízÆJh¬]eAN-mð{ñ3ÿjßw Š§˜”qRÆšÊØ‚æ‰Qé°³8-&¸MRßV ׇ0JUc“Rg2°I©ÈDNì³ìþB‚y3w Áb0jÐjË–Z…}i¼fˆ"wš1£¼É{† «(ÛÆ²3ÏTɳ6>Þ´Ž–”fÒžÜjŸ‰9|»g²]Óh Ч±v€8jßÄ'G«-e'Žƒ›D9x“š˜@z,Ù†&/l>wÜ¡ž’ÖÚè“U0ãÜþƒŽf/æó›üî§|5_ÞTï^]ÜAßíc ÚC±i ôXááþ\ëp¹ad'BÕ¥' ji‚[)¥uX?Ë`ã0(ÅÞPw²]Íh4X°)AëÕ³]DdójÒAmß5ˆTyyÛ%µ6‘B8ËmQ£¡¨2žíÊ5³‹ÌÈ­ ðÚyžLpn»˜(˜m®ÅÆWÓ Y¾Ça³3¨,k€°×6È^®j£¶²\'e+d¢­Crã)Kw&AÄ¡Mh’)®—4«ÍëŠ~Rt¬4R3c\"ÅÛl·(š}(¶ëå—âÍ¢Ä?_úÑ.{tF‹¡gô>%ƒŽs§2¢ƒW´ ÷Ì•yÐóîãVŒæ9àCW³ËÕÂ^OÕ6iL#ö§ ø• –È ~brY ‹[¹·1ÑÈ+á^%a6kj½gÐ`âPD½—p · —Úðg­¥°÷×`©é=¡ØX I¦ÜL†Ú[iöêÛCá€áÎDiÝ<‰X‹=“\**¡¾ô¤SÀ¡‹Q°ù°%œ¾G­˜ZjwÔ¼òàñFË^Ÿ£ƒÉ–IŒM23ÉÌ–™Ñ×¼‡¦tS¢ÐºEÓÿFÜ~FdÐCì8 ™›ß‚j3$Ê6ÄÐ]ˆ€Û@½&¡H5z µÝ7¤Ò7?dºçüqÒ{FTŒÞuÆx$¿¹‘všÍÁÜæ1W³à‘ߌ5‹¶Ó¬4>twùì ”ŽçëÕžŠm)Ä#)Ò>D [‘‚™W¤„愺CGsRÅ¡+Ç·ùoÅ¡kG3i[LÉèfˆöaóÃÓ›rZ¬8 Ýæ‚rçëyïµÒ9ä,îÕ¦x(Vs@‡Tða¬àCYs“ª›XŠ=©ï 1JŽo_B¬ÃÍÂt‰G+ªfj<°»O¼J¿¶#*¿Ÿ·>]¹ÑÇá—Yd/’½88{¡®A÷Ky¦ ŒT¡ð. ‘eN%èÜüV †(E ¸" R™jUa´Ü8¨áÔCJË„‘–iVbO²2BÉÉîI§€}l£`’iÃÔlF¦yÓž'd8³“ò1º Åæ"Šd(ËP(ëνR›)“21Jáºr&F`’S"f1‚ˆ?Š÷%ò‡^˜ØÇ n(½L ’¼àžt Ø 6 ¶Ü &TÉÞzÁË"ßcl…­ªåÎEøFÜ7‘@ÂC÷D‚e<ôP¼*Åp‡ôelÞáV‚\Ñ[uçf…2GÂÀ ¢+ ^iÎk”!ÐÓ4„î¦ñïÅæ÷ã'è¡ON@$FØ|Š„„ÅG,÷ôáÏßo««™YJD4^ehðÕí_7¯+Ì· QÇGÛÅ®Jñ?ZŠ’biäl¨½áw_¶Ý_ow›"¿ï£>È!?‚˜Á¯ŽÙíâR¯q€ò„Ä>§-DÑiÌÚ]´($ŠpÄ ælÙ˜Óq'Xƒ+‹„R2B§–]jPN›F _µYÈiÈLOC¶dPšû3öróE+}•j»V·|Źn/£¨¼ʘ‚˜OÀ ™°ô±tÖË2ꔲÀËõ׋­aQ²Œ™'˨,RÆŠ–‘m€+°Œ’¢¨õ÷½±LE´í¼/ÛΧ*ÓºÌÜ`eY$œö¥PX¼îèµV^iûZëôéýG±_ A6rbè]Ú̵œ³[ÚüÍ}wªFüòSHñW„]£O?aÿ°þzОrXmí´A„ôŒÞ_Fh$o¹ö•Üæ)S’þ´n‡X)·¹ô\¯Ö€ ?Ê·3 Ê÷b‡Yj¢Y ÜŸL ?®¶‹»Ui¢5–]§žê$Ë>\·3éV¹GkO*¾;!›Š7²Z–‹ôìúzŽzxI¸ fÓí¤òéN»SªJ˜~'u)‘’¹–Lü!YºC¯Ð‡Ÿ¾”_¬7”ª¬NEåËåú6g¿;ú¾üg">Áx$ëÕ‡Ha›/µ=ýeTõÚAújžg­½!Ô(ú¢”þn7ÛÅe^Ë‹Ç g©ovÅ·ÝaôÑäÐŽ¸&‹‡®š<yh®Y*†è™¹~Foÿã¼…6s<‹Û¾wlB-i¦”Db@B<œ¦¿ÉÂÆ,Væd ÿ½ Õˆø•"Ntjv³¹[–Ëâ]~¥¤à°Êˆœ`BÄ-$5R%å¤wžsï9iD§f¾þ%QÏÈš(Óò±-<9fâ,ù©¹†DsΡi+Ù‹rДɒø{²‹0II(]œ€2/Ÿ|R_¹Lºr㎕ËtW®ucEH vW%ô•Ó†é_båh›DöT²Á#üØäx\áuu]f&‘§ù¦ãKðëânSÜ-¶¥¾h!^ªþ ùÞ'¥•7—ÈPÐ#Σ%J”/–‹’…^æ»üXlc°ûO\JP…]è?Z}“UñuvñÞ]Üäw?å«ùr0xåcñëõúö·Ú?1á©S÷wØyìxëT¼…nkj<Ü#€ßíàåõ4ÙéilV¹Sóš,”`礋á&Øùd,ð¦žøê=”ÆÙ»W㕪´-Ó ëȃ%¯ÓM!ê†Âï¶e|yyýþã;ËÞ¿¹nbVDU˜Û(qj¬ñÈÙNϬúùoƦ£ï®Èšüt"ütªg• µÄã諉ÅPþ\VmÙP£÷ëK¸Dößü91¬¬çdXzQdÔ¯2 ‰pfåD20 I™H\˜]‹´ëyHæAÎeS‘øTÏX3Õã9a L«ðrö@çÓêë9‘®gÖ±žÝõœ YÏI¼ë© :r¸õ¼î5Òrb|¤%ðVÜŒ´œmß?îU§Z6b[’Lüñ޲™Zé¯%Hf ¯›P×Mz¤×†¿©+½Fó}ì96Q€g<ÑÒÅv[ŠƒñÀ…"ø†,tpB„’€ÀÈ×ÙUä ÙZkÈÕÝHjìÎ:ŒÝHרÉÒvNÝ~»ogbĦ½\¿»Œ´nŸÑ<ÄüN#‘b%å¾Ê¯jOhqe{[DHkä·¥^(æ³òµ£õË÷G϶÷ùfWC~ù×#ðþŽ{‘ÕF*ÿý ÙËWo^Ü›¯­»¸hg‡ åö x7äZ¢zAʘúèýÇwT÷ÎÄ(?ÒÙûÓt:†¿I+ÇmÑœ’L\')ÎÖÉÓqH3ï® Æ«oG*—W¼Nzc¹sÎÔŠ,À°­ûâSL–6{±š¿ÿº’ï”uq?ʦ•÷Vï³j™TPÛ¤Â\!VîˆROm^\ß9ž½}õöý‡o &Ùà_S 'v¶)A*3þCBfâQˆß ‚&·Û0êå ¹+vÇ8ŒdC’}Avܼó_›÷ÿù{%Pé'L\ #eXYøWLÄú6g›„$¼.v—ó˜µ\eØ5u¾ICã /âe©~ˆŠ'‚–ä*€hÃê­æT¢Úó¼éEcài+Gii6ÏDqöå<°²l†Ç¯’zõ ^¯’zDHê5©×êõ*hõúóÖRié¾)X@(cê<,)ØŠ IÅ&+P±•¼t©W¨¿ŒUƒ§Y9ŠKóý›’Z/nw‹/æãî¡êÝ-îAëwýâCVë6dOº—$FÒÀIó¸Cñ:LEýÖ@’L;»Õ“«ožµ:´f®¾g6Ýèê~óšúrûf}wWÌ/£ÞÇr¥¦{VˆŸ‹)~èš DRÏI=Ëê*Û”4¡¾†MÚЭ/æ÷‹¤X)VHî¤U+2$•šTj?•Zi­ðôéÏsÐ~o/ AT^µ÷ÐÕ(GTå[ú©ÆBj‘S>îZí\yí{7 å¬óª »Na¥•ަkŸ)´9FëÚkjw¬íDÉ(Úë>{dI¿î‹~U9Äß¾}eå ¿ ƒrgW*¡z¾ºš:/ØDæ+þÜäô8[Ë"ß¼-ÿÈï`çìmòÚ zíuÝmç ’ìÊAÚ¬8yýãÅqÿq±\†¡e}£ÂÐŽV|÷~^:»dÉ]R%é׃ԯ*~»æ[Z¬N.;`˃I.l59sÕ2åͲå|1ŸW îÏböŸ£iÝ^šÔ¹øG¿DÚlâõJæ’¢F2“i&+XÃo-£Æ³Áõ—±vÞÒdYÈÚ,é D…»ç•ž¥÷Ï‘îUhãæŒ)MòëÇÛÛò¯d£±ÎhÅ’}fè‘,t²ÐñXh)׆n£Í®f¥±:;M<òÞ¨J ê¬ôJ}üõ*¿+fU¾3Ÿ=SWÛÅݪ˜Cs\~“ è¤J=«ßæYÅíz^Èf$ôŸÁ@вñ Ñ‹µz”Â0EuµHGV„YDYAœÇß‘UF‹à¬±yˆy3\ë´0% 3¬yf×׳Rßài @‰6ªGhl ôWˆu@ªÈ Y€@êÞ9¢J¡~\£CTò°iJ[}¢×”ö@`¬ú§¢u6ØaôuÛýÑôJj [ís²ÌÁèöd™Ü2[1KÉ"¹³Hc7©ÅöH»‡0$;’,H0:È€¦ƒBU6ÕÈpå9rWßC^Ë—7›|µ]æ;¼I×ø®¿\å‹ 3‚”ÍcMº4R-hsQÆ^$yu) :í5‘xÉæGšI‡©äê)£Isî™æÔ«¹*,¿,õÛ™µL}?V¤O8²¸(ôz.-ÅjSöXX&^÷1Z÷ŒßmÿRªŸõæ¦úã¡TÇ7Xˆëÿïª/óår}›w_¼;.íÜ£“±ÛÇ«jçë*SÓÎ.™'vÑ€™Jž?)E Q¥ÿj«Õž`ͪëDš`è&XóS;‰ÀÎmM°Nº¬3 ÖÉEÙÖcj¹ÐÜNcòAå>è$hÔ‰·™öN“—˜¼Ää%&/1y‰>½DO.RòŽÞá7HæͶ¨Â°üð–ö ÊO¾üÇô?KzVLzXâ¯ô]‹í@—`vñ¹¸ý :¬¡o)¾:ú×ú]³7Åên÷¹ºý´Þ/Ð+ƒ¿üíhrrôô)ú<©dÓÅâOÂR^,Ä’ׯnf—7¯ÞV^ÊbqòWB+`þåh„«Ù—¿Ö¿—‹"v7à›Îþó´öQž=;9® }g_j­q]FX`Â5™}i >ZäöM˜j !þZc‘±_Dºß4’½©ó]üÛ”7â ‡ý³ HØÔšzg žÔÙ¢vÀ0æ`°iÕLpa£Ä$“`6‰‡]¬ËIVîÝ¢ŒPÍ1À€”UZÌ?†.ëYßeµ¬I Ðäï:Ì›‰˜W ’Å0)1q&fbòéb†®}Mø˜ëb£ˆ·Û»Ò1|õívön½»¼/]$ÕÉÒÓ'7ëÒ+_=ÞÿZlŽJÿ Fe¤€ƒ‡-ôÊÖ%/,×ù¼˜}z\ÝB/ýŸðÿé/ÿwõô¤t×¥¿øë²8ºø_úÓÑÃf½[ƒGoËçÄ…T êüœtg™á”ý›LÛžyd¿§ô}wKèsJÅ/UC~šÛI~šsF‰Z–¡~ª¬ªEYíÒz¯ƒBùJ,Ú·F)9²úWN« =Yƒ`ó®¬ú:fÒuw¬c¦»Ž‚b 5‚°U‘¬£6ØH_ B’ÚÔHNÿ ?–”[ô U„×eÔu™™FóMÚVûCñ_‹ò‘ö°ÚOxš‰*¢ƒ…4¨KsIã¢e3¹ñ¦ýãÁMú%xŽ&Í‚-}Æ\OÓDä|í;:H8j+׳.ú\@ŠÈåãuŸ´¨yÉhü£§­‚°E4°£BI~Á÷ÇϬKˆçü™hB^Ó ¯ˆ¥£GªË¼xtHDÅpýEºD@ÕN»gû"ª¤ ÙŒŠñËÂó` µQ°ˆMÕ™[­•28[‘\µÈÛºò¥Vz¸V}bß–Yjãʶ´ »MŒèn –›Þ@7úYeUÃÕR€‡4ÀGzžXG5¡äG{ ;5Së‘b€WÇ‘b·e 92SX%m © úÑ­§]Ìu©ˆ˜ïxh„—E¬,°¸Ë·GKgèlÑ8¤³E#;g‹Îðĵ¾¼40å¾Jg•p:Z½®ùŒ­kî¨hnàÝ'—x#(=¼ä­H¹†qPrý”ósF@:jtå7ê×Û24ÿq±Zl?ƒAÛèC›“r ²£¢'R b碚,gNaWäZÝIDÖŠœÎt¸Þ:¡qÛ°:j¢¼“Â=jqÛ­P ü•åXƒ^^”SɽdÜ'§¥Ž©w8.À!kÝEnŽÅéþôBWØ6P©Q®ªó3 á Õæô0#òû½aùÈJg]ÆA÷;.4ž)Ÿ²/Ž*µa2nÞÕã²I“…lí »qùš§6†ü×ëAÙûj…¼Yz¹ècãù…wnÝÕ«¦¼ŽE‡7q0±„döãzs[¼YßY*3³É©ƒ ÌhÜM3¯“x›AÁ»²Ud8k8) j1@¤÷+o ®sø"Çå-…€/òÙF¾§äÖg*ˆEUn¾,cŒœ ²ºwÀAŠV …yˆÂ,ÈyÜ(Z‰æá ³ #]ÏΙdÚ Cû¸vÔû¼K¶ù9¯»é92é‚fç”Ç€í²Öy‘–æêÆ(©–”*Šþb» Ç ¼õG9ã;t®ý —äeô¤SȾ†YÀy£ÑܤBÙÇ$€žW%R»›âþa™ï [5˜¦£È‹·ëùã²*CŸÀÇá´’.-j·¹Â^îxYI¤óóWˆ?TNÆÀ°’Zó= .i¼’òïI§p•¿iÀeá&êH{ô€–ƒ.„k"ƒ2Ì<zãÙ³“§xËlÒþý±Øü~ü=ôÉ hÏJ,4µÎÄ2#÷ôáÏßo««ÿ8*–ÛB¬Šb~ôÕí_=Ö•¶É· õ²£m¥bvO˜‚C¤ñøfHì'”ØWš¸Kêu";xyonf£»ÚTpB? =¾ɼp´•@I× Ÿ,T û@-*õUÅñ}‚¾€¼ ;åì½ ×!\ë¬)S7ü€ä$? ù6,Þá»4\HùpFHe„¿TJõL(ìÈpbç)¸CRv…‡$D4C„QHì3…)Çã't•R£Å€1§™:œ<““E3È ¢E‰'/MHžˆñk™#¢0;¤#É1ƒNèAÃN›.ÙÔò·:ï:ìA=ÏðÕ˜_CGáÇÅ2¥°(…ݬú¾%± ÌRøÚ›R°FAO!쾤²ÛØ"ŒdvaJg |”Ð ¡Ýê$¯ yÉ+H^A¯Ä¶¢õ;$×’Û)¹Ýý®Èò™-éBË—ÒÛ{Î1§·éÑ(Ü †RÜ„ šäVyÔ€4÷‹Õü¦¤¬—Ø’ÈU…¹êq¦RË:3Ïú·â'cO¼L{tÖȸÑõ¶ÚîæççÛR«óY¹€T3Уï{8âçªDÛõŠ@ÁC׫¼žäƒ¹‹P•ÜÂ1+÷l{ŸovõÃÐ/ÿzš+vÜ‹ýœ˜Õî´H¼Z0B¨yñ Ù"Œª$õâ{ÿñ]½5ܨ ´ü?€=O§î½¿ý¼Þì*'Ö„Ä<·4ÝŽ+ëTÚaüv= ßë{F‡T µÁ÷T[¬®òÝçp†œÇÊàyÇp!Jáw·v.ï Þl‘L®Ó>ÜHjÏ{_p’ò/¾”/´°3M©ÃÏýe@J/„!J#ÏíѸ¨; =fØöÛUâBEŒÄ^ßpð\NÌÈÓz<>)*@«pƒCÀ·eö¨è‚WAÚ >£Ñ„«Ô^Mýí×Åݦ¸[lKɨ~!¸ª&Ÿ|ï“RVÊ›K\(àš÷%ÆËEÉ /ó]~,TLðZú:øL‚&¬ÿöG«™Z_gÿçÝ…q£T>³oañ9ê‰@¡ãzBøüP$Á7V)X>Œ)o÷ê#aÌxx²¼5Ê×®@E'§‘(œ!÷–_”——×ï?¾³l¦IDºí2¤´ªM†Sö˜«$s’•PÌ^Â÷‚ÀÐ|2Ä;+²šäGëN" »uÄþÉîòÝ7ëõÞr!@-:öƒ@;ã;¸únîãf±+®s¦1›uÆLýw­8¼ :Æô™°þ5¶ýƒq–nFcpw¼M¡`ÇëÕB‘48Z¢(¬¬ô$NY,º¡ÊlZ‚Çþº1ÖàK"PJÌL„šÆ :`ñé)¾ç<ÊÑ%zë’+aišmâçùb÷ãzsñy±œ¿Y[È7ÉÒ,ÖÑq5‡€/Ææø' Þ¾Üþ´Þî^,—ë¯ÅÜ%cǾÂ/R§ÆAMD4Eñ‚ÍV‰…ÂÛ"±t÷ÖÈ1ÉøÌ­^c“„ЮñRÞWl( pJ:VOÇ H©¦a’ômO:…©uí€ÞS÷Š”ÏÁiàËÕb÷ráv'fÏΜ(+lì#’[8^âÐ-ÆHX£ÒÍr²„© ÂËkaõ•ó|€¤á1 /R¸‚.­µu0pF¤WÛÖÈ€…z¿úa½ÞFN´Â5ºL(ÛWþqH@YÏWßrp>lõiqšeYëþ®í%B¼¡Â2á§9é{:h|‰hI¢ö9d’©Gž0½I pó^¥¨ß)ÔkW-NÕPeÝ0cwkS¤× M‘±`_¬ßÍtOúg´Ø)ó#žƒO"jaÔi_’eI–eÿ-K_]{pjÖÐ@áIH…3;…ë.žv&ÈVŠéÀ§ÇÒP[Í·`ü©|H¯å™Í1‘¸ùMðîÚQÎñ^ ê§)½Ro*sk*Ac$³ó±¶"À{Ï´-v~ΩPÆ’œÂŒP{ ­­ ³Á¹NøàÃó— F¨©©«Ì ‘eâ„é&‡º»´"'Î[4úäàê( þî•©Çò÷áèö{Hؽ½ ÐÎ\öPœ;%Aôše(õ^‰Gò!”)¦adÞ{@üV…»G¸®ƒ€ÑÇe¤ d¿ “Ÿ>œ6]lþþXl~?~‚úäDëÄâRkK,-Ò)Oþüý¶ºú£b¹-ôÖ,ýª(£Ç¬nÿ‚è±®ÔE¾m¨—má-O`8²•R KöwœvcõàP}(>çÛÏ¡X¢A~–”$P¤(…‚#ÛÑO÷ŒŒëž±3Ý3ÖÓ=”à Û º§?ä·¿=>TÀ½/ÍX$šÁ 7ª©%X‚Eª)84’§©Gž0ÝM pó>'VlœîÐIRõª^öà6½.v¿Ð}ÛÖ_m‡åœLÞd±Úñ Pª¿2Ââ&¿³U‹‹[GT©ë˜*UÑ¥ªŒ7i²_Óà’¢ŠX­§ÆÝ£D6 ,-æÓ±-è±úD€vÚa ßH^Â'oÄ„qt׉I†#«`…8rM˜™.Lµ—/ƒŠ÷Ô\…Œ-96^.(ã6É• æÖÿœü¢äɹ2l†‡g»Á*uÛm@Þ@Ik¨f- ©fml§fí ?€¯æaØ”©áa4Ufáp¢£>錭Oê¨Mj¢²&©A¥™¨ÂLXÄçüÿÎ×ø²®Î¢.\t¥R²Ç8À…z^J·* ‡l!­(+­Í"®iùºg…4³¾X,‹÷жn‘ò Î4ˆ T°BäB4?—Z˜o«ªÃ€×Xa]YG¹£¶AM]Ø`¦áàØúbY䛫9h?¶¯møi$£cg|gMÑÞPȇdÌó9~õáíí ì×.Ò]ƒ´Á£L™0÷vÌ‚ÌoëH¶¯IrpUÈŠû¤=û–ÓÜG®=I ’öT¦L˜ÚÓ,ÈÊÚ“T §=¡ã{³yÜîŠùÕfýmQìudDcgxÄàà6FbXÅy D¼ÿ÷d%’|‘š|‹döµ¨¦é7¶NðD)•ƒsJÿ'iÕAAÔhU‹¤Uµ¨¦V5¶NPuØZõ‡Í:ŸÀCí#{FÃ+&ðÕŸõ.– À$àû)ü º éCÛ¼`Â>o"¸hÊ^4•(þþ§ŸéÏesà”-I}@ºæÁñhø3ƒ?'ñ–£dRé¦11 0oFÂèpÛ‚£±Ö¶±œfHN'”œ¥Ü%¨=Aèã>a×·²œ¤NÄ’Z]Du‚é0Óa‚è0¥èPŸ.JLõ(1Õ§Ä”¥¶Š-¦bZàë5¦T†­~q[ƒcðc~Lã>µÅ:H40ÖqÂpl{6Œª“\—äº$×%¹.±º.úÆz¿ì´ùƒZít4qÔi·-MV4YÑdEã³¢ZÖc¿ Gæßp„Þ¸H¨ð“ªOª~¯T½ªÜõgèþóNáOÓäç“cx{šFÆô£mó[goW#cø([cV ¹Ì“´ÌÁ,³ˆìBpXâgb⣔š.bàT¸P8•ŠÆ»›#§‰#Gªq¤¼N'bëãúiJ@ÊÀTɰ/z‰ºÉK/™—aídX4øë%×O›Ê²ÞÏпS뎞ÝlÀ±ÜßwÅöC‘Ï]æ>WÛÅݪ\Ö%`ø#Ç-5•2 ‚˜l²Ù)JY’Œ‘&F(¬çFDÍ7ñ’ή¯g`AñÿÝ6äl§›ZàÙ°»I§€u‰–äùZ2S †~€×ƒyH»Â|×âÃÓ ˆ’‘«ŒEÒrR¸WXJÝë /Þà#ÙÊnzödcm~<â¬kê ödãé"îÓÖ°VË©Jè–&ò”Ži‰ð`6ƒ ÚØE&z6Λh`‹J:@óÕMþéÓâä3œ6ò¨"hòíWùbÃl¿·\”©\$:öÕ"ÍEcö"QI@Æ^X-öõ×ÅÜÒýX.øC±ù[éÔÌÏÏïó‡ºyæ)ü䡤—ˆñNE¼Xݲ,¶[¢gõa¾\®oóÝ¿©z.•éñÂúŸ¾|ONÙ djÍYŒ\Œè‹I1B¤S™Ôr¡g3°Ð7âƒZþ|´;m¡šN¼ÐRXÑI5®ZA¬\žÒt„ðBtBÙ¿ÆÂìHáŠy@¤WWÔ¡M&æŠ1âŠÌ"Wè”ñÁË{r[ʧÉ™O®è;²°Ú\¡^úo+ è¤,wT@+&>¹¢ì¹ôÜC;WL×:¯{Sî'1´þ”„xW|½ZC@õÕñªø*xÿÛüö«+§]xáSÂÃ>á³t˜nð&oV­nSóôaí0ÝÏÅAˆû¼þCX¯ÞÃ`öþã;Â-1C¼+v_כ߼…ÂÒ]¥Øah}¯R0`ÊÏOþ<áÎ x.êS/”R]t"…Y$m ú\Ôdi/Ür%z…í[Da°“ιc"K.9o irÐ,9hŸSxñ¸û ª¨\ºxÐËØ–n@IÈRÍ• ø!ߥ¡W@&y… ^Ûˆ|±–`ðy&`yJr_Ü7žâTä‹Õüý×UGB²á¡RŒ1!kVÞU½ÉA×])Yã߯ùb?å!‘Sðì˜'v«45ù=‚ hž"š¿¸¾™½{õqööÕÛ÷þ½V)½ß„Ý–º’«÷%×`èÞêÓ⮪ðu¨ãŠÕã=2šÚ |à±¼Š¦^¤*ŽAÂKqUy›Û:ª.¤Y½$æÖîR* — Ê©Iô¢ ®[¬Þån[Fy U¼R_c².Ê” 3Õbd>¿Bè¨ZEìã™t€_©}·W%Åß’TPƒ½"V…$IjQ'\•hìvµHª=Uoóo?<~*É~½ø‡S±ÞVšN/@¤nõ)Rä‹WUÒhx?Šã#rì ôN «ÆáÀ¤â8‘D/‘â‹Õzuyõfq¿p:Uv?4A¼xõ‰ÄAjVXפúÉ›’!o>oÖ»Ý2¹úE¿xõƒÇAª‚.X׌0zQWåËË?¿^ÛmII§U‘¸çµ†2À­=*žfñ*.^”îŠìT¨ Ïja‡dNú›ÉœÔ $΋äÿ´˜¿Aù.‘'ˆ¯¬“HŽ·bm\ºI©òã?î>¿_-ÿe‘¿]ÏÝ:ùq 7G²xEœGåp]wãâÎK›¡/ùpU~ü²XæNGïGPOR/^ѧ°8È€¾ÖÃyJýd÷®ß\,>—îG*‚PÈåÕÔŠWè R„mÂ-0 tÞZüÐ(‹=-}(1É–õízy€ z­=Ž/Ÿ‹Èµ†l°H:R‹:!kI“`óz²9w ûªÓj³Q*:Š¶×ƒ±(¸Ä'G£Ðª¥„ÿ¸p›Z C©öó2¹¢V¢5I‡ê'djêNOkŒ=u5«C` ¿j‘’p}“pãU–&‡šŒë ‚‹„-”î“r¯½ÔÔÜ[rV?š<P!º߯Ÿµn‚ñ:ÔáÃ]-qДøTRCFf¹þm¾ÊïŠM=7,ο¸^ßþ†€ÇïÕ¶jç bäx ºCn§irô”àsô±„ÇéfNð£|;ŒPz¤˜ËézÄ»h¢Ú”ƒQ’ƒý–ƒ£xivˆ_6 ‡4J|dg”ø(Ü©³üðPÀMÖIÁta¯cO‡Í=%õLÇוŠê7^<R9ݱf*ÀÌdõ (Í$Ý¥»XÓqÿ3‡è6M¡NýÃ*; %ÀôbŠŠÝ5»0t eN`ÍA-Y¼ABeê~ê³¾úóañÁj]Ðm'.f×ï³c4Â-!Å`ý%à™=¸xÜ\åeäppÜ‘ñ1èaò<æ¨ Ùý§õ}q˜üŽ1‘ákØÃäøš©‚dùò‡Éññƒ&¿cŽ ’ÝÁÎ#€ÎÇ_çLûGÀô®8!:±»8’ 0N›¶"næiwÄ!h)kñõ3"¦ÍÏÁÉ-F²“LJnÕ¬2›ÚÇÌBÚǧ}L¡&SÚȇ‹%þ?÷n¢ÂwÊwi@ÏQx. ç_ªF\Á.1~¤ïT éàÔZeÀÓEõ~iÛ•CwUÁ¨¢(ÃÓF㣮aÆ×¢~»žw#”cdn z0¼Ù'DÖ¾*î߀ŸŽõùfoíYœ?6'Y)DVÿßÅï‡ÈêÚ1²: ~0¬N²Rˆ¬þò§’1òƒÔì ê1²<‹B0lϲUˆ¬_YsÝ@"Œ½Ò÷Ùž€>ÌS‚µÂÛ4…'‘K,*ÎïÙFêœÃ8:~§€wX×Nu¢xfhc!³jü‡ÅjþÓz»‹ç¤Æ/ÆÔx{t\Mï\‰ÿ¢¤ÅÎâ8~ûuqw~þ©dyšÛ·»ùùù—rÍ×›Z•ŸÂóå8CÄçG߃6kcn6Û]1¿Ú¬¿-":ÉdN>hÄ($ J Ãh‘ŠË›E‰ÄÊqÛâA’BÓÃôŒ§aó¤ã`ɪi£P5À;—§þ+Ö& çö=ü€n8ìIàÍ⾸Þå›R‘D#€»æÙ®w`B ‘°‡‘w"HåÔíñªøŠV–ê¹Õ7O‰à…>[}Š:w½‡¬={ÿñÅFžfhªCÚ}fÁìx¤…CÀ¹ÈëpÒÒÄ…ä±–HŸmì×ÖÏžËæi”tÁO‚ŽJôg@;’»‚zŒktïLI…p4rT‚Ñk(²sÙ`¦/¾f“!‚ÑbQ‰D¡b΂b°àÅÁïÀm[BÔc‰Þ³ FµE(­òãY,¬CO£§½2??A:*®×ŸíŒÝIn ‹Ï½ÎböÊí²‘ÊQñ|ßaÊÎ8Ÿç¯°øßÏÍŦÈwÅe‰E¾º5nµµ´ §£*ÕÄÀ+&®Å—vtGÍdZ¥Òµ|Ëõy­žÖšÝÜ´Nþ ’úe±ÝmÖ¿Á˜ ,Îd!vËš?.VsжèðÕ_´{Ÿ6@F“/Òö´5øid½YÂVoÞœSOØ„Jbê“·µîÐYßÃ^€wð–>´Q÷€(ÕV“:G±j%?ÍŒ)\ôUf@ÓŸ€W”쯥 5Mí²VŠþÇ¥®µöYIaË®Ê61¯´ÕW/“®Þ¸cõ2ÝÕËz¬^ÝêiCŒ”²ØäbH]TÊ 6»§Â3cÖ¸zy?{,¼.£®ËÌØmÍ7 °ïN›öKì{å˜!Fªý4Cv¾¹?c/Ï$Æ3Sé5t54¨cÒ ŽÌΠŽ,ÜÜà RYçxv„g¥˜œÔó$:gXð³+DX+`>cŽ”ÎX Pµ´ûp‚‰͘z¶FZ}!¡»ß7–¿Ïæâ Ç¥È×Ëà”äasSÎX·SÖÚiÞ"Š~³U~~˜—‹éþ|GûL=Š 8†¤]¤›L )ŠQ'M˜qŒa˜Û6œ¨>¯”ÑÙqR?Û°oþÞ˜;õÃ4hC¹Hõ'@Òžª„ Sw…XYsºãàôæ‹9,Qð²_gåÇ‚¬¼xO힨+Úæ¢±HùÏ-uR §7OŒçïéϳÁ:kq´Ž‚d>ü™Å£Î1&.úåÅ$!Œµ3Â:óÁ[4·”œ”¤ƒÇ éà1aÑPÒáèA˜Ø‰3çÇ@¼ž=;yú€ºiÞ” ýý±Øü~ü=ôÉ ÈÑ探aì¤?}øó÷Ûêê?ŽŠå¶Ð³†€¤«¢˜ýcuû¤DÖ•ÌåÛ†˜ÙÑÞò”ùþ•ÊqÔ¢ì79!>«&ÄODë_ݧ;!~¢Ë•éð|ÉtøIÛ´ôV8þê^òŸ µ€+ri‹åvw¹‡Å2g£L™ Þ¦¦ËÒ$“lL²1j6FYý†§y m~NCÚüœÜæ§x3²Ž‘ÚVdݱæ7NQ°ÏjŠfMSY4ù1`¢-4Öé¹9:IÜ?w¿ 6yëØ‚• }{òWê.…½] 1 ÝŒ*Ùè%Ц/‚}ØŽ/6YÈ+©·yŸžB³«sGÏÍÝ×Å<émþÍñxØOà>h: `bÀo–ÅvK4àÚÀ¿òщfSOk×ÐÌ#DÖÝcÐýÌ0²¿´m°4˜ª",ašÍJ”nðKeqð7¥æ«]õaÒMõ7@©¹Â\?eþY; ŠJð˜&— ¢î‚°ý¼ÞìªpNžÄxUjÅ 0•š¹wæ-_òå˜N°séÑi9ð•ÏÜ<1G«wÕ=QvŸ¶¹z ëÉ”šcߊlõ™ çV¯I“´:)tC°™Z¸œí˜ÍÙ2â³·dF%¢ókr"…{‚Í ÌH›{Ñ¢MЫÆéC;–ìFCmºwƒ!Ür 4*uö ¶„¹ü ^Ë~D#ø ‡†ŸÃ3q¾®$,†Ù˦}³rõ6±˜Þ7=†ÕBÄ´ŠÄ ¸Ý ¹°ÙÚáP·Í«îtãU‰ÝyjŸRoa%öât[U/!?Ðr_~2åã•ç´â:?õâ0þþ;î±ÿ¬·{k.Ê)¿š¾ÂÕISú±Sê±å÷ÏéßGÿ³Šþ\¹M%Ÿ?—|þÝ`­_ý×®ûÉÈ þœÀŸSøó9üù]²±lZ6á@ãµV…®™™ÖÔ×o"]¿¬cý&ºë×R9¦ÔE°~Ú #Ï€¶§â’¾I¥|¦Rå3ÕU>Ó> 3U)ë›ÊËú¦Ê}.L+L+<ŸKñ|®‹çó>x>WÎ*<ïÈ*qkR^.¶©L£cUÎxUÄ*n™õ*Ü«rxFǨ<ÎØ”g·Lú¡|Æý!p)htl*@ÁŸ øÄ-£þ¸ÞܯV·ë9H:î'R8FÇž4ôÎ8“f ·LùóêÓ°%ƒetŒÉÂïŒ5YöpËœ—[ å{£cÏž• çb´£ãWçEƒÕ»°Xg«€6Û\|{|ðÁïaEÁPô®ú¡èéÆƒ#Ñ©àŽä¸J…Â<´bè¼e2ºPñѺE{H:^hº›®‘ŽeTú›"ÿŒo÷ŽÛ$po' ßEW ¤p¤ªXŒKpuˆŽÊÉé6›«VnˆåÜ}A“Æÿ´¸s®l¼lø`D£‹[(xØî©ùÄ1£>Þ?To7ΠÕc Åø`ÓMCìY=̇6Ðws&¢²fh€×†âÒª2“`‘cæé•é”a›)„³hT*ûÎþUVõè”, »Ãºª†ò'÷y·IA åYø>puSÜ6OC=‚*¿ï}R.}ys¹ŽàGÍ9š2ÖºX.ÊÅx™ïòcŽApÅq |A%VäÿhäUñµŒ+aµ·µ9XDbK:í%oŸVƒçÒLXigó]f†ÈàI1þfeVK2hR&±´Ê32Õ“P5ñ¹$ÔYGj¤›„(2·næ;ûdZ$FìX†`Ä´b›fô’'¸±0f¡E:½c~'ž(âd€g+‚ìÈá0njg3L„؉ÕúIùZ¬äʼnà˜Šàfxgr.®ÞCOaöîÕÇ®Iž#*<’^7|âçð7)E5¼3dþP¿gȺûcÊ»îÅt81É}ñn’û’Ü—Ãu_Ì›ödÕí[õ±_«nÆ~ëWö 4ÆR[œ¬°wU–¬°+<@Ÿ‡¨¸‡+äaŠ6s£h[ªLKÕ†e˜Ôà>¨Á~ ?±.†Ú“MCjO6qØž¬»YÖ™¬YÖd"õÝ¿ï˜;$ðÿït6¶±ƒc½™Y"¨Ÿ9˜Ë(ï'ÇG.è$-¨Ÿ%—`ߌÍÄC2•Æc’ƒÅs$;xK8F—~rc Ð{·$¬n??Ç;¦±cª#<[fò‰ƒ¦w³~ÅÊ)8W†"*äåÖÅvµÛë´6”ÆÒPQЛ~yyýþã;Ë•v : ‘ ¢ºj©¾žª¶ãüw• H‹½.vïò{ó½?ì²çð‰"4ú†ùÖz=(½2›j–4 ™•Œ´©ù"ô;ˆ#Áú³1@¤!àpœââ~&ÚÜöa€¼ì¡÷ÄþŒ;Ñ&ÉZ$€wåÛßv%"ßn#““ö ±@è·Á‚´—Ûëë7‘ñ~ïž)$Α2|»'vÇ­RÄ|^±R RýPI‘½3#]¬ŽO„hŒ?§: –T h–Â’Òè}aáT†D5 ¸zÜI™‚þl±‚°†œ+QhjÈÙ„{ØdS µ±«5,W;q‡ÅI”´'9×´•ÝÜ4ç§É]¡Lîª%ÇÀι\Á…0·k ¦Í.VÇö™Åu¹ßÞð.ÔÁ›dò€‚hlis™ÞfSýʱ~Zo-¥õ Õñ Z)<#/å“a~YŸ=Èó–?(Pµô°<¯S꧉‡V¾‡){ j¯×d‹Œ‹—ůwÀt\ïæëÇÝåöææßM+DœÎQ™Š©0ÙŠI„”DûÕïDÙgU”=’FÙ:±ºWkB`;Uƒ0ÒÉ#mÔi ¾ìüœYo¹èÛØTG[æ7m»yÎöDÂRÚ““À%dfÍUð—ý‘høKø²\i_Š«Õõ!¿öøª·äVDW”Ù þ ¤õÇÅr¸b/’"$Œ=¡p‰ ú0 oKÌe 1²vŒ1´ x…¬hÆê©}k7ÎÀZô#~Gu&¬MAö8ü×zöËŒ.ÅÅ©VW¡ÞƒÁóRNÜæ én¶ˆ–Çi1±¢Ç„)®ºå‚.÷WIŒÔoì’?L& ¨å/5}‘ßÛÚêÙ¬èâO= p‚I1®žè]˜bŠ"WBK°ñM¾ 4æÕ öÐÊtyµp4þBϬW äW³¾ù¢ýÐÅÑŒwM~õ­¸½^ßþfœ‘ñƒ‡q1~J 7oªø·FÉóâ':ðjëwÍÀ/;ó›– ¹j IP-!Ï}ÎqCÒ/Kd‰h´,±áëKÝ6¶YKUÛÜç(·n"…7ÉÍÌyË ·rÍOðˆ¬W´'·•¡6@<£˜ØVSû/–K? Ð*×*ô˜¬óî£>½¢× ‡ŠSTÏ dgíªœ»sV³”°u—rW²^ÃŽ• (¹Þ°áÈÓãÚ"ÎnÓµl&w qg&j” ¦Æµ,>¬Š•ùž­ÊƇöäñ'ä°–ÆãoFĘÚ\Äõ€ç>¨G)XhçNνZ7Ö ÌeµÆÊsjb0ž%‡RºQ˜ZJFçåsOíÎ(í$†À¢’:.•ÿŸøNpF€ÌeóR¡º ¤nˆîô*Ñ*e:«”é­’ ¥{7ØNém«”ùZ% ‘Ún_¥L3†'¦×01|ÖÃOtcxÁüšnº°Cl áŒ,og\ hÑO«Q:Â`^2\gP0?¡BñI`^þMêv¹Þ=ªœl……’øcb.ÐGßgô÷û½·1ý|¥jõöÊWB(dªA†»‰dCÍï<–ã ËLŠ¥Žcnè¥ÀjsXfR,³ˉK'3亱d šKnŽ\å„J!å M´`r{e¶J§Æ2öÍa&‹c|gø‡ÇOo«ÂZsôüaûÃè!mÛÃõ{ªÝaô§¹Íaô@{Âe1ß}âm±ÝæwSEÆ~ðPžÁã0× ÝÙ øF¹åÒŸYs8(º ¼ \ØA¼#;¯IXåÞQͳQn`·Ó(¸½kÃà¶m[Ët÷1Ë(h‚‘Ζ¶%Mæ¸Àr˜œÅ–cX³¢¡ _¤ï“¦ß7Mß[cì‡èh@™ØÜ-î‹’CêÝÄãúœ+{+ÞZl9˜Øâ2*m#6q¯s—¹«m¹2uÇ'€™mê*#lÇÇÀñÊä°Fë°vî…Æ)È®Ìôð-ÑvÄÙœ%ÖÛ²V‡â=ÇZÛSûŽä†"M‘ QdBÙOl"º\*<§x§±&l†ó­”(—jâÃ¥Òƒ™^~ëŒVp¢ìR §ÈŠc°Óc†½NªmKè¶}K—›êTïá‘Ýð7õu'a»ýCS®Ÿ¯ËÃK¾]>Bòí’o—|»Æ·³ï$À…0õéô³ï!o&Ûœls²ÍamjX¢ds\Øœçá¶=t±Ù˜lDœ6¢¯® R©x蕈©Ô|9dtÌ4¤Ñ1;£cÎð¨!"ÂÒLf~ˆÒ…1,g’²Óf„)JƒfT°¡UfÑgÏNŽÏNì`ñ|À¸÷kÒM·‘Œn ƒq:âëY;gáèRÑ"/„F½©õ²Ã¢žh•‚Ô…©šDßIó¤N D`u/ëD´¬ÍØ)ùOÒ±Àdœ^oöÃÉ·+½_ A7“eb&kØLÆp®g“‘°÷K†î??o΃t]ÀVž²þ¾îºo _À¾ð”IœŸr›é†_0ôyº÷Ÿh~ÃÝeøhÃLª¡ýr|4¸ ½t^ÙÜc:í ¤Ã×”W­®oðÞkÞ›5R >õ¢:.ÈìÊPź¢ŠZ'}€Œh`•»éÑÙçœ_'…Þ2gýœ:ºiÎ?‹ÚF³³âЮ¢@~HÃíW ñi¯ ´ÕíÇ4À¹¬óO­%uÿQ­ï4ÐH2lu„b•§­ž@Æ!–tpµžlEÇ1+ðx2yc©Ž>ÂUÂJN¥:Žc˜FÇϧšTÏÂß=%ÔœHò`”çB»-†÷ëbçËÇ<Ó}Ýwi¹Ñ"í…ÝÆ¸$«­J˜0m¶p÷ÏbK騽6¯kM“ [­;¯Ï°•ýùažïŠ›Åý'sÈšNè83R ÎR8¸§Á+Îڑ׈¿ú¯Ç|¹õâ ’4›ó(ù}º.]¿á¾¤ÛVÓèä÷¢€Ý]SìfaÐ_“†óÔZØö×Ì€+÷רžcÆÌÃiÖrc¸ÃEÛ<—s¯1-¯‹ÝëÍ}¾ó¢(ƒhbÖCÖT‹\#6x8ó *ÈïíW¡QpþV€Î¹:ìß5ÊC§€ŸrúÂlÏEÒñ¦ø–”£¦r4‹_5B,’bÔ¦PÐjÑÈ­JªŒ}V‰ž²?dŠâêžÊ±I'Ŭf”tƒèºXÔY -% «Zè>_1´p¥14Û©€RˆUÓi@]Eš‚oò;/¹Â·ܼtZI¾=Ði‹`ušê a¥&¤ «%w]h5ðJÕ·Èë5 GÄûyÛëbw±¾¿ÏWóè6ëjJ×y×¾›x ¢ÝÄ#Pp¿{YבèÑÓÖnÌqý·¯ŸYLx¿ö™ð6"úyç<ö1‹‚vÊÚ°$´1?â­ K7^ûKf†c ˆÔd”̯™”ôe £k¢,_ÂÁò@ýu5ÓkíÄ“CÝßRè$(°GË)ª¯G_ÉËëëôVA8ª®÷•#$5oÍZ&ϧðèe8 Ï[uóXÍT«&âð¾Aù¨ÉûÜÊš1y­üTllM­|\mw«bŽÇ<ޏOKE9ªu¶ª6窄zxç¹O`m„ú¢†må‚ñ²îÙõ55{Vš‰ÔCõÝQ³-Íå´Ú$.7n DY4j)àÜYш(Hëܾ­ü«J©R虇A5o~ è0Ö¤8³}J+¿(Q/ˆ¡VwãZÝ|´º#™»O§»êA;"‘ Ìq$°ÜªÍˆš²’ÎNq¤m’6ŠóÕR§nHGòöª™ à~Ró_¨Kõyù4Ø ’«<2F¨´“ÓsA4–æâ^ºnñ¢døkªkÄðúú»91ŸCÝâõv6•œ ²}Nœ81P*;¾ÝÍÏKùø¯Ç‚ˆ¿??¯¬"à ý´ª1 VÎαq(~.¢pGÒ¦[dàöôQ+AÂ;}d\i‰äôQ…’Jupv$«wTgºÕÁ’Ãã­dbÏbQlb¤Å…ÍÊQŠ ½LvHL<¡í@x¥géd2ŠHè=EampFÕgí–Wó ,´½ØY×Bû«Ç³bX[íj²¨É¢€EÕÕÉ&”¯Ùp¦j¯à9¢–/SZ”˜ÀN\<ÑÓ­C'ŒÓæm…@ôç™] Nèð† ”Ò‡®Ò ”iuuÿÚÿé». yþÎ8Ðy¯Ñ },³™–Z]à 5ãl±©–Yˆ‘%P°Ï™¦DN¤™uHäDW"ìU(ÅŽ†B"µFV½-îmÞ'9{*ö¾2qD,Lo "œ–^7¡®›ôˆœ‡¿i˜Óè#ÈÖq¸‡‘¤Á[]½ää%'/p“’œ¼ääIz§u\zî;o4«ôê[~»K»ØQîb3+¸76¼Á(åàU f.Þ0Øû¾ËÝI®`w»ÍC®°ëͼ4í~+Yø´ n{¼Í.'‹œ,ò[ä¾:<¼Ýrº´hLÖS5‘AN½î”&n65–-m ²šGOØ'‰6ó§ìEÓÞÚ_wÇþ|b׊¨•)Wûððç$6“â¸À*¶,­zýR(ο9ˆùüll!\*TfB¶‰XeHMHUT÷¡hWE=UÔ²É.Åݬf&¥s i"THlÛÒzy*&ÊeÚ«QãT,Ód™öëÓ8õTñ©.r|Ú4N»*>%; ¢4Ä)Óµ¶­˜Hf¸M½( On Ó?=‹ÝO÷íÇ^ÝÚåR'g:9ÓaºcÉ™NÎtr¦δ5',9[Ü­IØÎ–EW*’’Ô!¹A±Òä%7È€ÅO¶}˜mŸ†bÛ]O°L ’-N¶Øäù m¾ÿeù3ÝEŸ‡Ô]tj§»h]1E6­Ì—J À4%tgŽ»‚>wˆ{Ëž!íÐÑ+”íÚñÒQùÒ3I)~cç;ù·2ÝIeý¸¥XPÿˆÎ´Š¯IµÊ³g'Çg'–é;Õ£o}ñq÷ºŽåëªðFÑ;•VWÐß·Yß½YgërìúNú®ï$­¯÷õ‘[KôLHôf/å„|–pbð”03`Â*Ì8M̘˜±‹;À˜p¶C=^ Jb1–‰)ÝBâº?ƒÌà>ü8NdÏKœ²q³Þí]—Óg_vÊl£žrUlF?ìizwë1¶È ü°ˆ¶Š-»¥©™bLéÝÔg'õÙÙÿ=W­61¬¡Wõ5L-÷ª…¢¸d.ÌŠ‚ÝnχC4¬#càgR^jØÜÃä&÷0r÷Иk¢vmAi3u#ÓêF&vêFÒ>lËÖ‹äXißì~¬ ·xÚrvLm‰%›ži×=&iîÆ6kc0óë‚ÑVöÖËù×*᳚t¿:ÔêƒÁ›Ô„_ÊmÆöÛ·Öxb'ôÚ0VàÐ=d¶•kàÉ)³—:´tŽO§ÍjXI"“ïK¶/õeG«©ß—=%ÿœ·yf×o¿è¦ÞîÉ–'[>\ûïÿA^–f6f&!mÌdé@¯ç½²/é`¯ : 7+ödêøÊF"¦]Çh÷4ÖY’¨19_ƒn(Cßx)ƒÒòòǨÞ6 /}Jÿ¬ûëb‡H÷Áôãj»¸[•<äºÝÊÁ4uk1ŒëËŠÛõ¼è?6­§ŸÕ^õ…~Ý6êš@C9z–µ½Õ‰¡ë…Dº´ gxÙg×׳ò)8L ¢Cõ J zÑ‚ 4I­èpô?꓊þ(†þþ¸Æ¨‰=Î,C’ãc†Ô'(4%äYƒ–àÕ®ˆáGùv¯´À8þä,1x(ÍvfÇ• S.‰s}ÔV«•ÔÅÅrÖÞ ¤&Œiž+EÑm›.kž“±ÏíHzq€éÐgg‘R {u¬ãã]¢ô“í©¦:;±[ŸvË2­d31ãŒãd´6¬¤¿kZQ¦Ç9-»sRÊq{[H/µ+Ê:ᔓ5-Ò¬>Ǻñy½ŸÖ9:€\CÕ‘Sæ†HÉžyT95ñ´Šzàæ²aÜÈ)vÚA‹‹Sû7§Ç á“›ÂÙRmG7q˜Niü›SVi·ÇÃèêÁnSÿÆ”ë2ÄEQðP’o’|“ä›$ßÄœM Øv¥y{r"¯e+ƒÐÍõÎ àý ¼Ï`â0Vs¶Næ±nÙ^žÙ:ÌõVhI©Ö ÒôÁ6Ù©þà ;lU:ý¤SÆPò½«_ ¿¦yj¿=·ëòÁîÃ<¥(M]Ù¨8='éB¨ØÂ&ºÓ˜©Û—„ìe¢øÐ¬¯x¹}uÿ°û=2Æÿu½^ám„u¤ì¡÷Äá€ø'R>Ç ÕÂêà4£Ãõ´ÉæË"ßDÆäÚ\ ‘Œ”§+ØÀãWˆ9µ q)WïØ3^W.ÎÅúqµó·¯.®ó’)Êü«\õŸ]^јÏ"÷4D ™\¢=È#Sè8²+…Úé`§V¨æq‚Тd1)ò: atCOäÙL+‘C:c‘F†»Æõ°óK¼ºÊ¦väN=¸­ìaÛ/Äê˾ê´[›&=šô¨~Íe»j W«¤“x{r¯#AÏJ§…L½0Q-´`{tPÌ?Ù[ö+Ç®Þ,a^¬´5Ñl#(oŠ ãÉŽ‘pÞž -iCN¡¹Ð¼iÐÑ‘Â!áDYÞÙÕ×¼»›£÷º—£g6ÏJñcWJÅo-¾«Û|.“î¦èöëânSÜ-¶%Ê„B•)É÷>)y«¼¹ä vÄ.7år¾+¾V»Š/ó]~,â@x)}|$A+6øG«â¨öFgÛÙ¶0®0ˆƒ/P_Ô­N‚jœ£P’´2HÖ…–Õ §ZÁ‹£¨O˜Âí¸zÞ´S&¸F7†Á͹î6È+Ô›ÀÓ„rÚ½]fššfwîÝ ¿¨––Ú6knБ˜›qˆœ+¬;W «ñ%uôô踃þ·Ï̧yVÅWÌ×¶6òÖæxWÕúeâU «›š‘ÔÔœu˜š‘®©ð4H·gïÛб°‰Z½L寈;¨Ä¨zë°Ê~½‡6{÷ê#£Ò834¢ÌШ‡!“?¡ŸÐß'&«¤¨ ìLË‚;\ZÓú×Pr}Rr}d'¹~†@e\ÍäÙçŒDÙâînKg²nKšéàvèP_ùζ¾YÎêîsäHŠú I¯ÕÏdb2ζåÊÍ¢ôÔ{$/i¬£ôÒ1ìnýt†]䂟Cq•çDøÌ¬ÌºŠf9—2à//¯ß|g™—idœ°2ç Ú,ÅuÜépŠ?Lfí¼¸úýízþ¸4çç-µ{VýY'Ã/?\¼+v_×›ßê„ø1õ¡(mηW¢ÛL]”¨\®>­ÏÏ_UHÝ Þ SFøËžƒ76Ÿœ¸ú½”¼ê;ñ™–¶i.³qˆà]«D_•Qí”®;› ^ýû¦ï:µ¡©&Xôç²æ[SÉçÏ›uÅLÚ¿'!üïœâxiW-øsNáÏçC·TóÛwMhìºS•Hªî VW³~ÉXL†"Ø"C#ß]ÄÐ) ortƒÛ6 uG’±˜$ä=ˆ0cÍ ¿³o:ˆÜÄÓð"›ÒkjÑDºrYÇÊMtWNÐR«ƒl‡ªÐWN^d÷‰•ûÿÙ{Ûæ¸q$]ôó_¡î}ä^ÏÞ–ªdGh6ú„\²Õ¿iTêö½»w£‚®¢å:.kÈ’mÍÎü÷K ‰—ˆß@Šãµ„ ñ ‘ó 6 £ñºÓ4^÷D¯{‚×=A·È‰XCˆ«H»'bÄ.Lq’ÐÝ´z”Ú¹‹šèç°‰~FMôsÎDçT§ÌB?ÇYèçh…=–±0É@?‡ 4óµÏÏů‚Z$ÎÙ‚“™P}à Nž’GNÈgäÇ󺼼y¹ð>|à T`¾)—ojáë¯þ&³xïL$t,Ö¾x)zE¾€a:JñíxW„¬†š‹®Öx \…rÚZ4„)u-žPl3ëÀlï;ïZÒ.ž5_`•@,ÃØ£YMô»Sçµp¨_ç}¬Å®}ž˜ûÆœMÍ÷n‹NÌ×¹ÇýX¨H‹]9ëµB÷iï~‚z™i1f~=ìöì4ŠèqÇ–ëÒ‰™f)×Å\ÚÜã´–/¬ú8 ˜Ua-L%Çë÷H(ªÑÉ àvY˜!QtµÚÖÒ 'GÝãäýöEÔ0­ùb}å—PõZNFwæžv"GNÚçúùà¼öÿ~¿Žß·ë>ÎÕ{¹¨„÷w©*Ý÷|©‹9<ÎVwãH”0Œ1VÅ©1v1ׯ@LÐâ2¾õ·÷7ë}/;u-ŠY5ôxˆ5éxAÌu.7—Ãï·q!¯BŸ T?êˆïÏâ2̃eM§‹žk%x­®à² Lªš¨[&»Y£ðµjw¨–F~qKnÚ=Ÿ6ó…Pÿ•ÕWyŽK g÷Užú‹ì)ãÕrÑË`5„ªœ \k²ìžĦt%ðU2U(¢[ªòLÓøê&&íþÌØ³ÿn·ñö¾ñÞÊLîÄ•­i€ÄÔ$ ž*wFF€Ô‹£$`df  ·ÓÃs?ê+ÐùÌ¢’5|ÚPR x>ñµýèº ì©>ÍÌíŠï@Ë,΄Â=-ûàó ˆÜ¤5cåJ™Í¯_¥·D¸Ïë'FÓ\ñÊèj823;5¹GÔ)þðyJmÓ¸fëaìÑÑM~Ù»sáïç÷¯¼[?êáŽäd´Óâ×¢˜Áõ{c2¯E'›’|³<9ø‰Ù¦Ì{[]1ŠÑ~µX|;GÞ¤DqËú«EüÀM:Y§¯\ìS±·ÙKÏ${ü¯é¸ÇÄÉüÙ‹>÷pôY 0¦Â=`l-:8âÁöšÎwį¢ý#ëµyûÝm‹jtÓo‹ŽÓIǽ¼ž¯£˜àmã þê±ô^¡Ú½îÂb]:éÇb?êª3ÏaOž ¥Ï:ïÃ3W:p—`º ã2p.èÃ"¥þ ì°îåYZÜô›kßæóWªáSÜÉYÏ7O»EfWÑ·ê3fÕC;Uó—¹!´]ì–ö|Ä­n€¯µðˆý÷ d}è ܺ/¤J_«ÿƒ`ZëlS•&J2Q•íÕí°ŒQV©Ñ"áUÔ”YmO6²Õ¨yt\|z¤4™fǽ4¾¾O˜I…®Ö­tIR3WëÖA®Ä˜I¡5KîÍí­™ãêØ¢£•H¿Ñq°£±ü§=’JÃVðôÇŸ~òÓŽ^ Hn„üÛ½>ÒÛþñ ù4³ÅË)’Ùà¥#å§ÝŸÒÜÿ:ð7‘Û&šÞúþêàÛå¿Ó!¤½Õ‹ ¥DW^ý(|1¤Š:ŽkWǤ5uL¢wëå—:Õ1©]ÓÖÔ1=ˆ.Wñ/uêcZ»>NZÓÇÉAtí{›wÞ/ªÄtiÂMÉix(˜ü±^ö“$`Ë#÷€³=¯Ù§Rdšˆ™ øfÍÑ1¾º¯š$u‰3<ã3<“2<ç3ôï“'˜Åš`÷…ÞâgNº™Äú:ìž"ãº]ßT©r$ÇTb{ÒhQcßTj¯DùVÍ1UÍ„?Ouë%ÖÎ/ ÝLpº)9BVª)p—Ñ*ò|Òüq¤:ËM瘲6Í#†qgËHIÛ;WVªé¬V2§vx°¬ž{Ê“e)gàN•AŸIÉ&àÅ|¾ 3KkßLAéBü‚ GÊ¿œÂ³ æ‹)9…`4’DÁ'c¢…gJ-<ÃjáYE-<´@J*Uþ™XyßW%gE@Ÿ¥u~®¬3æÓ/ôju?Öù¹ºÎÏ…­q pÈMzO¼ôàk4Ù•F_xixƒåý®× —lMrâìš$[H(—"]-$0 ƒS¡Ë rç†Ôk¤üe yÄ4Ô‡£Ô¾jY‡DçA]8GáíKY™¶g„­uªÖY¤ç I“XyAÒN’F(Ž1넎ûÁHÈFB†#dI§$%Kk6’²r•¦<ùÈŽKLRò1U’ =¤Ø´ŽH¹À³S‘yG"¦ÌÉg“K0\Lø°Ä´äÃ3ì®%lL¡‘Š9ô‰úÊL© óÁ§µ(ª9À£,ŠšÖ}€%¥×Ðb eÿ ù?ý;¸~¥ã„ûJlj~D@/4®½o½ZkÔ~ÑX}ë Æ?,.4+ŠÞùˆ³3Hq^¹‘×iå‘R{µBœc÷‹Š"øæ´—Y´wRB{§XÚ[²PëGò¾ºÄ|k,6IòÛÇå‹Z!N¯`j,¶¼ˆ)oNóÔœ¤»*lË}§s6È‘«¿É†K·ìaoÙ‹•6€ûõH-Æ›õÒÜÍÞ¬÷f½µ»VŒN'/Ô›Ç/¼fÁÝ·íè“=}6 œú`JøúŒF¥ £’iÛÆ®ðÃ×I ÿÒWó¸âªzÎìÌK¡»Ø¦2­“ådÞÌÒrò¨d9yŒ]N–oe+5%9½\ZPÖZp:^Á%%cTÀ5¢É—SÀÙ1·";¶Xû©lLç» ¶Öþh9-,gªºaNZ—ÑnÚ*Êu³Y[¹K¬&µ'Ã6š³›ÙÕh2mÈf¬¸a̤&£¹´S“ëÆ²¦R—LbEl(ÿv¿îêÃ<\äl9‹’h¿:=ý¿+ó]ß§I¢·ÙKM?ø5þLJæÔ„ÃÜ(âk Ð›¦ãkŒ ½`êIÓ+Chúió“*98ƒ>HXoä ¬]ÔŒ*Tä¸ùP‘Ê…õ0!>æÓõD9]—L×ìt]÷kH ¤qi®®©ÈtJ‚DäÙ¡dr íŒ~Nо­oãÌÑ®8sÚfÔ¬U1ô=u:Ücš«›'Å0!HÀÍc8.eòèXfåJÃ]lYå„ã„e> *É>«¿ ÍR‰öG–ú(YjòEÝa±Ô¤J#K-W‰£,µraÏRa 9ÍRk*òÈR ´: –ÚvÝt,5!H#Kí–¥¾îK…î¹kú좆Ýr7¤³‹¯ut¶Ïç_¤ÖL%Ž’ÚÊ…<©…5ä4©­©È2© ݾ{®·s÷îU(¦‡¹sÏ|´¹sšÖÓ')k*²§9EùËó›8BiJ­«¡¬þ&4‰ÿk°Þ’.ß ÏÙ92n̈‡w~PŠêvÁeYM\&¼eSn½dW©‰Bjgݘnµ’ªi.7ñ²Ñaúã[™Åqòà)œC> à>¦–ïXªËã`îAL(à?è¯uÚ„¶ï3€Uâ¨Ï raQ>ƒÐí™`e8wS…bR³kv?¿Ák–Äwr»ylo] {6¾fÐ ]!-;°x‘¤Jã4Y®G§ÉÊ…Ò4 +ùi²B1QÓ¤¹kÖ aÝ8}YaMEö4! ¥PÓÅív5^cWýz:[6u¹ýºÞwu?qèC+ uÑ¢:|¯<1Ji0¾Z‘™(ÅQbTCqQÔÈ|²u'ê@¥#§ãj+´E”»Ôé„„Ø(­æw7ݼ¬¾ýi;EêùâþSÜzó}LTœÚáœÍ6kÒAáׯâ–›n0“8P5—'ôvwTM”ãÜæjm…Æî³"}‰ÅiÏëa¢Ù¹šÅ½ 5[ã¡Ö_ü¸où4Lj¥ Ým¥¥}¹]p'à´á8ýÒŠ“¯¹jžz+y¨¯J)NO» Ýì¤K§±^L¹Wï|¸ÁõI׉mÿ¦÷ök™¢UstÖÒ *8ÎÖå8<_W,ôPglµZœž³+9kÓšY}5eRûWSȤÕÎWS¦>Åv¯^³5ß™¹ ×_Ý 3qioÏÝ]÷€Ü.ƒqUsšt”NU5G!¨GžÁõSUñˆõ[C=ø©ê¸òTu\ûT5imªšT˜ª³ïòŠ;iö7ÁmWÇÆ*}2Ðt8UT™þ~{¶-Zy†”1}§“S!iÎ×Ñ2Ønã<«õ@7f*Óa_fºR'ú÷ÈÇoB[ÜT@7€› ²šŒŸqmœåUù6t6R¼€Ž|çÚßm\2&œîú8mÆ•À×j´FmX£›ø/Ú£G¼ëG‘wko¡ #èð<+èh¨[2Ôƒ³Ñ£yÍs_ͳë–ùlIT5ÚælsªêAYgZ¥Ñ>ö¹‡ö™Ú>Ç-ôÛ¨«£Ë<Çz”m&õ óh˜{h˜‰ÉsÜ*¿ âwvñö¸ sªêAÙfZ¥Ñ<湇æ™Ú>Ç-t‡W…?.û<¨;Àó ¶¹ ÛL>lýÍhœsãüÚ°6̉ÉsÜ,wxÕõã2ËŠ›§ûk–Û¾wz4Ë£Y®3'fÏqÓ|ìÖËÑ6·`›MÊ8§5­óh»°ÎiﳵͩÝëƒq¾öÿ~ïGNñçþ `58“\•FãÛ¡ñÅ›l;{¼âo÷ëÑÊXY¢¹X—¤*£UiêT]^&ãÕIkÒõA­¾ÇâîÚsxç¸:9ÃZz¥ëçÔ:?eÒå­sËêá?¸ò(WÈU&˜^3#÷ÒtxÌlœf€¶Ì,“WhœdÊUâÜS±¨ãÓü“[o‡gâùql†qõCÝ=½±[1gõýžîqæ2T‰s3WÅ¢¢f®Ðíu«UáÜǺ+•šsÌ»åmÛ•–´Ù\Þ‹k¶;=¤?®lÁÖÔÚ¶ýsüŽsRœc • ;®pÛYáºá™›mÆUn­«\åüÕ÷uî8‹!”âÜ,V¹°C[íª”áäz·RaÇo;+^™¸»æíîÚ£qÁ+7Å V»-ߌä8IPjÄ9†P­¤ã"·E®ã—7‘yЭ¹e\ÞÖº¼…g«¾¯mÇ9ËH#ÎÍYÕJ:´%-¨ '׳ö%³í,fžáîJ¶Ó«"ÇÅ,؃Z϶›¤ãô@§çBåÂŽ Ûv¶î_{I¦Eçf›qy[ëòV9õ}…;Îb¥87‹U.ìЖº*e8¹Ú­TØqÁÛ΂Wæn®y»¼Fp$ Õ½…}æ­ß\è8íPèÃ9ÆQ¥œC" =8Ç3ª”s¤fÃþLéL7¹ÅÜãÖšy»³¯1’÷qãÔ'˜ŒCe¾sþþÅ_­ÁÇ ØØÌê§z•àú: R­_d—÷‘Ý>LºQö÷“_ÒÊö‚³(Öâ‚fɸ@ü cdT“~=Ó¾‰Æ¤¹•Öhl£=k³S½Ñb“Z”µòüÒHèðŽ«ðÉš’ÑÇXPÀ4 øOÊnè#¼QM†8oU™ çÿ-¶ YwXùï'eÖ[_$‚½•¾NÞí’‰Nô™Ð‰: v‚wÕIžÑ_+¿þ5žù‚ ¶íiC f×S¬×hÛ«©«†½¶ÒËV=¶´ÁâB§Æ˜®òȇzvú¢oÓª5—¸f"%MkIªsP,˜ ©$¯ 0uQ{ Ï[OÕ[žW‹?bSzØ“ùéf}ç‡g÷û Ãoæ^Iäò¡‘œÚoÂæ4<€õ_—…eΧš…z½H–Yë„jÃiXCyÕÎCÎÅòü2ç gœ¼ÆûåÝGµòWüÝ~„$.À<0ŒiœÝøw»·÷Ûèa6uĵAñüTÌ>µ6ÔØ= [‘`ÎåÖØ&PA—<íÙyýHÆ3ªÚû:Ë­¶û¹MB-MVŠÌÂCX)—¬'Ø•bÉÒÃD_ÒŽK‹ÅF*@'Þ 8…G섎Ø)?b³™H7d§¸!;­Þ”SQù„©³S7ƬqÁé¼ Ú‚ÐQ;›àßPº,WËåûgö¾Þ ·žX¬¥Õhbx¶Z½ó÷ß‚ðKG„ðòzF 0žs‘Úd0_¦J.³¢3¶ÇÍtª‘¸ 3Z:¤e5YÍÈX£0žIÏ¿$ÄöÅ*>„1ó€9Oæ4G磹w9=À½Ë×gœ`PÚqtŽ©¯ÔÓŒ‘Må­•“nß¹¿]ݳÍ:ÖšKa³´HÕ¸} ±ùõs{¶EÃî¹J_œmœ DoÖ[è(2Ò=i±öbÝõýD%OD‡AﵘÚ8hÑZA.þÝhîá »ÃŒ>-g<Ϻ4ûôãkä¹ê@ЋºŒ³C‡³ƒ©]!ãÕI>{í}£Çp;²'ôíÃu €Ùa*ã²S€–±=€N/ÒÂ:ëòúê(¯Ú i¼ €±GNÚËw±šÂõ²[›Éb¸¦“¯ç̧P!—M(_Ôö,i™Šäãìü`èШÖ\tµ}Ç?ÞÌ fÌISû·ûõ¾[;Ë”@0²Ñ~uzú5Â<Ìùi’èm6ÁÒcÓ~ÿ5s¡‰·íø¨£¼Á¸eÙ:¹l¼™r¶g¹µÊ‘l;¶:´ÙµZm­9+Ä^ȶ¤Ä”ÐÀYôsB€môm}gŽv…G»ÍÈZ­æEG0ÚÞ:{ÛQ=):·˜øÙI•FkÚ¾ø‰Æ?^~þÑ©˜MrÉQÇKº¢#ÕÀR Fyƒ¡l\¦L9[\$ê”^xæÕ¨­Ðš…!kEFªa¤ùaPŽª¨£ì¤:R¬¡^wN5^+©Fw®c;ÿðkżßÏÿuOfü×]ÌøZåH“çk7füÚ ­žñ_+gü¿ ±!­ßK®rèÖð1%è¹ácj2ÃÇÖÆeÃÇ”³=çUŽdCØ.Þ¡á«­ÐjÃÇ f…ácMNw†/Ôïc1%è¹ácj2ÃÇÖÆeÃÇ”³ÅoÖé”#Ù¶‹wùíºº ­6|Ü`V>ÖätgøÈ:þÅý§XqWïa 3m4V Töl$\/—­eë–ÒPE.Æ¡Ö\tµÕ¬+›1'C¦ÈW9G‹Û’Å•=‹ ×k´¸x¹hqk.z#6cNZÜß#?ÏP5mjy-ÀÆ +B7.ZÕºÊ܈9l”³vtv3»ºöw›Ž‰+)Æ£°¨¢¾bW¥j¹l]™ÎÖ®…-×’|÷?30:¶µõ–^mu9[`gy%«æ´ýMok¦wxVw4¸¶ rÝÖöÃÌ:oaÏ–¤ºµ±\†me¹ªÄÎòurÙÒr%m×Ö–(I2Zü˜èØÞÖZxµÍì€Õå š³v÷ÆÿÞqS‚aÛ\¦¢±¸l\¶·L9Ûµ¶ZIæŠ [ÚÚ ®¶²Ü¸·³±¬ñrÖ¾ âwúŸ¡fË0l+ËUu v–¯“Ë––+i»¶¶DIò1bnLtlok-¼Úæ vÀÎêòÍY»;žªjÍæëЕX#—ím'¯Jäêá«Z ®¶²êXÆ6Öð|V·v<¾Õš…Öé.±F.[ØNNx•*ÈÕS^µ\maÕ'½Œ-¬áA°Ž½³Á®ëµÙ" ÛÆ²5ˆ‘åªä²•e Ú²‹V«"ÙÕɇ®´õ]ã¦åÆ¿¥Ÿ–5cÎ[—oÕ˜©UÝ€Ý_K;Þ]EA®Þ]kÁÕ6V}¶±‰•n/vÍÂŽGZ¼ñ`xÇÆ£ ¥wôöØBOŽ,ôã¸9!<Wh횃aWk4Y¬‚\µ±µ¼1+/'-,¹õf´°­]Ý5, +Öh´°X¹jak-xs$V0^NZX2 ŒÂZå±C;&×ÉeKÛÑ0%¹{ ¬ö«mnåa²AsÒî’Éa´»­²Û¡Ù]¹N£ÝµQ’»v·öÂ7hweƒæ¤Ý%ÓÃx·5®;¬ƒ¸b\¶·Ä-U«qk-¸ÚÊV<ˆ+/'-,™F Û«–…k4ZX¬‚\µ°µ¼1 +/'-,™Æ«Zå±C»ê@®“Ë–¶£« ”äîUµ^ms+_u 4'í.™F»Û*»šÝ•ë4Ú]%¹kwk/|ƒvW6hNÚÝñhnKw`ÇrÇ#¹ÔãìqÜ^ÅuÿîÜß®n‚Ùf+®[Û:x³ ¨zÖª•ËF¶uûj¤ ¿#VkÁÕ6¶‚y…Œ—ÃVöòz6šØLl¡çÁØW¦J£qEiÇ]ËZG©4«ŒµrÒ¦ž­V䆎L)yµ`Ggó}¸ÞÞ&©¬+Ÿ~\«ÕåÍ.m ÎÚ&?ûis³ú¸ljIÛ³³JH†*ÚÖj%UÛÓtÀsÆ”V%õ?ìþ’üI‡mÖ–Is­·æ!õ?ÿüä§]Ú²‹›¸h»÷ÇÃ)èq«ü’ÐT‹\ç-œ”›˜œŸvþ5JsÿëÀßD~žÁ¨>°õýÕÁ?¶Ë§Ö,HmˆÊœDÉ#±íø‘–í_TFóKf¹óù41—®M.çþÆßûnÍ/âé…zÀЙʌ†‰Rœ›3*5mÙHÆ9ɾS§KÜñ¶q†Žl供̓å—ÜL)O´œü~­o·ñ<}Â=i½iÍ–&L²†zÿæüý‹¿B/{ë4Ä_+Z;ãçÓ =˜Ó}!$ƒm|€õ'?'ý´æ|Ý3è¬zh_/ÓNÍ1zíHÆ2¦ö2`Úù`ÞíÃd¸g?ù%e¡ìˆ;‹bí-hʸŠdÈ4¯¨ C§T5©¤ª‰¨*Z™e°öìü’jŒ–˜T ¼”Õ£Wj.;µ¾qéÿB{@néhcÅE^d–q1Ÿ/ãHšm7±‘P÷NAœ>P¥Ý¦BÝysžVÔñ íæ¤ŠÜä,˜ÿ_óÊ19Ü䚬’?If´§ä 05¸zXüÏT‡¹Þ¨ÚÞùßâÉ ëð«„f$í£ç H4Ÿx¿Ç_½ n×ÛŽØÃjñé1œ@¤vP×”oéÉcša0Þ<¶N-ÎçæsÖ±rÎ:*™³Ž±sVÉô®U•4¹»4cÕ[rj˜ùª D«§ùG½%—ÙG1Õ²ó8Ǫ¦^ÛY÷˜›3œ«¿ ÿQ‡í—mð-¹ýÚûÖÕ= {b¼Y‚Þ)ð6êøöÌ /TËáE{ÚÛ]³—iG¾%‘Žã iþqs,Ý{³ÞúVc‚ùtw{Œ/èÔÖìç{ e`ß ®—cÆ»Ûð6C¹ãVsÑÕ³O…@7ØŒ9¸ßvQ— ·›ßïvA¸÷Wýb׃`ÓòF[òÊ.·×’ØpvÖþCM?¨-7°‚ŽÍÝRx3 5Iãûä÷2Ó–Ã*`¶GlVÛnfu÷ÞHaËwÜ3Ìì³Ô€Hr:αv{o MH4 „% îoÌåJ¹öÿ~ïG]ÅúŒ´£­¨ž¼¥Å2€ê©Ÿ‘a˜ëÊa~ÑHñf&5®‡[H1<żiG%zÆ“þò&ðVdd:ÈC|C—ÛOAêŠaÈ.CÁ’Ö%Oœ€8ÏÚ""›(^}"¾é¤5ÊÁ§«¨Î §÷Ê;›"áúž’¼$?§ÉÏ“~¾žcDSe9ÓTwÙ½AD5•hÅiâUwÙÍXÙ°è‚t•ÔVd\àd\NÁà9œ÷÷œÀV}J­ú ·ÍGf}Ýß ÎšŸTRÒ @K•Ûz'ÍoëÕP\ʧäy'¥[tÊ9©ErR{ɳ֢HžD1-zÝZÅ‘ð,Ö˜,E’ ““äç³j¡/2ýå÷í¦Ó5“ç˜é,EŽ|iÃ,†˜¥ ´¾¨ê3-2MÄLª•Dý+•zVÀº#oñ¹MÅÚ9ì55SO½^ÓRõÈ.*å¨â[xÕä‘)X5ÇT5§™à”bDÑ5J‰®–ÕLÚb5 Li ¯™Tæ5“ÚyÍ´5^3­×s«—È&?u»±„É^ÄUM'ÝÑòv#_hΦ`Æ“ÆíY·¼mNÅÄ*9û¿Ëû¸ñãĨ^íW§§‘ÏÌ8O“¤EÌ,ôkšêm6ÁÒÛ!+Šÿ ¤ZJ0i€4ÇÖbÂÔïA3g²"åZx0‡Œ¥Š9Ìcã~»XÄü&g´iéàLÚ>MÍ;8'Ú·J‚KT+RËzFp·<Ú…*+©xM&’ãñ¹¡’÷¦Ó½é‰roã ¤TìrÙ5Úžž ¶§'BÈ 49¦¬ 6vǧ·{ÓÑ<]õ?oú.V7­,§\¦3Û²url¢e•Ói >¤šfbô±ÛM ÿHÇ'G?hÀ>r‰–|Ô»Y¥U§8 äö¦ÃͪZ ¬Ü¬*,*·a¶Ç³‚WrCIÃTrm×Ù~ïßí::—–Ò¤Ø.û«ÅnOèÏÙýþó /ЧøtYMGàTÔùE$¬ºpÿWÖèIónýowþ]ÖãT³ÏÙvõþÛ¶l±—÷ÁØŒf}šÑø©ôM­E]ëU ¯làA;Ãé"Îb?ªÖ/ŠYLnŒFhcüDÕ6¿Y¼{ùañöåÛ÷×ÿoî³~ã/÷r†Ísä:’TÅhíÆâÙR•©4µ{§b]©¹«ÏÐ¥ÓãûDÕ‹óËùûï6}R•Z4y…÷ø¨yžP¢èÛú6ôo×Ѿòw|’r˜öö½?Æ!~8n>®ôÅFÈ;ÿ[ʩν½w¨é.|Ɣї¨ÈióYÔØ0–q­C˜éb¹)Eî¢î5 ë¶Ø SðòÁ‹ºªõp6[1¦˜é<É”Žé¸·^É[È6R’äE Òöñ,™MO|ôÌkZ7„¾·÷ëôù÷ºÒ.Ÿþ™û±.¯gïüý· d?VÃ&êo±€#³•;N'ÂòÒ“ LÙ±«‡¸m“\ϳᚥ¡FlÕ/&¼ Å å~Ï I{.¾éy©Eéê,Ÿþ¬F —Žåº¼Ñ‰Øä糪ö0ýÔXãk9¾zå1”¦öûr—w°á-xK´!9YócêdŸégˆV‰–Ü Íª»Àž’eÞvSeÛMJÚnŠm;(P«DÒyR×Û]`:ý‹Ç}O -Õiº¥z¢ÜRÅœc¥ ÛD<j¶‰z‚ØDMëG)™Â¨¡~êgÔP? |JyÊìôsœ~Ž×Øs@c“Ìôs%•Ï¡Vú¹†Í ̘̈O=M¸˜<%œÏÈç ¯ LãÔÀ|S.ßT¿ÆhèMFk–­ÿ(àf}×Õwˆó¯•6ïgˆ©Ý*VNߘ%}©qÉÀ!iÎ>çlnÀ%Sµ: ¨+aúú‹ÜZ[)ðK®ÿ¹Tê–nëuãÙ®¹¸2Õ6o·e»MKÚíÛn%×+B"än·º¸”e0í&/ L§È'q!ò“!À:º &§¸Fî›”HØ-|÷òCx'˜ï„ËwbÁ„«¿É4ê'QÅâú~û×àcd˜v† g£Õg¡¢µí;ÓŽÔB| W|^EõlN«è«Êb'hÿh3-­ð…¿Od½ëšâ»+ôÙL½íµyZë·ÅtÄ,€³Îœ÷)©;¡|õwc2Q=9WCŸ;s^gúsÞ¹ïÒE¼SSþ3G(ƒPѺû+Ç=[ŽT3wÎÔÒyÛSKÇiÿ£ÔØžRgZ¶31:ÀGxGp® ÌÎ×푺ÀK”0|x‰·¼D9ÎyÁë.oÝà%špÎ^wyíá<ãrÐ^28×7Ý ™Ë/~G§\9Ðã d}„5«·=‹;åô×Óc«|Zdj´½‰¶$›‘µL¶{F{hn4jü)´v¬6?hú®&ýù™â˜—ëÒ?¨ †Ú¼JYS¶à«`2n²†07ÙŽºõ %4è×ïY®ÝµßI§F9÷[ê×]¸÷cFM÷jãÎ+Öµö~Û¥AjjêÄ­ºùEC7Ì6ø«!wX º=¶µEZ줙Q-úK›1-´æçëhù¸ú+[ãwY®ôZ®ãtÐq‰·(¸4)*ÛãîšÕ ƒžšõ”:)5í±Î®ýO÷Ñc1±Rµ{ÜqåºtG˜~ÔAg¾ö½UòÑINûY榽ŽÊ¢õ?ü¦aÔßó‹K ô÷Ÿø{L’›K‹$ú÷îæZ¨‘;‚ÛzyuÚu0a ³XÍéýŒó¸é³ˆÒMž&£‡¨*é"M^ \ª 1‚!ééVÝÏÅþŸ4×~¤Ý)V©š2~!íþm^æ^Zu1v!-byÔÉÀ%í¹•;dÕøÄCÜÓžÜ_I-G¶'òòÃûÍv ÿ뿈¢õFÚÅ ¿Yo›¸æÑÀ ³QsÐmì&¦»zš±=•õVóVc76©H‹6-»It c‡…è’£’è’š.»-Õ’tãRç!&MšŽO&΄µ•‰?@oh*¥p à›îÕ¿ o½©F~ëlO 6’yÌ]ô9­y¯l<Ü6xî,Šk\!‚÷j«ð_¦B£¶Ô“Ã&ºÖbËFº,9ãy]µ•¡ÈIaÁÈ©cè=×”ZvO;3ñð4¦¡ý¡NäíAŽÎESõÿÜ·ýÝÄÁ¥1hÓ2h“W`O£6…J¸¶)tR¯Á¸Íú¯óþÍûê_^}}¶¨{p%_?.‚• »ìi^žþI•O Ÿ×|Óƒää?ê‘«‰¯zòÌço\Ò#)މ“b»£EâŽâ¡é&³"™h3/¾%ÄëýÛ³ÿgöþÝ»º5J§8¤BÙiƒ?á ï·{âýá‡Q<}½õþOPûYjk…²…*×)WÇÔºÞ:¨VR(sµ&UpK­uktÜÜø•”ªÑgŠÎ¨T§Í43¯PZ¼fuúòû>¬›ž®«h6)˜Z½b 4ºÍœMü%â´ˆMh—Ðz›}¾t“äÅ")Í/uë™{‰íëT*®¦S oLN{qiІÀ/8Ô{ñ ö|°¶áæÊ–ë¢Nióeɧ§$|·X¼C²ú?ÏÓÜ) ì:—õBßiziÕ¦t}/´ºá_xªÊi’/…Þy»âK˨Ï3'ï¼5ó¥æÄÊ~·9þ·È:hó½1jÑ[$Ãà@rßÁ¡'=z’ï‚~~.\¬Í‡ä‰:¹íÚªUr2B·ô*J&è¶®“TŸÛÎŒ@¸¹é§ƒÃ| ÔÅ:5`Í2Å£¦)Ó(I3ÙB9=Ç?¯.ó&#ù€!j2<+ÑÑ÷µ—B"}觤J±î  Ÿž®üh®w{²ìÛZ9`þùσR(ã¡›o@%ÂW:ðU6ÂE‹2{žþ&òiá Ê.nþ迦¾ M¶zØzwÙb ñëaª›¿ü)Û"OA‹Mrj_Òä?ÿzKìË}Æõ<¤OqpO¿©™ühõÔ #¯Æ£¶½8’ôÇØ'bTöhñöKiòëÿw¬ƒ´™!*ý ÿÔzÍŽÄ^,fŸýå—Äjˆ¼%$¢ƒÿ¿kñÆßÞî?§Oœ¦ñSÜ[×ëÄ>&¿üÇA<žú‰þNâq½þ·Ë:nRàõš”8+ÉÅË›ÅåÍË·© [¯óèiÊü–$÷— €*¼ÌGê3),—[b’_ÿ¢äéhÎ&€Ü„3©Ù/ÿ­6š(›y—ŠŒÎl&ªMÊCT\Õº<9øè•±1‹¯…}1Òó‘¨çbPç#$É8÷÷‰QyÝÆþå÷åâ]°¿¼‹›ŸX•õüø! ¶·Ûû»qã²&v$¶'™‰‰’Ä*ßÞÊ_|ºß&§tþ—TÄÿõïÿßöǤH?ÆÃ!ˆGñÎþïÙ¿ýÛÁ. öbhÿ”É(Ì¿§<Ã=|bžUV=y˜5'¿ »Í}Dþß㵇åÂ"«ùÖyU:X^d‹‡¼#µv¨×A¿×ÏÖ~y±Wc±ÜùR™vjÒ©\ڿ൴Žþ¶öÓȸ^?cBÜøL pëÎëm‘!9ÁS5Æ N«ã¾|fX·{Z¥)š[¨ø*»x,˜œ$Â'3=M#~ó#i—sôxRO?˜éœVÇõ‰<‰3ÿ·# :§°Y2Ž^H’¨s¾Û5¿;i¨[Õd/ää/”’5±­ž¦‘•4 «¾&Fêg\€VÄÌG?±´`½¯õtM­f«ÞO}µ°aèÎ.Pé&†UgÑvû†u ³VC8ÓÒóÈ ÷ÔzqÞÕõ¿ÏÎô5²h`ÞÀݟǤöørA{5ßœ—£·rÑ­X“ ô˜V4¿Cy¨¯—Ý–êÊÅ«në/´']t+/#"ó5„k—¯‚F²‰ ÂHÖr<¡Êw}]Ôö5©îŒÙÊ£fcǬ<Š&fV ¿£Éy…ŸØd5¶ˆ×(á¢ö‹[6ûå€z?²zt7Àîå)C »9´S|C9/ko‡z]Ì¡‰þÞݺ˜­Xë Ýu17ëõ|],÷žú×Å/‚`³øØÜª˜à‹£‡ý:ˆry««¾¸N$Å“¾Bª®qåç—ŠÛŽ:akÚØº®|˜wú)T¾Îi½ƒqŠXÄÕ3N…@ÏbåöÑ‘pÎB;‹ä½M­ØÜïßYý{ÝÅóJtÙË¡NU²NkÿpsQÈ^vx»µ)@ýý»ãuYR©Vû{+²d4 b=Æô™zVcdûóê!îÛÞ+(¯ICç»ãµð•·nì"üh¿:=%w¹æ>¶§¹¯­Ò½ø´Üšñõ¯NŽ ë²Ôv ¸Î6¿È¶¥"ùF®ýÛLg^vq-“plå)ºSqñ™R#?60«‘É4Ãd íÊ0usn<öËèté,™©µÐ&l&}áPè UßÈg øL¡«!¦VÎYÐ2F“–Ý)JC°d÷õ°•ñàáõÑÆÀá¶;Ú º«gϪaÔjT^nWúqfÐÇêŒAû#ÑYv/Q#f#½+©¤ãˆVÄô¡'’½È¯*d’j1=ð·dåɾ?18æÝ‡oˆíUvU•®c™|¾È¼oƒ&ú0³m¦½cêL1î5Oˆ‚SäÅ|“¨›@“ß3=ϗů·‹äÿù0­?€(._ü®”ÂŒÆOgõ–´‘‹m°ý‡õuiÏurXFÒßh7d•Ôj:p¨Ã€$x¬Ì;®PšûÜz‘Ó⡬U›9÷H¬D§é†`"Læ ×>Ðá4ã°ñ·Ö6 ÞxzšF’î]Áš$Ú ¯Ž~ÛK+’Ž»&ŒHÚQy3BCg›4$·þ>Ú¬—~Ÿ­ Ê ¬ÖŸè†Wj¼ìàXU”‰¹e‹—¦ nZÝ58\® ŸkRj%U{Û|ú1Þª>M„¹a*m¦ §è \tSn=ùy<šdV?=sA— å=¿µ…Lô(nuW1åwU2GÌF¹¹Pé÷8ÕïD©ß V¿;ýNšÔï¤~ý¦Û‡ù™îxSC¶ÔvýÃLô¹K•ü˜äçSâ",?§eî÷‹àÓ"ô¶·þÁO ¿´\nWþw_rHøó¯ß>{ûÃ':?Yäoò6‚~CMîágƒÖœÌQÞØÞ¶0²»¾°; Ê”KK¹¢‘rÕB¹tz)WuÊ¥Óoß)—%¦ÇGĉ¸¦TÉ;j¿èqòŽ&ñK¦¸“u >­áÔ†Šûðé NdHŠ’Ÿ“‘Ôh¤F#5ê„å´¨±é‚½£©)Wqj‹Ì  O“’ãZSìq­©]™Úv¼F:;Ö=PÃ*«p$¬ž69Ø+¬¦g5ÛrÇð¦úU ÁruSÓ•Y'.]™5mæÊ¬‰õMWŒ¬*WLeÿ.›âyŒ—]7EºW~û“Á5Sÿ¢ÿ•¯›*~3{û±üvƒ÷%€Ê \z¥Ùlî¾* ù[°Ø¾2ûÊpúЦÝ&-¶›qmàZ˜öyð¾7^Ipÿoû8¹•.ƒ3]³p³g•ÕÎÓ*—Ëõ«æÛsNô]yY—Š)ÖK8î6[í6}gÜm†VàŒ~F—j—ªN£KµºKU§ß~ºT+{’˜iqÜe®c—9VèzïßÁm¨Ïîš…æ®Ê“Z¯ö›òú?ÅSÅŒ3|µ^¥Æ~NðuL@‚½ô¸K5Æ)ÈæØÜP¦ «‡9a'Léè•B\r-'wµß`sììÙ©ÔÔã|%åéç|õ?¹ÇþÚËé¦mXóèä¯âKn6ªç$aÜåÓŒpª<>IáåÝoç%=Ê™éñKzœ³f“cú>ð7¥ç>£bn-<À8ÏŽ`I=ãl[2ÛjTÕÈl›/Ît9‘ƒ.K‚.'Ø K}T®ªù¬=ÈýŒ¹tY tÚ©9äRÅ[ ¶|DNy0TrÂ…JNô‰P‰+öø$™¼Û¦c#‰˜»D¬öèè‘ø#Zܬíx»v|ÜnÚvkûv±¥ê†—ÎhÇë²ã5}š¸tö鸙³OÇC<Ï’<È/=Ãbp4òÕL8²ÆÎ„à1¡¤¾eOèm\¼!éˆ#¶.ñÀIìuöZL€¡õ,ÏéÆRñvzË/”$!yM¦­‘Òúèéâ$ïý-¯Obb]8ØV 0ù#>µQ0„Ú¾³a:ì ¯%N<Ʋ:éÙȇ.u-èZ‹7ºªÔWé<·š±U»ÆU`l|¼[Z“ÃÞüЋ›Í}ÜH# ø¿~&`@€µIµ«ÞÔGȶ-2)“¨¤gYž-,ÂÈ:ì§¤ÏÆ*0ØÑ9øEm}ðÏüBë>ù«ô㩊V¨d׳ñ˜uùÙ)v@‹›ÿ°‘¿¦VaA–⫇­w—Íu¿å×ÃTýùSv°;}oq´›N[irê6\Þ‡a¬ÐCú§†ž5aq[dîúˆl.Vá'Aû„ÓnfÀœ¸M£æ`ýø¤Aâ¡~`">0©õÓ­15…?2™‘ÈŒD¦WMÈ™ <ŽÕC`RqLŠ!0iiTúÐÉp‡ÀD?&. z›° .Ä|‰†ho$ô¥„~ü¬Ìcü¬ŒzÁ-Èøº‰Ó“—}ÕB5C¡&¨¼‡Ü,•´bR&Òš-ã'?ĵ/¾ŽaôÞ—ðX¿ 3v(»e¦·RÍש97ugüž8ÿ𤏭|{&ï­š¥Â'^*¼÷U¶¬¸o¹ˆŸç>1Ï+?”`6ZãgP^!ËHS9ÔÞÖNë 8¥ëmÝ£}ù‚¦=zÿõƒ.ëæIŸ>h3Jù)n¢>¦¹„ª7ÁÎŽÝ¡&—ÃÄ%—Ãq3.‡_2ŽçÊßÉX®s-43Û~À’ÎŽù²“ûzeÉÚ°0r,[×ÖøR$´`ëÑϳVÀ²Rèj¹Y5Ú?B~Œ´ôS¤%þ™Æ—zcÚ^òåEleÁ—æ;¬°x£˜‰»ú§Fñ/eèjWïíì ¤÷Ñ瞟Fªguëúgó†p¹ãP¹Zz»2 µpiKô~EÜ} åuq~ .·àM.^{ðù¿´‘>Åìjßßɬ“j[ŸÔgT>žÏe•Ñó«F¬;Ò“ƒŸ*ÝS’Ž^ÉY~8ûç,hFoŒ,®}ï5a`.¯î>" ß=àšñ¢h}Ûã»™íw¬-ŽÉkúâÌJ]wäg_ª/ûU'aŒÝ™AL{Èx”øl{ª™žùœ¹%A¥¾þܒЄke"»VŽK\+¬ke‚m’JõîøU:«,§ ““µ¸Ug ÊÝ*Î)2±p«¨l¯Oz,ÇwGbbAL€‹›FbÂjf$&õú¦ÁU“ „˜tV=51 ‹›¿FbR´Ñx ñ1C,¹J£ÕŽÄh5ƒx±ì˜Ñ9¾¿_ô±äë¬I4ê:F”Ãø4™°nrþ8YZÞV ©å¶£Uâô*½·«8½õ6Š×GþâÍ6—ߨ[´ZXŒÛi/´¿/+ívãb^^PÍôl1íÆ,U3ŒWfõçʬvÚ°`Vƒsè87LgÕ“Ý0yKds×”@â¼ü²)}?3p×ôùN*—½K\‹=–m¯Š´›Û5›T¦íÓ†i{±Í6á·Ù¤»o§ 2{>½xµ9c/¥ìÉÏÉHÜGâ>÷‘¸÷§ âž›ep+ú8ÝŠž(·¢'Ø­èv ·z+zRçVô¤±­è©¼𔬦Ø5ÐÛ$Óa¯¯e`̨úÒG¼g±þ™ÚnWO¹åÀÔbA¡F@/(jÚ®>qi»zÚÌvõ€öFÇKNí.9utkWðæ ¶vÙþ=û÷cïßl?+š8–£&Œ:õ¿´Ý[Óá&è!fT¸åMCÁVÐ¥xŠ´ì­ÄSPjaÕ]ëkp¾ØqÄ#À¿úÄÜïO“†¯Z¢¡¥ôÌsêÒùXý9ÀÀD¡'†ÌkÿÔKoç-×û‡þÑö®ß(ÚvÊ«{¼{CÐGÏïߨr…F>á¡ÿ* î2 ËÛŸtb/âê³ ©_Nºú1YãÍêÊýaÍ…Œœ_Îßx×ð@çôÓ3²Sø§šŸ–S‹H¡»Žâ:TzIL»1ûÞã^?7=WrÚÈ>æ;ÿÛl³ŽÛðÜÛ{‡mö]þÍI)å‹­ò/=úàœß¼òný¨ˆéjÒÞÝoTš7!ÏÉPe7í2%­‰ Ç|–Ë #}bëÌ{¨í¦,f¿Ö_-v{ÒŠ«ú:{;dT ÎX ÝÆÆ6 ª»ÆÀ^ò„ßÇd Ò Ëltå[•µ}Õ#.ÈbÁG˜çøI®¦åÛd‹Å6ØþÃÅÂUóQÉ0| ‚Õ¢G¡¤qÔK£žÕN•_aíc6üI_(ììp¨{¡ö˜ƒqïÖFêõ)¿Jºhk!¡•È{ÆQ®婆Æ! qªšþo: †6¸7þv cÕPU]€RGs˜ƒT3.[ƒ2;˜fÌ@Ë>O¡mný}´Y/}wírH¯ÖŸhPlé|Xœ‰¹}Š1 @Ɇ4—Kyލ¹k” €Àt½Âçt%KZôÉ6®èµieTå”Ú>Ï{{{;èæÊ*ßMÇX ›]u”5bvסã-œªÛ9áb®êòã.•Tmpì¯êTyûð!ÿ2ªú“õZÕÒ5 3ƒ{Üùˆ<0>~ÛòsZÐà~¿>-Bo¿á§…_Úð—Û•ÿ>9$üù×oŸ½ýáNYä­mòöx ü†š¨ [þ¶]±QÞî­Üï42¸îœ=¥ŠFJeJ©¢‘R™S*²FJU+¥Ò©z”ªŒçóÝ#â;MDÆ–ð‰f/®Ÿhz ࡯³©“¼ôåáièN›‘öŒ´g¤=#í1 =9åitâ`¯biÒEÕýe.æ}¦üê“Z•ÓÝ0ýS‰']Sau ¸-¦ñj1÷Í<еˆ£×æ¨zÿx‡NÛwèÔ9ÈüÆHAt¼ú?3Rüfööf®ëà/É(ÝMèöjš±Û¸ÒmŒnyi§íŒkdvOL©¬/—ƨ*RË 2Üêüô”›M«­ˆ€U0k®q¶Ì˜Ç«°Pü]3|й×8î*ëw•‹N2î*—¬¿UîÕ*ÊÝ«U—»Wuªî¯{ÕÜoÄÌsãnr»É±^×{ÿîñ§Õ8ý7xO¢‘š½²®ï7ÕÑ8oWÐU§mÔ\"Ø<»bœM*œRëÇlrõ0'l‚y7½Á†K®å¨«j6hz·×ö˜pÊkœ|ÊѸ8ùüOî)ÿölº·E[Ð|;?ùK÷Å c}ˆŒ0ä„ï哆<4Iäýg·ü<Êif<ò slzDQ_bÎmá£ìö^ל8G§+ô4NŸfúhdúÌ—M‹rìê³ÝÆ­YÁsÛó G×5Bç"ÛGñk5ºñùÆýʸž:{pË»f]#ßù–;|Ë~*9z$>„ö7>GcqÌb|²ùvDãîÒxÒV”ÔÑâ¤d"z*ýGÀHCÑoât'ñ.Ã!ÜŽßMôîå‡Ú©‹¢«tw-‘ˆ¤$—öÔß ßËý^nå»:»åè@ºå—’»QpÇþ`J"i½zÈs÷™´S :j˜;Hê1º‡Ùéìh6¼Ö㈻ÖãHok‘øå¤·Û?¸ºš¬ä7û›Êž°D=£/L¢æ©^<1R)ÒþO ÌMz€àÉŸM‡lv^…ÁÝ‚ ò>§¤~£†\>$N`C¹ Jã%Hߪ:¬ Ò8ª¥Q¨ÅéAÎɨьæ´7ñã™Fä4?¢¿yÎnV•àôØGK´>zhUcŸ(§ÿþÙ›CÝ5ûvá¦Ðz=y=vé´­»ðfÞX¸¥.ÑÃlB F·]O)§™þízëªÕo"DÁœÙ­ã¦%±†Ø…DË#·“Æeª× <¥ut„¦#ÄÄñ“:ï¼/þ"¸ßïî÷‹¬ Õ÷F6&àiêŠMÞKúûÕÃ%Ívzºò£e¸Þ‘·?y*†4eNŽŒ1)¶ôGSÂkÅmCBÆÆhFŒÌH8Òe †~<®#Q£E G~•°%t„¡HÓm3R• ÌÈY@óâ>i `-ý2-Ëï…ƒ´-v£?ÑÇ8ü¥áŸêÅ©ñŸ û´ wã’¼‹7Û ‡‘bŠÆ…®U“95£S¼~†²Í.“‰Ýæ8Tþ†ºŽDñ€%Ç¢½ª…ƒRŠhãf/:ÃÄ­$=1AH ¾z›#þª0dÐL»áÈy Óž¬§aÔN‘ )¯”ÂX ú@Ý!¼ˆÆ’.‘J‚–+\"Utƒäú(ѲT ªH¼l gì½å—A’;6’©d$"ÐïT5N®ò¾ÜÍb!Æ"Ìñ¯ŠW™›ßL(&ðÚ>˜`:š%‡Í:ƵɎ¿ÊQ­­ÜÎYð¨ö¯æTé¨âA[5•ªz§@¥ø8¯´6‡Ýzù¡9o'ë ³@šNÀ}|ð3B„m i·$b é £uV…’$ÚqÊ8kÃŽ…YCý”ôܸžÛ"šÛ!þùσR(c'™~ÜR¡êŠ6>*Œ‰÷7‘Ÿ\T²¸ùûᘘ‰Y/¯¶Þ]6Ôÿž_Ó¶øËŸ²#½é›‹C½tK“Soßò> cµÒ§8Uôµ=‹‹ÿrWE¤½¿‚Ÿý<îãA’2ËV1ÿðG¥×`¿õÁ÷…EDçÄÁˆN‚òæ{ƒÈÐFîTj ¬TW ѥMD—öêŠûrý÷ü~ûÎ+è5}¹}}ÍO±ÓðI)ÍuO02Zì}59&.9Ž›q4ü’pDVù%ÆŠhGÐÂ2£Ëà÷ éD˜/3¹–¬‹kÉYVnRàÀÐ:¬N×É&šV*f@ÿTË m° ·ý:eé·)K5Jz_ê¦i{ñ'–´‰¥_š|h¾ˆ£h&ZôW%!HùlíEÝnò>úìôÉ¢º¤½»æ7o™1êVuÌ)×PS\­šê´çkVGªÙøÊ5?f—[öf MCù³½«³S›ß`[Üö„¼¬Ùñø¬dR½8}G…®óäà'Ìõéð«Õ÷¤[“5{ŒÞe¢ÛkS2ćo+¯JNdH4Gþ{gG¼(Zß:{Ûp•]àãÝ`=]í‚8™b».WN1^¯‹ßNO:ÅxDÿ1ìTIN-Ø]»Ç@¥£~Ýc =†ôòIn ®›N,› bpº±¤ü E ߥ年t‚hÂ2á t’&ý»®=xEü«W9{œv¤Ðà⤑vŒ×'áiÇ0®Oê5íP5ÁhGGulv0÷v ‚vŒÇøë1¾"Ú©4ÄëH ñ2ªÊŽÃ`NÁ…üåù\g­cp:Ì6Ï \ØsYÂÚ©/³Òb7žG­zó¡q_ÔyhÜzÅýúQ^€ÙîB{oU«Ër·îªJû䏨׮0¨’œZìkƒ…Ï>ÝV¥Òõx]ø÷¯«j«A ï«rÝc£R×<6Õ±qMiïƒx —_uXònÎxs”Žt;»ÕåéæöÏ&5Ðöiô½Øp›ðnÐza*bLkgö|zQsnnJΓŸ“‘¢}¤è#EïMƒ=7ÓàVõqºU=QnUc87} Ö­ÞªžÔ»U³Á)lp&t˜Ö¸ð™â,øÔ² ¦--|¦.|®#åbM,|¦O(O4]ïˆà¢=Ónö­Ó Ô´o}âÒ¾õ´™}ë팎„Ú^Ú¯­]Á1ƒØÚe;ÿtìücç'ÿc;]iHűRaÔÃÿ¥íë%Í2©4þŒÊ—Ëx*,Øz;l‘V¡‰` JE,{o=!.–Ô(¸ûûáWßUOs§p_¿MÚc¼ôH>èÇ)שƒG`%õë,RžØ(¯³Kx–ÞÎ[®÷®šÉ6/Ï(š Ïu ju¼9CÁ¹jœ¾=qýE>‚àü* î2“ÉÛ‘tf.¶ìëá+ãï}ÕUÊÃ߯ƒPH?†&q~9ÿá]ÃR•S”$-`ÔüŒÉ™.âÁýÛu—¼âxJŠbÚ{Ù÷þ÷Âøá¸™¹ Ðö&ïüo³Í:n¨soï¶ÝWù·'%eÚAl é‰Ê•·g«Õñ|.ê¶` za¬èŸ™]šÅ¯\oo…»fÙTd0CêžÈÙIùœª‹y°˜ô‹éû~K®òWÉ<œ„h¸b¾FNåÜkâ~>åý±í…Á*bœu—6çÛÞŸJ-oAkn9”–ó—Ëy„µœkXJ :7žM”™Ž<«¹¯[Þb  ç¨KeV±Ù…Jød-û4VDC(2'ÿ²NÑä+ŽÅÆ|´D® K¤+é$år÷B–X¦Wù”Çì+eäb>_ÄÓb.K¦Jå&ö•>`ÓBb\(;—K;FSqLj›ù“] )ïn–)È)Õ ´Á!đڧêØOþÀÛ!ù~"ãÅƒŽ¹1böäî>hÎA*{G%2{Ä‘Ù#hx{%*èzÚ1C|› ƒsÿS ӿ¢ÿJ#cÿ¯ƒÿ9È ]½\Æ çÅV#ÍIýǧ1¡Ÿ½¢8O”Ÿ¼}yóÛâ}^õ¯§<>u;óáa16·¡ÁK)àg×g×sV7K‚LrTHhºÞ.C&‘Y@®|5$‘Ù@®ÓQÂR¹´ÿ÷{o£ÂM„ Ë`÷ Â$2 È­ÿ}¯‚$2 ÈEòàb¡‚ÍäлÐÿºî#t&·€öV_u]Š­Ôáÿ]§ "µÔ²^Ç–°koµÒ§r;èèþ£:‘[A—Ú¾Ì%E¶-±°¥‘š€Ç”€Ð“Mü@~Š>/3$Ä‚Æý)ØþÃF 9úcl”¸©ºñ·JÌD†‡¼õ÷Ñf½ô•¸E<Í<˜ƒ éèêÉ…ê›I±°ôˈd"A=UmÊ–}f²€‰?Z”F+¡é½"[‰È¦S«›$—Zu n.Ækô«*F •™@Rw4ld~náØ¶JdûÇåõì¿ÿ„_"™kƒR4,ĶU,À¾ J-`yÆ -@έÌa°ne x€w+sØÁ V•ÁNózpù–µªGÑoîY–‹4˜ÀÀ’çಠÈMh’ÇòpI‚†ãé®,ÂëOÕ6jŠgNÇùÇ”4%äÜC<#—Eh@˜“«³Ø @ž‚R|»s¼\™söIŽ™³|¥%n‹ÑÀ­e5“4Ä&øæ‡ñŒz/#1"à=9T 2"‡ì—Š¢uRMÀæoƒÕåöS ÛhI‚‚ƒØ$D‚ J’ áx% P`‚EHG– ˜ÚA)VæzWíTç®Â«u´ôBˆ Lgàì9nÎQ%âça>ÄÍÅ\* †Ÿ<ød\y؉KÅ•‡›2ød?=óɸƒvä…Šâ˜ó…â°@¦œ¡¨7­òÉ( njåRQ0Ðô Q Ð qš#'µ¡·½…ôWq³$ïéÒ$@2UB:rPó'R t#Àìþ)™ ˆH!T$¢ 'A€ÉŸŽ,D ) €WíTgC2å—È€ 0&ô9ž d§Â1%È—ŒâɛЂÈ—Œ+GØT\yx2À%£€„Ù—KƵ4ø°#O$|: ,1ÈkÀ“.Ä“6’@ˆÉ Äi"€7K d€OÇÑT éÈAÍ“(Ýl“FE$ ë±#ÌsRP`Czðd€y è¤HX0œ"aÁ`@Ї•‚cd!^³jPd«95(2Ї>Çñ‰()„Í*óGÄ,¥ÉŸvÑ‘”¦x€ÞA2‘ü1NK E@zÆ*Y ÛAˆâ°@æ1; sä“Q@ª€HŒ(bĈ Áµ£¬ƒeLiT°Èq•uD P Óa“q,º *‹eÎãÙ‡3åòÌ#<›H0˜Ñ«2`KÊyˆE¶e9N/ `œ'THGBAÞPXŒ†<¢°Áû$IЦ€c ‰!húäöç°‚W0Ie&˗ȬÎa /1L0ƒ%8È6•™,_2Oe&«—,Ì`.2RYj+³SHn;°î4Ⱦ*¶ÌZÕ¹l5n`,x, aƒYqZQ% ³Uf²z‰Ìr!9‚ër‹Œ—Z•Wb¿€Ø Xd²ÔV`Å²Ô V¢¢€ØN¿<µ„V 2s†ävÐÚ#¸4ÿ Ä¨±°’]k²ÙÕ@dڀخ‡ˆ¬[‹ \–ZÁ*ظ2“ÕKÌ\™ ÇÏa›ª[š)‘±«å¦“èöÀ¬(²Šå Jµ4©²0 V÷?ú#ù: ÈÀ 6àŠU‰*Ý+ä5 ˜Á\Z‘@r;h ¦B—Éî%@„….“ÝK€x ]&ë—ÈœR•ǺEJ_] ʪ.}–s³q€ÌRˆÚ€Å6À'–¥6°"#–„V –„6 ½”¥VzÕ´–eSÉL[ë ‹ ÁÜs –¥6°J¬Îe9„ùpU«¾!²`YŠX4³‹kfVf¥)ÖD™Ãž<¥VCZW`Û² Q)°Ønôi¥y¨ŠÄùˆXlYb.~E!·²b4‹*nŽXl71‰+ ¥Ø(‚æ ɺõCè>DY†„C§A1X Ÿ–ehH!„Z¡¡0jXކ†B©a9 §†å6Ðb 2(¶Ñ´X-èQŒ ®.žä«¹d$b-JpB˜µ @‚ññ|:Š ·æÓ‘PBŒ³ Àê Ö=^ñbèµ(ÁÂ) f€]<"„` $˜" [‘?¨„¸`Y†m_>[˜2çâ9Ž4ÉØŠÊaÙ€ *„f ì S΢\bˆ¶(A •YBj3ÄHÕ%øÒñáÚ’;z¥mY†à·@O–$hÓ·nÃÐ÷ŸÞ¬·>Àd% b± *0XI‚„ãÙ«(@‚Ì”"aÖ J‘°c¥xXûAB¼fÕ (žÊkN Šâ¨ùs,CeQ ;ÒQP<3å“Q@œùçRq0,#åRQ0<íã“qúôŒUr¨(Ž9- dÊ?óxöÉ'£€`æ ‹±…§;’׎ãä“MùföÇ6³D\å$¦)‹P€<Ëä“q,º<»Ò‘=6-æ¼² )<«ÒÑÝS¡tÔ÷ùvW!¢¾ìH™£Ô[…t¤YæØ$˜nDP•Ü’zD-¶™çDo¨M€6óà µÈfž¼  y@!)ò~BR<¬èG´ çu§Åù ^HÆ&£€T’Abì@oÇ$¸v.$c“9$}Šç4W9àB2Q„/$c“q,º<Ò…d\:²Çæs!YFSÄ É¸tl©„ Éxn4Ê’  ‡{©Ž4ÇÂ…d@ºàœ(ŒÎ%(8CB$¨È!E Nà‚ qHHŠ„…8$$EÂB’âaEfñšUƒâ8$§95(ŽCfÏq’IDˆ’OGA ’KFñ†žMÅÁp’MEÁ¤KÆéÒ3VÉ"‡äÓqP`Œ9dö€À!¹d‚C‚bì@(Áµ#Ï!¹dcIŸâ9$MÄUNæ’(pH.7pÀB¡Ë#rH>ÙãaÓ‚à9M8$ŸŽ-Ï!n4JR”`8¤ØK…t¤9æ9$”nø·{?\Cq‘’rH@ˆ9¤(A R Á  I‘°‡„¤HXˆCBR<¬ÈÌ!^³jP‡ä4§ÅqÈì9ŽC2‰(‘Còé((CrÉ( Þг©8ŽC²©(´qÉ8ý@zÆ*Yä|: ,1‡Ì8$—ŒRpHPŒ(¡%¸vä9$—lÌ!éS<‡¤‰¸ÊÉR¡É%ãX(tyDɧ#{_uN„©<Œ JÀ=!©@-µiýóàÎ[oãô[°Yù¡²3ù,û†êmåY±=Gx\בtYUBïÁ_)Ç•,7ª‘üØâÚ‚ Ã×4y0­¤©€:‹mÄÖ(ÉbÜ ïwäYo£l ƒQ€çä†Ðd´„®š<Öõ£,qkÌ‚Ðg@Þ®¿¯…æ€r`T¥}ƒ.“‘² %m•f2yÕÜß¿ZÍ6Aä¿ß¾üî/ó:ˆcÝÿ¾_oøå}š„Ñ.Á¥é/ÉI¨ëåU1H˜DÈ›`{ ¥ØU¸Þî_†!ãæ‘$X¸·~qüR–a!¯Âàn·SðlÉÙY„œï½ý}¦"\ ϽÍÞ_ýæEŸ¯¼H‚•2àÁ ´oÏOH!D8Nˆÿvv|òL[ÈqWè¯ÁËíîRa’Žƒz\.ÃA¾»¿S!f"àÍúNÎ4ôv½Ù(À2pAÍ ¯‚ðÎkXHÐp鮬´cìŒF¾Yã[ø{àá _n—Áj½½… s¦µ?ûË/³Ëók©Å3²/¦SÑ–‘bÌ—vn +-9Õ˜ ½ü¾ôwòb OÆ"K’U2Ïô¶Æq ‹€¢æ`‰¹·Àû¸\%IÊÀap©f+{’sq¶ZÍ‚ÍýÃaì:ø Å©˜¸ÏüÍFÄ¡É Âd×[_¢É8 TÖ«ýg‘"`gÜF+›ˆá6À˜4¿ÏÏ&bÊ!ºƒ¤TÄ*wûi}ûr»øAÂpkZ®`óü‹»Ån~ÿ1Máwt¹ª½æÖè5†[G€¼ ‡eÈf„ZQ¶Å AJÁn[BB èËíJYˆÐ¥Ìõ¯(h!G–UÌI1°±Y~í?üA¾Ñwå­C X#¡ó2A¸¹új×4ý ÿ¹*ƒ8o%r,4Y€©s)ö÷Ëí^ ›KѰóÏA¨.äXèóà>žÔÐŒÝ|ÊÇI1°Â¼È¦b`’•“¤b`>„ë½ “¤â'CÅ<ˆ)<_ØMóYü׋ûOŸÄý2F€©$„ÈŒªËä_,KoÃFƒR4¬¨J•Ì\Ÿó`ù%¶´¢6³d”.%,IbVá,7 ”xåÝ­7ÌØ„xЫ€ à’EX@âPÿú LEHÀ 5à…-`öû«ÀerØÃ—`ã5 6*~êÕµÿ÷ûuè+Ú+—[”U}a-zPb<æ©êäð/F€÷ 3ª4“q¹]3£T” á®Â`é³þx@ˆ)ÚÝ5ehH±µU2³N´€Z‡O6"®‹(îuóù›ËÕ÷ˆO6"M—<Â,O™4£ÛÏ÷ûUðm+Âé†Õ"c‰ßdM@n^/þóåõû K0}xþò†{6þÛôÑ˹øp’búøìÍ5÷pü·É£‹Å•Ï©,K0y8ž²7ë=»¡§˜{ BÑ¡LRPì6ÜȦ IÆExÏL¥YŠùãó½îßzßgË ç^…HP Áœ.*’Ì®¼{n“§™Cü¾…@hª9̵Ï;Ûò4sˆd“5¶¶_Ù¸[Q‚‚S59+B¦¼ñ?‰Uådæëèo³^ `4U²wÞØ†4ÑA˜9†¼×ÿ¾¿–Æl!@ô«ûí_ƒbÇJÍA¤e±˜h¾ˆ{Ä3h¾:Vqy:j'£É"3ò‘g_\xûÏ~üKô*ç1Ú’]é²a_?{óÙÛß„ëÛ[?ôWàkÄLØ—$;À1ž ± 1ñât,Ôµ°Ñ‘’ x¾ŽÈ. Mù,Ø\F/·äqX¹ +­œ`‘ùH‹yá,¸»ÙG‘Ži2š,2«rž=ÙÜÞïˆ5aû'œÁüÕ9Õ£ö E.ìkÈÄ¥,&D—e|¢ Fv½UxT†…<÷7JH*³„|ñ xQ9Е͠,Dk69Ü©BÍ¥XXyR¥XXÉÀÀ"cC–®¼i!)F¥"³µëûÿ§¨§ ÀX(®8l¢y‰Îã V:D%JÌáfÁîAÀ!Iæ‹Å&ú¼þ´g}ó‚Sší–ã2l*æ÷íú; E$æpé×ë´B€ÌAΖ$ JI± óù'N7‡Š3§—!Æëˆû€Ç Q i8¤”¢»†\ëB€(!ñܼ™‹e£Éæ@Âc‘fqí{+$¡LÝ›`ém؃ ‚F˜ñÞ‡Ð2‰9ÜeD›ÇëÈHíæïÕˆ¼Wå9kßùdTé  9(~õ¸DÐ%‚€æ6@0ºbp½p03o³‘ÝÕ€ 3 £4àZÄ+æ`‰w×yº9uõ`Œ3IþäAy@"TÇ Ê îÅI­Ø€ñÁÈ€Õçà^X”ðBW Ë&+¸Œ¬Ñÿî£Ï$Bì~4UÝĵ»õ6¤sñ!š¬YJ$/Ä—’y&HmÊ KrT‰Ï¾ÞÂZ¥,´a$üŸ “eøõ Œ˜‹P€0fÂ̱0ÉÉxqÚ&i¨ %OÀÖ=¡–]ä!`Í•$›½ ¶/6ñ/ëííå{“álŸ´ˆOq³…2G‚üæEjÊÁ 1ÝÁ÷B5¬(FT9Ú\F/£½÷q³Ž>Ë«_AŒö¬\ný½ʊЀ¬‹™OÇQ/$.(%7àå8+¢ƒ–ä8G€'ÙcšŠ³ÅñÉ$˜âL„„YG&A·³Ô-|0çëh©@cEæ€ðr ½’"sñ¹·÷IÆñG+¹ds tXÇ Qê×  R”U@2”—±eË—P².91b¼*|I~$Ú÷×ÁöUÜÁƒ ±[ì5…t›ò]ûŸ/$ÇuqгdãW¢¾”ùz»ôßxÑžŒ¶äŠ#O¸@Æ$7Ž«ÆÏk<2@<‰±ÒË9pSš¿]É¥àHi°%wè@œ”JPs¢nn7 ý8? ‘Ì3X’È+neºÞ®ˆ{X•R Jƒ ¸¹ Üù»ù› ø"mÐå騒Ýïþ€ F8‡ wè‡MÅmÉ0˜sHÙÀiI„ؼÝl‚oÐr½à–A_Ö;x÷â< ÒA Q‚šq¾úaò wêb½­¤j3Î$Èm\ˆgs01FJ4‚™³±fW0Q, 3‹ý)òg.Õ-·ˆRd°—WhŠ 6à²MUd°XÊBP‰9Àrèˈs«@RXè@ "~^Öùæ:¸+¡È`®ï|Øy]xVÝù0NNá9mçCnú j:ßܶó)º*r áåsè°ÌÜä“ +•Õçd(ãÂb3%p's•bsU¤Ë[邃,¥ K’˜U;ËMºÍ¹¿÷–Ì™W@ˆ½Ð^؃ –@ᣉñÀ€A„Äx`ѸH2<¤Ì@A1X¶±€ BPŽ ª†šhاt =ç²Oê:z¾eŸTv0ÜÜÅ>¦ë`sëN‫í`øy6Tš]@‰ùÄcño½­w+M.¬5Á€˜ Ô¬òìÂæ ¡(=¤‚¥b `èì…*‡M¹Eo(¶#ü!©ìo^$â¥6¥ eÛ™äùC¼HZ/Ó§:|)£ÅËȵv Š-€“ÛËâ”P$KyÞJ¯"]J³Vz¡0IjrUzx^ ÎSá‘YU¢Êu‰²¶X@yf;Sø2 ·Æ&rK+›Œ?y2׿³xÕÜðUb>äoÒÎ$ŸÔTd²I ¼¢¾y»´dìå@ºL•^¢ÓŸË®¡šê<^!EXj³ÙŒýs²ÉHöT•>ÏaÏâ%ðY xèl-,5¥ÀÿùNC‚E!‚+qrhñˆ^jòX½BиVn¼ì (ü‚ƒ&b–"ŽnÔÁh^åæ,GAS·ûMð‡®?=p‹cuÔ+Ò¨Ñ+ßãù:n—ùêü0¶.1ÂMx7øJ´¦ÍŽ}qs¶ÙÌâv€ßÅåÀ*°^ÌaUú«×—ê‚ÇB«2ƒ – óâÓ(`I3!¶¤òYZ@ˆ'(å QúA,½ :Ö¯½eÂ.Ë-¡Ïدg€bKàko»Ò!¹}™ËÐiô @‹­ƒ…™“϶Á¶Øš÷[Å;à¼èWjVÕÖ:jV‰$¤<rJ⽑ 7$‚jBn0àä?BØ­(ÁÀ©BoA±° »ñ¾Åd)XÝo$‡I!ÁÀÁK ».|y öâ<Ó‘e,IbTÍ<·TSXb\ÙWkñ»T$SEM4ªɘ|¡5þ/ï?%æpä&€[(IÃ@œ³_H)Ò0³Ï2Dœ†x±ù"AÄiˆWk6’IÄ€¼ÙÊåˆÓ0¼ÇŠI4yÅ0,ÒÌ!^~ÇG$`¤‰æ dAÆ}„‹MEÁœñg™¸dÐ[è-h™3{â÷Ës&ND\@ H>˜M5‡9O ›€’&šƒ¼å.óÌ“ÌøKÓò$Àç»`%"4Œ±öÅqL’ÌâîvéIÊÌ’%yØ.Å’ÄIæïw,—É“Ìxßrž„à—qÉ8 n&æ“Í„Ðþ" ÑÉøåE—>ç#I0]îáå÷7ò”§c& òûI1S*ÐÓD”y$ß~¨#ÁÍŒä[a0^.BÊL,M4ùÍ[ ë4.3Ê"_üê½ @´ßv½ÿ-¸ó¯<ö £’¥+#1‡WR¢ñ"ƒmÁ,³Ä`ŸgÒŒªçKC~g¢A˜Dc¸ú¤ ñða½Y-½p%2ójñ“yžd ’š"Í"Ù¨ ÷gû}Èã0c°x…åGKñ¨(AèÇ_~!}þ*ô?±w¨B¨·½õ9›Ä%½õ¾È04£þÙ‡sIóqš1„8ÌÅ4ãQN?QÎtšhTš7Ùáz‚öòï÷Þ&’±ÒtTÌa¶@©’dlßùûoAø¬#•¡ çȹdru¹>,d*–Q8·$ňÇ\¾X€.6·#­¸^*šwmÈòØöÁæ`Éá÷»;nãE–¡5§‚œ[C^y¡w Ü\„­¶ ð¢à,ØpdäVÐjP+]ªU‰¶Îœ‹H`˃Í-ÀH¼[¸…‰]2ln–@U0‹r©Š…‚º Ò/\Ë`™'|õ˜KFE‹ÙÞú{‘R¨³ _p–l¥i_ÀeA¿`v3»ÒÂ3Ðà Öú²3Ðàoƒ•¯g2 ÁÉ„¥g2àÁƒýz©/;—ÿ‚û;?\/õoàò _ñºLA¯+(èŠ|PÎd@ƒÿí~­g2à ‚ÿ½ÄðàÁ®¤QÙ(øÅ"Ú‡ì7J,ôw ´T‚q«ˆÒQ%W‘Pº gÕÓ ’$5Vd°Ÿ—Ï1àÉrž¶d¦™`LPj¡±áÔR#pnÎLZ'–…~A±ð\<7NÚ&²Ól0&(µP€Ølj©8ÃE’P‰Ý†Ùg„hP©'B4¨Ô ¡q€øš(À´?„ÈЕ–>7ª34‘´ÂkŸivY††œk çÆI+@ŒW`šÂdè*‹Í£’™Í®Ѧqqì _ÔÜ[ |Q€" CW[" ™0³¶ {¿YñŽ5XnýÎÿ¦…¦r4ô¼zŽ‚NZ‘‰LO€ðºêbOPÉÌ€Ùe <;b `i†ÅæM®oeª¹@LPj¡©Ñ”R3pnm:¬WÌ’ –›ë^Þ2”†aTXl£IÉj±ükÞV‘?}ÁR*³ _0/Á¼Ò ’“J^Ä:éA±MÉuÀsk`ÉB›ÒªA±†rR‰ÌðºÒâÈPÉŒ€ßÔ©@1èT Ø¦Ä|ûB›ÒªA± rNŠL§‚ðºÒb§RÉŒ€Ÿ(Ô©@1èT Ø¦Ä|ûB›ÒªA± rJ‹L§‚ðºÒb§RÉÌ\|…/\n"@ˆ•šš;M×¾(@9L<@†®´ä*UÈÌ€™ …¤Èߌ>!1x®ž[˽ Ú•W ‹îXжŽ$Au-â«.õ.•ÐÔ…r¿ñ_n÷áÃb·üãä[v¯C™¥Â nË_`ºW>ýòû>ô ª‘ç«úªò åù,^5 îvëÿ~Gœ÷‘®^rÎê¯ÓÔMΉ~ݧ kŽSÈA+uÕ¤l_¤¬”” ã*ÍP$Wi&@ºJ%<@†Và*eæö“ûžx‘„²˜—jf#IÎä¶XḸ À‘hòp½ã?ÅI°À‘vA€Ó”ñ¶ŒÒ$#¥wŽWW@÷ ‰˜"âéF•£y“ãâW3o³ùèqÇ« 1 X: ¤cì w$•MDÚGH7µ‰=\,6{.®„KGAÍïw» ÜGB ? EÁž­V0" ÀÒñH‚ •yP¯ ›<Ü)8A€ãu ,h[`9úÃúËúÊ»…+ž ± gámô›¿Ùñ‹E,øo^Dq© ù&ðVìÑUI„o°OÞýF<ÊqƒUÕKç½t®ê¥s‹^ªš¥a9ZÝKç–½t^ÖKçzé\ÓKçv½t®î¥s«^:/é¥sû^º_õŽQ =–Ò1s¸xæEH7-ÍžžùûWQQˆçF%&•a!ÁDØøÕýv)v@n-Af©2Opì Oa‰IÅ“EØÒƒ !רÐò¿²V,ªëib«~ÓȤ#¡ä“™¢ (£$¸ß·›À[IXi2èýö ”&ã€^\»4ôÁÿH?ؽ n×[ RÌ` ~¶ºÓƒ'0à„*ûßúÛû›õ~ãKØ‚-ñ4^„$·CDÔ\Žë ¤<¡OôèGP—àähh-®èÞf½òö~ñôl~ýJ¸Y½÷ûöË6ø¦Ç–ò Ë€‹Ê𪸙])ôKppðéw@ЇUà!{,x¯ ÅÃ*ðp@𽀫Àу|0A¥<œººèë;ØxÈ% xS ÅÃ*ð¬{û•»¨Và)ez§llZCÅ:DÎdû’— ‡Ê,¶/¸ÚxêÆóUy¹ªXEó…\U_côìú~ýµ´ñåL¶/Q6¾˜ÅöúÆóUy•ªñ\U_côdKüå°w˜“ÚÀÎ%v‘I¹"?„ù1•XÁ©» ŸNøTrs„þb¶ /*{ƒtyñ+•\ƒ‹T]q¦Ìcû -6¾êI‘ÿ6‚¬/•àáTwŽ)óؾB‹ÕP!‡¼¨'¤B;x ®E/†ïSe±|ÙR½“"fÁ¿@¿HrØÁkp‘sxù”UmºÒMU–Ó¡CúiJÈa¯ÁÅ|}y…vð\¼ʦU)í+´ØxE”•[Êcû -6^z: äÀÃÃt€Jð*ЗVȇ‡KK%øÊ—‘)í+´Øx5”•[Êcû -6´„Ø“° s?ü/7¼ÝÙWo½ñ>¡GP&Ë—\ûÑýš°…Hu“9g÷û@AA99úlµRÅò±BìN#‰RTãrr¬¦·«› õ4¨{Ëþ5%ø6À—×ÒUµê,–/Ð!#ÜÎß¼"œâd ÐÕý*VšŒCYi:*Ýz„ÀR .ý ‚KÃÃ)Ì6+D¶'yN<"Ë,¡]©B„<÷ö÷5!HŠŒ+äÏeŠ صƒe ØïÛÍzûÆcdÈWë­¢¶¹÷¿]§ÓŒ˜IGB©Î`Êb$pü¨ÊB„” 2éÈvõw×Ÿæ «,FƒÕEžµ-0ª^mÑŠ£ø£ê£VG;/”G;/lŽvy[ï®-¡=` ör‰ïKXm‚of%‘73›°›$èl¿÷ïv2+Æ¿òÖ¥ŠCb¤ÈMÑ4êZ-Äe¨®ÙÖ…òY5©·{#NнŒòé­DÀÉ6(“eÙÕëbÜ Ò_G† 9¹ tz\žçÀÁ§œ»Ä ¢Aó‰8ê0bÌ äºqé|TÆÊ8²/: Úž 0`ðU‚è«ø Š–ÒM ˜! 6Q½Hu¿CdqÁC¤¹á!²»â!RßñY]ò©XOdA{" ï‰ìˆO¤f>‘õ‰èýgÂ*¼ßJ‘¥#¡”gÊ9!Tyªœ—"aKΕYð/Pž,åÖÐÀì%e°Wœ.‡sá_£;_dÁökÕ sNˆéϘY*½@:d©ô‚r|$uÎÊì 5ˆH@Õ)oVf©AD* hS:UÑ,ʬ™i²…Æàõ1/EÂêO¡Ë9ðÚsèR|3ißÚœ§Â! œÐ¢¬@1#BBêYº”¦ØÅÓ']ˆQÉÒ- tÔêp7y:Ý¥[@iÊhw<©88Έ,UhPšJÛJVÀqš,ÝJSF»S? k ¾¨?G ç²~ |’Êcý å_E¶Ê/2{zµ]vÂÎeýuËT8äÍ?®m™jg¯a³÷TêšQf¬T'I©xF>Ê]úà†Ž ¶V-‡ò _¡Ø.bDv€•[oe+ÓIª€—Ô Ây@Bo iPpû2ÃǾx©5lIÉmO¬eϪ‘ æÅâêåÕqpþÁ’’Ûž©ÊžWQW‹cáìc%¥¶§±ª“á¬Ì²¤Ìö´Vy6œÚ‚–um»SlÜãŠ}r(Å+TKo‹Câìc%z±_†k'6ÛIÍdB«8™©Îг2KÈêf?™ÍçÅY™%d ·µ/³ú¼8/µ†-Ñv• x¦<3ÎK­aK´^¥ìгãŒÈ°„<ØvÏj¬(ñ }€<{ª¤ÄB •¨éŽÕrþÁ]W¡;3år^j [¢õ*eWÒêPF*PíQo)\}Ø›—¢7ø4ǽ¥ ØÍIlQ^ZÓšÕ“ÀágNh ZZt«£äéãew'À¹l_ßždA½€ÎI—‘  ’Džª ™Et— ”•¢`¯},+Å·½…Ã\Y™$9û ƒÍäXhmü¬œ O?¨gä6}:, -4}¾–J³2ü܇cÚœ£(& ¦ÕIŠÂ‘¬8J!e@‚ëSˆr$´æ8… Æ.÷µ*ä•àu>…Šg*˜¶ƒUb°É± 8—mù5£ '+ÈãéoŠ£R+påá òºyÇò|}°d‚¨tÂ"Z„þ]ðÕWMì jˆ¬O5p2l¢ HrtCÈSŒ*E2ÆŒ$boŸ(ÒÌ!®¼0òˆ$Í‚|&;ˆöo½è‹ÄHPp$ô+HV±‘ŒÈÍAÉ—¿÷6"`!0ƒ|ÅĦ¢`.WܪKF‘6“qHª9LLcHh´CS1=ü€¡©¨>E˜ïC¹?Q,î 4"1‡ûÍ‹€*ÒTT©€~tíGp?º@÷£ °]`û­l\2‰9ÜllEs—¤™CHÙT Lèï œ4ÙHœÖ¤DãéˆØT~:")˜)‘C`ªC2ŠsZ‘fqÄ ’Oë[%K6zK‘†€xXn$’fA|—üÊŽK6Š×RÞò3UÌÁÎ}X!0{¿ýð9p’4sˆôböë²\²9ÉN~¹›­ T¾"N‰¦bÅCSÍaRÊï‹7ºÈ24ä« |çÝIÚ¤˜‘G.À‰-™ˆXÌÁ’ ‡¸¹‘KFµ&T¦, ã ºCSÊN:5€TP"”»Bšn5 î·âœÀ QvB :·½Ü~öõX΀œÕТÕ Á¦ÊÓ‘ãc$˜FÚÂE+¨n$‘A`&±u6¥z³<ʆ:ƒY±“äkâR„çÏD„¼ŒÞX$óÚQâDˆ°ŸÍ%ãÞÛý’‘á!Ͻ½8¹³"`±{‘!VŠ‚%»èÉXžå¡ø2: mDË_¤Îˆ4ªå¯ReC¶aĬ\”àFÖ\Þ0Ü,ô“[à>ÈJ‹ƒuÄo€³©æ0/·JšˆéVK²Tº ×Òx`EÈ®£‚ä…¨IJò) D•#•9g$¨9X}ÐTTß'W «*@¯;ÎBÅ:& BBŸ€Â2LHÓnî#íÎ];Ϧ¢õ¤X˜á.ÏÅȹøž‹/Ðsñ…f.¾°›‹/Ôsñ…Õ\|¡‹/lçbê÷ð‹Pú„bq•‹¤¶t:­Æ"ÅDZ0³8‰âgÐ í za;ƒÆuJgK ²T€*£j¾º°š­bÛϬ8ç’ÃV’£ ^¾Îgþ*ɓϦb`DO>—ŒÙ"Ržn%n H‰Æ›œ‡7OÁl pl¢QuHÆtGZ°¢Änîmöþê7î¦4A`&ï6pÉæ@³ÏþòË•ERžnu¶"÷Ûßâºp{p€ÐôÚ¿SƒòBD¥Éøež”*/ÊÍ¡/#ò}V€ådÿ?{ßÞÇ‘ä{ÿ•>E™=+ƒeÙ3ã½½B¬04’׳wNŸ¢»€²º»z»ºyÌXßýæûY•‘U ÛcïŽMgDþ"2ò™•‰|ŸOJŒ¥¢aØJËǃ¨ñ°oóµ×,ìÑ㡹¿HË8˜š8ïÓP ÆCžÓ—m¹º ègÑâ!Ù·Р ªCäêCRâáÈ€7˜ç#ö¦¸…õy#¸û ™™Š‚!F˜ûž™žå^ù¨(X÷œŽ… ©÷K SìþýÒuÉb<( Fàõi8H8€)HFu£j”OövwOýn¨iñð‹ 5.Ò;Põ2ŸÎý‘Q‘0óu5+cECBBPñ¯È2cT€Ÿ÷usÉ(û½º_õY‘» Ç$áX”Ëe1 ` *£uO™©(˜IIP`ÎQ2+DŒ<<ƒ‚‚{E&]À‰5((8ÒËÈ ¬D* æíj²,ánáPqE.f÷âòPdMĵ½ñ´t»„LFk×XÍ œOå§‹â²¼ó‘M*Rg¶HWêÎ~aˆÏ+y6ªÆþäâÑQÐ,¸E ` jtâ]x$ÔR#h’pƒt âªGoa•ÿ†9›Ž¬žbqß„í0àºlÓžoSšCÓ)JÌQ>»ZY®\ ®¤#ñõ,0FšT¬rÚÈJlšMÐaHߙϋ ¶ÃNFÇtÁm%×'³Éýû2M Zÿø¾ªAAÁ[ò 7Õçw4#4Í nžûPÎ`ŸKR°ÚÖ 6 jôvØdÀyÔÕù"¿¼,G´z«ÐÕ\Ôâ‘­gAÇÌ&¢@ƒk ‹†Öh×´Cé’q;bþ²sýE[)€„^ùwi¬dP`t²:zÆ).ñAÓè qt.€° ‘~ѱ_Í„¨hXú¹†¤l¿ }q¨(ØfgÁg@öä†%…GOÓôC|†4pØ8Ð㥃¥`Ö/¡evÒû°†–Ø"§Uxy¼¶nتHÛ§hó;¸ƒû©û­ûnÜ"]ñõ‚FC˜Ü%±KF&94s*n>ov¿<¼kq°kA‡:±“à{ó67I7.¿(eš6<:Ò¢M >ª#·ì2tÚbˆØ_è¶¹pX7lØDôL¬HRV¤¡ï 9¾p¤}Þ-•ÖÉE2~…|\!¤¬‚ûO)ûOáÕvÒR»y¼ÈöNà™©÷ž•œt®Â3Iñ€î9`±k\“±ÀàyH˜Ž…ö3D,høû|¾kÐÞåH ²¤ †2Ð M|Û6"éÔwxÒDÀgaÙ:5D¨GQZJ_µfZŸ†¯NñWK“q¸4ojõšŒ¦'› :Ú{ݧ%@+pVСTŒ^ÝÊ>-Ò=kQ`Ý ˆšÒf¯­èk1©½^‚ b*hCHÑ•ž6©*h Î@RаtÅ.¼¢&Ô>uçËp¿ä”Êb …`e1j*lHaƒžÐ KbBKƒJbb—åŽáš3y†ðVƒn"ë`ᤳ4¹àšŒ¦çá€59¥5ó¬ÁÆÌÉÉ«‘æÅHBi€UÔ¤ÅÙݲÚâHé.«Å¢˜µH°˜: ùÕ ÀdHq¨š 4èb Ãú(¯›ÐM†ëŸ/V5YZæ|U,拲Á?X©j°>gBW‹râvE¾ˆ5hˆ9­q‹Å(ʯ  Æ„' bL6¨Fðþš&'78ÉãÏk]Éi$óáµIcAÆ]äÇÎm{XŠšfˆ ®&£û¯ûÀ‚OK2Aón’Í’8·‘^PÀŠ› hí[uï 9ù³uÌáAW(½²­u„+ÖæIXùšo$y¤¤Iä,¿u?Yæàfx“ þn>ΗE3¾Ã“&bÿ.-cäØŒIµñ¶ZzaÃ< õÑ"ÀâH3W‹—)ÉLüæj›¡L®Sµ qxÒÌÕ*ÅgK2xС)eõÖ0¯'z ÞÑ\œâ8ÙÇtb¨d¦'@û'ï`z´œ¦'m*:'®@rÊ:¸Á7Môx›šò2¬ã›êb¬¯±©a/ÉÚY›ö˜§µ±© Ò›t%$'´áדª"^Ê2Ø«C*ø«Õ"ܱ5G‚QšutÐ}Ъû ‹î"HÙ^1 ,½L†Ý›ÁÝÀÙV =ÕP,;2.SênZ£—)µ$§ß6‚ÐSõA¤C‡!j¬wÀ1Ààl6«Ž<ämR>% …‘b`À‚{'}Ò==S¿ Ã¨Ššþ9+,éé_}ƒÐ’Ž…vOAHÑGí¯§: s@ÑÆ°R£ŠÇ8õA|m2‡æù‡¨ØPÈˆŠ€^p0ðý„*´ÿ‚„KÁUí_[É ·+ø©˜FL/0½Ê]B”f’™E: âÚO†‚dðÎhTÌ—Î{¼{V\®ê"kPq°âˆâ̪pˆŠ†¥WCɰ7†a% ëîÂû44$s¸,̸f{8»¡Ó­@ĺ $DÏ,ü¼$ۧŽéžšOŠ*®f­’±À¼zÏf‡8°ð¼;6 › Xp/Þ1LB¶¨ àë?P÷ˆ"²9‹¾`].б%ÜPŽ­¬à€íÓ0à`íÓ0Þ.³že¿3êÓl?¯¼,­@øû&¯wó9­ÒË{Õ$"Aé‡ë0ª¦baG#êX6 › Hðý;²>cº?a›t$4õëê;”SpïÞ;ï#º$ àamŸB°’‘šñõ"½/ )§©HØWùrt !2¶žG×ÕÛ¢®­Ë‘ ]øÉe°AÆU»×Ðû= @T\÷ƒ  lǽu(°X›´¶#ç¨OFWã© ± ô¥å׋jj?7`À‚ïú5!*²y±Ç¡I2Ô¸$-¶€¦¥X.8£¤À…m©¨XXÿ @L ¢ v΃´ÎéùÏ>  |¶ðHX@ïÃ…OÃBB_š@2þÖâÀÂÃ_› Xpè3 HÆ62ºP wUEEŽQt;žQ9«¥-S1+NÉ%DR2 GÚrv:ж¼ñxa{: {jµ—‚†óïé@T4,½9äÕN ÿîìÐ  ’ñ•ÆztCµ):zÐ=H‡æ˜ü[¶TžÇƒáŽ% !z0uõ(˜AD„ˆQÅ63{7t1¢MÛÀ„"ož\ü ðàÀþLÇC»í"HŒßØœªi9»Òuö8=:j»3Œf‰›u½lÐ~h˜©ƒÐö[;sªPϵhfÁÔЛóóSpGZ¢t–Ì̼{ù2×fñHx@»R=Øæöi8Hh4ˆ8Ð×Õbäéˆ8ГYQP°p§ùUAĦwÓqЧ4pÖërU¼¢!kžF…9­@M 9(fË7¤šã@L(zÕ â`‰7U4lñiÄl2û8.[€!Á ÇÕòuµšAÕ¢c•q¹°‚y¤]Ùœ~jw 0 ÁiÄyò¯ÜÜe„¨ °dÂ$$ô0(½  áö¬›. ç_¼¨ °l|Û­ªe@]‹=ÄŒƒÐšˆî¸{Õ謪 . ‰hP2‡\ãCh‚1¨ ÍÊ|CÂ¥ààë%5ßVƒöªª9sîüÛºiBø!”Œ|Ôy&󟽱ÖÌ×EÔ±u·©‹³êöp6.îZIÆda‡³Qœ0ƒ1YØ^)Ì`ìbFº FüÁÒÚ[aNÕ»¶B/(LS!ñæ;èÉ|±Mÿ ‡¦Ï1œàD-Œ…Õ1‚p3ª[çä¿£½mp¾.¢vW‹Iœ­£ábìÖEDÀ„¸’Å„&óOÊ„œÅÑS7<_£ ÏÞ4ñ×?:ú€tYnå0àÀÏŠºšÜG%©…|€Û 8ðÃY Œ7,mâ'Ðè¥i8H!Ñþ²q bn goyºÜÛüCÀ“$àé‚]u `Td_š7 j"¶¡O«›Pñ5ÊnýÒlP·ÔD¬UËÙÒÝN…¨ °!@¬ìZHJérи©hÈ‘§>_@³œ àÀˆK'.MPЃY`N›xÙ£ß hí`°σæ XNPppô ÏÕZi7ð 5náñ¤ˆðœœÎ3ð¢É¤â`ë2DõPgø…i»‚;Þ íh[$Œw c‚Ô¨¢[9 måC¸kÜ05ÚÂ?ƒ¢®½Ó€:c[Í'E\³ó oÚœ.%î4w(ÀÎd»õi ôUH70Qˆ }Éxàñ´ ¡2’¿ÔÓb — +Ä{¨Ý§a!ù«R<èFjÜãŠ!Cý¤UŠË„B| ç3@L¬F£¢†uÖd,°;FH¨ruawrÒ±¤ƒæ“¢‹ÌÙý|Ÿ–y^.'ALFÄ‚’Ju¾ùD,¨Ó =ÞÛžöi aÛ$Ú8þQ±°PoH îÆ[#€ìÓã¿c²'DnÚ§Ç÷>m‡±ćÈUÝí‘ßDØãJAdŸ?¤Ñ3qû³Q5ö¾ØY¤øÙdv†tˆˆT’†õȈýn5ß$ÅŸø(òfEе“3 ƒ, -˜8YºO‡^MçЗož0éC³î0 ¸”v¶ˆ¡öñ"ž†9aä ØÉQ…â¬þp; e¿Xa§c¡¬ v:ÊyéÃLEjäž(p)8­Øq7º‰šß¡c Ý– $GÁí«+þÑm\­–‡õùùZOˆŠmÀL$Ëaú !ûâ`AÈÂyi‹fjôXak¢“0#…a¥"Šã6*?­é4…q] áìäไøÂr~¸È-ZËý»bäßU©QúIæ!ýce~ s)8¸ïËÉÀ¢É˜zõJèpZÍ«y1ûЋp`£IU'àÀܶ¢ƫեõ6„™ˆ1¿‹ã¤GQðÏ+q«R[Ì#¡Ùç€'(0¾)d?…çÓPûÿ»ÊÍ­J;EƒåT‹i¾ôÑ xnÅrph0Ðp‚€˯³ ¶‰ìVÓin¾“àÓ°¡ª8HªŠƒPU$TÅA¨*ªâ T UápP:f|»t—<ñ/ £Ø%°äAòGK€Ž¦ß Â'!ChX(û묑ˆ9¬÷§ó彇#Ò1Plk×b©¨bqK8+b‚ÙaЃDP ¿»É1p|!<¬­€;f" ä ¹Š¡ƒŒ³`×I-†Ãz¹]=D2bür”±R1V±+ H–OïïmVjTë‘ÌlcæÞºŸê‘ЀÇÅm¦¤â`Å3·ä!†#ìßÑ·=ËjFª&d “-‚õº_^›.@2ؽúåp`?2.…sm=È’,À dAÛ™¼-f+'šEˆkm’÷táßÁq$À·`'Ë;º:?p¡7†]"0G ׄ¤bÍÄ L¯ÔVRT4lU/›p |x¶»WÖ#ÿíÇ0O‚àmÉC:¸µ“âè_Íœ°Nl ‚ÎØt»pN¥†yÐñ] ¢baw¯óÙi±˜–ì¬ß× ¸Ãƒq2‡aI:j¯¨`Œ‚…{_•£Æã$¼~7aHIÄ‚’?ˆŒ‚…;ËoÈ’˜ÂÃBñ{ÞÆOˆ#ÁšMØšœ|\-ËäÔ}ÏwOƒÊò¯«E( v\‚s='`Á¾}Ÿö_U9 M+‚–ÄC{ù®J@Ï@³›r 7=NJ™ÄaxzÌ>dHŸ-]ÐþlÜ.†3¥ 9ä÷ö6U#Þƒ,o"ùlèMÊb¶ -§,z´vð5V=qš5-’އgÅ|rV©ðÈ) ;£ Ó¨É)Àok¸7 Z dçÉ)ÀÁ¡US@ƒC¬$¦€žWórDeÔdئEºË”"$8õK"z¬hìoÉ}ŽÁ¾&‰)“@TS4mèÀšœ¢m°&§h-Eפ ¥hÙ0ØhrŠ® ÀšŒ Ic?§·›ÏÕí(x1ä±% ¢G¶'ððàð MCÏüUp”·8°ðûÓ‹b<.Æ-»œ>V¾š ÐdüÆýÌЄmqà«x6>¯¸Ë¨_Í~x¶Û€L¨)ûî‘#Œ^±®HS+GMà6KÊúº Ý §¬¶×ô”µwô÷éдO7Aô”Et´Aï¶flrv[96– âL\5ɱY:­ÆÚĸŒ©ÂbätÁ®6!WÒR ¸klÔOú:®MˆÅ•ºªkÒ¡÷Ëe\›ˆ£€ZuµVˆÁ”º4k“ÑaæˆêŠ]»¡\™µ^º¡\§µÇDè5[[9:õt½‚k+K'1T϶ÅáI)I›‡'}9ØVŽNc–^ýµ•¥“˜Ö¥Ë`búòM2¾d׿]ŽfJXtÙ|ZÚr+ˆŠ áíŠï¶î›ï¦mš¿&KübÞô7èè)höaVÝ6oË[,Ý4Ît'NÜa-ìœÏ«ù¼ZÀ§W ¶Ä*§[#á­—)á+0ùã¨Êƒ_È,Ž4øw³I«ÅƒÁ"Î.+]“€ÕÖI„N„ùLÉ•|ãt,4ë­;Ëe1ÃmÇd@0VîcEÀiê  1;µ§™NŠÒ‰Å]ò@ìdıg;b™i!Æ;<[Íþ«º0«ÐLGAAǧm :<íq­Ë6›“ŽÒÏoZ~:¦a8!(ÌTD³ 8Vjdñ83X U¨OÅÕ¨Sb—€Ó<5êÒp¡³®L›FµZ˜‚’Tt²f;+.Wu“ 4N š¿—/sY’ð€îq‡„n£Þ#eê3T8MÞNŽz“߇§7ßè+A*%6û`pdç¦ ±™ÉZtQX21„VÅÉÛÿÞ=9>V fb$ˆíù6ÿÉ8fí¤#¡Ê EÓqP `ÿn¹È–õvWÜÍ*I ÞY7âZ äU$âšœ•Õšþ, ^ÃùdUÓÿ””dÍÈ?‹b¹ZÌ2‘mc}Ý# YF“,™4õncãåÓ¾vçÄ1™Ðç ¨^òó}g$ÔGJiÒDœäbv7 ƒ‘JM:¼>}`„€f;ðï»\ þww-8Ž6…þÒC}ÚzHE”Mè÷n¦G½‡7¤]W‹sI‘Éʯ1)Ëá²³Ò}{› ýK¦J°Å’•Pƒ’}GþO—*ߨu›Û]ô1"PÕõÚÛÛƒÉ7¤'ô¿‡Ô%¢ò˜oó™R@Û«ÙÃ?~Ëéý·; µ:žn¶9Kõö2rsÿí˜ýìnqd+Ó¤ÅáÙ£(¢Ä4éÂïÑ<œ"Ž´2‰öyL¥Äïæqã¡+mÝÖI lRê¬ÈÕÃÎÛšLIMÉ—¸V)¥±ÍFÕ”8e®3ú`ý͓פݛóóÓ‡nåVs’›”¢‹ŠÇÒÉÖˆ° á ú±¹§& ¤b<œ/éäÓÕòz¸Ôs–ÅB‰¯òºðæ'­ºÐ\§dßf´œ$óà|x¼ÿÃðíþÛ“³_BÌH®ŒMRZ,™¥¤Øì»õÍuŸ¬gÓØ]x¾2gäs{’VuÔÃÜkCÿ%SµfͲs,Éwž_½Égã‰ZYÈE—Jïa™áaJ=-b½º—–^«fn¶ùŸàaÕA{§Ngÿà1UC{ ©\¾Âö²4áauŠñDއP'³gC¬çòÀ£BÿåÑ:Ú‹yÍ|2G-® Fì9ñ=l:q µ'bŠjÒÉŠ{ôp:Kxã̤#M=¶Ž†è& k­¡!ºe±øD¢›44"k>lï05êcÆŸzl›Yµ´©>°á,YMZ}ÿu [îû¸Ú5>¶††è& P„[­† ÆùKÇ–{l‹¢54bº=ºŠ†läŒkÁõ°Pvµë6×>†v©³ìcè–:¿>†n±3«?“=†vÑs˜7[<†v©óÄcè9Cx#òcè–<?Šr‘£°½kÃÿîá ŠZ¸ÆnÑØ‹ê‡Ñ½‚î_”å²¹©öåº+emñ%l?>¤*Ûç4¾¢ÿ±Þþr/ïå»_îEú’üŸKCôþùß> Âxgı«ï²ï<ÀÎr¨Æ\/4hi«â“O¥§Ö ÅžêÈÓ§1fÛ¡%qþÓ¨Ge7éæ~&ü*F~”_E?•šê«lËÌO¤Ý¢™žy>‰v­³4 :ÿ‰Ô£²£é€tWÉteâ|™Ë!oø÷i9²Øcõp1üßᨚÕË¡šd¤]Ày8ÜGhïçÅû³Æ™Ú‡×÷YÙuòKé¼%†¿-k*Ù’37S2{æÿÚnoÚn¸ÇRÒ'«}û$óïÕïV¿qûÔ¿qô‡ErNên@svÓkvÈ(reEG.êVörOCañ5_-?›örú£ø4GŸùÄ:¶+èïyZOä¦P*¾ŒÙ!áÅo†®ây$ƒ—=Ñ–¦&cÒ7_Çãý¢ 4&ÁäI¤6_¤™ÀDè­™T|ãó” “˜ ó‘3Ÿš¤~fU¹ýaè¢ «¶F:‚Kž=7±fîÅ$‹ð·Ë•,Ä…ì©ÒÍÛR¬‘ÆäY‡ºS™'ˆ¥ # ²N§ :ÊgW+‚0Us-ÊJeÂl¾tqr¿PI ¾c§·]×NSRÕpMkšµ³IÓt _%qÆy»R¬ÁQ¿Ï½¦hb8©‹%°Å‰1?÷r…3˜‹  Š/ㆊ7|7#‰â›ÉR衺 ¾³¸RÄ•È$Y\ɲ‚÷µÜJd²,®.²ÎôòAü”øg–4¿Þç¿$n‡ pãFŸ‰-’¤É‘,ÅÂWÈÝ0éuZ,¦Ú(*…¡kz²úá˜äo/i]ÁÅ˳®Cý^íšÇ›*TÙÂäo*DŸçíÎÓu%°DS çJ–¥N•*Aæ9Ó5ƒÞAÄ^¹ [[†‘"DHzª»2tUt¬2ÛgøTWÔÎøFß0Ó,)]úˆ âöˆæ îÜ_ÂØ¥aªLÓ©îT•ùåe9¶Ú°¿“Ì„;œ}H¤ÏüA"Å“ßkoªPu+ÁÚF²S©@‡/UÜ…ñ!êB|‚ºèòñ‰=s(éß?}˜ ÈÎã/ŠËbQÌFÊ"N2ãp¦J——ª'™Jt9“%V+cÿbø<=ö±"DHÅKÞš>ð‘~ÖÉä£*ç; ¿Ìšp?[?žDeñÿ¿sxžQd’AT㦉SÀæ=¥fž5uA‰ÞK’]cËxðgÉ¿Ln £ð¶b.ÅS‡mÔ=Ûè š]$¬jv~èü6iâSe¾gT?;%YÇñ°Ö `þ‹ÊéÉCx¹ ­Ïœ†t ƒ×ôTWåX»uìæ©©˜ål˜ÅOŠ+)éÈKÊ4ÕÚ»¦›?—n‘¼üzh¢ÓŸ\gNé€üÍŸ,dúS 3J*²:<* åoŠ­–&‚O*½F£SP–– hží¸F…·Nÿ¥J©Æ…66ÿŰyz*ì|xzrñS1RÐ:…Â+êfªÏǵ¼Ûî~m]¹Ì6¿‘ÄGƒ#YŠû ÜúòÝýƒ7íëtêëeF“apt–R“%–ñÁM·äIÞ.B'ÅL7^• Åpj2>·¾Bç?¶ lþLGSù#U ¡+äo>íæ]Cq)´˜‡šóëÅîúç†p½éN÷öIzXuÉ 4nô¶k.y{Tœ]±mV]±Êwƒ#ÔWÜýÀðõ› a³ùqïµÆÎÑ_äñÃÆâ˜L~aì‹=íE1ùû+ˆZÕ„‹¡YüB˜W=Ú‹ ¹û+;ܨ¿âðÕ7ηk¯˜ûSžŸ„lÔ^³øê›,Ûõ×Ü=@„’ «/”òÒŒ€0!Å(ó‘%”!cú*CLjž*ts.e‰Æ(8VüÇ&Íܾ¡Î" ½Èƒ4ˆ“S¾šÔZõá0BâaÛ„W o }@A•:ÃlSmŽ”÷.ÐvK×…ÉÒž¼øÙ¯@<ÐÃvdëAw} «µò k=Ónþ m ükTKj4 )h8\ÃLù [&Æ¡eKLÆð"Sšø°K/W3D™íÄ/í¡êìµSÌvvU8Éú0΋ÆJkÅ@ëz…iXÎnò Q-_\­¦F*¨”õruÒA„9”9l\¢ö2yØAu—¿@gס¹ôã’R§Ù]·¬ž]5S\§Ýú²Û¶Öî§ÈíÃ'TÌö\ðz¤qx㉳€éVJ;¼§ˆ¬kŒOÊŸ­O,;0ÀS··s`€‡dfî<Ô éö]÷ÆhÛ‹-Z:J.|+¦_Ak,¸F(­kU¨X¯u`öð~"á6ÔCÿÂyýFÎ…êõ!¯þ4dv͘,öÑj‰8MêÜhS}Y|òX³™Ø_u:w½ºØ…kër!>P½o×zv/Íõ>ŠU-$PÚê¥aZ§ ;Ÿ£ônóGv¢:>¶¶båôö!üwc¢ {ÕÖõƒÐäã¹Ü{ &b§ÕöM *ÑÏ™w«HäwšÖ–øKWn…ïûY?¼Wy‚Ë<ƒ¥Ÿ/R½Àôѧ°äúðýèU*Éyh_7›ãkl[ŒCLø¼@ó|ì6Lsm³Õ4“™¶·­Lfå²»g5Ë8xµ6)Ò·-â{jAþ†®¶š÷¬ú—´`ÃÚTú1¬òÊÙ2¹äH“‰H`lå&¦d‹› ½™ýºZXàEi(?e³*˰rà¶Q™)Ñ4&3K“-)ƒ˜€h^hH’—a|t}O¦¹¾ ©Km9—µÌ4ïbV'ACo–àR$t°­Å"×€º‘9×D Ûsç·ÒNX t*s]ÐO¡âL»éÿÊc(¶ :!©ŠåáõùéxË ”æ}7N¥ïÅò˜€YutÀ/‚&AÖHs "(–EÔ¹ß$úHƒ~œw ú0"ánôÊD |­yëïðƒÊ¨©öBC$B&Õ´¾7€DaŸ¨ × 2[’k gUh¦Æ­ÎLnóçüÙƒ­øMi»]È4 ŒšÓêúw,*®z[ÆiõéAÚs0Û]R‘ 43$€m æ³¶»©<¹ó`eF•ïdºE‚y´ÖæaSõÖfŸŠé›T3¹`北ûTωyÛ¤£Ç +êFÑ}mu˜Ä…Mîfð‹}ª­w6©krÁjÁFûVOänVOr…ÕS‡µÑG»­GgÏ{ˆZ[û¶¦áõ"ò….Œ6{´Wcû*­¼êë­îŠK•7|Ó(·¾U ”¼§+§ZÿE×O—»5PföÆ)Pb–Þ}ŽSÊu8ý›ˆÑv·ñ¡Æ‡> ¬Êd\³õJd^Á Ù$>Ó%^¿¸Ö…]ßVýÝçU%Q7u¡å§¸Ã²B\Þ¦À^ U0$h+3=nÙ ±šoG»n¾|¯H)fìw!¡L!/O{–P·ªC *&gðF¶_V}ûÚoh=ÝÌÖxåkM­nc‡Š—7|—Xkë{Û~ÑûºÔø¸(wk> Ìí_oC×Á á}/ÛªrUA  >¿oýÊ °Y h=Ž–ì; ¨H²=Ÿ_8Þ/Oï¯PuÃ×…¦oF>s¨ø½Jð U7}ý@ˆ8MáÝxß)v®o¦Öe8l°öl•óRá kÝD€+£}ï¡ß~¾¶Ýnû–w´ù;J‰0wóUòóô͈ˆ:sd³.¤ÓÒ_ðŠ>ææš¹K†Oª‰×ümé—Ý»"Àm*"µ™PÂp@þ}zïÆ©‡hÌ”·ì¸¸'Ue95ö ù/*D¤w½É'&.ù))%ye[]É`««NÁVWålùÕ7&,ÿÍ‘­ ¸¼teD/]u _j=RŒ4&Ä<4ÔY?ÍâŠb©–0Η*ÎØB¢t cn1§Š00ËË*ÂõÏŒ‚`oš¿Ëe™OþçïTÂÓ,{&åNÕæ ¶ìEÇfªl™9æÃÝ5B<‘çÅ·.7]Êð“/‹…›º{¾{À§ûÙ^Ûé…S©>…]Ó€Sù=ŸD_ÐýëªXì3«Ï°(Œ+yoË»Ò×rQyi{ÅÅÊS„%ØÁ)Ÿ4É!Êã(=åÔsP>¡Ñc nº-î%—¯:Š%}õ—5qHoÎÏO!t½a Pøa 0USÒLwÕÇ.ÇUe¨¡~_Ž>HGùìjEÒ£jîÅ«›ÀÒáS d6v a!+¿nx*Ø Å.a ™Nã.‰]ÚÒWdD ©{¼"­K=²éRù÷Ý|ÒÐÈOóÅ2[¾bà§ŸËWU5 ¯òHp»OÕ»ÉlÃÐO,CªšÏ´»4ãauŸlîƒ œztÜ£X„ûTñ¬·G`;„^ªz!¢ˆ×ƒ ’ocëÁ!(f'ñÎsˆ¬‚S» ì-e?ÑxùØ#ŠÅt(ÝxS8Ä"Î-„Èz™îsÜÕ‚Ú¡ù‚­G wªð;° œÐF¯G{iô½T7Q;SÞæsˆLzìRþv¼ $AÖK™.‘¿rSkÆxYÒ¥XWJšùr#@;ó: 3HϘ¸(M½.èÄS}d¹ÒsÈ2zD ™}Griê…;Ÿ Þ¥s u_9”î—ºâì°„_Esí;• Tº#êÕJ¬.ü9‹†s’ì·²ªó®•Ke¯R9‰ø¾Î§ì{÷À’'8üÇê¾Ì0°í/qñÂ}1ÇegÙ¸‰ê ‡ÀžqÒÄó/^ªÏÇž\ñSé~ƒ“*:q’Ù…;Éx^Ä¥°ÇAœDýÀ‡Cõãý —p-Œ·*Bñª@f¯A¸é\’›JF/ÉÙõTñ,Û剳V>uJ«Ó>òÓÆm‡iãÕG%Ú8Õ€6Fý½•Sì#·ð5£Ãgvb®%t×!e»=FVÃ'›˜ì( @LlX({ÐU(—Òâqï5ð4µÎ¤@ @톆2?^€›véýFAl—‡¹dÓ…?LÅ®]úc[k×¢ÿÐb­2¹­w|lm—Ð)Ç8›þ‚Å•ä—d&XŠÇÒ¢Š?Æ¥¥hõ@Á‚B{ŒUÉ€W„M¾k˜5²‡@n‡Ó/R‡1{½^Ü &í:n°¿ ªAÈË |£²•Õ¼áØÊì]5ŒÎažÛkÍdÞ¸‹b–ëˆqc¬9{Ôõ«fˆÖ›LÙ»/?®×4ÂÄÝÉè"¦'¡.94Ä]h†HZá%œ[o„i?Þ”½i2‹ñ ZƒG;%ŒÞñŒl«°Ç>±é*tëŸDtXøyA ñ&w?¦¬€]myÊHö«MŸ.DâÑ›l¢>5æØÆ¾{²k”ÓñCEžÞ⇾²ìŸJ@Ü¡/qÔìÅÇ­¾Ð?œ“l¾Nîù0_¼w‚¬ƒ$á&€BŒó_™ýû¼23Kᮎ9I=±kj'ÏÃuB¿,!pzp$Û8€ÛÖ8 ×A q\`xzȯ.«é†FÑ›6ŽÖF—.ƒmšÀøüwWl¶!Ó €ë$Å>0’å«ì"Ñ? U‡º´,‡£®Ï#Y¼fˆg›2'Nà‰Ò€° +¨½h2È+ fƼzP—pxÔIÔ ‡:MäGz2ãZY=꛿Ð0Æ×Ìþ†’§‚åfÇ­2ùß:…ØÖæZ<²å_h-è-YqèÌÆÛÌþÝ…gÈRWĦþ¢U°_,šºž Ì;[ßAf Oyôx~:ª:bëÃ]$ð8 À¥±ø¢Q‚ðªõ¦£—Ø_eWÒq[ ¼y "]Šœâ@íóŸš(Œ¼óÛyñŠéÙ TÍœì’ /&˜€ŽÍN¹lMø1þ››ÖÉž7œè2yŽ\¸&+Ó¸O 3ïÛ¤K1®æ€RÌ«;éR¬[> ûPI½‚…ø¾¿ÉVö­†ÌKâѲ¦ïÛÛ5^R †µcà$Ää·Z–““ß¼=•9 1ùÍ»N™“•ߺ•yIQö½©ÌO‹AùÞ-É÷¸’˜—¯2'!&¿y#*sbò›×a2'!*¿y=&sS¢ÚRç±G¯PÀNk.hºÈ:,òîa't~z?„/Îöw’ ;GHFÑKM¬N£8­ß°D“æ/Ñ€Œ¼ÐX$­cý„²¦•'¼¿g^ íjµºABÝ~Ûi’À®©¦K¡8Ï®ºvÃmj·Ç½x/Öä˱gœtIÖ ‹r&¦dYÀÝ_P tG8]ª1Á[ÆæŒ—.å¾a¬ÑcI|qÃ9 @Þî($ Ë·óºHiXª»÷xüð„ÚuKFgG4@l~=¼ rÙØJ-¿*Yй Š ìcåÜA1æø.Ršǃ˜¯ ÎùÌOã·– o£é}Ø]E€Eè@dXÆå86í KD(ˆ‘ñ :H`G¦`x¡¶ ˜ÐøµÚÝu2â,ÀMÖØ\²~Ff7ó¢2êáÙü«4°S§#ŠÑü•5Òˆ¾£wÎÍ_‘™õö­ù Q“â©xþÜÚš5¼SÝšÕž}Ü\ï6eÛ²6ÄÈÉ!ø”CÀÃ#’Ùä; K¬m£¼mî”·µò`ÆæÖ”¾¿nÕeƒ-|s' Cд]edD¯²r¡KaôD¸0VçM·V˦j?›©á0rmBݨs½èüæ±K—F]‚"øÉÌt\3fÑôÒ‘õýDÞˆËׇŒ·ù¼E ˜ÖMRèèz6ߎ QÓe¡g§b» íÚáQ«úÀ°^Ü5çlÞjÎÚ‹’,ò›óÅì04#4mö4ç´¨CÓ"¹:¼Jn1#rSÎAKh³-^ãÉ$÷s!ÂQ¦cרnW§õ¹†lÍ®!c¨·µËºZC¦º±¡ÇôÂð¦.Ø-¼§Ù©©O6d wÈ&K#{cÞ ¶PS6cÜ&w+Ü (ÅŠ—›.Ç ­ ʱbïv’soœÊ¾°á7" p'd§4/ §Ë¢wÄUñ‹ApÝ8]‚ˆx âË ÉÑå=ö&)ê®{²4‡¹esÆÚ ¨Œ|ð¨dS»èÅÂc@ÊÙ¤Óå¨XÓ ‰º‹´: A†´N–®Á®µ âaƒà*¾vwü@o²Bu÷"¥©WÑ¿“¥†¿¿´¦sXkúÜõÁ6þ¤2Ù1Í¡‚¸aÏ{‘E#¤· cQÔ“¥Ù×!YNHödIóxNâÑ8Z* ŸŽjÇ8aæ“e9é!YnÐútY,¾=(‚G¾OF~¼˜ñ\{S÷GŒWÿ ¶s áq ÔÃ-‡ÇzìjýöÐBh•ÿ˜MøQű)üqÍûø¶µo±<¢¼Ob]t¿Vô/ëQ¸/†ù»Œ.î{!°lïU‘NÍð²î$!ùMy:hÃÞ7eò—OÒ‘Õ#) º~B%Y{mçϰ$ãŠ[ dù˜KlPã²KÄ-ñrL—=*Ó›Æó `³PÉØò\½p“ŒN*CÈ쑜dTã=Ü|n']{™„çoö$#ëç} tãñŸd k£VEÆ{Có9¢tMÇ){8EI?9ˆ@ šÜƒ ñ–R£ ùÞR'iìi¦þnS:>·:ˆ.^JÇ&t˜¤wAu⵪÷q`Y!î5A°£P/^õ(_ÅÐŽÓ@¿¥ÕŸví(=œ—ºúÓŠ¥‰õ Xzè ÜQZï‹õ§ƒ Û¥‚~¸¬? tØï(Œ'ÑzÔAÄtŽÓ@¾9Ñ›üæøÞ1J5#<¨¦ÎƒS‰ÚºÉ=‚Æ-ì¿]÷ðZ§Ä(ïT¼¤ èýÚ¡!"|tÑšžñëW[”­¢õǽ#Ø­D˜'ÁOˆòn¼þ›í‹¡Áe!ûàa’ÍÑþ‚b°#_즛ûNcPïAÇnrÝg‹‚r½G"{‘Û:_»ïNv”šòDeX·¤/{)AûàѦuÄÛ+Ý4}¼çþ‚E}Ä·@û´U¿Ï†FZ§ç·Jû´æ±²ï.Ú&ý 6ì2î5 »3~<¾R¿Ä6¤Ÿ©ýd­Éx)·ÏþöêFÚìQÞ÷íÓvý?i©xƒ¸G»<òtÜ𱵟+Ž«÷ß ‹6lïíú×ðd4¢5ýŠÓ{þÒËFÔß/½(}ÔÝã?Þ\ŸàÉòÞ¬èû¥é¯›ÇX©Oy½Yá^°ÇC=ùÞƒez|¾Ù}>Cß­Ü GMzG)|A©þ^´ˆœw[t‹Dé¨1kÞ|£\Ì]êyroöÑ—KÐ µ—É]uS¸Úi÷¥kR[¡Ò{)¿0æ.Ke" €A‹_=€¬~JØð‰Ù¹ï„ÚK‰øqÛÄ2 ®IØÊìOPåfmûÔ,’[* ÖUós¹|j´IE˜?¸oígÒO±Š°¡Í,z3¹Qt¥7¥Æ•ß.JõàDñ‹UÇËö:é¸7XµÌœ}j¦CxÅjdæè[yÜ$^™££&jm:*HOÑ›¶òª/KOÒ8 §7­lž§q+F_Úötž!¯¯R‡s=™æÁݘÄcõ¥½:Ô 9Õâ¸oà”Uðô ÓtÒcY&ÚAìˆÛW©ä jO¸:ZÓNcPúÒX¸öW ê(vŒÎq8½i~Ò Ñ—¶Ò‚¬cТ´ŽÇêK{zÏ’&Ò£´nÇ®%âBI×ü`B@¡‡xc©ß´¹×´óé3ÇÔM¯Òú´@ërÖ®=[´URƒ³”uú½]?û°|’e:JìÓ诜âÇZë±µ ¥â5õ§?v~B…ñõO Ãù÷é}SÀ5ˆ/½Õ-Ëi`¥Ï)Ýor0j— ¥c¯BAVÝ‚:¬ÊÙò«oBÐœÖ ='aÕ9P‚ù}”`Ð{¾G6Êaé’HY…oØkj @.Í¡[°›æïrYÊ–ÿ4S§jÙÆbµx1t¸`#ÃÜ}¨È¡‰ d'YÜ&òSé=';Ñ|¼È¡\ç37‰G´†©&.G¹„ù«Ù…F\&kÂUÁ_qé‹Â8Úú¶¼+=ý•›´W\¬\XÚ€âv)“ü¾›ïw8 ¥«–v즋ÀÙv²|ùÄI-'®ùŠ%}n“~©t(*L¶¬w¬|Ì.š;é~`l›Á|¨Ê¦˜=Ù”£|vµ"ɃQ5÷h28¹ ÑȲÕtJųª½©àÐÄÜ"„©:`Mç.¶›f¾oæÐä8Ù|E æ¯~ÁTãÅ —á.¤ÐÞ¬‡ R°Ó4¼°d%ö˜‘“Äž!²ÓŒ·ƒB(اùc½ñ´ŽM Ïâx)€ýTˆM¾íÄÚÃ0Ÿ9° ÖË6ÉzLÀ#¹Ý@Äï÷ÒdÐ}›$é(÷vºŒN¦ª%˜EU—ÊÀT~Ý&é énº un¥Cð:¶8œì•ŒÝmq4lÚ|Në ‘œ¶¨j! Œ?Þ”ÃB3Û)N,e‹è?¶‰_°7³?bèXGnCœN‡Ó‹ªéÑÙ†Œ8¶êE½´¹y¼J;MG™´Òy€H+IFvt=.OÑMdë{+Q0´RYðA+ÅŒhx¬?+͈Ðg¥ºˆ Ï&À>y&ÈHq•x³“Ed6;‘FUsRœ-7û¬™O…(kaÓqÄš@_ÍÌV,®fV#`V3£kÕÌgÄžja”'­Ùš¿• óº!”ówÖ i·]TSŸöܸø9>*ÞŒŸ="ŒŸÉ‹Ùâ³xáU‚, M2- I'â³¹Ÿ÷cn´ ï9¤E›8ÌÁì˜^ûID!Ú„?ÊÝü6%àÚ{‹ÈGnå[Û%xæ*Ƥ¿ŠkÇ1ùÅß¿ âÜamÔ¤×{¢M’êf@fŸ—}àÊ®ÉA rÆ^éóów»PÂëp—-Ùï± ”Ä[!¼/GD`ï(0Ë<-œÖ›^ÿ:Ldë¢JKë*I¯ºìáób._4去Ñ„Ð~1¡!wçÕEÊ!ý”ÈÃì"úîXwCþÈ#ÖM)k·”£Ç (gsù›¦¬©mú¼ãŸÙ]X¶ÈzôÓ~¶>·Àá<‹C«óÒèy8+qåo?«#h^ª¿µl÷‚)ü€–E3ŽUÙélßž~zúåfö…ø';ÿñt?Û=9~¿68<9ÎvŽ÷²ý¿¾;|¿s´¼»Ÿ½;ÚdëûÇ{:Óæ—Î*>æÐCTÆïe®›|jœÀznžÄú·òr\\fdØšOV5ýßÓOÿ­˜ËKSÍ^þyšmfô£F&Nw•ÿ`ëøm–~]ÖÙ|Q§ùsY­®®³‹ûly]d‹âW墠›bäw¾ÌfU6¾ŸåÓrDóN‹iµ¸§¹Vu1~žíLêj+«ËÙ¨àæ •!¬³\¬FËÕ¢¨3ºÅ^dóŠTn± )·ž:‘f°“ÎÚ@uÀ.òÑ ·¬Â le·E6+ [M‹lRUVólD–>)¡m¢çÜDÄrã"gæ¡V ÐÙÿÈ€B4œL˜µ µ ˜b ³XÍh‡¡ì3"r2!–r5)D¾ ’'÷ÙeIcOåüpx0<”*|Ìä®g¶Ì?N„h±Èïë¬Z-³êR™z*^¶£ÖWF!¸9¶˜d¨ 0¼l:ÓsjÔš"1èì¶\^3žQµXòdã|™3`ðb˜D»*™>†Ùª«‚0/hye‘¥Ç MŠZ:¯ùÐñþÉ IšA>“–P?Ï~(²ŸVõ’vN´[°6/êŒ0p³\³i"+ò¡ñÞ3.oÊñŠB³yM¿¾ÑÖ$ÚPyI@h#¡Ü×9iŽ©æ|BV|ã{”“¦À± 'í*¤ÛPãP,NÕ…"Òˆ‹•I¥1ûi3T³â9µÌŒJ¾Îo ZLZ]¢®(503Ak¡^² <•ÕQRX…X‰õ¡1ÍM;)©²Iù˜”u¥Ûê‹1i³³šÌ’&ܧfYT·¼bëy5×ÌÞ¼ôë´ V1¬ùäS¦×l5½(´L$+©7ÖXŸÙÒD--xCˆ,ènáeµI»Ðj:£Å!V‘¦ —Õ‚W3ÅWÊ<ø*Ú4ÌIfÒ‚x"çi‹Tì(§•WH+ÚæÝä‹’ÿFQ¹’õólP1 Ià‹U9óÎáT×Å"µ{IšcP PNj7⤕¬5¨ÞÇϳng¶êrÉôUGdDÖÛUÛ ö›P5ˆ‡0ú †HÂ7®¨9¦9íʬ¿®D¥²ŠC¯U{®íi~ÑÿeÏæ]§º¼Ü2úTï‹ï4™gXÛ®‹‚v˜’áØ½IÖ¡jj‹‚A°±Dô`6Íe_md‡—®ÚG% ë«¢R_@•ð–cs2,òáÃãeÅEÕdr\Z(ë\cfjA6znleçoö ª„ZÄ1®nÒ°V«TÖŠ õ%˜!ŸÙ&ûš•ûÕÉùP³žÉjÛ*—[ Þ’Äh" Ì5Û`ÙähÆ £Ú0˲ê…Ò’òÏÅMY­¤]ÈØC5bÃ2Çé¬^.yþ¸AšËŒv™-Úœú£V¤mñ9ö–™K wš¨ê ª÷eë²{ÛU²aÔÉd¢-n¶í~7æožbqG´˜ek»kÄÃ$ôìÅÓñG_ÐC4—ð$ÅÏ¿œrƽˆ³wÇç‡o÷‡{û¯Þ(¾§)£ŽóSÐãX§¤lsÄv4脲Á. ðóYùòif: â’øqMjj+Û¤ëtÊG ʦ"ú7ùZˆë‚ @ºß³J(£Õ$_ðúQSk],©¯B˜H+Ø¢?é(AFbŒ&¯›~ËŒ˜íÛo_p]™(].×Éá™ç÷¨yâ[¢zéå°f–o­–ÈAu$œÏŒ4ÎDsÂWô×Ǭ˜ÖùO“ð‚”Ï÷b. .D>»W]dDþCç Ž]órUC X•KQ×F-¿VýÌÈ`˜“­%˜“L§.:À cŠ€O¿lH$µOÚ—„¡Iöºb5(kBf&̼‹¹˜ª@Õ-Ë„žÕˆ8’¶*¡h΀3é$_¬x›+—’•‚ ¢ÿ)¡Íù[Ã*¼ÒÈÔÉÅq³1¦o-Å©t²Z¨Rë1TL­Ì1 Fb.Óçläc¾Ú”–l¢~.Õáó qzf/ÅïRªý×ßѶÆÉ³Ûë’e~ö­Ù68‡4ZE…ß–5›>¦t°¦Ãkeè=3\ ¨‰nˆ05ñ’Π[ùtˆŸ®&Ër>±*“/ 誔LdRµQµšŒ¹ÇlMjÉÇœ`i¿<“0—&2o tÒ¹/–Ìv‚ìöý\â õN˜ÓC…¹Íéâº"Ú‘¥ál¥&d6[?þ<+nŠÅ=¯éúšᢠ´¿áNG {|P £Â†Ñ ¸Íމ·J7€Ió5yÞÍ"|êñ狌Lߤ—ëkàü°Í¦‚ìßÇÿo¶¶eAÓtÒ¤Ä|“±!a½dãWVfñx_føC){‰³Üd>€ú|*)¸A0n»Ñ?E«n(`k™ôgÿ^³R–[ÁÉâÊ¿“ÆL¼Y³äºOñ9nÁûüŒõ0ÙdmoW 6ÀÄ–}fw=²+±R¼ÍgW“bL7ƒØ^·7]0{ôŒ+˜d¨zÜ_’*С´âÛ_2=H“öWLÆ- -¢&.«uVY}ðÊ C&÷mçÇuj´MšœÍÛQ^¶.²xt6¯”Ea³–Ò~û1ó©Ñ ¿Y›ÚWª‹ÅR­ÔAÉÌ÷ÿ6èú(D1˘.µÑDöªÙçKµì¤ó í¯‹)Û‰ƒfC=Û‘¾Î‚n ‰®CyaD;ҚƵ¦æž(õìÒ!ÚÚÕ’HÞˆkhfùI®¦†e@ÿÓ’Æ›XcÛàK—fÍÛç™å<«&vïj-ÛªX>~›©9ÂiF2Áé9¢¡î² ºdohlœôwªD—aÅ¢m€a®+Íy§Ž©\np†×ZÁÊZQu,±?à¾uœÆ`´‰ÏD£è:ö»±}R·@2 3ÅÍêÓé_|G· H‰´?`¶á|j~¿Ü&šƒ#YhÚþ`ާ¤ý‹ÚÇ” 1^¢Zìôÿ»"+FáI³¶XÖ¤' -¥k`aõãÑm’à ÛÙ.-ékÝìR!lêG¹qtÉÿ“ã·9îYÌdò în˜¥Zd2ÕÍ‘h«~»Èˆq~2›ˆ”¶€Î«%i l×v[xÔ?mȺN¯3Ñe>²¢lᮾ"ÑÝ-úIpž_åK± æúlt«–sY=Ýdû ³â¶áØ®$‹%þIdÆ½Ô gl`âþjÁv¾Ø¡µï@ø?뛪æ×56ÁÞ …°²Â%Ü”=ò£Cy¶h—ùO«xÃ7û;{Ú©0‘Õ† D£mñðø|ÿìØ0—óE†á¢˜/Ö=6iîwÇïû{§;go×o6„÷›þ8GŒˆvÿ}GFö»|Áþaªòé€È|7+i‹#ޝՔ×Z_ûË€8±ë¶þŽÏãdbãˆC^Ñbpúˆ0©Ð 7Ñ¥ÖØ‹ ÑMÅ__£»Î´Ìˉ›öSE ñËPýs›_iÒ·™X³ aÿú–üÏÆîd©g(ÆÙM·Ž«`ñ“ñl”/×k:\R0Å{z?Ü+FgÅ%¥©37’YB>Õ:û&ÝÊÖŒ£vHñ ê°òzþÒwCª¯*¤&¨¢­žîP~z–j›½µ8%†—kg6Þ+&ëÏhñ t#Ü4 $ kÖ†.`ƒå7åbh"Œï7Æ@C&w„a+xŒÙÊ^íg›—ôÓ/™’œ¡÷r’_Õæô¹¹œÎÝтש7ªÝˆ’_Š¥²žª™œrûy:—{;¹!ÐÚ†xb­Qdu9ˆY_W‹Óû?®£Éîïží¿6š±°ç Øšlaã˜s\°cÀáA;ЄFk®I‚n°Þ¤N3å Ûß¾\0`Êd•ÀeÎtóÃLKĵ¡>I¨Ùð¶0Ûp¼ú©¨&BßûrŒ!Ørl¹M纤[DÿgîSq뛌I»cƈy±(òî^’ж¬þäÂPy)تëô~±žŒ˜+7^ß0GJyͶ։û¶7î ʋղ “uíÝììºe»žKùù¿×Ÿ“6>³†Ñ"‰Ñ=¼Žª¬-£šææ7âW_aÚó÷Sc_ýòªëôž®Å¹Ý½^F½rcDm~°“LÃq5Ù!x>~Þ°Ó;³¯ãµ—fVS^fʱ¸J±-44ϼˆ] •®íÆ64˜#]Tnû÷ùÂX\ Ï×iÛ"MÄpÌÅáÔû/¶²Öè!‹ ÀÆØmÄuÞ+6Öh…;­myËùž4>APÀêèl΋¼.GR>Rs’½\S7÷ú¸àK¸Št>h^Ú’¹Åo+3Ÿ_W³Ñà"l¢Y‚•UL@fAÙYÅO+sÌ\Û™k?s¼½FÕtN«˜’é*K“·¬Ì4%Ml^Å åÔì5 ÕB¯z¤ÐÈPôãNRþë¼¾N48½êam¶ž°rÖ©u,ZW•–»î”›ú‚EMËμi3«=ÀÃ8¢/Ûý8^ær‘ß‹:±e&EžXØE9ºúc<À-qè׌êò’Íâ'[à™ækòæLób+îÿô0»È¾øÎjžû Ký£#5¶hãb'à›D´ÊÙEîü*FÐ_ü)QÐ%=Lnϯb÷äÝñùpçèèdwÒÕèÔU'ö3²JÌ:ÍïÔ¤ÙP/N4ûJî»"/ÚóKW„~Iw> >åíÑ/Ùr¥žY®ÞW/¡¢ýÅïH&ÜsâH ØgÜ dŸ˜^ZnõñŒžáXfBlPÒ^3_'¥±|êg®ûª«î²³×æ%!yCN¬{èV½w@/*‹!,´î |ò±Ür`aE<þÕdÉ6³„¯z¼ÿàn.¿ÜµK‚£}mþ›¯·´gnf]})ØÜüðêƒÝ.xüe,Õ2‘}—jøÊÁwŠàÏó&‹Ñï‡àu#›Ã‹Ï+ÅHÝȦb ÆðÄÝ´í•ñÍU||fõ·tmRÌÖÙʾ’ýäꆯ\©T±>0DY»‚’Õ\ÜÐÙh~¯h[ì_VV.Cš”È‘Ú µf¨Aq¦ÆZ—Û[Á7ª ]Ý„–¦n/àF¬¡%©fš¬üóº^ƾgD˶øí.ßëwC*sSý’^Ö¬ÆônÞ¬œ¯xp6ÎÓ«Xõ¹’Ÿ¥i3õ•Ö¥Äîcã—]]-ã-ï"½*ßÿüÝß©#Ï89dœÌ°ONhŒòï츀u‰uÙåèzÝc36òZ|Ì&sÎé +ܶjÌ\ ñ­›~«È'ÇÅí)¿@tµ‘çìSè–Ìäçsv´áEhÉRáÕáñÎÙ Tr>úPŒƒ‚­Ä ¨ Wf#¤ ñŽr2`»ò_ØÍã¡„ÓnNï÷J2í ŠåᲟ ÆŽŽ|<§9íÏK|#ÜL7Ïq±æfÓ”@bK»žá¹kOoºÅ¼ÃÍé\ú»ŸkdT&~RL¾Ü°'κË[ÝìÛOFûÚ8Ÿ¤ôçœ-’YmèÏs_}ø·"Ò0¦|/CmñðAwšbdUó{IøÈÄ«]¹ÖËÚ žªÜì¯/¾âÿ5Ü—%ô×S¶C£®Òà'<ÇëTÞéçoˆí^½;<:?<ÞÐ@eÞëS¼"A˜Èº@Ç ¨ãc©ÿ*¶‡Ô"î X‘V&½BK·Óéú’¶U‰¢>ŒQ2Â<ãb_­Ê q†ô€û¡K¶„yõ¿q<'ÉäU·3)rÄ1´XRÔ×âÜü†]T’k+‚§¥¬†ì`q )±]`‚B:®*²MØDn‰gpQ¥~ÖgÔÍ 4¿—»\Ôg’©4˜è¨ZÍØowÞ5¹dnã`ßj>IÒõh¡íP+ }µ¦ôK‰‚4)T‰ù½>ïé5ÓÍÑØVd¾º˜QlEw™è‚I$Õ÷Ó‹jâ¨MÛ嘪ê§S£¤º˜\J?’ÝxÉz>ú¶Ómû4;—²*ÿé™Q$^ªU1òÑ$¯kà.yÊ)bñàDƒì#¢>ÅJˆŠ KT£ÁŸ³mD*‚À‹åºä3‹u_nAæ0è…ëÛÒí´Þ²Ú,_ʼ”£`Ë<4e{«"2)ßð]fLAÆ‘]ÎÊnìˆËŸÀnÁ±Ò”ƒ›òH¡‹ëõ醮Ôéø¥^,ú‘\^¨’É{aöÐ.:°ì;N…²ýô“ÙHÔªêX‚Z7Ý=__·&ûšÙ2|FÑò®»½wsk_–+DµCØœ.Š3×K?»&>çýUœ,4Gq•T^Ù‘$²&2\|F–Žc²Ž¹ç ™4½F äã•âDÐ,(ÏNÙ †‚þÜÎr2ÞOçKÞ…YH˜å-éË3ö­sY²;D§/t9q+ñ9;!Þà0yÇØÅÇ‘Ì9–þÒp]ôFÍÎd">}Ô2”ÆçtÄüœjÌ8ñ­‡WÖÜÙœ@÷½øa7þ­BLhÆäiô {´nÖ…ŒÞ :jTGjdÏèŽRÖTAþß„˜,z—Š}ך•ä„Â!½ ëi`ÿmJ<í5*v8$¾„+vƒÏ\rÿ $›Û:ƘelíÐÆÍšÛâQc…ôJvÆãS<`êzR¶°žtwh—ŠTþ‹dá!TgPÝr³o˜£²˜«HÈ,tGtmðfçloxz~6Ü;œüp¼¶ÅØéYë!;Íçqzuï/̇øŽ´‰ Q[p5+ÏqD¦lê6š_PxV÷²˜Í¢®†oŠ»½òª\{ ¾ TÚÎy­yÒüQ²øC£ÃzïC¿ÉëkC&@udC–*Яd÷ÿ{8¸^-ÇÌÝn­q{Ûȹ±yVÊb‰—(2ÆUëû£Ã½áàd÷ûQ_|+ßží¼îÿS•i{[ä‹:<Þ?OE³màº1Ý«#b³ÁáßöÍöh$» Ñ$Eµ@ýäÝù«“wÇ{1Å¢¶·eŽó1G‡ƒóýãý³x2G´ˆÃcd!D†hgt fÿäu¼™)â a&™)bç`ç0fÄ·¤°L8A»'ÇÇdV§÷gÒŒœ8‘ôþýi Hy2[´°ÁþÑð$f@R8? žê„*‰‘ %ÛtœLË¢œ âÁ s¼æƒ£¯ÿˆÐ›²£ÀqØhœÚñZó}…2vÔœ® ‘Ø8p„¹{4øþÞéð¸šñø2J©¨DT´DãQYPBˆyoU­²à… SÄ S!kFdÂÖ ºf¢ì·ƒó3Ĥ£² „ì#†k‘%àÕáñÞû7'dIT6\iöçøñL(AÔ-ÚßE–IdJ„jlv>”8Œ'ÅùãሩOŽ169P"ŽO~ÀI Pv^ŸïŸýpvx¾“£óáL¶OÜoò¿ã]¤<#cüÄüö„yYä@‰@ZOeA ÙÙÝÝ?E´6'æÑ3E†hdX"O•%„Ž84GÔ¶ {¯óm>˯ŠÅpðŽXx5@[‰cÌs&ˆÜ?"!]ÜD-{\¹Födáˆ$,±š„8û1zmÐ@ àU ¹éµ›Ù2kšÐhåD©,o„ؽ½³ááéû?Ål~Züüoøß`ðãÆ0ÉS¯ËI1|M*oÿàÝÑNT¿£Y¶·uŒ˜½Ã3Ri'gQÛÏJÊ…µûfçlg÷¾¯_cÄãùØÁ@"òoo³ ÑðoòÉåɃÏsD À#€wÆSÛmnÃfâõ¾ ”ê4C4üÛá颼ɗ¨ªU™bÅhQ,qRx„ê²³;89*B_cÌ&÷8Y:BØq%æÀ'LçC;™{®U»$‘ !樜–ÈöÀ² D|_ +‡d@ k#8z¼Y"^å¨q‹e@Àó#ù8 ›UK3{ÉÞ0¦ò ¶€"Ý;£ñ-&eN©¸-—×LŽ@¡šd? Œê‚h7ËòŒ…Û¢okÆ,_ ¥é?×Ëå|ûË/oooŸçLáçÕâêË g­¿<"…>ìA”™ÞÍ&E]“AáW傸â>ËçD©ÿßfÄ:ùÕ¢ñufÙí¢¤oÊ[V—ËÛœ†`ÚÌÆÄ7ã(L›IIÉMbµ|–­í ²ÃÁZöjgp8Ø¢ ?ž¿9ywžý°sv¶s|~¸?ÈNÎ22òíž“ñüzíÿ˜}x¼·•ÄbDNq7_Ð5iðŸ²3Ó DEKh%ÓßêUÛI>»Zï.»ªnŠÅŒF9Ÿ‹iYÓZ­‰‚,†Ý„ngälHñË%[ ý–YÓj¡ƒyFg`ለvŒåKw¯¿¨ÄsÕ˜ÈuT”|µ¬¦tÉ'“{¢{š¾„ãù|’]’i&ÓC$©K¶WÍ>gáAgÄ4‚_>[Q€çî Öß?Äj4|E=§aEþI,ø„ƈ¡‘çÿ£>÷ô‰§Ç‚Õ — àHxŸ<Ùå%²é°æõŸ<ÜœW4:ãˆÎÊ™`x–1úËôDpÓà82×Gò¿‹ªšd՜ڸZ¬ëÈì›DîVv¾¹™éhóå|3»£qWó‘‚<¡39£‹M÷»üijªM}³Åc¡lnn<»á.t"¡Ñó{ûocƒ>êÄ/3~éÿ°>ùžF»ßÒŸèúwŒó‰ðˆ¥X‰X‘žìí¿zw°¾6­Æsæ¯ðx³šû2'΂0ÀÇ—OŸ>Qß$öÉgÅ2£ö;qYmûL*R/Ô wГ´©OèóÎv07ñûœnañ¸5åœÖ¡Œçøä ÃôÑv©dˆ,,\“|ЋÕ1£9HcHQéºúµ^¢°4/-‰.UˆAñGISÙ™éÙÉu+Ö8_€´À 7Ê»’Z ð'6YdVøÙÛï¾5\E^"ãÕÒëbô…²–ψ=‘,òµM‹ƒ9“„…·B™¾¨IóÔ2äl1ƒ¼VGa\þhȳg¬p²y?ù’Ì4³(Ç-WL»íït­Vœ0bÃ65 _é°]ŠPèˆÅ~¢sG1ã#<Ák>n”3ñ zöG:¾Û|ñõ—ôßÊÈ–ÝrÂTPyöîüõÿ×|®èç'{'ë×÷ÙÛŠLÜß C6™¾ÈLÄ哆üÄ豬þ͸Y¼?³þû„Ç7×ÕµSùÿWÄÑáÈ)Ûéý«ûeQ2'ÉVÄÚγ{Cê©Á^^®‹öÂÛ á¾ÿÃÉ«ÿz©ÂÕ "uã`kU'MPMô‰¨añ1Ûá,ã«@2­.²šÔðdÌüª âýP7…8&d$+/ïE5“ùPCˆ*u*&;¯2â¼,ÈúŒæÊ—[4ŠuÚxQŸ¯êxйÁÎë}z×ðŒ,ð[¤ÒgÅí—¦S&”å25†xáŠ4¥|r›ß×bF}Ít~]È8ö¤d×ùMY±,?·žq¡Ÿ?ŸóHþü ó-£¬Õ5ʈø —«ÉsIï˜RÁmˆ ´RDøL´€“£=ÒŒ¡ÀáûÖj)æ€ðD lzÉpÛâ%bJ£0;ƒ¬“†C#HoÈPÔ”L§?Þ®ÌÄMÅ+Ú0“¶^Aü(ÿ`ï|ÕØ¨€âfp¡D켈1–þ#"¾ÏÑ‹æ\1ŒT1ñÙ™ãh Aúq"[SsÃÁxÁWw¡àGÕ÷晽ªªå:+¹l9æïb1ކ\¿§ëú սƳ0K1Csæ k¡Y³¨§ôᜈâcòßKþ”ǽ,Åx¬¾²¿ü%['ìôkî:}oBýÍPèŸTê:2dÓ^ûˬb>Ñwk¤c€µ/á':v–Ì‹°-Üfá0KÏèsNýœúÒ$B#^,s]¶ë’Ú2åk *ºè.éi<*&IØY\ÕdU;§Ä-aö-¹V6,|FÁ¯ÎÀdÙLzßx¤Yíí‹¶cP/kÊ|)- %lÍš- ÄL¦6@h=ðèE¸¨©Ãú|AZ=·¾­¿øŠ ¸@Zu|²ú¸ÍkºÂ"…ãÛ—Âærƒ¬åüºj¶Ÿ4 Þe!ªÓ½¢¦Ü4±«OS\¬þ€¡é‡â⌯*ë£êªœ¡)7ó¯z¸r ¸\>äæü÷Á 2§a-lä8XÈ¿ÆPçÕVOƒhÓÇþØñëÔáöþ ¬0ÃãKþ„Áþ ó÷5ü9F~˜áÏò/7üñÚêøÓ6íqø“ö5F@R8"õm1[—ËI¼¿êñÏ)KhøsØ£Ÿgìß?Àöƾ ‰½¬Ò8I£(F~›T¨ýUÞÙ·²öA¹ì­ìÙ\ŽŸŸÛ?yýF»Ïòçì{%{fç[†¸~¤ŸÏ}6ÿUZ~b“u¾–RnŽ9w¶¯‹[úž5o |Û8›§{¿'3¢Ã颠sNQ/Õæg™øC¼@mœ\¡gÓÕØ½—i‰ùUONY»›z›Ó®UÚüþÄA&‡¡`4Ag¯îÌF…z]œnœ›ß­?nxÔ)øÍ5yHT›!ë·T{ó|A˜é7îÏEéZ*.n‹5±2îVЬjÙõcwÕß^ ©ò%Ô‘‘f6åÞªïÄYŠl¹-à·àä9†D9y õå¬ZéR™žašTèòý$J×·ÛxzûÆcãÜd $¸_[Ùî¹8™ü,;' ý±ßŒ3ã‰upÃÂMc‹þwO¬ïª{87,±2ÿu=±_––X}”Ñå€J{"Cº¡âú¡‡cULËÕoíâ¶„ªïß ×Õü›qÈÓwˆ²Ú:VxOŽz@¹Žþ{T)þ…\ø‡ðßclü€.hóû¡*ËÄ)'ªcz|vëÆŒŒ²=ÐÁ7úı(u§ãøÎ²¥r˜I稬* '²Šq”Ê8]ö1zh¢¶´¿C±¯`×y}¼¦¨òýªÇ#£áIŠýÉ0îcïŽ÷Ó6y|¼GÀ= ª—i]@eüµ÷U†N xð½À0ðïÝÀ5y×~7±#žíî•5©ú›œ½ÁÉý+ïNiÂýÂaDwÏè¿÷°:v“ ™ÓûÊnzGÙýíô’ݨ.²Û¥ìþÞ9š ß½gŽê^œÆ@¡¥“Od›sñWj¯¡ád~+݆äŒé7ìžIrÇawŒ¤ÑáO’ñKÕãwø‚¥Ø OXVøÔ›ñõC¯—ãkÑõ˜ú-CBþÖFFªn‡ï¦¥ñÕÒöõÁÌà £‰çNTÒûm !qío ÌXÓÑhµXЙáWö‘Ám ½< [Y™YDXwëvãîeÖe»Î^ÍX¨½>gVùÛ™^E¢æXÁÛe¢•Uòûlû(ÕøSnDþ>ïµõ8“o°‚03pÒâæ¬¸¢ïL°ÏëæÁ¾ºÞ2ú—´ŠõïÃq1[š gE>ÁžôøõÙfiÇk“1e°¶êMT—¨%Y9ºNàœå¢nÁ)i/K^ÞííÛE>ç€þɯúWØŸ›jÄ>ëU·}¨wû¨Ê¨Jr+‡¥ýf+‡–®û!<Õª®Ö_ ÚÍ­7žø›­8V¼>kÎ%ȾðpU*éZ5³›kMˆ¿Éº•%|”êu ª3=HŧzÃB’¡ü–52l¹ê7ã6›ïâ3wj .ŬáÛI›S®Ê*B°Mèqƒ ]êÑ7«Q÷¹÷†­€þ7嚆¯U>¦{7Æ’ðmQ×ùr§€~åK;Uކ$ þYemeä€/"ÈWÄÈlz"fÅý,nº ¢h½¬Û¢j!Ù1¿ù^™ªÓLoXW­ó¯‘¡¯Y3 Î¿âĨk¿¿Ç"@ë>Ƨ¨Ýë|vª^±ýZ>vJçbÒßOæ|R6RŸeb/”æ|–ÑÏŠÉV¶šÕå žÉž¬Z ¤³³{W;ãq1–?Ž«]ön,nuÔü•ϦNiÂsªÃˆžYÝÚU*êPUž¨.YSª’Ÿ¾8Lû—/Ѿ“‚¯^‚üä%2ý¦*×üÜÅË×Ëìý@5¬ægøJþM×ðÿoïêšã¸íý)›<°˜˜qU^U·\%Ó¾…ŠLSŒSu_\+r$o™Ú¥¹KÊþ÷ €™ßhÌ=H«ôéÁ9݃pò¶ü>˜yö;‡§Û¤&ÁžýBõd»«¢BŸÿ&W`ãÃõ©hzß誹úÛ?³–$éw¹BÜn€¥ïùÍ3)ö´Þü‡üsü…Ö’ü€}™«#ÐáÍî RQCNè"¼Üê%°!è(B¥¯ð.×]¤‚᎞Ƒ‚dñK&¸%Íd± aZ»=8|•OÔš®É½M.>“Ò­KÏKh ¡·ƒÎ Z+˜Œàö®ÛɘÔM{á•§kÚèS4m¡wZ†`¡óËš{ÁE*Q¾%šTñ†nŠDJ ¤5[ŠìÌ’Ћs̈.'¶Áƒ;}4’YÈÑz9a†-fðóŠ ƒÿ]s˜Kéw—^¹ÖïÆ Wû]±·Þ§˜TÅ?^‰4ŒUõÀ7…*ÿptgÖþqÀ«þm¨.Yÿ‡C^#€7YO àëËŽ~:ìîš™Âzí•Çtú@€–{G — LY¢X È „8E4 l "ð9ˆ„¾Ø€ÀŠë’#‚ÐkHä(ë‰ ¼}cÙAÁwÍËŒa¿úÊ> Ó3‚—°à Ç§†—ìaA$˜5DqšG‘àÖ0! ãÙDÂ_l¨à€í’ƒ…(àk¸è,ë ücÙ!y1A/ÈÁÁØøý¢ß<©½<ân]¯VGtcÐ]±wAáâÐ0T u—‡Dð% %PQ­Ê3Ô$²31Þšwõ?dô®¾ ¶ôoè›U#*ž¤¶šIÉ×w? ª¤(3PÉ&ÃÔãzT°KÛlÁú[,8Á.t·×îPjÚÀê“ä ¢\Cÿ‚{B§AJ9HiaãÚ8¨L³(‰R‰<Ë3{évá™ }ÊB·3¼vìñ©›í¯ì‡”ñ ¿=*!G¿dïÇÊó|ú”¯áõè‘».‡Ú½æ9Ð`K”ꈄ²&7¢œ(¿ 2­£‰»2]Üæ׌ ŽX@I™>§¡…³çÒ¼Ð$Ú+Ža·:Ìi~UàyÄÜÒÓ‡À’Í3RÄ C×u=W óA0íÀÀ0ow{Ï'•íïׯے=D­ŸSKjØ€”iNxá?ƒ,Ѓ²j›B #ÂRÓZSŸäBÚËf–:À…[ÖÉò¶¯¯ub‹Ø…j!ø¢Ñ"˜sêóÈÞŸ¶§çãåáóçíþûÆ“„ÆVÎNÂXô<%Tóf,Ñú½Ñ5ôÅŠ5 ~ I ™‰õ!£¹YÞÔœÑf8Öd$'˜+Šî€¥ýa±ÒøºT"Šž€FŒz+Oq~Yû‰_Z~ÔDŽC{+gÆa ÆE¦¡œìîNˆª+ÕåøÖIŒzã§bE7<*%Šè$äC >dè¼NÿÝá´»kF³`бÅ}sëŸé8Œs ­22›»[¬|dEKµ­Vy|±Öò©Ž/vB£_,`“ðøbÖÙüÀyö»¼½¼F›ûHcëŸùÈ(ÌÚ¯­$üˆ­ëœçjó„3ž ‰:ß\ÒÎvj(ð纟w'¸$‘oÕ¢™ûxÁK‹ÿቯ{:Û¼ž+É¥W>-’!èçDRê=!v€P £3óªçƺ³‡#2ñ»z`ÀU"•YЈà1÷]6ü‘¢…4»kï£öæ:—o 0ñe"~ìgêãáis.RЫWt®Ûµ#ضßov­ýé¾þÐ|Úí[c·ßý©ÿ²Ùß“¯¾újGÁƒàÿÔÜ}¯[õû×um/÷®™ÕåõUÎÑ<4Ÿ›ýisøÈ˜ßÑI”^¢u£ŸÈ…ƒCøq"ö¦»³_?>€-_p?Xß“ˆàöþ=jŠÅcªê1RŽ×]&‡ð†˜9&¶qšõõÀ‡·-0Ò¬þÔÄKb—Ü)r—@ª¥X€H‘öVH‘!è)µ>v›æ6½Ñk …LŠ@Ê.^MH±R] ÅŠóBƒ*i åT¶”ŽäwâP j 5±sÌHA?ñÝÊ;‚..J‹éTTýü©N›¤¤ ò>” q‡R O‘ÔÕ(’NèC)R³¹wÜ?#äÙýÕú«+c`uXuqLD†·4Oó½wÈ8 Ù!c•d¨ðŠqoŒxÁ41ØPA† 5ò ,^ÿ·¿ˆÇ±ns 3Ú'ú·ëá-’ìN.ð™´íF{&í­×.)q¨‡Šwq Ლ=5rZúu)éQ\Áïizˆ›Ø‚ínÒ(<öÚ0¯[3¿ÎüÏÃnOc?©ÏÚX¹Úg£Ð ~VÁ[ó÷& ¬B-‚W(ô³Fó93SÌ”n&i¶ÔÇz}YÕ•ß[昣½±¬0ì¯*“˪IJ`hæ¿ ò;4S]@HŠÎ(U• ZºÃÍpÂãÙSvJ&ÅÃ&»¼Ñ`ø I#]oŸ”/0%y D.¶r~$CÐó#)õæÇ¿„ceJGhR0e^•3ƒa›‚3-1åoA*Ákh^lê‰"ªÊ1[Oì™Zù%ãFUNñÙõ7û—Ý©qyµôÀOOѶW®¨è ôšŠ–{«*fwö঳mÕR‘ ¤PSÎ8ueºmëÚ"ížuü¶ÊÈúÝ ’J"'XP–°’¶ó Lj³$kV9~H…®Få`=;Ñt±ÄÇ'ÌGОž¨M;õŽèäºß>üØ<½?µMZM@²I»fjÿÛýë§rƯ\ñŒ¤W?ãºÞJHE…‚¡OYxæ+¼“Ùá&å-PR |]¡ €]ÅBÚž DZG ãpCç d7Âx±e pˆc–Ÿ\.’‡ô[0vQŠòûŽ]Ö®¨¾î[ÁRe..Q¢)| M®9Ø|>íöýþ>•r£Mg£Ûèp\T­¡Ù8(U±%@,­^󀮪5§ÔjnðV¥fFsFfp*M×ݲ5ó¢ McïùôÙõÃöræ¡Q¡]€'Šþ'äŽ/–fãrQm¼n„nÀþs±1µ[\|i%\ŠUËaá9¥š @º€³±½ð =*WÕy‰©Ïι‰unÕÄr]~m8ÔÛñhA¯ë¾Ð·Ž§lÅß»bÍo3ýÔâÿúi÷2ÿˆzÜþÊõþx@†·5FuýßÝPàS5bj14"–¨@/D°T Ií@¬órÕvcFi» 猣U½M&Óœº\¢@Søš@s1ú›FЋ¾=tûxû%V‡_®\a‘R©C%ÿ*42ÆDžÃl Œâ5M;š×4¿Þ§m}·;¶°oѺ)†Ÿgqg ñÝCÍÀ{¾Þ(jPî•¡nstO{³ýrÁ³6V~ë°QèïVÁûFá&.<‚ÓØ!ló7yð1ØùÄ^ÌDQg`Â*5¶ =Tw£Ä¸ˆc Ì:uRšt€°~Ó<>üÈëvûô©ÒA» ÍgÀkýXÌìÖW â¸Û&´ž†÷h¡Ì|ìÛŒ0€ HG‡Æ ›Ê¨0?^ÿf2Ψ í*|±`ÃÛÎqÓÁŒQú å·KŒ+’V=4ôÀÐL±dëu©òip(Te1÷\²*¢ÊDLÙuT°„ªêÉÕ艅SÕLXL,—ªRŠs^‘´:}T¥Ñ؃ÐUÑrÑë;bæ4’ˆ¶(¢1Ë"Z'H1 ª4r6}Bqä FaòȎDŽɫ*‘Œ€Î'’¬.O&»\ªPb~„*•L†žC,ýëø)RjÎ@&µ£0k¤¶B@"v¯êÈÍâ ¥‘ …é" Š"W”ª"ÒC9Ÿ2£·<-¤ïo©Bˆ¸ª Òšx ôîpÚÝ5iTm;!DbÖB´NbTEälú„¢ÈŒÂt‘ ¥‘VUO Y1\žF2v¹T™ÄüU)™ =‡XêΟ„Q¦ÚðÕUó‡¿NÊàt> ³F :½7ü`ïÎÌ>f•4| N­“ϼZßI :£Ë_…D[¤Aý"Àoœ¼¬ßŽ A™ñtG%XÉÇv¶Íç#€b2à‘˰YeáNÖ¦æÑuµT¹Óy ªØÑXxÓkÔ9Á9¡ Ž´çÃ0k £í{ã?°ä Ó;¶3µ±õŽ'…eƒ&;áÜA¹#…¦ƒ²KÅanÔBö\ ÂM”(dêr©Ú¨ó"Tmd°òúèöð¸»3 ¤®Š¿<ê~–>êÆaH]• …DÍÜ» $­åS*$?4ºBÝ£KþCáÉe#e†ƒ‹ÿã(#g„ЄQw|duÚTº¨G# ¾QÔ·„)‰ ý-UQB•Dz+Ϧˆnšßž›£"s¨ƒX{¹È!6UÄj†‹#޼÷«62Â\"9`Ï¿Y1.³ñ†€ãîè$ªìUÑÊ]ŸJU¶žƒI|ÞA ~ÐBÚÉ€9É0ÌŒIj1egéšÐ·š'¡†A0#f—š'–ŠbB{ú] †•eÖǽ)•ù:èQodÛÉi¶Ã}·»ûõlCþŽ^`Ë.¸;à†ï~;˜žÚÜ€¤ÒÆ~ð©FŽ]#ÿª]ëÊUG®u?ÈÀ”dX8g+ûÁU’`™v;ÜÎQ£1 4´áÅ Êî·=8~ªÇ œMüðëN ‰Œ}-Q%ØåÖdã9޲¥ÛÛ"*$Þèʆù¬Ú m{³Wu„‹M qäVIÚÈ…I¤‘;BUé0œAÙ`[.2uµDYÔ{ êi² Ož7úe»Wˆ"òõÙë=~‘•‹$> C‰ÕðÏ!q˜ý_¨jɤ$©¤0Ô†E"6àHM„ªÀ®«¢Ân«Jà _Lâ‘€ C¶$Aì€TA,}o^€"†hÎú­&nÓ:üe'g¤uö´ïA9¦D)Þ;^‚ÒÁÔs$*ù±È©Ê,NœbNWž8Ì_S–Ø¥JZúV’JsBb²Ä¥+J5u©Çq¦ä¥º…¥/õ-Q5ßAMaj­Àø¼„ yº"'lDè2:Ô„(*Gú⢫2\|Ä¢ö‡1»ÏÍÓëçÓះÝþ\|ãùض´r¦Æbx «ù?ŽM?d‹jj,”8v¡ÓqŸ`ÊaŒ3ÿZõFLl³+¨–”Õv¨Èt¬àxiY‘§HÈ~ÿùCsßÜÿ§ùpÓüöÜOç—íç÷²´}¸ØÈQéõöSCoöËÛæóãÃöÔœmnÛ~„;¾øÊYw< =õŽëzó¯¼2€QŒš•YuVf5 1³*bæµTÜÌ–¤€ ÙQ:ܾ–&)Á‹u™ ^ž3bý ãƒ`îß©à$E7*ŸÉÚµ¦¸Mû:ªû´ŸÇ3…œŒm9Ìíoœ®*ÈûKH¼î•‡ZÛ7F²;-røÀ¦þA7M½Ôt2æÑ”ïhJy\¥pC´˜ÁÓæˆ°Ìɸ×÷÷ïšÓ—ÃÓ¯ç—on.Ùç³ û×E·ã;<‘Æ+d.°òPaˆ>Dêx‡ˆÞöƒÉÕƒUtдݢiúQ%4@EåêiöË\ ƒ«¨€s BÀìË5koáÏ¡ènËÌ0釰—y.`Áknyãxyè¸ÁŠQëmR²2‚Ãh]\;tÀt}¬œ­½Ó%æn/¡‰0«¥§~/í»æ¡èLÌOl í­\o cÑK.¡š·ê7~U[i€K$¸\qŒæíhZ0SûbâAÂXD«ïP‰+zÇj<5·¾oö÷·‡Ë‡]³?YŒ·»=y J¿?ÛÐ}—è-¯œdáPL‹s‡Z+sÜüÔêš@˜ÔÑÁ¤H€»ïò1; ÉЖãz‚@ ]u»å_´=Õê/ZG¹þk¸ÿ²ƒÏé†qYʽ>Øà•º´]ˆXJZ/j•n¼Ä«‡" ;ë]~aíu±Ä“¥³%*(Á{_l2zÕÆ©’„ QLm+YÈ¥v6­ÔV JÄÔý]]²:RX9¡42™=’6ó!ÊÖH8,鎂3âòœØ‘rÉ ŽÌl‚i§¦³›í¶ ]{úál´?óÐÒÊ9mˆžÔ†:Þ¬,nÞ÷uØöÕr²š$æäM*‚N^Ku®s·X=R€Ã7‹ Ä.”³ÚÍu°T Ašwf5 acÉûªjzS"UðѸRmÞ©éòÝóçæiw×S¦øÿ@æY9{ŠƒÑ3¨XÏ›E% °˜TlÖB¨Rå|xÕŒa"nuF´òë¢tkAež5ô¨D®•oõfÆçÜñ¦R?>ïN=É‚ÿô Ëßè=žî_½zi‡{xâû.œm^ÈÏm¦ÀEVÎÀ`$zú•¼¹‚ÓÃÁlKÀ m ûšùP¯¼D¼ë&-¤ë®E®…ó\¶>¸s3>ZüSl3ñÚaùxxÚœ‹Sß«Wô^Úµݶßov­µé¾þÐ|Úí[Ó¶ßý©ÿ²Ùß“¯¾újG¡‚PÿÔÜ}¯{]÷¯;ëž6ܺfVG«WhšÏäçáã†ZßÑ%”>ar ¹l@?ÀaˆÇ0ÅÓÝ´¯ ø°å úúT®íý= TÔ" PÕ/ìðHt‰‚%`Y¬HIlÃzRÚK«vžKk²{ú¿þ“NZƒ‹¬\Zƒ‘2[C%ÿ´[Zƒ¶m‰-P3im/UJËÍl¥µ›ñ§‘ÖvXª´žÇ*­-“·´VÀµ:ií`•Ö‘Þ1‡´vaØé¤õ”ÖW ií§›¯²ÑÍW.ºù*B7_ý Z/_9ëå«,õ²´DzÙ ÅúüW'ÝÃ_a³ªaò${÷“'øOàä ZXùä F¢Ÿ±*ǤŸb•Õ½'[5:XÓ®Û”›ßtëe¢‰×Ñ:ëK7»a4ÃRp{ÇJ\®ö´…áV£OýNÖõÓ®œ²•c2DEªêþñ‘JÙ@™*VòD´R¶°„ñ“F3P¶½c%R¶Ú;Ð(Ûjô©)› oç±µ•“´8=;‹õ¼iYB òqJÔ±3†•G¥£^ *3p®¡G%’­äh,«7óôzy{y}Ó<> 1ù&žhåv3 [yHfÒ•kQï, [HÖÌ‹ˆmx&¤c\+)kàJKÍV„f"hc¿J¥é‘k ’µÉäsQv¶Î‹¨9:–ž+3O `bR®|Rz*^ WVû:÷.„v_ßS÷Ä+ü7‚z…v2 _a”:@£Ö¥ì?ù¾Ùßß.vÍ~xôÇ«Š&WN¯ŠéYVQÙ›lU¨`q®ÝæÇ´ &"\?4+ïªÁJG¿.øÌÀ¶n•HÆ*¿@ãd‹Áç¡æ77—¨¼<´—)ñ1òP3Ž•‹Ób—”ˆp¬,¬€)5™5}*—|; 3¯ÚÔSÓîëûûÎh—äï³ ùû‚›ëlslÇqx"—ôâ^ÖèÊ)—BÏ´¬‚7Ár›Sc6Vó+©å@®¤aVò¯ŠV»r§v?ÈÀ£¸¸‘¨V}9¹á¯Û{òDG÷êÕ—§íã¹ðsx›å„C?²0$Îëü4¤P¡C[–ÐÊCö0ãŨé{‰Ül2ˆ_×tY,}dêk‰òˆ» š*2xjQô]óÐN_².òÓ@C+—AÃ@ôJh¨ã-†€­ùí\EP.)t¦8jÍI¡©;®<‰Å…ª~”Èp4TØŸþ^»{ix÷àò°ß·C8¿üÿw—ïw¿¶÷5ùçbÓM² /ðñ•¿ÏûãîÓ¾ðñ—C;ï<_·{.‡—]9Q c1,‡Õü† 81t8ýÕÚÕt`Pü7´m‰ò**¥?Ê7À¥ÝØpÖ‚ØUQßK]Ñ×w?‰!åô)Ë”nlñÉê·¸huec´þñgð3€Ò0{æ‡R76L”䈿óp<øBµ,ktê:C2W0hŒÒu€S*èñŠÂÙ&—û~麥ëÕHz)¥Öÿu{{ø´ÛŸËºŠ€³ïJ.¹i>NÍ›k?}®µruF¢×V ’·²‚°Ãk8™WÕð2/Öq3/ÏÈÎ|t(²)!^®Aˆëî¼ì⣋gçÁ•Ñà åaмb LCÀ"br!Ä%NÝ ½0uBE¯æDþ¿÷¿î_º£¸o¶_Î/©Fh=‹~€+Þîöž+ ÅÆWN¯â`ô +Öó&Y j~Mê‚VrH^0x¿áí*O£u”É ö«œƒù :<*Á±+Ó,Œà?ƒ¼Ûß‘bÑ ! f‹RpÔËÀåÁ³¢£b]€”ÌqŽ`­ípqݵ± Ù;\âƒ"ÉÐY­=õÊ ±CH¯r(ÍJoY_êPVT_õõŽ ¡Lôއ/¢õE`éÞöpÃh†W>ì«\þò‡Õèø”ýápx€4ýæÈž•lß??>žÚ1)r#òˆ¶úŦkëÃûÓöäEâªK®šÁUÒÑ·ª®'w+!ä…†¢R“(IÀL’H‰†•TÑ<ÖhKtO4Ú¢œñ!ãK›[‰ÆŽ‘{h‘;ç\û—¡ €˜|3ÅŽA9ïAntd±hÝU Ú9èn•eSeÔ8ºÒ÷p¸GdÝXÿ´ÝëTVª÷Ç ðmϼ÷Íñö©’Duÿ·¿“>ü¾2Q¯t=$Eïgpnñ¾ßÛ±žZ;·ãú¸mKFÎ忆{ûxÓüöÜO‰5ýø‚«VôãáX×p÷5C—qPU-?Œ‰‰FAZ†Ž÷Â&½ŠÄ¬, ï…Ýœ >ժ߽`9êÝó„ÚÝ•ýôö°½'ˆÈÁ0ÖnÄ#/:¼Ù<жÛv·oº¿©²;kÇþ|w×ÂròÓ¿ŽŸüäžÐÏ•k=a,z¡'TóVy"°’ :RGE£Øï5:•ê´+Î &(Ø/Q”2läWÌH‘0R–+Zdl ιOO#WG0îˆØ#:¯+—0¤ßå‰a76d å²î˜\^¯_úmKœlm*/IxöužðòáM…°TÐßMé§gZªY—<üT|#¨Où!ÏF7;ð#=܆I"ø£þš`ˆ=.¤ÙæBtÁ<‚Dˆ¨—“Ò¹Ïø%#î <Ëúú§n˜ºQ©#Öò±Ô¸°L¼3ДEÀ0õêpúéßûÖYV»ué‡4 ‹þzY¤,úÑØ’}ÅÀ´ÅӀޣ¦b?pY3Nà~ åŠqZGù€Šý*+ áó)Z1«jiA’ @xawåDàæ¸`‡è@èB¢–@XƒŸVñ‹ôŽzbåˆr@páåÖGWC?8­Üˆ`ðNä˜ÀÕöS‡Ôä¡å9zy¶aÆ9Ó„CV ÑCïX`Õ#t4ßÉŠwHé/ÝâR³{‡”~ÔD]-å;¤ìg¹ _uÂÐ-@ÁõØÇyšÒm¡áyôú"7'˜ŽÁA›üÊ'så„–Ó9A‡ÎAì _}¤‡sc–í¹ÝXž#¨~1`4àÁïôó« #(",lõÚ¼;x‹žbÝY`†~³†’/1œ^Iú›~ŠÓ*Ú^½~ioÜ퇇¦ýöx~<Ý¿zul†â›6.$ý4¯õŽ…«®?r†cŒ…š!Q¤„æ’­1]{Ð8Æž„ô׊èQQ]G²ßç)EG$cItKYOé Ö’Jê¹HX/‡bí ëŸ2ÑŽ‚£Ö8 Py,€tÄк𨿸Ãò"Ãyý«7oŠ7ŽßyZòêÌ1ð ã·kg[0‡÷Šßús,„axù‰Ú\=×÷ˆCKý ±3„´ÐŽ ¿ ©2êCØWRë¡þîÍ B:´ÉÞ5vëUÔ®ý<ˆ0Õ›§=øE¼VÚ7äÿþhwÃëÓ©ùüxb‘ð/Û§æþçñÿ½|ý|úåÛí±ùfC>ùÑ/lyåü ‡¢'`XË›:c«'mR¤™²÷Í—AÚ¨.¤Uý¢›Ê»ê×?¼ywûýÍÏ?üç4³÷n‘˜`b'#C!fdCglÒ\4´RÌ Í ì„mê啱rÒêž”˜v`GK<+틟[þŸú§þ©êŸ)ÿüÄÐ[æ[znc-1.7.5/modules/modpython/Makefile.gen0000644000175000017500000000155113542151610020443 0ustar somebodysomebodyall: VPATH := $(srcdir) ifneq "$(V)" "" VERBOSE=1 endif ifeq "$(VERBOSE)" "" Q=@ E=@echo C=-s else Q= E=@\# C= endif .SECONDARY: all: modpython/modpython_biglib.cpp modpython/znc_core.py modpython/pyfunctions.cpp modpython/swigpyrun.h modpython/swigpyrun.h: @mkdir -p modpython $(Q)$(SWIG) -python -py3 -c++ -shadow -external-runtime $@ modpython/modpython_biglib.cpp: modpython/modpython.i modpython/module.h modpython/cstring.i $(E) Generating ZNC API for python... @mkdir -p modpython .depend $(Q)$(SWIG) -python -py3 -c++ -shadow -outdir modpython -I$(srcdir) -I$(srcdir)/../include -I../include -MD -MF .depend/modpython.swig.dep -w362,315,401 -o $@ $< modpython/znc_core.py: modpython/modpython_biglib.cpp modpython/pyfunctions.cpp: modpython/codegen.pl modpython/functions.in @mkdir -p modpython $(Q)$(PERL) $^ $@ -include .depend/modpython.swig.dep znc-1.7.5/modules/CMakeLists.txt0000644000175000017500000000635513542151610016761 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This is not recommended, but whatever. file(GLOB all_modules LIST_DIRECTORIES FALSE "*") function(add_cxx_module mod modpath) znc_add_library("module_${mod}" MODULE "${modpath}") set_target_properties("module_${mod}" PROPERTIES OUTPUT_NAME "${mod}" PREFIX "" SUFFIX ".so" NO_SONAME true CXX_VISIBILITY_PRESET "hidden") if(moddef_${mod}) target_compile_definitions("module_${mod}" ${moddef_${mod}}) endif() if(modcompile_${mod}) target_compile_options("module_${mod}" ${modcompile_${mod}}) endif() if(modinclude_${mod}) target_include_directories("module_${mod}" ${modinclude_${mod}}) endif() if(moddepend_${mod}) add_dependencies("module_${mod}" ${moddepend_${mod}}) endif() # ${znclib_LIB_DEPENDS} is to overcome OSX's need for -undefined suppress # when accessing symbols exported by dependencies of znclib (e.g. # openssl), but not used in znclib itself target_link_libraries("module_${mod}" PRIVATE ZNC ${modlink_${mod}} ${znclib_LIB_DEPENDS}) set_target_properties("module_${mod}" PROPERTIES "" "" ${modprop_${mod}}) install(TARGETS "module_${mod}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/znc") endfunction() function(add_perl_module mod modpath) endfunction() function(add_python_module mod modpath) endfunction() if(CYRUS_FOUND) set(modcompile_cyrusauth PRIVATE ${CYRUS_CFLAGS}) set(modlink_cyrusauth ${CYRUS_LDFLAGS}) else() set(moddisable_cyrusauth true) endif() if(PERLLIBS_FOUND) add_subdirectory(modperl) else() set(moddisable_modperl true) endif() if(PYTHON_FOUND) add_subdirectory(modpython) else() set(moddisable_modpython true) endif() if(TCL_FOUND) add_subdirectory(modtcl) else() set(moddisable_modtcl true) endif() set(actual_modules) foreach(modpath ${all_modules}) if(NOT "${modpath}" MATCHES "/([-a-zA-Z0-9_]+)\\.([a-z]+)$") continue() endif() set(mod "${CMAKE_MATCH_1}") set(modtype "${CMAKE_MATCH_2}") if(mod STREQUAL "CMakeLists" OR mod STREQUAL "Makefile") continue() endif() list(APPEND actual_modules "${modpath}") set(modenabled true) if(moddisable_${mod}) set(modenabled false) endif() if(NOT OPENSSL_FOUND) file(READ "${modpath}" modcontent) string(FIND "${modcontent}" "REQUIRESSL" requiressl) if(NOT requiressl EQUAL "-1") set(modenabled false) endif() endif() if(modenabled) if(modtype STREQUAL "cpp") add_cxx_module("${mod}" "${modpath}") endif() if(modtype STREQUAL "pm") add_perl_module("${mod}" "${modpath}") endif() if(modtype STREQUAL "py") add_python_module("${mod}" "${modpath}") endif() endif() endforeach() if(HAVE_I18N) add_subdirectory(po) endif() install(DIRECTORY data/ DESTINATION "${CMAKE_INSTALL_DATADIR}/znc/modules") znc-1.7.5/modules/identfile.cpp0000644000175000017500000001560013542151610016661 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include class CIdentFileModule : public CModule { CString m_sOrigISpoof; CFile* m_pISpoofLockFile; CIRCSock* m_pIRCSock; public: MODCONSTRUCTOR(CIdentFileModule) { AddHelpCommand(); AddCommand("GetFile", "", t_d("Show file name"), [=](const CString& sLine) { GetFile(sLine); }); AddCommand("SetFile", t_d(""), t_d("Set file name"), [=](const CString& sLine) { SetFile(sLine); }); AddCommand("GetFormat", "", t_d("Show file format"), [=](const CString& sLine) { GetFormat(sLine); }); AddCommand("SetFormat", t_d(""), t_d("Set file format"), [=](const CString& sLine) { SetFormat(sLine); }); AddCommand("Show", "", t_d("Show current state"), [=](const CString& sLine) { Show(sLine); }); m_pISpoofLockFile = nullptr; m_pIRCSock = nullptr; } ~CIdentFileModule() override { ReleaseISpoof(); } void GetFile(const CString& sLine) { PutModule(t_f("File is set to: {1}")(GetNV("File"))); } void SetFile(const CString& sLine) { SetNV("File", sLine.Token(1, true)); PutModule(t_f("File has been set to: {1}")(GetNV("File"))); } void SetFormat(const CString& sLine) { SetNV("Format", sLine.Token(1, true)); PutModule(t_f("Format has been set to: {1}")(GetNV("Format"))); PutModule(t_f("Format would be expanded to: {1}")( ExpandString(GetNV("Format")))); } void GetFormat(const CString& sLine) { PutModule(t_f("Format is set to: {1}")(GetNV("Format"))); PutModule(t_f("Format would be expanded to: {1}")( ExpandString(GetNV("Format")))); } void Show(const CString& sLine) { PutModule("m_pISpoofLockFile = " + CString((long long)m_pISpoofLockFile)); PutModule("m_pIRCSock = " + CString((long long)m_pIRCSock)); if (m_pIRCSock) { PutModule("user/network - " + m_pIRCSock->GetNetwork()->GetUser()->GetUserName() + "/" + m_pIRCSock->GetNetwork()->GetName()); } else { PutModule(t_s("identfile is free")); } } void OnModCommand(const CString& sCommand) override { if (GetUser()->IsAdmin()) { HandleCommand(sCommand); } else { PutModule(t_s("Access denied")); } } void SetIRCSock(CIRCSock* pIRCSock) { if (m_pIRCSock) { CZNC::Get().ResumeConnectQueue(); } m_pIRCSock = pIRCSock; if (m_pIRCSock) { CZNC::Get().PauseConnectQueue(); } } bool WriteISpoof() { if (m_pISpoofLockFile != nullptr) { return false; } m_pISpoofLockFile = new CFile; if (!m_pISpoofLockFile->TryExLock(GetNV("File"), O_RDWR | O_CREAT)) { delete m_pISpoofLockFile; m_pISpoofLockFile = nullptr; return false; } char buf[1024]; memset((char*)buf, 0, 1024); m_pISpoofLockFile->Read(buf, 1024); m_sOrigISpoof = buf; if (!m_pISpoofLockFile->Seek(0) || !m_pISpoofLockFile->Truncate()) { delete m_pISpoofLockFile; m_pISpoofLockFile = nullptr; return false; } CString sData = ExpandString(GetNV("Format")); // If the format doesn't contain anything expandable, we'll // assume this is an "old"-style format string. if (sData == GetNV("Format")) { sData.Replace("%", GetUser()->GetIdent()); } DEBUG("Writing [" + sData + "] to ident spoof file [" + m_pISpoofLockFile->GetLongName() + "] for user/network [" + GetUser()->GetUserName() + "/" + GetNetwork()->GetName() + "]"); m_pISpoofLockFile->Write(sData + "\n"); return true; } void ReleaseISpoof() { DEBUG("Releasing ident spoof for user/network [" + (m_pIRCSock ? m_pIRCSock->GetNetwork()->GetUser()->GetUserName() + "/" + m_pIRCSock->GetNetwork()->GetName() : "") + "]"); SetIRCSock(nullptr); if (m_pISpoofLockFile != nullptr) { if (m_pISpoofLockFile->Seek(0) && m_pISpoofLockFile->Truncate()) { m_pISpoofLockFile->Write(m_sOrigISpoof); } delete m_pISpoofLockFile; m_pISpoofLockFile = nullptr; } } bool OnLoad(const CString& sArgs, CString& sMessage) override { m_pISpoofLockFile = nullptr; m_pIRCSock = nullptr; if (GetNV("Format").empty()) { SetNV("Format", "global { reply \"%ident%\" }"); } if (GetNV("File").empty()) { SetNV("File", "~/.oidentd.conf"); } return true; } EModRet OnIRCConnecting(CIRCSock* pIRCSock) override { if (m_pISpoofLockFile != nullptr) { DEBUG("Aborting connection, ident spoof lock file exists"); PutModule( t_s("Aborting connection, another user or network is currently " "connecting and using the ident spoof file")); return HALTCORE; } if (!WriteISpoof()) { DEBUG("identfile [" + GetNV("File") + "] could not be written"); PutModule( t_f("[{1}] could not be written, retrying...")(GetNV("File"))); return HALTCORE; } SetIRCSock(pIRCSock); return CONTINUE; } void OnIRCConnected() override { if (m_pIRCSock == GetNetwork()->GetIRCSock()) { ReleaseISpoof(); } } void OnIRCConnectionError(CIRCSock* pIRCSock) override { if (m_pIRCSock == pIRCSock) { ReleaseISpoof(); } } void OnIRCDisconnected() override { if (m_pIRCSock == GetNetwork()->GetIRCSock()) { ReleaseISpoof(); } } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("identfile"); } GLOBALMODULEDEFS( CIdentFileModule, t_s("Write the ident of a user to a file when they are trying to connect.")) znc-1.7.5/modules/keepnick.cpp0000644000175000017500000001607013542151610016511 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::vector; class CKeepNickMod; class CKeepNickTimer : public CTimer { public: CKeepNickTimer(CKeepNickMod* pMod); ~CKeepNickTimer() override {} void RunJob() override; private: CKeepNickMod* m_pMod; }; class CKeepNickMod : public CModule { public: MODCONSTRUCTOR(CKeepNickMod) { AddHelpCommand(); AddCommand("Enable", "", t_d("Try to get your primary nick"), [=](const CString& sLine) { OnEnableCommand(sLine); }); AddCommand("Disable", "", t_d("No longer trying to get your primary nick"), [=](const CString& sLine) { OnDisableCommand(sLine); }); AddCommand("State", "", t_d("Show the current state"), [=](const CString& sLine) { OnStateCommand(sLine); }); } ~CKeepNickMod() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { m_pTimer = nullptr; // Check if we need to start the timer if (GetNetwork()->IsIRCConnected()) OnIRCConnected(); return true; } void KeepNick() { if (!m_pTimer) // No timer means we are turned off return; CIRCSock* pIRCSock = GetNetwork()->GetIRCSock(); if (!pIRCSock) return; // Do we already have the nick we want? if (pIRCSock->GetNick().Equals(GetNick())) return; PutIRC("NICK " + GetNick()); } CString GetNick() { CString sConfNick = GetNetwork()->GetNick(); CIRCSock* pIRCSock = GetNetwork()->GetIRCSock(); if (pIRCSock) sConfNick = sConfNick.Left(pIRCSock->GetMaxNickLen()); return sConfNick; } void OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans) override { if (sNewNick == GetNetwork()->GetIRCSock()->GetNick()) { // We are changing our own nick if (Nick.NickEquals(GetNick())) { // We are changing our nick away from the conf setting. // Let's assume the user wants this and disable // this module (to avoid fighting nickserv). Disable(); } else if (sNewNick.Equals(GetNick())) { // We are changing our nick to the conf setting, // so we don't need that timer anymore. Disable(); } return; } // If the nick we want is free now, be fast and get the nick if (Nick.NickEquals(GetNick())) { KeepNick(); } } void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) override { // If someone with the nick we want quits, be fast and get the nick if (Nick.NickEquals(GetNick())) { KeepNick(); } } void OnIRCDisconnected() override { // No way we can do something if we aren't connected to IRC. Disable(); } void OnIRCConnected() override { if (!GetNetwork()->GetIRCSock()->GetNick().Equals(GetNick())) { // We don't have the nick we want, try to get it Enable(); } } void Enable() { if (m_pTimer) return; m_pTimer = new CKeepNickTimer(this); AddTimer(m_pTimer); } void Disable() { if (!m_pTimer) return; m_pTimer->Stop(); RemTimer(m_pTimer); m_pTimer = nullptr; } EModRet OnUserRawMessage(CMessage& Message) override { // We don't care if we are not connected to IRC if (!GetNetwork()->IsIRCConnected()) return CONTINUE; // We are trying to get the config nick and this is a /nick? if (!m_pTimer || Message.GetType() != CMessage::Type::Nick) return CONTINUE; // Is the nick change for the nick we are trying to get? const CString sNick = Message.As().GetNewNick(); if (!sNick.Equals(GetNick())) return CONTINUE; // Indeed trying to change to this nick, generate a 433 for it. // This way we can *always* block incoming 433s from the server. PutUser(":" + GetNetwork()->GetIRCServer() + " 433 " + GetNetwork()->GetIRCNick().GetNick() + " " + sNick + " :" + t_s("ZNC is already trying to get this nickname")); return CONTINUE; } EModRet OnNumericMessage(CNumericMessage& msg) override { if (m_pTimer) { // Are we trying to get our primary nick and we caused this error? // :irc.server.net 433 mynick badnick :Nickname is already in use. if (msg.GetCode() == 433 && msg.GetParam(1).Equals(GetNick())) { return HALT; } // clang-format off // :leguin.freenode.net 435 mynick badnick #chan :Cannot change nickname while banned on channel // clang-format on if (msg.GetCode() == 435) { PutModule(t_f("Unable to obtain nick {1}: {2}, {3}")( msg.GetParam(1), msg.GetParam(3), msg.GetParam(2))); Disable(); } // clang-format off // :irc1.unrealircd.org 447 mynick :Can not change nickname while on #chan (+N) // clang-format on if (msg.GetCode() == 447) { PutModule(t_f("Unable to obtain nick {1}")(msg.GetParam(1))); Disable(); } } return CONTINUE; } void OnEnableCommand(const CString& sCommand) { Enable(); PutModule(t_s("Trying to get your primary nick")); } void OnDisableCommand(const CString& sCommand) { Disable(); PutModule(t_s("No longer trying to get your primary nick")); } void OnStateCommand(const CString& sCommand) { if (m_pTimer) PutModule(t_s("Currently trying to get your primary nick")); else PutModule(t_s("Currently disabled, try 'enable'")); } private: // If this is nullptr, we are turned off for some reason CKeepNickTimer* m_pTimer = nullptr; }; CKeepNickTimer::CKeepNickTimer(CKeepNickMod* pMod) : CTimer(pMod, 30, 0, "KeepNickTimer", "Tries to acquire this user's primary nick") { m_pMod = pMod; } void CKeepNickTimer::RunJob() { m_pMod->KeepNick(); } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("keepnick"); } NETWORKMODULEDEFS(CKeepNickMod, t_s("Keeps trying for your primary nick")) znc-1.7.5/modules/chansaver.cpp0000644000175000017500000000536313542151610016675 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include class CChanSaverMod : public CModule { public: MODCONSTRUCTOR(CChanSaverMod) {} ~CChanSaverMod() override {} bool OnLoad(const CString& sArgsi, CString& sMessage) override { switch (GetType()) { case CModInfo::GlobalModule: LoadUsers(); break; case CModInfo::UserModule: LoadUser(GetUser()); break; case CModInfo::NetworkModule: LoadNetwork(GetNetwork()); break; } return true; } void LoadUsers() { const std::map& vUsers = CZNC::Get().GetUserMap(); for (const auto& user : vUsers) { LoadUser(user.second); } } void LoadUser(CUser* pUser) { const std::vector& vNetworks = pUser->GetNetworks(); for (const CIRCNetwork* pNetwork : vNetworks) { LoadNetwork(pNetwork); } } void LoadNetwork(const CIRCNetwork* pNetwork) { const std::vector& vChans = pNetwork->GetChans(); for (CChan* pChan : vChans) { // If that channel isn't yet in the config, // we'll have to add it... if (!pChan->InConfig()) { pChan->SetInConfig(true); } } } void OnJoin(const CNick& Nick, CChan& Channel) override { if (!Channel.InConfig() && GetNetwork()->GetIRCNick().NickEquals(Nick.GetNick())) { Channel.SetInConfig(true); } } void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) override { if (Channel.InConfig() && GetNetwork()->GetIRCNick().NickEquals(Nick.GetNick())) { Channel.SetInConfig(false); } } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("chansaver"); Info.AddType(CModInfo::NetworkModule); Info.AddType(CModInfo::GlobalModule); } USERMODULEDEFS(CChanSaverMod, t_s("Keeps config up-to-date when user joins/parts.")) znc-1.7.5/modules/samplewebapi.cpp0000644000175000017500000000334013542151610017365 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include class CSampleWebAPIMod : public CModule { public: MODCONSTRUCTOR(CSampleWebAPIMod) {} ~CSampleWebAPIMod() override {} bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName != "index") { // only accept requests to index return false; } if (WebSock.IsPost()) { // print the text we just received CString text = WebSock.GetRawParam("text", true); WebSock.PrintHeader(text.length(), "text/plain; charset=UTF-8"); WebSock.Write(text); WebSock.Close(Csock::CLT_AFTERWRITE); return false; } return true; } bool WebRequiresLogin() override { return false; } bool ValidateWebRequestCSRFCheck(CWebSock& WebSock, const CString& sPageName) override { return true; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("samplewebapi"); } GLOBALMODULEDEFS(CSampleWebAPIMod, t_s("Sample Web API module.")) znc-1.7.5/modules/schat.cpp0000644000175000017500000003775313542151610016035 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * Author: imaginos * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Secure chat system */ #define REQUIRESSL #include #include #include #if !defined(OPENSSL_VERSION_NUMBER) || defined(LIBRESSL_VERSION_NUMBER) || \ OPENSSL_VERSION_NUMBER < 0x10100007 /* SSL_SESSION was made opaque in OpenSSL 1.1.0, cipher accessor was added 2 weeks before the public release. See openssl/openssl@e92813234318635639dba0168c7ef5568757449b. */ # define SSL_SESSION_get0_cipher(pSession) ((pSession)->cipher) #endif using std::pair; using std::stringstream; using std::map; using std::set; using std::vector; class CSChat; class CRemMarkerJob : public CTimer { public: CRemMarkerJob(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {} ~CRemMarkerJob() override {} void SetNick(const CString& sNick) { m_sNick = sNick; } protected: void RunJob() override; CString m_sNick; }; class CSChatSock : public CSocket { public: CSChatSock(CSChat* pMod, const CString& sChatNick); CSChatSock(CSChat* pMod, const CString& sChatNick, const CString& sHost, u_short iPort, int iTimeout = 60); ~CSChatSock() override {} Csock* GetSockObj(const CS_STRING& sHostname, u_short iPort) override { CSChatSock* p = new CSChatSock(m_pModule, m_sChatNick, sHostname, iPort); return (p); } bool ConnectionFrom(const CS_STRING& sHost, u_short iPort) override { Close(); // close the listener after the first connection return (true); } void Connected() override; void Timeout() override; const CString& GetChatNick() const { return (m_sChatNick); } void PutQuery(const CString& sText); void ReadLine(const CS_STRING& sLine) override; void Disconnected() override; void AddLine(const CString& sLine) { m_vBuffer.insert(m_vBuffer.begin(), sLine); if (m_vBuffer.size() > 200) m_vBuffer.pop_back(); } void DumpBuffer() { if (m_vBuffer.empty()) { // Always show a message to the user, so he knows // this schat still exists. ReadLine("*** Reattached."); } else { // Buffer playback vector::reverse_iterator it = m_vBuffer.rbegin(); for (; it != m_vBuffer.rend(); ++it) ReadLine(*it); m_vBuffer.clear(); } } private: CSChat* m_pModule; CString m_sChatNick; VCString m_vBuffer; }; class CSChat : public CModule { public: MODCONSTRUCTOR(CSChat) {} ~CSChat() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { if (sArgs.empty()) { sMessage = "Argument must be path to PEM file"; return false; } m_sPemFile = CDir::CheckPathPrefix(GetSavePath(), sArgs); if (!CFile::Exists(m_sPemFile)) { sMessage = "Unable to load pem file [" + m_sPemFile + "]"; return false; } return true; } void OnClientLogin() override { set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CSChatSock* p = (CSChatSock*)*it; if (p->GetType() == CSChatSock::LISTENER) continue; p->DumpBuffer(); } } EModRet OnUserRawMessage(CMessage& msg) override { if (!msg.GetCommand().Equals("schat")) return CONTINUE; const CString sParams = msg.GetParamsColon(0); if (sParams.empty()) { PutModule("SChat User Area ..."); OnModCommand("help"); } else { OnModCommand("chat " + sParams); } return HALT; } void OnModCommand(const CString& sCommand) override { CString sCom = sCommand.Token(0); CString sArgs = sCommand.Token(1, true); if (sCom.Equals("chat") && !sArgs.empty()) { CString sNick = "(s)" + sArgs; set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CSChatSock* pSock = (CSChatSock*)*it; if (pSock->GetChatNick().Equals(sNick)) { PutModule("Already Connected to [" + sArgs + "]"); return; } } CSChatSock* pSock = new CSChatSock(this, sNick); pSock->SetCipher("HIGH"); pSock->SetPemLocation(m_sPemFile); u_short iPort = GetManager()->ListenRand( pSock->GetSockName() + "::LISTENER", GetUser()->GetLocalDCCIP(), true, SOMAXCONN, pSock, 60); if (iPort == 0) { PutModule("Failed to start chat!"); return; } stringstream s; s << "PRIVMSG " << sArgs << " :\001"; s << "DCC SCHAT chat "; s << CUtils::GetLongIP(GetUser()->GetLocalDCCIP()); s << " " << iPort << "\001"; PutIRC(s.str()); } else if (sCom.Equals("list")) { CTable Table; Table.AddColumn("Nick"); Table.AddColumn("Created"); Table.AddColumn("Host"); Table.AddColumn("Port"); Table.AddColumn("Status"); Table.AddColumn("Cipher"); set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { Table.AddRow(); CSChatSock* pSock = (CSChatSock*)*it; Table.SetCell("Nick", pSock->GetChatNick()); unsigned long long iStartTime = pSock->GetStartTime(); time_t iTime = iStartTime / 1000; char* pTime = ctime(&iTime); if (pTime) { CString sTime = pTime; sTime.Trim(); Table.SetCell("Created", sTime); } if (pSock->GetType() != CSChatSock::LISTENER) { Table.SetCell("Status", "Established"); Table.SetCell("Host", pSock->GetRemoteIP()); Table.SetCell("Port", CString(pSock->GetRemotePort())); SSL_SESSION* pSession = pSock->GetSSLSession(); Table.SetCell( "Cipher", SSL_CIPHER_get_name( pSession ? SSL_SESSION_get0_cipher(pSession) : nullptr)); } else { Table.SetCell("Status", "Waiting"); Table.SetCell("Port", CString(pSock->GetLocalPort())); } } if (Table.size()) { PutModule(Table); } else PutModule("No SDCCs currently in session"); } else if (sCom.Equals("close")) { if (!sArgs.StartsWith("(s)")) sArgs = "(s)" + sArgs; set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CSChatSock* pSock = (CSChatSock*)*it; if (sArgs.Equals(pSock->GetChatNick())) { pSock->Close(); return; } } PutModule("No Such Chat [" + sArgs + "]"); } else if (sCom.Equals("showsocks") && GetUser()->IsAdmin()) { CTable Table; Table.AddColumn("SockName"); Table.AddColumn("Created"); Table.AddColumn("LocalIP:Port"); Table.AddColumn("RemoteIP:Port"); Table.AddColumn("Type"); Table.AddColumn("Cipher"); set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { Table.AddRow(); Csock* pSock = *it; Table.SetCell("SockName", pSock->GetSockName()); unsigned long long iStartTime = pSock->GetStartTime(); time_t iTime = iStartTime / 1000; char* pTime = ctime(&iTime); if (pTime) { CString sTime = pTime; sTime.Trim(); Table.SetCell("Created", sTime); } if (pSock->GetType() != Csock::LISTENER) { if (pSock->GetType() == Csock::OUTBOUND) Table.SetCell("Type", "Outbound"); else Table.SetCell("Type", "Inbound"); Table.SetCell("LocalIP:Port", pSock->GetLocalIP() + ":" + CString(pSock->GetLocalPort())); Table.SetCell("RemoteIP:Port", pSock->GetRemoteIP() + ":" + CString(pSock->GetRemotePort())); SSL_SESSION* pSession = pSock->GetSSLSession(); Table.SetCell( "Cipher", SSL_CIPHER_get_name( pSession ? SSL_SESSION_get0_cipher(pSession) : nullptr)); } else { Table.SetCell("Type", "Listener"); Table.SetCell("LocalIP:Port", pSock->GetLocalIP() + ":" + CString(pSock->GetLocalPort())); Table.SetCell("RemoteIP:Port", "0.0.0.0:0"); } } if (Table.size()) PutModule(Table); else PutModule("Error Finding Sockets"); } else if (sCom.Equals("help")) { PutModule("Commands are:"); PutModule(" help - This text."); PutModule(" chat - Chat a nick."); PutModule(" list - List current chats."); PutModule(" close - Close a chat to a nick."); PutModule(" timers - Shows related timers."); if (GetUser()->IsAdmin()) { PutModule(" showsocks - Shows all socket connections."); } } else if (sCom.Equals("timers")) ListTimers(); else PutModule("Unknown command [" + sCom + "] [" + sArgs + "]"); } EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override { if (sMessage.StartsWith("DCC SCHAT ")) { // chat ip port unsigned long iIP = sMessage.Token(3).ToULong(); unsigned short iPort = sMessage.Token(4).ToUShort(); if (iIP > 0 && iPort > 0) { pair pTmp; CString sMask; pTmp.first = iIP; pTmp.second = iPort; sMask = "(s)" + Nick.GetNick() + "!" + "(s)" + Nick.GetNick() + "@" + CUtils::GetIP(iIP); m_siiWaitingChats["(s)" + Nick.GetNick()] = pTmp; SendToUser(sMask, "*** Incoming DCC SCHAT, Accept ? (yes/no)"); CRemMarkerJob* p = new CRemMarkerJob( this, 60, 1, "Remove (s)" + Nick.GetNick(), "Removes this nicks entry for waiting DCC."); p->SetNick("(s)" + Nick.GetNick()); AddTimer(p); return (HALT); } } return (CONTINUE); } void AcceptSDCC(const CString& sNick, u_long iIP, u_short iPort) { CSChatSock* p = new CSChatSock(this, sNick, CUtils::GetIP(iIP), iPort, 60); GetManager()->Connect(CUtils::GetIP(iIP), iPort, p->GetSockName(), 60, true, GetUser()->GetLocalDCCIP(), p); RemTimer("Remove " + sNick); // delete any associated timer to this nick } EModRet OnUserMsg(CString& sTarget, CString& sMessage) override { if (sTarget.Left(3) == "(s)") { CString sSockName = GetModName().AsUpper() + "::" + sTarget; CSChatSock* p = (CSChatSock*)FindSocket(sSockName); if (!p) { map>::iterator it; it = m_siiWaitingChats.find(sTarget); if (it != m_siiWaitingChats.end()) { if (!sMessage.Equals("yes")) SendToUser(sTarget + "!" + sTarget + "@" + CUtils::GetIP(it->second.first), "Refusing to accept DCC SCHAT!"); else AcceptSDCC(sTarget, it->second.first, it->second.second); m_siiWaitingChats.erase(it); return (HALT); } PutModule("No such SCHAT to [" + sTarget + "]"); } else p->Write(sMessage + "\n"); return (HALT); } return (CONTINUE); } void RemoveMarker(const CString& sNick) { map>::iterator it = m_siiWaitingChats.find(sNick); if (it != m_siiWaitingChats.end()) m_siiWaitingChats.erase(it); } void SendToUser(const CString& sFrom, const CString& sText) { //:*schat!znc@znc.in PRIVMSG Jim : CString sSend = ":" + sFrom + " PRIVMSG " + GetNetwork()->GetCurNick() + " :" + sText; PutUser(sSend); } bool IsAttached() { return (GetNetwork()->IsUserAttached()); } private: map> m_siiWaitingChats; CString m_sPemFile; }; //////////////////// methods //////////////// CSChatSock::CSChatSock(CSChat* pMod, const CString& sChatNick) : CSocket(pMod) { m_pModule = pMod; m_sChatNick = sChatNick; SetSockName(pMod->GetModName().AsUpper() + "::" + m_sChatNick); } CSChatSock::CSChatSock(CSChat* pMod, const CString& sChatNick, const CString& sHost, u_short iPort, int iTimeout) : CSocket(pMod, sHost, iPort, iTimeout) { m_pModule = pMod; EnableReadLine(); m_sChatNick = sChatNick; SetSockName(pMod->GetModName().AsUpper() + "::" + m_sChatNick); } void CSChatSock::PutQuery(const CString& sText) { m_pModule->SendToUser(m_sChatNick + "!" + m_sChatNick + "@" + GetRemoteIP(), sText); } void CSChatSock::ReadLine(const CS_STRING& sLine) { if (m_pModule) { CString sText = sLine; sText.TrimRight("\r\n"); if (m_pModule->IsAttached()) PutQuery(sText); else AddLine(m_pModule->GetUser()->AddTimestamp(sText)); } } void CSChatSock::Disconnected() { if (m_pModule) PutQuery("*** Disconnected."); } void CSChatSock::Connected() { SetTimeout(0); if (m_pModule) PutQuery("*** Connected."); } void CSChatSock::Timeout() { if (m_pModule) { if (GetType() == LISTENER) m_pModule->PutModule("Timeout while waiting for [" + m_sChatNick + "]"); else PutQuery("*** Connection Timed out."); } } void CRemMarkerJob::RunJob() { CSChat* p = (CSChat*)GetModule(); p->RemoveMarker(m_sNick); // store buffer } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("schat"); Info.SetHasArgs(true); Info.SetArgsHelpText("Path to .pem file, if differs from main ZNC's one"); } NETWORKMODULEDEFS(CSChat, "Secure cross platform (:P) chat system") znc-1.7.5/modules/ctcpflood.cpp0000644000175000017500000001157013542151610016675 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include class CCtcpFloodMod : public CModule { public: MODCONSTRUCTOR(CCtcpFloodMod) { AddHelpCommand(); AddCommand("Secs", t_d(""), t_d("Set seconds limit"), [=](const CString& sLine) { OnSecsCommand(sLine); }); AddCommand("Lines", t_d(""), t_d("Set lines limit"), [=](const CString& sLine) { OnLinesCommand(sLine); }); AddCommand("Show", "", t_d("Show the current limits"), [=](const CString& sLine) { OnShowCommand(sLine); }); } ~CCtcpFloodMod() override {} void Save() { // We save the settings twice because the module arguments can // be more easily edited via webadmin, while the SetNV() stuff // survives e.g. /msg *status reloadmod ctcpflood. SetNV("secs", CString(m_iThresholdSecs)); SetNV("msgs", CString(m_iThresholdMsgs)); SetArgs(CString(m_iThresholdMsgs) + " " + CString(m_iThresholdSecs)); } bool OnLoad(const CString& sArgs, CString& sMessage) override { m_iThresholdMsgs = sArgs.Token(0).ToUInt(); m_iThresholdSecs = sArgs.Token(1).ToUInt(); if (m_iThresholdMsgs == 0 || m_iThresholdSecs == 0) { m_iThresholdMsgs = GetNV("msgs").ToUInt(); m_iThresholdSecs = GetNV("secs").ToUInt(); } if (m_iThresholdSecs == 0) m_iThresholdSecs = 2; if (m_iThresholdMsgs == 0) m_iThresholdMsgs = 4; Save(); return true; } EModRet Message(const CNick& Nick, const CString& sMessage) { // We never block /me, because it doesn't cause a reply if (sMessage.Token(0).Equals("ACTION")) return CONTINUE; if (m_tLastCTCP + m_iThresholdSecs < time(nullptr)) { m_tLastCTCP = time(nullptr); m_iNumCTCP = 0; } m_iNumCTCP++; if (m_iNumCTCP < m_iThresholdMsgs) return CONTINUE; else if (m_iNumCTCP == m_iThresholdMsgs) PutModule(t_f("Limit reached by {1}, blocking all CTCP")( Nick.GetHostMask())); // Reset the timeout so that we continue blocking messages m_tLastCTCP = time(nullptr); return HALT; } EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override { return Message(Nick, sMessage); } EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) override { return Message(Nick, sMessage); } void OnSecsCommand(const CString& sCommand) { const CString& sArg = sCommand.Token(1, true); if (sArg.empty()) { PutModule(t_s("Usage: Secs ")); return; } m_iThresholdSecs = sArg.ToUInt(); if (m_iThresholdSecs == 0) m_iThresholdSecs = 1; OnShowCommand(""); Save(); } void OnLinesCommand(const CString& sCommand) { const CString& sArg = sCommand.Token(1, true); if (sArg.empty()) { PutModule(t_s("Usage: Lines ")); return; } m_iThresholdMsgs = sArg.ToUInt(); if (m_iThresholdMsgs == 0) m_iThresholdMsgs = 2; OnShowCommand(""); Save(); } void OnShowCommand(const CString& sCommand) { CString sMsgs = t_p("1 CTCP message", "{1} CTCP messages", m_iThresholdMsgs)(m_iThresholdMsgs); CString sSecs = t_p("every second", "every {1} seconds", m_iThresholdSecs)(m_iThresholdSecs); PutModule(t_f("Current limit is {1} {2}")(sMsgs, sSecs)); } private: time_t m_tLastCTCP = 0; unsigned int m_iNumCTCP = 0; time_t m_iThresholdSecs{}; unsigned int m_iThresholdMsgs{}; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("ctcpflood"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s( "This user module takes none to two arguments. The first argument is " "the number of lines after which the flood-protection is triggered. " "The second argument is the time (sec) to in which the number of lines " "is reached. The default setting is 4 CTCPs in 2 seconds")); } USERMODULEDEFS(CCtcpFloodMod, t_s("Don't forward CTCP floods to clients")) znc-1.7.5/modules/block_motd.cpp0000644000175000017500000000600413542151610017031 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::set; class CBlockMotd : public CModule { public: MODCONSTRUCTOR(CBlockMotd) { AddHelpCommand(); AddCommand("GetMotd", t_d("[]"), t_d("Override the block with this command. Can optionally " "specify which server to query."), [this](const CString& sLine) { OverrideCommand(sLine); }); } ~CBlockMotd() override {} void OverrideCommand(const CString& sLine) { if (!GetNetwork() || !GetNetwork()->GetIRCSock()) { PutModule(t_s("You are not connected to an IRC Server.")); return; } TemporarilyAcceptMotd(); const CString sServer = sLine.Token(1); if (sServer.empty()) { PutIRC("MOTD"); } else { PutIRC("MOTD " + sServer); } } EModRet OnNumericMessage(CNumericMessage& Message) override { if ((Message.GetCode() == 375 /* begin of MOTD */ || Message.GetCode() == 372 /* MOTD */) && !ShouldTemporarilyAcceptMotd()) return HALT; if (Message.GetCode() == 376 /* End of MOTD */) { if (!ShouldTemporarilyAcceptMotd()) { Message.SetParam(1, t_s("MOTD blocked by ZNC")); } StopTemporarilyAcceptingMotd(); } if (Message.GetCode() == 422) { // Server has no MOTD StopTemporarilyAcceptingMotd(); } return CONTINUE; } void OnIRCDisconnected() override { StopTemporarilyAcceptingMotd(); } bool ShouldTemporarilyAcceptMotd() const { return m_sTemporaryAcceptedMotdSocks.count(GetNetwork()->GetIRCSock()) > 0; } void TemporarilyAcceptMotd() { if (ShouldTemporarilyAcceptMotd()) { return; } m_sTemporaryAcceptedMotdSocks.insert(GetNetwork()->GetIRCSock()); } void StopTemporarilyAcceptingMotd() { m_sTemporaryAcceptedMotdSocks.erase(GetNetwork()->GetIRCSock()); } private: set m_sTemporaryAcceptedMotdSocks; }; template <> void TModInfo(CModInfo& Info) { Info.AddType(CModInfo::NetworkModule); Info.AddType(CModInfo::GlobalModule); Info.SetWikiPage("block_motd"); } USERMODULEDEFS( CBlockMotd, t_s("Block the MOTD from IRC so it's not sent to your client(s).")) znc-1.7.5/modules/autoattach.cpp0000644000175000017500000002232213542151610017052 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::vector; class CAttachMatch { public: CAttachMatch(CModule* pModule, const CString& sChannels, const CString& sSearch, const CString& sHostmasks, bool bNegated) { m_pModule = pModule; m_sChannelWildcard = sChannels; m_sSearchWildcard = sSearch; m_sHostmaskWildcard = sHostmasks; m_bNegated = bNegated; if (m_sChannelWildcard.empty()) m_sChannelWildcard = "*"; if (m_sSearchWildcard.empty()) m_sSearchWildcard = "*"; if (m_sHostmaskWildcard.empty()) m_sHostmaskWildcard = "*!*@*"; } bool IsMatch(const CString& sChan, const CString& sHost, const CString& sMessage) const { if (!sHost.WildCmp(m_sHostmaskWildcard, CString::CaseInsensitive)) return false; if (!sChan.WildCmp(m_sChannelWildcard, CString::CaseInsensitive)) return false; if (!sMessage.WildCmp(m_pModule->ExpandString(m_sSearchWildcard), CString::CaseInsensitive)) return false; return true; } bool IsNegated() const { return m_bNegated; } const CString& GetHostMask() const { return m_sHostmaskWildcard; } const CString& GetSearch() const { return m_sSearchWildcard; } const CString& GetChans() const { return m_sChannelWildcard; } CString ToString() { CString sRes; if (m_bNegated) sRes += "!"; sRes += m_sChannelWildcard; sRes += " "; sRes += m_sSearchWildcard; sRes += " "; sRes += m_sHostmaskWildcard; return sRes; } private: bool m_bNegated; CModule* m_pModule; CString m_sChannelWildcard; CString m_sSearchWildcard; CString m_sHostmaskWildcard; }; class CChanAttach : public CModule { public: typedef vector VAttachMatch; typedef VAttachMatch::iterator VAttachIter; private: void HandleAdd(const CString& sLine) { CString sMsg = sLine.Token(1, true); bool bHelp = false; bool bNegated = sMsg.TrimPrefix("!"); CString sChan = sMsg.Token(0); CString sSearch = sMsg.Token(1); CString sHost = sMsg.Token(2); if (sChan.empty()) { bHelp = true; } else if (Add(bNegated, sChan, sSearch, sHost)) { PutModule(t_s("Added to list")); } else { PutModule(t_f("{1} is already added")(sLine.Token(1, true))); bHelp = true; } if (bHelp) { PutModule(t_s("Usage: Add [!]<#chan> ")); PutModule(t_s("Wildcards are allowed")); } } void HandleDel(const CString& sLine) { CString sMsg = sLine.Token(1, true); bool bNegated = sMsg.TrimPrefix("!"); CString sChan = sMsg.Token(0); CString sSearch = sMsg.Token(1); CString sHost = sMsg.Token(2); if (Del(bNegated, sChan, sSearch, sHost)) { PutModule(t_f("Removed {1} from list")(sChan)); } else { PutModule(t_s("Usage: Del [!]<#chan> ")); } } void HandleList(const CString& sLine) { CTable Table; Table.AddColumn(t_s("Neg")); Table.AddColumn(t_s("Chan")); Table.AddColumn(t_s("Search")); Table.AddColumn(t_s("Host")); VAttachIter it = m_vMatches.begin(); for (; it != m_vMatches.end(); ++it) { Table.AddRow(); Table.SetCell(t_s("Neg"), it->IsNegated() ? "!" : ""); Table.SetCell(t_s("Chan"), it->GetChans()); Table.SetCell(t_s("Search"), it->GetSearch()); Table.SetCell(t_s("Host"), it->GetHostMask()); } if (Table.size()) { PutModule(Table); } else { PutModule(t_s("You have no entries.")); } } public: MODCONSTRUCTOR(CChanAttach) { AddHelpCommand(); AddCommand( "Add", t_d("[!]<#chan> "), t_d("Add an entry, use !#chan to negate and * for wildcards"), [=](const CString& sLine) { HandleAdd(sLine); }); AddCommand("Del", t_d("[!]<#chan> "), t_d("Remove an entry, needs to be an exact match"), [=](const CString& sLine) { HandleDel(sLine); }); AddCommand("List", "", t_d("List all entries"), [=](const CString& sLine) { HandleList(sLine); }); } ~CChanAttach() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { VCString vsChans; sArgs.Split(" ", vsChans, false); for (VCString::const_iterator it = vsChans.begin(); it != vsChans.end(); ++it) { CString sAdd = *it; bool bNegated = sAdd.TrimPrefix("!"); CString sChan = sAdd.Token(0); CString sSearch = sAdd.Token(1); CString sHost = sAdd.Token(2, true); if (!Add(bNegated, sChan, sSearch, sHost)) { PutModule(t_f("Unable to add [{1}]")(*it)); } } // Load our saved settings, ignore errors MCString::iterator it; for (it = BeginNV(); it != EndNV(); ++it) { CString sAdd = it->first; bool bNegated = sAdd.TrimPrefix("!"); CString sChan = sAdd.Token(0); CString sSearch = sAdd.Token(1); CString sHost = sAdd.Token(2, true); Add(bNegated, sChan, sSearch, sHost); } return true; } void TryAttach(const CNick& Nick, CChan& Channel, CString& Message) { const CString& sChan = Channel.GetName(); const CString& sHost = Nick.GetHostMask(); const CString& sMessage = Message; VAttachIter it; if (!Channel.IsDetached()) return; // Any negated match? for (it = m_vMatches.begin(); it != m_vMatches.end(); ++it) { if (it->IsNegated() && it->IsMatch(sChan, sHost, sMessage)) return; } // Now check for a positive match for (it = m_vMatches.begin(); it != m_vMatches.end(); ++it) { if (!it->IsNegated() && it->IsMatch(sChan, sHost, sMessage)) { Channel.AttachUser(); return; } } } EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) override { TryAttach(Nick, Channel, sMessage); return CONTINUE; } EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override { TryAttach(Nick, Channel, sMessage); return CONTINUE; } EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) override { TryAttach(Nick, Channel, sMessage); return CONTINUE; } VAttachIter FindEntry(const CString& sChan, const CString& sSearch, const CString& sHost) { VAttachIter it = m_vMatches.begin(); for (; it != m_vMatches.end(); ++it) { if (sHost.empty() || it->GetHostMask() != sHost) continue; if (sSearch.empty() || it->GetSearch() != sSearch) continue; if (sChan.empty() || it->GetChans() != sChan) continue; return it; } return m_vMatches.end(); } bool Add(bool bNegated, const CString& sChan, const CString& sSearch, const CString& sHost) { CAttachMatch attach(this, sChan, sSearch, sHost, bNegated); // Check for duplicates VAttachIter it = m_vMatches.begin(); for (; it != m_vMatches.end(); ++it) { if (it->GetHostMask() == attach.GetHostMask() && it->GetChans() == attach.GetChans() && it->GetSearch() == attach.GetSearch()) return false; } m_vMatches.push_back(attach); // Also save it for next module load SetNV(attach.ToString(), ""); return true; } bool Del(bool bNegated, const CString& sChan, const CString& sSearch, const CString& sHost) { VAttachIter it = FindEntry(sChan, sSearch, sHost); if (it == m_vMatches.end() || it->IsNegated() != bNegated) return false; DelNV(it->ToString()); m_vMatches.erase(it); return true; } private: VAttachMatch m_vMatches; }; template <> void TModInfo(CModInfo& Info) { Info.AddType(CModInfo::UserModule); Info.SetWikiPage("autoattach"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s( "List of channel masks and channel masks with ! before them.")); } NETWORKMODULEDEFS(CChanAttach, t_s("Reattaches you to channels on activity.")) znc-1.7.5/modules/controlpanel.cpp0000644000175000017500000017242313542151610017425 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * Copyright (C) 2008 by Stefan Rado * based on admin.cpp by Sebastian Ramacher * based on admin.cpp in crox branch * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include using std::map; using std::vector; template struct array_size_helper { char __place_holder[N]; }; template static array_size_helper array_size(T (&)[N]) { return array_size_helper(); } #define ARRAY_SIZE(array) sizeof(array_size((array))) class CAdminMod : public CModule { using CModule::PutModule; struct Setting { const char* name; CString type; }; void PrintVarsHelp(const CString& sFilter, const Setting vars[], unsigned int uSize, const CString& sDescription) { CTable VarTable; VarTable.AddColumn(t_s("Type", "helptable")); VarTable.AddColumn(t_s("Variables", "helptable")); std::map mvsTypedVariables; for (unsigned int i = 0; i != uSize; ++i) { CString sVar = CString(vars[i].name).AsLower(); if (sFilter.empty() || sVar.StartsWith(sFilter) || sVar.WildCmp(sFilter)) { mvsTypedVariables[vars[i].type].emplace_back(vars[i].name); } } for (const auto& i : mvsTypedVariables) { VarTable.AddRow(); VarTable.SetCell(t_s("Type", "helptable"), i.first); VarTable.SetCell( t_s("Variables", "helptable"), CString(", ").Join(i.second.cbegin(), i.second.cend())); } if (!VarTable.empty()) { PutModule(sDescription); PutModule(VarTable); } } void PrintHelp(const CString& sLine) { HandleHelpCommand(sLine); const CString str = t_s("String"); const CString boolean = t_s("Boolean (true/false)"); const CString integer = t_s("Integer"); const CString number = t_s("Number"); const CString sCmdFilter = sLine.Token(1, false); const CString sVarFilter = sLine.Token(2, true).AsLower(); if (sCmdFilter.empty() || sCmdFilter.StartsWith("Set") || sCmdFilter.StartsWith("Get")) { Setting vars[] = { {"Nick", str}, {"Altnick", str}, {"Ident", str}, {"RealName", str}, {"BindHost", str}, {"MultiClients", boolean}, {"DenyLoadMod", boolean}, {"DenySetBindHost", boolean}, {"DefaultChanModes", str}, {"QuitMsg", str}, {"ChanBufferSize", integer}, {"QueryBufferSize", integer}, {"AutoClearChanBuffer", boolean}, {"AutoClearQueryBuffer", boolean}, {"Password", str}, {"JoinTries", integer}, {"MaxJoins", integer}, {"MaxNetworks", integer}, {"MaxQueryBuffers", integer}, {"Timezone", str}, {"Admin", boolean}, {"AppendTimestamp", boolean}, {"PrependTimestamp", boolean}, {"AuthOnlyViaModule", boolean}, {"TimestampFormat", str}, {"DCCBindHost", str}, {"StatusPrefix", str}, #ifdef HAVE_I18N {"Language", str}, #endif #ifdef HAVE_ICU {"ClientEncoding", str}, #endif }; PrintVarsHelp(sVarFilter, vars, ARRAY_SIZE(vars), t_s("The following variables are available when " "using the Set/Get commands:")); } if (sCmdFilter.empty() || sCmdFilter.StartsWith("SetNetwork") || sCmdFilter.StartsWith("GetNetwork")) { Setting nvars[] = { {"Nick", str}, {"Altnick", str}, {"Ident", str}, {"RealName", str}, {"BindHost", str}, {"FloodRate", number}, {"FloodBurst", integer}, {"JoinDelay", integer}, #ifdef HAVE_ICU {"Encoding", str}, #endif {"QuitMsg", str}, {"TrustAllCerts", boolean}, {"TrustPKI", boolean}, }; PrintVarsHelp(sVarFilter, nvars, ARRAY_SIZE(nvars), t_s("The following variables are available when " "using the SetNetwork/GetNetwork commands:")); } if (sCmdFilter.empty() || sCmdFilter.StartsWith("SetChan") || sCmdFilter.StartsWith("GetChan")) { Setting cvars[] = {{"DefModes", str}, {"Key", str}, {"BufferSize", integer}, {"InConfig", boolean}, {"AutoClearChanBuffer", boolean}, {"Detached", boolean}}; PrintVarsHelp(sVarFilter, cvars, ARRAY_SIZE(cvars), t_s("The following variables are available when " "using the SetChan/GetChan commands:")); } if (sCmdFilter.empty()) PutModule( t_s("You can use $user as the user name and $network as the " "network name for modifying your own user and network.")); } CUser* FindUser(const CString& sUsername) { if (sUsername.Equals("$me") || sUsername.Equals("$user")) return GetUser(); CUser* pUser = CZNC::Get().FindUser(sUsername); if (!pUser) { PutModule(t_f("Error: User [{1}] does not exist!")(sUsername)); return nullptr; } if (pUser != GetUser() && !GetUser()->IsAdmin()) { PutModule(t_s( "Error: You need to have admin rights to modify other users!")); return nullptr; } return pUser; } CIRCNetwork* FindNetwork(CUser* pUser, const CString& sNetwork) { if (sNetwork.Equals("$net") || sNetwork.Equals("$network")) { if (pUser != GetUser()) { PutModule(t_s( "Error: You cannot use $network to modify other users!")); return nullptr; } return CModule::GetNetwork(); } CIRCNetwork* pNetwork = pUser->FindNetwork(sNetwork); if (!pNetwork) { PutModule( t_f("Error: User {1} does not have a network named [{2}].")( pUser->GetUserName(), sNetwork)); } return pNetwork; } void Get(const CString& sLine) { const CString sVar = sLine.Token(1).AsLower(); CString sUsername = sLine.Token(2, true); CUser* pUser; if (sVar.empty()) { PutModule(t_s("Usage: Get [username]")); return; } if (sUsername.empty()) { pUser = GetUser(); } else { pUser = FindUser(sUsername); } if (!pUser) return; if (sVar == "nick") PutModule("Nick = " + pUser->GetNick()); else if (sVar == "altnick") PutModule("AltNick = " + pUser->GetAltNick()); else if (sVar == "ident") PutModule("Ident = " + pUser->GetIdent()); else if (sVar == "realname") PutModule("RealName = " + pUser->GetRealName()); else if (sVar == "bindhost") PutModule("BindHost = " + pUser->GetBindHost()); else if (sVar == "multiclients") PutModule("MultiClients = " + CString(pUser->MultiClients())); else if (sVar == "denyloadmod") PutModule("DenyLoadMod = " + CString(pUser->DenyLoadMod())); else if (sVar == "denysetbindhost") PutModule("DenySetBindHost = " + CString(pUser->DenySetBindHost())); else if (sVar == "defaultchanmodes") PutModule("DefaultChanModes = " + pUser->GetDefaultChanModes()); else if (sVar == "quitmsg") PutModule("QuitMsg = " + pUser->GetQuitMsg()); else if (sVar == "buffercount") PutModule("BufferCount = " + CString(pUser->GetBufferCount())); else if (sVar == "chanbuffersize") PutModule("ChanBufferSize = " + CString(pUser->GetChanBufferSize())); else if (sVar == "querybuffersize") PutModule("QueryBufferSize = " + CString(pUser->GetQueryBufferSize())); else if (sVar == "keepbuffer") // XXX compatibility crap, added in 0.207 PutModule("KeepBuffer = " + CString(!pUser->AutoClearChanBuffer())); else if (sVar == "autoclearchanbuffer") PutModule("AutoClearChanBuffer = " + CString(pUser->AutoClearChanBuffer())); else if (sVar == "autoclearquerybuffer") PutModule("AutoClearQueryBuffer = " + CString(pUser->AutoClearQueryBuffer())); else if (sVar == "maxjoins") PutModule("MaxJoins = " + CString(pUser->MaxJoins())); else if (sVar == "notraffictimeout") PutModule("NoTrafficTimeout = " + CString(pUser->GetNoTrafficTimeout())); else if (sVar == "maxnetworks") PutModule("MaxNetworks = " + CString(pUser->MaxNetworks())); else if (sVar == "maxquerybuffers") PutModule("MaxQueryBuffers = " + CString(pUser->MaxQueryBuffers())); else if (sVar == "jointries") PutModule("JoinTries = " + CString(pUser->JoinTries())); else if (sVar == "timezone") PutModule("Timezone = " + pUser->GetTimezone()); else if (sVar == "appendtimestamp") PutModule("AppendTimestamp = " + CString(pUser->GetTimestampAppend())); else if (sVar == "prependtimestamp") PutModule("PrependTimestamp = " + CString(pUser->GetTimestampPrepend())); else if (sVar == "authonlyviamodule") PutModule("AuthOnlyViaModule = " + CString(pUser->AuthOnlyViaModule())); else if (sVar == "timestampformat") PutModule("TimestampFormat = " + pUser->GetTimestampFormat()); else if (sVar == "dccbindhost") PutModule("DCCBindHost = " + CString(pUser->GetDCCBindHost())); else if (sVar == "admin") PutModule("Admin = " + CString(pUser->IsAdmin())); else if (sVar == "statusprefix") PutModule("StatusPrefix = " + pUser->GetStatusPrefix()); #ifdef HAVE_I18N else if (sVar == "language") PutModule("Language = " + (pUser->GetLanguage().empty() ? "en" : pUser->GetLanguage())); #endif #ifdef HAVE_ICU else if (sVar == "clientencoding") PutModule("ClientEncoding = " + pUser->GetClientEncoding()); #endif else PutModule(t_s("Error: Unknown variable")); } void Set(const CString& sLine) { const CString sVar = sLine.Token(1).AsLower(); CString sUserName = sLine.Token(2); CString sValue = sLine.Token(3, true); if (sValue.empty()) { PutModule(t_s("Usage: Set ")); return; } CUser* pUser = FindUser(sUserName); if (!pUser) return; if (sVar == "nick") { pUser->SetNick(sValue); PutModule("Nick = " + sValue); } else if (sVar == "altnick") { pUser->SetAltNick(sValue); PutModule("AltNick = " + sValue); } else if (sVar == "ident") { pUser->SetIdent(sValue); PutModule("Ident = " + sValue); } else if (sVar == "realname") { pUser->SetRealName(sValue); PutModule("RealName = " + sValue); } else if (sVar == "bindhost") { if (!pUser->DenySetBindHost() || GetUser()->IsAdmin()) { if (sValue.Equals(pUser->GetBindHost())) { PutModule(t_s("This bind host is already set!")); return; } pUser->SetBindHost(sValue); PutModule("BindHost = " + sValue); } else { PutModule(t_s("Access denied!")); } } else if (sVar == "multiclients") { bool b = sValue.ToBool(); pUser->SetMultiClients(b); PutModule("MultiClients = " + CString(b)); } else if (sVar == "denyloadmod") { if (GetUser()->IsAdmin()) { bool b = sValue.ToBool(); pUser->SetDenyLoadMod(b); PutModule("DenyLoadMod = " + CString(b)); } else { PutModule(t_s("Access denied!")); } } else if (sVar == "denysetbindhost") { if (GetUser()->IsAdmin()) { bool b = sValue.ToBool(); pUser->SetDenySetBindHost(b); PutModule("DenySetBindHost = " + CString(b)); } else { PutModule(t_s("Access denied!")); } } else if (sVar == "defaultchanmodes") { pUser->SetDefaultChanModes(sValue); PutModule("DefaultChanModes = " + sValue); } else if (sVar == "quitmsg") { pUser->SetQuitMsg(sValue); PutModule("QuitMsg = " + sValue); } else if (sVar == "chanbuffersize" || sVar == "buffercount") { unsigned int i = sValue.ToUInt(); // Admins don't have to honour the buffer limit if (pUser->SetChanBufferSize(i, GetUser()->IsAdmin())) { PutModule("ChanBufferSize = " + sValue); } else { PutModule(t_f("Setting failed, limit for buffer size is {1}")( CString(CZNC::Get().GetMaxBufferSize()))); } } else if (sVar == "querybuffersize") { unsigned int i = sValue.ToUInt(); // Admins don't have to honour the buffer limit if (pUser->SetQueryBufferSize(i, GetUser()->IsAdmin())) { PutModule("QueryBufferSize = " + sValue); } else { PutModule(t_f("Setting failed, limit for buffer size is {1}")( CString(CZNC::Get().GetMaxBufferSize()))); } } else if (sVar == "keepbuffer") { // XXX compatibility crap, added in 0.207 bool b = !sValue.ToBool(); pUser->SetAutoClearChanBuffer(b); PutModule("AutoClearChanBuffer = " + CString(b)); } else if (sVar == "autoclearchanbuffer") { bool b = sValue.ToBool(); pUser->SetAutoClearChanBuffer(b); PutModule("AutoClearChanBuffer = " + CString(b)); } else if (sVar == "autoclearquerybuffer") { bool b = sValue.ToBool(); pUser->SetAutoClearQueryBuffer(b); PutModule("AutoClearQueryBuffer = " + CString(b)); } else if (sVar == "password") { const CString sSalt = CUtils::GetSalt(); const CString sHash = CUser::SaltedHash(sValue, sSalt); pUser->SetPass(sHash, CUser::HASH_DEFAULT, sSalt); PutModule(t_s("Password has been changed!")); } else if (sVar == "maxjoins") { unsigned int i = sValue.ToUInt(); pUser->SetMaxJoins(i); PutModule("MaxJoins = " + CString(pUser->MaxJoins())); } else if (sVar == "notraffictimeout") { unsigned int i = sValue.ToUInt(); if (i < 30) { PutModule(t_s("Timeout can't be less than 30 seconds!")); } else { pUser->SetNoTrafficTimeout(i); PutModule("NoTrafficTimeout = " + CString(pUser->GetNoTrafficTimeout())); } } else if (sVar == "maxnetworks") { if (GetUser()->IsAdmin()) { unsigned int i = sValue.ToUInt(); pUser->SetMaxNetworks(i); PutModule("MaxNetworks = " + sValue); } else { PutModule(t_s("Access denied!")); } } else if (sVar == "maxquerybuffers") { unsigned int i = sValue.ToUInt(); pUser->SetMaxQueryBuffers(i); PutModule("MaxQueryBuffers = " + sValue); } else if (sVar == "jointries") { unsigned int i = sValue.ToUInt(); pUser->SetJoinTries(i); PutModule("JoinTries = " + CString(pUser->JoinTries())); } else if (sVar == "timezone") { pUser->SetTimezone(sValue); PutModule("Timezone = " + pUser->GetTimezone()); } else if (sVar == "admin") { if (GetUser()->IsAdmin() && pUser != GetUser()) { bool b = sValue.ToBool(); pUser->SetAdmin(b); PutModule("Admin = " + CString(pUser->IsAdmin())); } else { PutModule(t_s("Access denied!")); } } else if (sVar == "prependtimestamp") { bool b = sValue.ToBool(); pUser->SetTimestampPrepend(b); PutModule("PrependTimestamp = " + CString(b)); } else if (sVar == "appendtimestamp") { bool b = sValue.ToBool(); pUser->SetTimestampAppend(b); PutModule("AppendTimestamp = " + CString(b)); } else if (sVar == "authonlyviamodule") { if (GetUser()->IsAdmin()) { bool b = sValue.ToBool(); pUser->SetAuthOnlyViaModule(b); PutModule("AuthOnlyViaModule = " + CString(b)); } else { PutModule(t_s("Access denied!")); } } else if (sVar == "timestampformat") { pUser->SetTimestampFormat(sValue); PutModule("TimestampFormat = " + sValue); } else if (sVar == "dccbindhost") { if (!pUser->DenySetBindHost() || GetUser()->IsAdmin()) { pUser->SetDCCBindHost(sValue); PutModule("DCCBindHost = " + sValue); } else { PutModule(t_s("Access denied!")); } } else if (sVar == "statusprefix") { if (sVar.find_first_of(" \t\n") == CString::npos) { pUser->SetStatusPrefix(sValue); PutModule("StatusPrefix = " + sValue); } else { PutModule(t_s("That would be a bad idea!")); } } #ifdef HAVE_I18N else if (sVar == "language") { auto mTranslations = CTranslationInfo::GetTranslations(); // TODO: maybe stop special-casing English if (sValue == "en") { pUser->SetLanguage(""); PutModule("Language is set to English"); } else if (mTranslations.count(sValue)) { pUser->SetLanguage(sValue); PutModule("Language = " + sValue); } else { VCString vsCodes = {"en"}; for (const auto it : mTranslations) { vsCodes.push_back(it.first); } PutModule(t_f("Supported languages: {1}")( CString(", ").Join(vsCodes.begin(), vsCodes.end()))); } } #endif #ifdef HAVE_ICU else if (sVar == "clientencoding") { pUser->SetClientEncoding(sValue); PutModule("ClientEncoding = " + pUser->GetClientEncoding()); } #endif else PutModule(t_s("Error: Unknown variable")); } void GetNetwork(const CString& sLine) { const CString sVar = sLine.Token(1).AsLower(); const CString sUsername = sLine.Token(2); const CString sNetwork = sLine.Token(3); CIRCNetwork* pNetwork = nullptr; CUser* pUser; if (sVar.empty()) { PutModule(t_s("Usage: GetNetwork [username] [network]")); return; } if (sUsername.empty()) { pUser = GetUser(); } else { pUser = FindUser(sUsername); } if (!pUser) { return; } if (sNetwork.empty()) { if (pUser == GetUser()) { pNetwork = CModule::GetNetwork(); } else { PutModule( t_s("Error: A network must be specified to get another " "users settings.")); return; } if (!pNetwork) { PutModule(t_s("You are not currently attached to a network.")); return; } } else { pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { PutModule(t_s("Error: Invalid network.")); return; } } if (sVar.Equals("nick")) { PutModule("Nick = " + pNetwork->GetNick()); } else if (sVar.Equals("altnick")) { PutModule("AltNick = " + pNetwork->GetAltNick()); } else if (sVar.Equals("ident")) { PutModule("Ident = " + pNetwork->GetIdent()); } else if (sVar.Equals("realname")) { PutModule("RealName = " + pNetwork->GetRealName()); } else if (sVar.Equals("bindhost")) { PutModule("BindHost = " + pNetwork->GetBindHost()); } else if (sVar.Equals("floodrate")) { PutModule("FloodRate = " + CString(pNetwork->GetFloodRate())); } else if (sVar.Equals("floodburst")) { PutModule("FloodBurst = " + CString(pNetwork->GetFloodBurst())); } else if (sVar.Equals("joindelay")) { PutModule("JoinDelay = " + CString(pNetwork->GetJoinDelay())); #ifdef HAVE_ICU } else if (sVar.Equals("encoding")) { PutModule("Encoding = " + pNetwork->GetEncoding()); #endif } else if (sVar.Equals("quitmsg")) { PutModule("QuitMsg = " + pNetwork->GetQuitMsg()); } else if (sVar.Equals("trustallcerts")) { PutModule("TrustAllCerts = " + CString(pNetwork->GetTrustAllCerts())); } else if (sVar.Equals("trustpki")) { PutModule("TrustPKI = " + CString(pNetwork->GetTrustPKI())); } else { PutModule(t_s("Error: Unknown variable")); } } void SetNetwork(const CString& sLine) { const CString sVar = sLine.Token(1).AsLower(); const CString sUsername = sLine.Token(2); const CString sNetwork = sLine.Token(3); const CString sValue = sLine.Token(4, true); if (sValue.empty()) { PutModule(t_s( "Usage: SetNetwork ")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) { return; } CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } if (sVar.Equals("nick")) { pNetwork->SetNick(sValue); PutModule("Nick = " + pNetwork->GetNick()); } else if (sVar.Equals("altnick")) { pNetwork->SetAltNick(sValue); PutModule("AltNick = " + pNetwork->GetAltNick()); } else if (sVar.Equals("ident")) { pNetwork->SetIdent(sValue); PutModule("Ident = " + pNetwork->GetIdent()); } else if (sVar.Equals("realname")) { pNetwork->SetRealName(sValue); PutModule("RealName = " + pNetwork->GetRealName()); } else if (sVar.Equals("bindhost")) { if (!pUser->DenySetBindHost() || GetUser()->IsAdmin()) { if (sValue.Equals(pNetwork->GetBindHost())) { PutModule(t_s("This bind host is already set!")); return; } pNetwork->SetBindHost(sValue); PutModule("BindHost = " + sValue); } else { PutModule(t_s("Access denied!")); } } else if (sVar.Equals("floodrate")) { pNetwork->SetFloodRate(sValue.ToDouble()); PutModule("FloodRate = " + CString(pNetwork->GetFloodRate())); } else if (sVar.Equals("floodburst")) { pNetwork->SetFloodBurst(sValue.ToUShort()); PutModule("FloodBurst = " + CString(pNetwork->GetFloodBurst())); } else if (sVar.Equals("joindelay")) { pNetwork->SetJoinDelay(sValue.ToUShort()); PutModule("JoinDelay = " + CString(pNetwork->GetJoinDelay())); #ifdef HAVE_ICU } else if (sVar.Equals("encoding")) { pNetwork->SetEncoding(sValue); PutModule("Encoding = " + pNetwork->GetEncoding()); #endif } else if (sVar.Equals("quitmsg")) { pNetwork->SetQuitMsg(sValue); PutModule("QuitMsg = " + pNetwork->GetQuitMsg()); } else if (sVar.Equals("trustallcerts")) { bool b = sValue.ToBool(); pNetwork->SetTrustAllCerts(b); PutModule("TrustAllCerts = " + CString(b)); } else if (sVar.Equals("trustpki")) { bool b = sValue.ToBool(); pNetwork->SetTrustPKI(b); PutModule("TrustPKI = " + CString(b)); } else { PutModule(t_s("Error: Unknown variable")); } } void AddChan(const CString& sLine) { const CString sUsername = sLine.Token(1); const CString sNetwork = sLine.Token(2); const CString sChan = sLine.Token(3); if (sChan.empty()) { PutModule(t_s("Usage: AddChan ")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } if (pNetwork->FindChan(sChan)) { PutModule(t_f("Error: User {1} already has a channel named {2}.")( sUsername, sChan)); return; } CChan* pChan = new CChan(sChan, pNetwork, true); if (pNetwork->AddChan(pChan)) PutModule(t_f("Channel {1} for user {2} added to network {3}.")( pChan->GetName(), sUsername, pNetwork->GetName())); else PutModule(t_f( "Could not add channel {1} for user {2} to network {3}, does " "it already exist?")(sChan, sUsername, pNetwork->GetName())); } void DelChan(const CString& sLine) { const CString sUsername = sLine.Token(1); const CString sNetwork = sLine.Token(2); const CString sChan = sLine.Token(3); if (sChan.empty()) { PutModule(t_s("Usage: DelChan ")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } std::vector vChans = pNetwork->FindChans(sChan); if (vChans.empty()) { PutModule( t_f("Error: User {1} does not have any channel matching [{2}] " "in network {3}")(sUsername, sChan, pNetwork->GetName())); return; } VCString vsNames; for (const CChan* pChan : vChans) { const CString& sName = pChan->GetName(); vsNames.push_back(sName); pNetwork->PutIRC("PART " + sName); pNetwork->DelChan(sName); } PutModule(t_p("Channel {1} is deleted from network {2} of user {3}", "Channels {1} are deleted from network {2} of user {3}", vsNames.size())( CString(", ").Join(vsNames.begin(), vsNames.end()), pNetwork->GetName(), sUsername)); } void GetChan(const CString& sLine) { const CString sVar = sLine.Token(1).AsLower(); CString sUsername = sLine.Token(2); CString sNetwork = sLine.Token(3); CString sChan = sLine.Token(4, true); if (sChan.empty()) { PutModule( t_s("Usage: GetChan ")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } std::vector vChans = pNetwork->FindChans(sChan); if (vChans.empty()) { PutModule(t_f("Error: No channels matching [{1}] found.")(sChan)); return; } for (CChan* pChan : vChans) { if (sVar == "defmodes") { PutModule(pChan->GetName() + ": DefModes = " + pChan->GetDefaultModes()); } else if (sVar == "buffersize" || sVar == "buffer") { CString sValue(pChan->GetBufferCount()); if (!pChan->HasBufferCountSet()) { sValue += " (default)"; } PutModule(pChan->GetName() + ": BufferSize = " + sValue); } else if (sVar == "inconfig") { PutModule(pChan->GetName() + ": InConfig = " + CString(pChan->InConfig())); } else if (sVar == "keepbuffer") { // XXX compatibility crap, added in 0.207 PutModule(pChan->GetName() + ": KeepBuffer = " + CString(!pChan->AutoClearChanBuffer())); } else if (sVar == "autoclearchanbuffer") { CString sValue(pChan->AutoClearChanBuffer()); if (!pChan->HasAutoClearChanBufferSet()) { sValue += " (default)"; } PutModule(pChan->GetName() + ": AutoClearChanBuffer = " + sValue); } else if (sVar == "detached") { PutModule(pChan->GetName() + ": Detached = " + CString(pChan->IsDetached())); } else if (sVar == "key") { PutModule(pChan->GetName() + ": Key = " + pChan->GetKey()); } else { PutModule(t_s("Error: Unknown variable")); return; } } } void SetChan(const CString& sLine) { const CString sVar = sLine.Token(1).AsLower(); CString sUsername = sLine.Token(2); CString sNetwork = sLine.Token(3); CString sChan = sLine.Token(4); CString sValue = sLine.Token(5, true); if (sValue.empty()) { PutModule( t_s("Usage: SetChan " "")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } std::vector vChans = pNetwork->FindChans(sChan); if (vChans.empty()) { PutModule(t_f("Error: No channels matching [{1}] found.")(sChan)); return; } for (CChan* pChan : vChans) { if (sVar == "defmodes") { pChan->SetDefaultModes(sValue); PutModule(pChan->GetName() + ": DefModes = " + sValue); } else if (sVar == "buffersize" || sVar == "buffer") { unsigned int i = sValue.ToUInt(); if (sValue.Equals("-")) { pChan->ResetBufferCount(); PutModule(pChan->GetName() + ": BufferSize = " + CString(pChan->GetBufferCount())); } else if (pChan->SetBufferCount(i, GetUser()->IsAdmin())) { // Admins don't have to honour the buffer limit PutModule(pChan->GetName() + ": BufferSize = " + sValue); } else { PutModule( t_f("Setting failed, limit for buffer size is {1}")( CString(CZNC::Get().GetMaxBufferSize()))); return; } } else if (sVar == "inconfig") { bool b = sValue.ToBool(); pChan->SetInConfig(b); PutModule(pChan->GetName() + ": InConfig = " + CString(b)); } else if (sVar == "keepbuffer") { // XXX compatibility crap, added in 0.207 bool b = !sValue.ToBool(); pChan->SetAutoClearChanBuffer(b); PutModule(pChan->GetName() + ": AutoClearChanBuffer = " + CString(b)); } else if (sVar == "autoclearchanbuffer") { if (sValue.Equals("-")) { pChan->ResetAutoClearChanBuffer(); } else { bool b = sValue.ToBool(); pChan->SetAutoClearChanBuffer(b); } PutModule(pChan->GetName() + ": AutoClearChanBuffer = " + CString(pChan->AutoClearChanBuffer())); } else if (sVar == "detached") { bool b = sValue.ToBool(); if (pChan->IsDetached() != b) { if (b) pChan->DetachUser(); else pChan->AttachUser(); } PutModule(pChan->GetName() + ": Detached = " + CString(b)); } else if (sVar == "key") { pChan->SetKey(sValue); PutModule(pChan->GetName() + ": Key = " + sValue); } else { PutModule(t_s("Error: Unknown variable")); return; } } } void ListUsers(const CString&) { if (!GetUser()->IsAdmin()) return; const map& msUsers = CZNC::Get().GetUserMap(); CTable Table; Table.AddColumn(t_s("Username", "listusers")); Table.AddColumn(t_s("Realname", "listusers")); Table.AddColumn(t_s("IsAdmin", "listusers")); Table.AddColumn(t_s("Nick", "listusers")); Table.AddColumn(t_s("AltNick", "listusers")); Table.AddColumn(t_s("Ident", "listusers")); Table.AddColumn(t_s("BindHost", "listusers")); for (const auto& it : msUsers) { Table.AddRow(); Table.SetCell(t_s("Username", "listusers"), it.first); Table.SetCell(t_s("Realname", "listusers"), it.second->GetRealName()); if (!it.second->IsAdmin()) Table.SetCell(t_s("IsAdmin", "listusers"), t_s("No")); else Table.SetCell(t_s("IsAdmin", "listusers"), t_s("Yes")); Table.SetCell(t_s("Nick", "listusers"), it.second->GetNick()); Table.SetCell(t_s("AltNick", "listusers"), it.second->GetAltNick()); Table.SetCell(t_s("Ident", "listusers"), it.second->GetIdent()); Table.SetCell(t_s("BindHost", "listusers"), it.second->GetBindHost()); } PutModule(Table); } void AddUser(const CString& sLine) { if (!GetUser()->IsAdmin()) { PutModule( t_s("Error: You need to have admin rights to add new users!")); return; } const CString sUsername = sLine.Token(1), sPassword = sLine.Token(2); if (sPassword.empty()) { PutModule(t_s("Usage: AddUser ")); return; } if (CZNC::Get().FindUser(sUsername)) { PutModule(t_f("Error: User {1} already exists!")(sUsername)); return; } CUser* pNewUser = new CUser(sUsername); CString sSalt = CUtils::GetSalt(); pNewUser->SetPass(CUser::SaltedHash(sPassword, sSalt), CUser::HASH_DEFAULT, sSalt); CString sErr; if (!CZNC::Get().AddUser(pNewUser, sErr)) { delete pNewUser; PutModule(t_f("Error: User not added: {1}")(sErr)); return; } PutModule(t_f("User {1} added!")(sUsername)); return; } void DelUser(const CString& sLine) { if (!GetUser()->IsAdmin()) { PutModule( t_s("Error: You need to have admin rights to delete users!")); return; } const CString sUsername = sLine.Token(1, true); if (sUsername.empty()) { PutModule(t_s("Usage: DelUser ")); return; } CUser* pUser = CZNC::Get().FindUser(sUsername); if (!pUser) { PutModule(t_f("Error: User [{1}] does not exist!")(sUsername)); return; } if (pUser == GetUser()) { PutModule(t_s("Error: You can't delete yourself!")); return; } if (!CZNC::Get().DeleteUser(pUser->GetUserName())) { // This can't happen, because we got the user from FindUser() PutModule(t_s("Error: Internal error!")); return; } PutModule(t_f("User {1} deleted!")(sUsername)); return; } void CloneUser(const CString& sLine) { if (!GetUser()->IsAdmin()) { PutModule( t_s("Error: You need to have admin rights to add new users!")); return; } const CString sOldUsername = sLine.Token(1), sNewUsername = sLine.Token(2, true); if (sOldUsername.empty() || sNewUsername.empty()) { PutModule(t_s("Usage: CloneUser ")); return; } CUser* pOldUser = CZNC::Get().FindUser(sOldUsername); if (!pOldUser) { PutModule(t_f("Error: User [{1}] does not exist!")(sOldUsername)); return; } CUser* pNewUser = new CUser(sNewUsername); CString sError; if (!pNewUser->Clone(*pOldUser, sError)) { delete pNewUser; PutModule(t_f("Error: Cloning failed: {1}")(sError)); return; } if (!CZNC::Get().AddUser(pNewUser, sError)) { delete pNewUser; PutModule(t_f("Error: User not added: {1}")(sError)); return; } PutModule(t_f("User {1} added!")(sNewUsername)); return; } void AddNetwork(const CString& sLine) { CString sUser = sLine.Token(1); CString sNetwork = sLine.Token(2); CUser* pUser = GetUser(); if (sNetwork.empty()) { sNetwork = sUser; } else { pUser = FindUser(sUser); if (!pUser) { return; } } if (sNetwork.empty()) { PutModule(t_s("Usage: AddNetwork [user] network")); return; } if (!GetUser()->IsAdmin() && !pUser->HasSpaceForNewNetwork()) { PutStatus( t_s("Network number limit reached. Ask an admin to increase " "the limit for you, or delete unneeded networks using /znc " "DelNetwork ")); return; } if (pUser->FindNetwork(sNetwork)) { PutModule( t_f("Error: User {1} already has a network with the name {2}")( pUser->GetUserName(), sNetwork)); return; } CString sNetworkAddError; if (pUser->AddNetwork(sNetwork, sNetworkAddError)) { PutModule(t_f("Network {1} added to user {2}.")( sNetwork, pUser->GetUserName())); } else { PutModule(t_f( "Error: Network [{1}] could not be added for user {2}: {3}")( sNetwork, pUser->GetUserName(), sNetworkAddError)); } } void DelNetwork(const CString& sLine) { CString sUser = sLine.Token(1); CString sNetwork = sLine.Token(2); CUser* pUser = GetUser(); if (sNetwork.empty()) { sNetwork = sUser; } else { pUser = FindUser(sUser); if (!pUser) { return; } } if (sNetwork.empty()) { PutModule(t_s("Usage: DelNetwork [user] network")); return; } CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } if (pNetwork == CModule::GetNetwork()) { PutModule(t_f( "The currently active network can be deleted via {1}status")( GetUser()->GetStatusPrefix())); return; } if (pUser->DeleteNetwork(sNetwork)) { PutModule(t_f("Network {1} deleted for user {2}.")( sNetwork, pUser->GetUserName())); } else { PutModule( t_f("Error: Network {1} could not be deleted for user {2}.")( sNetwork, pUser->GetUserName())); } } void ListNetworks(const CString& sLine) { CString sUser = sLine.Token(1); CUser* pUser = GetUser(); if (!sUser.empty()) { pUser = FindUser(sUser); if (!pUser) { return; } } const vector& vNetworks = pUser->GetNetworks(); CTable Table; Table.AddColumn(t_s("Network", "listnetworks")); Table.AddColumn(t_s("OnIRC", "listnetworks")); Table.AddColumn(t_s("IRC Server", "listnetworks")); Table.AddColumn(t_s("IRC User", "listnetworks")); Table.AddColumn(t_s("Channels", "listnetworks")); for (const CIRCNetwork* pNetwork : vNetworks) { Table.AddRow(); Table.SetCell(t_s("Network", "listnetworks"), pNetwork->GetName()); if (pNetwork->IsIRCConnected()) { Table.SetCell(t_s("OnIRC", "listnetworks"), t_s("Yes")); Table.SetCell(t_s("IRC Server", "listnetworks"), pNetwork->GetIRCServer()); Table.SetCell(t_s("IRC User", "listnetworks"), pNetwork->GetIRCNick().GetNickMask()); Table.SetCell(t_s("Channels", "listnetworks"), CString(pNetwork->GetChans().size())); } else { Table.SetCell(t_s("OnIRC", "listnetworks"), t_s("No")); } } if (PutModule(Table) == 0) { PutModule(t_s("No networks")); } } void AddServer(const CString& sLine) { CString sUsername = sLine.Token(1); CString sNetwork = sLine.Token(2); CString sServer = sLine.Token(3, true); if (sServer.empty()) { PutModule( t_s("Usage: AddServer [[+]port] " "[password]")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } if (pNetwork->AddServer(sServer)) PutModule(t_f("Added IRC Server {1} to network {2} for user {3}.")( sServer, pNetwork->GetName(), pUser->GetUserName())); else PutModule(t_f( "Error: Could not add IRC server {1} to network {2} for user " "{3}.")(sServer, pNetwork->GetName(), pUser->GetUserName())); } void DelServer(const CString& sLine) { CString sUsername = sLine.Token(1); CString sNetwork = sLine.Token(2); CString sServer = sLine.Token(3, true); unsigned short uPort = sLine.Token(4).ToUShort(); CString sPass = sLine.Token(5); if (sServer.empty()) { PutModule( t_s("Usage: DelServer [[+]port] " "[password]")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } if (pNetwork->DelServer(sServer, uPort, sPass)) PutModule( t_f("Deleted IRC Server {1} from network {2} for user {3}.")( sServer, pNetwork->GetName(), pUser->GetUserName())); else PutModule( t_f("Error: Could not delete IRC server {1} from network {2} " "for user {3}.")(sServer, pNetwork->GetName(), pUser->GetUserName())); } void ReconnectUser(const CString& sLine) { CString sUserName = sLine.Token(1); CString sNetwork = sLine.Token(2); if (sNetwork.empty()) { PutModule(t_s("Usage: Reconnect ")); return; } CUser* pUser = FindUser(sUserName); if (!pUser) { return; } CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } CIRCSock* pIRCSock = pNetwork->GetIRCSock(); // cancel connection attempt: if (pIRCSock && !pIRCSock->IsConnected()) { pIRCSock->Close(); } // or close existing connection: else if (pIRCSock) { pIRCSock->Quit(); } // then reconnect pNetwork->SetIRCConnectEnabled(true); PutModule(t_f("Queued network {1} of user {2} for a reconnect.")( pNetwork->GetName(), pUser->GetUserName())); } void DisconnectUser(const CString& sLine) { CString sUserName = sLine.Token(1); CString sNetwork = sLine.Token(2); if (sNetwork.empty()) { PutModule(t_s("Usage: Disconnect ")); return; } CUser* pUser = FindUser(sUserName); if (!pUser) { return; } CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } pNetwork->SetIRCConnectEnabled(false); PutModule(t_f("Closed IRC connection for network {1} of user {2}.")( pNetwork->GetName(), pUser->GetUserName())); } void ListCTCP(const CString& sLine) { CString sUserName = sLine.Token(1, true); if (sUserName.empty()) { sUserName = GetUser()->GetUserName(); } CUser* pUser = FindUser(sUserName); if (!pUser) return; const MCString& msCTCPReplies = pUser->GetCTCPReplies(); CTable Table; Table.AddColumn(t_s("Request", "listctcp")); Table.AddColumn(t_s("Reply", "listctcp")); for (const auto& it : msCTCPReplies) { Table.AddRow(); Table.SetCell(t_s("Request", "listctcp"), it.first); Table.SetCell(t_s("Reply", "listctcp"), it.second); } if (Table.empty()) { PutModule(t_f("No CTCP replies for user {1} are configured")( pUser->GetUserName())); } else { PutModule(t_f("CTCP replies for user {1}:")(pUser->GetUserName())); PutModule(Table); } } void AddCTCP(const CString& sLine) { CString sUserName = sLine.Token(1); CString sCTCPRequest = sLine.Token(2); CString sCTCPReply = sLine.Token(3, true); if (sCTCPRequest.empty()) { sCTCPRequest = sUserName; sCTCPReply = sLine.Token(2, true); sUserName = GetUser()->GetUserName(); } if (sCTCPRequest.empty()) { PutModule(t_s("Usage: AddCTCP [user] [request] [reply]")); PutModule( t_s("This will cause ZNC to reply to the CTCP instead of " "forwarding it to clients.")); PutModule(t_s( "An empty reply will cause the CTCP request to be blocked.")); return; } CUser* pUser = FindUser(sUserName); if (!pUser) return; pUser->AddCTCPReply(sCTCPRequest, sCTCPReply); if (sCTCPReply.empty()) { PutModule(t_f("CTCP requests {1} to user {2} will now be blocked.")( sCTCPRequest.AsUpper(), pUser->GetUserName())); } else { PutModule( t_f("CTCP requests {1} to user {2} will now get reply: {3}")( sCTCPRequest.AsUpper(), pUser->GetUserName(), sCTCPReply)); } } void DelCTCP(const CString& sLine) { CString sUserName = sLine.Token(1); CString sCTCPRequest = sLine.Token(2, true); if (sCTCPRequest.empty()) { sCTCPRequest = sUserName; sUserName = GetUser()->GetUserName(); } CUser* pUser = FindUser(sUserName); if (!pUser) return; if (sCTCPRequest.empty()) { PutModule(t_s("Usage: DelCTCP [user] [request]")); return; } if (pUser->DelCTCPReply(sCTCPRequest)) { PutModule(t_f( "CTCP requests {1} to user {2} will now be sent to IRC clients")( sCTCPRequest.AsUpper(), pUser->GetUserName())); } else { PutModule( t_f("CTCP requests {1} to user {2} will be sent to IRC clients " "(nothing has changed)")(sCTCPRequest.AsUpper(), pUser->GetUserName())); } } void LoadModuleFor(CModules& Modules, const CString& sModName, const CString& sArgs, CModInfo::EModuleType eType, CUser* pUser, CIRCNetwork* pNetwork) { if (pUser->DenyLoadMod() && !GetUser()->IsAdmin()) { PutModule(t_s("Loading modules has been disabled.")); return; } CString sModRet; CModule* pMod = Modules.FindModule(sModName); if (!pMod) { if (!Modules.LoadModule(sModName, sArgs, eType, pUser, pNetwork, sModRet)) { PutModule(t_f("Error: Unable to load module {1}: {2}")( sModName, sModRet)); } else { PutModule(t_f("Loaded module {1}")(sModName)); } } else if (pMod->GetArgs() != sArgs) { if (!Modules.ReloadModule(sModName, sArgs, pUser, pNetwork, sModRet)) { PutModule(t_f("Error: Unable to reload module {1}: {2}")( sModName, sModRet)); } else { PutModule(t_f("Reloaded module {1}")(sModName)); } } else { PutModule( t_f("Error: Unable to load module {1} because it is already " "loaded")(sModName)); } } void LoadModuleForUser(const CString& sLine) { CString sUsername = sLine.Token(1); CString sModName = sLine.Token(2); CString sArgs = sLine.Token(3, true); if (sModName.empty()) { PutModule(t_s("Usage: LoadModule [args]")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; LoadModuleFor(pUser->GetModules(), sModName, sArgs, CModInfo::UserModule, pUser, nullptr); } void LoadModuleForNetwork(const CString& sLine) { CString sUsername = sLine.Token(1); CString sNetwork = sLine.Token(2); CString sModName = sLine.Token(3); CString sArgs = sLine.Token(4, true); if (sModName.empty()) { PutModule( t_s("Usage: LoadNetModule " "[args]")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } LoadModuleFor(pNetwork->GetModules(), sModName, sArgs, CModInfo::NetworkModule, pUser, pNetwork); } void UnLoadModuleFor(CModules& Modules, const CString& sModName, CUser* pUser) { if (pUser->DenyLoadMod() && !GetUser()->IsAdmin()) { PutModule(t_s("Loading modules has been disabled.")); return; } if (Modules.FindModule(sModName) == this) { PutModule(t_f("Please use /znc unloadmod {1}")(sModName)); return; } CString sModRet; if (!Modules.UnloadModule(sModName, sModRet)) { PutModule(t_f("Error: Unable to unload module {1}: {2}")(sModName, sModRet)); } else { PutModule(t_f("Unloaded module {1}")(sModName)); } } void UnLoadModuleForUser(const CString& sLine) { CString sUsername = sLine.Token(1); CString sModName = sLine.Token(2); if (sModName.empty()) { PutModule(t_s("Usage: UnloadModule ")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; UnLoadModuleFor(pUser->GetModules(), sModName, pUser); } void UnLoadModuleForNetwork(const CString& sLine) { CString sUsername = sLine.Token(1); CString sNetwork = sLine.Token(2); CString sModName = sLine.Token(3); if (sModName.empty()) { PutModule(t_s( "Usage: UnloadNetModule ")); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) { return; } UnLoadModuleFor(pNetwork->GetModules(), sModName, pUser); } void ListModulesFor(CModules& Modules) { CTable Table; Table.AddColumn(t_s("Name", "listmodules")); Table.AddColumn(t_s("Arguments", "listmodules")); for (const CModule* pMod : Modules) { Table.AddRow(); Table.SetCell(t_s("Name", "listmodules"), pMod->GetModName()); Table.SetCell(t_s("Arguments", "listmodules"), pMod->GetArgs()); } PutModule(Table); } void ListModulesForUser(const CString& sLine) { CString sUsername = sLine.Token(1); if (sUsername.empty()) { PutModule("Usage: ListMods "); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; if (pUser->GetModules().empty()) { PutModule( t_f("User {1} has no modules loaded.")(pUser->GetUserName())); return; } PutModule(t_f("Modules loaded for user {1}:")(pUser->GetUserName())); ListModulesFor(pUser->GetModules()); } void ListModulesForNetwork(const CString& sLine) { CString sUsername = sLine.Token(1); CString sNetwork = sLine.Token(2); if (sNetwork.empty()) { PutModule("Usage: ListNetMods "); return; } CUser* pUser = FindUser(sUsername); if (!pUser) return; CIRCNetwork* pNetwork = FindNetwork(pUser, sNetwork); if (!pNetwork) return; if (pNetwork->GetModules().empty()) { PutModule(t_f("Network {1} of user {2} has no modules loaded.")( pNetwork->GetName(), pUser->GetUserName())); return; } PutModule(t_f("Modules loaded for network {1} of user {2}:")( pNetwork->GetName(), pUser->GetUserName())); ListModulesFor(pNetwork->GetModules()); } public: MODCONSTRUCTOR(CAdminMod) { AddCommand("Help", t_d("[command] [variable]"), t_d("Prints help for matching commands and variables"), [=](const CString& sLine) { PrintHelp(sLine); }); AddCommand( "Get", t_d(" [username]"), t_d("Prints the variable's value for the given or current user"), [=](const CString& sLine) { Get(sLine); }); AddCommand("Set", t_d(" "), t_d("Sets the variable's value for the given user"), [=](const CString& sLine) { Set(sLine); }); AddCommand("GetNetwork", t_d(" [username] [network]"), t_d("Prints the variable's value for the given network"), [=](const CString& sLine) { GetNetwork(sLine); }); AddCommand("SetNetwork", t_d(" "), t_d("Sets the variable's value for the given network"), [=](const CString& sLine) { SetNetwork(sLine); }); AddCommand("GetChan", t_d(" [username] "), t_d("Prints the variable's value for the given channel"), [=](const CString& sLine) { GetChan(sLine); }); AddCommand("SetChan", t_d(" "), t_d("Sets the variable's value for the given channel"), [=](const CString& sLine) { SetChan(sLine); }); AddCommand("AddChan", t_d(" "), t_d("Adds a new channel"), [=](const CString& sLine) { AddChan(sLine); }); AddCommand("DelChan", t_d(" "), t_d("Deletes a channel"), [=](const CString& sLine) { DelChan(sLine); }); AddCommand("ListUsers", "", t_d("Lists users"), [=](const CString& sLine) { ListUsers(sLine); }); AddCommand("AddUser", t_d(" "), t_d("Adds a new user"), [=](const CString& sLine) { AddUser(sLine); }); AddCommand("DelUser", t_d(""), t_d("Deletes a user"), [=](const CString& sLine) { DelUser(sLine); }); AddCommand("CloneUser", t_d(" "), t_d("Clones a user"), [=](const CString& sLine) { CloneUser(sLine); }); AddCommand("AddServer", t_d(" "), t_d("Adds a new IRC server for the given or current user"), [=](const CString& sLine) { AddServer(sLine); }); AddCommand("DelServer", t_d(" "), t_d("Deletes an IRC server from the given or current user"), [=](const CString& sLine) { DelServer(sLine); }); AddCommand("Reconnect", t_d(" "), t_d("Cycles the user's IRC server connection"), [=](const CString& sLine) { ReconnectUser(sLine); }); AddCommand("Disconnect", t_d(" "), t_d("Disconnects the user from their IRC server"), [=](const CString& sLine) { DisconnectUser(sLine); }); AddCommand("LoadModule", t_d(" [args]"), t_d("Loads a Module for a user"), [=](const CString& sLine) { LoadModuleForUser(sLine); }); AddCommand("UnLoadModule", t_d(" "), t_d("Removes a Module of a user"), [=](const CString& sLine) { UnLoadModuleForUser(sLine); }); AddCommand("ListMods", t_d(""), t_d("Get the list of modules for a user"), [=](const CString& sLine) { ListModulesForUser(sLine); }); AddCommand("LoadNetModule", t_d(" [args]"), t_d("Loads a Module for a network"), [=](const CString& sLine) { LoadModuleForNetwork(sLine); }); AddCommand( "UnLoadNetModule", t_d(" "), t_d("Removes a Module of a network"), [=](const CString& sLine) { UnLoadModuleForNetwork(sLine); }); AddCommand("ListNetMods", t_d(" "), t_d("Get the list of modules for a network"), [=](const CString& sLine) { ListModulesForNetwork(sLine); }); AddCommand("ListCTCPs", t_d(""), t_d("List the configured CTCP replies"), [=](const CString& sLine) { ListCTCP(sLine); }); AddCommand("AddCTCP", t_d(" [reply]"), t_d("Configure a new CTCP reply"), [=](const CString& sLine) { AddCTCP(sLine); }); AddCommand("DelCTCP", t_d(" "), t_d("Remove a CTCP reply"), [=](const CString& sLine) { DelCTCP(sLine); }); // Network commands AddCommand("AddNetwork", t_d("[username] "), t_d("Add a network for a user"), [=](const CString& sLine) { AddNetwork(sLine); }); AddCommand("DelNetwork", t_d("[username] "), t_d("Delete a network for a user"), [=](const CString& sLine) { DelNetwork(sLine); }); AddCommand("ListNetworks", t_d("[username]"), t_d("List all networks for a user"), [=](const CString& sLine) { ListNetworks(sLine); }); } ~CAdminMod() override {} }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("controlpanel"); } USERMODULEDEFS(CAdminMod, t_s("Dynamic configuration through IRC. Allows editing only " "yourself if you're not ZNC admin.")) znc-1.7.5/modules/watch.cpp0000644000175000017500000006374613542151610016042 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::list; using std::vector; using std::set; class CWatchSource { public: CWatchSource(const CString& sSource, bool bNegated) { m_sSource = sSource; m_bNegated = bNegated; } virtual ~CWatchSource() {} // Getters const CString& GetSource() const { return m_sSource; } bool IsNegated() const { return m_bNegated; } // !Getters // Setters // !Setters private: protected: bool m_bNegated; CString m_sSource; }; class CWatchEntry { public: CWatchEntry(const CString& sHostMask, const CString& sTarget, const CString& sPattern) { m_bDisabled = false; m_bDetachedClientOnly = false; m_bDetachedChannelOnly = false; m_sPattern = (sPattern.size()) ? sPattern : "*"; CNick Nick; Nick.Parse(sHostMask); m_sHostMask = (Nick.GetNick().size()) ? Nick.GetNick() : "*"; m_sHostMask += "!"; m_sHostMask += (Nick.GetIdent().size()) ? Nick.GetIdent() : "*"; m_sHostMask += "@"; m_sHostMask += (Nick.GetHost().size()) ? Nick.GetHost() : "*"; if (sTarget.size()) { m_sTarget = sTarget; } else { m_sTarget = "$"; m_sTarget += Nick.GetNick(); } } virtual ~CWatchEntry() {} bool IsMatch(const CNick& Nick, const CString& sText, const CString& sSource, const CIRCNetwork* pNetwork) { if (IsDisabled()) { return false; } bool bGoodSource = true; if (!sSource.empty() && !m_vsSources.empty()) { bGoodSource = false; for (unsigned int a = 0; a < m_vsSources.size(); a++) { const CWatchSource& WatchSource = m_vsSources[a]; if (sSource.WildCmp(WatchSource.GetSource(), CString::CaseInsensitive)) { if (WatchSource.IsNegated()) { return false; } else { bGoodSource = true; } } } } if (!bGoodSource) return false; if (!Nick.GetHostMask().WildCmp(m_sHostMask, CString::CaseInsensitive)) return false; return (sText.WildCmp(pNetwork->ExpandString(m_sPattern), CString::CaseInsensitive)); } bool operator==(const CWatchEntry& WatchEntry) { return (GetHostMask().Equals(WatchEntry.GetHostMask()) && GetTarget().Equals(WatchEntry.GetTarget()) && GetPattern().Equals(WatchEntry.GetPattern())); } // Getters const CString& GetHostMask() const { return m_sHostMask; } const CString& GetTarget() const { return m_sTarget; } const CString& GetPattern() const { return m_sPattern; } bool IsDisabled() const { return m_bDisabled; } bool IsDetachedClientOnly() const { return m_bDetachedClientOnly; } bool IsDetachedChannelOnly() const { return m_bDetachedChannelOnly; } const vector& GetSources() const { return m_vsSources; } CString GetSourcesStr() const { CString sRet; for (unsigned int a = 0; a < m_vsSources.size(); a++) { const CWatchSource& WatchSource = m_vsSources[a]; if (a) { sRet += " "; } if (WatchSource.IsNegated()) { sRet += "!"; } sRet += WatchSource.GetSource(); } return sRet; } // !Getters // Setters void SetHostMask(const CString& s) { m_sHostMask = s; } void SetTarget(const CString& s) { m_sTarget = s; } void SetPattern(const CString& s) { m_sPattern = s; } void SetDisabled(bool b = true) { m_bDisabled = b; } void SetDetachedClientOnly(bool b = true) { m_bDetachedClientOnly = b; } void SetDetachedChannelOnly(bool b = true) { m_bDetachedChannelOnly = b; } void SetSources(const CString& sSources) { VCString vsSources; VCString::iterator it; sSources.Split(" ", vsSources, false); m_vsSources.clear(); for (it = vsSources.begin(); it != vsSources.end(); ++it) { if (it->at(0) == '!' && it->size() > 1) { m_vsSources.push_back(CWatchSource(it->substr(1), true)); } else { m_vsSources.push_back(CWatchSource(*it, false)); } } } // !Setters private: protected: CString m_sHostMask; CString m_sTarget; CString m_sPattern; bool m_bDisabled; bool m_bDetachedClientOnly; bool m_bDetachedChannelOnly; vector m_vsSources; }; class CWatcherMod : public CModule { public: MODCONSTRUCTOR(CWatcherMod) { m_Buffer.SetLineCount(500); Load(); } ~CWatcherMod() override {} void OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) override { Process(OpNick, "* " + OpNick.GetNick() + " sets mode: " + sModes + " " + sArgs + " on " + Channel.GetName(), Channel.GetName()); } void OnClientLogin() override { MCString msParams; msParams["target"] = GetNetwork()->GetCurNick(); size_t uSize = m_Buffer.Size(); for (unsigned int uIdx = 0; uIdx < uSize; uIdx++) { PutUser(m_Buffer.GetLine(uIdx, *GetClient(), msParams)); } m_Buffer.Clear(); } void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) override { Process(OpNick, "* " + OpNick.GetNick() + " kicked " + sKickedNick + " from " + Channel.GetName() + " because [" + sMessage + "]", Channel.GetName()); } void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) override { Process(Nick, "* Quits: " + Nick.GetNick() + " (" + Nick.GetIdent() + "@" + Nick.GetHost() + ") " "(" + sMessage + ")", ""); } void OnJoin(const CNick& Nick, CChan& Channel) override { Process(Nick, "* " + Nick.GetNick() + " (" + Nick.GetIdent() + "@" + Nick.GetHost() + ") joins " + Channel.GetName(), Channel.GetName()); } void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) override { Process(Nick, "* " + Nick.GetNick() + " (" + Nick.GetIdent() + "@" + Nick.GetHost() + ") parts " + Channel.GetName() + "(" + sMessage + ")", Channel.GetName()); } void OnNick(const CNick& OldNick, const CString& sNewNick, const vector& vChans) override { Process(OldNick, "* " + OldNick.GetNick() + " is now known as " + sNewNick, ""); } EModRet OnCTCPReply(CNick& Nick, CString& sMessage) override { Process(Nick, "* CTCP: " + Nick.GetNick() + " reply [" + sMessage + "]", "priv"); return CONTINUE; } EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override { Process(Nick, "* CTCP: " + Nick.GetNick() + " [" + sMessage + "]", "priv"); return CONTINUE; } EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) override { Process(Nick, "* CTCP: " + Nick.GetNick() + " [" + sMessage + "] to " "[" + Channel.GetName() + "]", Channel.GetName()); return CONTINUE; } EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override { Process(Nick, "-" + Nick.GetNick() + "- " + sMessage, "priv"); return CONTINUE; } EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) override { Process(Nick, "-" + Nick.GetNick() + ":" + Channel.GetName() + "- " + sMessage, Channel.GetName()); return CONTINUE; } EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override { Process(Nick, "<" + Nick.GetNick() + "> " + sMessage, "priv"); return CONTINUE; } EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override { Process(Nick, "<" + Nick.GetNick() + ":" + Channel.GetName() + "> " + sMessage, Channel.GetName()); return CONTINUE; } void OnModCommand(const CString& sCommand) override { CString sCmdName = sCommand.Token(0); if (sCmdName.Equals("ADD") || sCmdName.Equals("WATCH")) { Watch(sCommand.Token(1), sCommand.Token(2), sCommand.Token(3, true)); } else if (sCmdName.Equals("HELP")) { Help(); } else if (sCmdName.Equals("LIST")) { List(); } else if (sCmdName.Equals("DUMP")) { Dump(); } else if (sCmdName.Equals("ENABLE")) { CString sTok = sCommand.Token(1); if (sTok == "*") { SetDisabled(~0, false); } else { SetDisabled(sTok.ToUInt(), false); } } else if (sCmdName.Equals("DISABLE")) { CString sTok = sCommand.Token(1); if (sTok == "*") { SetDisabled(~0, true); } else { SetDisabled(sTok.ToUInt(), true); } } else if (sCmdName.Equals("SETDETACHEDCLIENTONLY")) { CString sTok = sCommand.Token(1); bool bDetachedClientOnly = sCommand.Token(2).ToBool(); if (sTok == "*") { SetDetachedClientOnly(~0, bDetachedClientOnly); } else { SetDetachedClientOnly(sTok.ToUInt(), bDetachedClientOnly); } } else if (sCmdName.Equals("SETDETACHEDCHANNELONLY")) { CString sTok = sCommand.Token(1); bool bDetachedchannelOnly = sCommand.Token(2).ToBool(); if (sTok == "*") { SetDetachedChannelOnly(~0, bDetachedchannelOnly); } else { SetDetachedChannelOnly(sTok.ToUInt(), bDetachedchannelOnly); } } else if (sCmdName.Equals("SETSOURCES")) { SetSources(sCommand.Token(1).ToUInt(), sCommand.Token(2, true)); } else if (sCmdName.Equals("CLEAR")) { m_lsWatchers.clear(); PutModule(t_s("All entries cleared.")); Save(); } else if (sCmdName.Equals("BUFFER")) { CString sCount = sCommand.Token(1); if (sCount.size()) { m_Buffer.SetLineCount(sCount.ToUInt()); } PutModule( t_f("Buffer count is set to {1}")(m_Buffer.GetLineCount())); } else if (sCmdName.Equals("DEL")) { Remove(sCommand.Token(1).ToUInt()); } else { PutModule(t_f("Unknown command: {1}")(sCmdName)); } } private: void Process(const CNick& Nick, const CString& sMessage, const CString& sSource) { set sHandledTargets; CIRCNetwork* pNetwork = GetNetwork(); CChan* pChannel = pNetwork->FindChan(sSource); for (list::iterator it = m_lsWatchers.begin(); it != m_lsWatchers.end(); ++it) { CWatchEntry& WatchEntry = *it; if (pNetwork->IsUserAttached() && WatchEntry.IsDetachedClientOnly()) { continue; } if (pChannel && !pChannel->IsDetached() && WatchEntry.IsDetachedChannelOnly()) { continue; } if (WatchEntry.IsMatch(Nick, sMessage, sSource, pNetwork) && sHandledTargets.count(WatchEntry.GetTarget()) < 1) { if (pNetwork->IsUserAttached()) { pNetwork->PutUser(":" + WatchEntry.GetTarget() + "!watch@znc.in PRIVMSG " + pNetwork->GetCurNick() + " :" + sMessage); } else { m_Buffer.AddLine( ":" + _NAMEDFMT(WatchEntry.GetTarget()) + "!watch@znc.in PRIVMSG {target} :{text}", sMessage); } sHandledTargets.insert(WatchEntry.GetTarget()); } } } void SetDisabled(unsigned int uIdx, bool bDisabled) { if (uIdx == (unsigned int)~0) { for (list::iterator it = m_lsWatchers.begin(); it != m_lsWatchers.end(); ++it) { (*it).SetDisabled(bDisabled); } PutModule(bDisabled ? t_s("Disabled all entries.") : t_s("Enabled all entries.")); Save(); return; } uIdx--; // "convert" index to zero based if (uIdx >= m_lsWatchers.size()) { PutModule(t_s("Invalid Id")); return; } list::iterator it = m_lsWatchers.begin(); for (unsigned int a = 0; a < uIdx; a++) ++it; (*it).SetDisabled(bDisabled); if (bDisabled) PutModule(t_f("Id {1} disabled")(uIdx + 1)); else PutModule(t_f("Id {1} enabled")(uIdx + 1)); Save(); } void SetDetachedClientOnly(unsigned int uIdx, bool bDetachedClientOnly) { if (uIdx == (unsigned int)~0) { for (list::iterator it = m_lsWatchers.begin(); it != m_lsWatchers.end(); ++it) { (*it).SetDetachedClientOnly(bDetachedClientOnly); } if (bDetachedClientOnly) PutModule(t_s("Set DetachedClientOnly for all entries to Yes")); else PutModule(t_s("Set DetachedClientOnly for all entries to No")); Save(); return; } uIdx--; // "convert" index to zero based if (uIdx >= m_lsWatchers.size()) { PutModule(t_s("Invalid Id")); return; } list::iterator it = m_lsWatchers.begin(); for (unsigned int a = 0; a < uIdx; a++) ++it; (*it).SetDetachedClientOnly(bDetachedClientOnly); if (bDetachedClientOnly) PutModule(t_f("Id {1} set to Yes")(uIdx + 1)); else PutModule(t_f("Id {1} set to No")(uIdx + 1)); Save(); } void SetDetachedChannelOnly(unsigned int uIdx, bool bDetachedChannelOnly) { if (uIdx == (unsigned int)~0) { for (list::iterator it = m_lsWatchers.begin(); it != m_lsWatchers.end(); ++it) { (*it).SetDetachedChannelOnly(bDetachedChannelOnly); } if (bDetachedChannelOnly) PutModule( t_s("Set DetachedChannelOnly for all entries to Yes")); else PutModule(t_s("Set DetachedChannelOnly for all entries to No")); Save(); return; } uIdx--; // "convert" index to zero based if (uIdx >= m_lsWatchers.size()) { PutModule(t_s("Invalid Id")); return; } list::iterator it = m_lsWatchers.begin(); for (unsigned int a = 0; a < uIdx; a++) ++it; (*it).SetDetachedChannelOnly(bDetachedChannelOnly); if (bDetachedChannelOnly) PutModule(t_f("Id {1} set to Yes")(uIdx + 1)); else PutModule(t_f("Id {1} set to No")(uIdx + 1)); Save(); } void List() { CTable Table; Table.AddColumn(t_s("Id")); Table.AddColumn(t_s("HostMask")); Table.AddColumn(t_s("Target")); Table.AddColumn(t_s("Pattern")); Table.AddColumn(t_s("Sources")); Table.AddColumn(t_s("Off")); Table.AddColumn(t_s("DetachedClientOnly")); Table.AddColumn(t_s("DetachedChannelOnly")); unsigned int uIdx = 1; for (list::iterator it = m_lsWatchers.begin(); it != m_lsWatchers.end(); ++it, uIdx++) { CWatchEntry& WatchEntry = *it; Table.AddRow(); Table.SetCell(t_s("Id"), CString(uIdx)); Table.SetCell(t_s("HostMask"), WatchEntry.GetHostMask()); Table.SetCell(t_s("Target"), WatchEntry.GetTarget()); Table.SetCell(t_s("Pattern"), WatchEntry.GetPattern()); Table.SetCell(t_s("Sources"), WatchEntry.GetSourcesStr()); Table.SetCell(t_s("Off"), (WatchEntry.IsDisabled()) ? t_s("Off") : ""); Table.SetCell( t_s("DetachedClientOnly"), WatchEntry.IsDetachedClientOnly() ? t_s("Yes") : t_s("No")); Table.SetCell( t_s("DetachedChannelOnly"), WatchEntry.IsDetachedChannelOnly() ? t_s("Yes") : t_s("No")); } if (Table.size()) { PutModule(Table); } else { PutModule(t_s("You have no entries.")); } } void Dump() { if (m_lsWatchers.empty()) { PutModule(t_s("You have no entries.")); return; } PutModule("---------------"); PutModule("/msg " + GetModNick() + " CLEAR"); unsigned int uIdx = 1; for (list::iterator it = m_lsWatchers.begin(); it != m_lsWatchers.end(); ++it, uIdx++) { CWatchEntry& WatchEntry = *it; PutModule("/msg " + GetModNick() + " ADD " + WatchEntry.GetHostMask() + " " + WatchEntry.GetTarget() + " " + WatchEntry.GetPattern()); if (WatchEntry.GetSourcesStr().size()) { PutModule("/msg " + GetModNick() + " SETSOURCES " + CString(uIdx) + " " + WatchEntry.GetSourcesStr()); } if (WatchEntry.IsDisabled()) { PutModule("/msg " + GetModNick() + " DISABLE " + CString(uIdx)); } if (WatchEntry.IsDetachedClientOnly()) { PutModule("/msg " + GetModNick() + " SETDETACHEDCLIENTONLY " + CString(uIdx) + " TRUE"); } if (WatchEntry.IsDetachedChannelOnly()) { PutModule("/msg " + GetModNick() + " SETDETACHEDCHANNELONLY " + CString(uIdx) + " TRUE"); } } PutModule("---------------"); } void SetSources(unsigned int uIdx, const CString& sSources) { uIdx--; // "convert" index to zero based if (uIdx >= m_lsWatchers.size()) { PutModule(t_s("Invalid Id")); return; } list::iterator it = m_lsWatchers.begin(); for (unsigned int a = 0; a < uIdx; a++) ++it; (*it).SetSources(sSources); PutModule(t_f("Sources set for Id {1}.")(uIdx + 1)); Save(); } void Remove(unsigned int uIdx) { uIdx--; // "convert" index to zero based if (uIdx >= m_lsWatchers.size()) { PutModule(t_s("Invalid Id")); return; } list::iterator it = m_lsWatchers.begin(); for (unsigned int a = 0; a < uIdx; a++) ++it; m_lsWatchers.erase(it); PutModule(t_f("Id {1} removed.")(uIdx + 1)); Save(); } void Help() { CTable Table; Table.AddColumn(t_s("Command")); Table.AddColumn(t_s("Description")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Add [Target] [Pattern]")); Table.SetCell(t_s("Description"), t_s("Used to add an entry to watch for.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("List")); Table.SetCell(t_s("Description"), t_s("List all entries being watched.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Dump")); Table.SetCell( t_s("Description"), t_s("Dump a list of all current entries to be used later.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Del ")); Table.SetCell(t_s("Description"), t_s("Deletes Id from the list of watched entries.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Clear")); Table.SetCell(t_s("Description"), t_s("Delete all entries.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Enable ")); Table.SetCell(t_s("Description"), t_s("Enable a disabled entry.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Disable ")); Table.SetCell(t_s("Description"), t_s("Disable (but don't delete) an entry.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("SetDetachedClientOnly ")); Table.SetCell( t_s("Description"), t_s("Enable or disable detached client only for an entry.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("SetDetachedChannelOnly ")); Table.SetCell( t_s("Description"), t_s("Enable or disable detached channel only for an entry.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Buffer [Count]")); Table.SetCell( t_s("Description"), t_s("Show/Set the amount of buffered lines while detached.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("SetSources [#chan priv #foo* !#bar]")); Table.SetCell(t_s("Description"), t_s("Set the source channels that you care about.")); Table.AddRow(); Table.SetCell(t_s("Command"), t_s("Help")); Table.SetCell(t_s("Description"), t_s("This help.")); PutModule(Table); } void Watch(const CString& sHostMask, const CString& sTarget, const CString& sPattern, bool bNotice = false) { CString sMessage; if (sHostMask.size()) { CWatchEntry WatchEntry(sHostMask, sTarget, sPattern); bool bExists = false; for (list::iterator it = m_lsWatchers.begin(); it != m_lsWatchers.end(); ++it) { if (*it == WatchEntry) { sMessage = t_f("Entry for {1} already exists.")( WatchEntry.GetHostMask()); bExists = true; break; } } if (!bExists) { sMessage = t_f("Adding entry: {1} watching for [{2}] -> {3}")( WatchEntry.GetHostMask(), WatchEntry.GetPattern(), WatchEntry.GetTarget()); m_lsWatchers.push_back(WatchEntry); } } else { sMessage = t_s("Watch: Not enough arguments. Try Help"); } if (bNotice) { PutModNotice(sMessage); } else { PutModule(sMessage); } Save(); } void Save() { ClearNV(false); for (list::iterator it = m_lsWatchers.begin(); it != m_lsWatchers.end(); ++it) { CWatchEntry& WatchEntry = *it; CString sSave; sSave = WatchEntry.GetHostMask() + "\n"; sSave += WatchEntry.GetTarget() + "\n"; sSave += WatchEntry.GetPattern() + "\n"; sSave += (WatchEntry.IsDisabled() ? "disabled\n" : "enabled\n"); sSave += CString(WatchEntry.IsDetachedClientOnly()) + "\n"; sSave += CString(WatchEntry.IsDetachedChannelOnly()) + "\n"; sSave += WatchEntry.GetSourcesStr(); // Without this, loading fails if GetSourcesStr() // returns an empty string sSave += " "; SetNV(sSave, "", false); } SaveRegistry(); } void Load() { // Just to make sure we don't mess up badly m_lsWatchers.clear(); bool bWarn = false; for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { VCString vList; it->first.Split("\n", vList); // Backwards compatibility with the old save format if (vList.size() != 5 && vList.size() != 7) { bWarn = true; continue; } CWatchEntry WatchEntry(vList[0], vList[1], vList[2]); if (vList[3].Equals("disabled")) WatchEntry.SetDisabled(true); else WatchEntry.SetDisabled(false); // Backwards compatibility with the old save format if (vList.size() == 5) { WatchEntry.SetSources(vList[4]); } else { WatchEntry.SetDetachedClientOnly(vList[4].ToBool()); WatchEntry.SetDetachedChannelOnly(vList[5].ToBool()); WatchEntry.SetSources(vList[6]); } m_lsWatchers.push_back(WatchEntry); } if (bWarn) PutModule(t_s("WARNING: malformed entry found while loading")); } list m_lsWatchers; CBuffer m_Buffer; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("watch"); } NETWORKMODULEDEFS( CWatcherMod, t_s("Copy activity from a specific user into a separate window")) znc-1.7.5/modules/perleval.pm0000644000175000017500000000215013542151610016356 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # use strict; use warnings; package perleval; use base 'ZNC::Module'; sub description { shift->t_s('Evaluates perl code') } sub wiki_page { 'perleval' } sub OnLoad { my $self = shift; if (!$self->GetUser->IsAdmin) { $_[1] = $self->t_s('Only admin can load this module'); return 0 } return 1 } sub OnModCommand { my $self = shift; my $cmd = shift; my $x = eval $cmd; if ($@) { $self->PutModule($self->t_f('Error: %s')->($@)); } else { $self->PutModule($self->t_f('Result: %s')->($x)); } } 1 znc-1.7.5/modules/kickrejoin.cpp0000644000175000017500000001015613542151610017047 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * This was originally written by cycomate. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Autorejoin module * rejoin channel (after a delay) when kicked * Usage: LoadModule = rejoin [delay] * */ #include #include class CRejoinJob : public CTimer { public: CRejoinJob(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {} ~CRejoinJob() override {} protected: void RunJob() override { CIRCNetwork* pNetwork = GetModule()->GetNetwork(); CChan* pChan = pNetwork->FindChan(GetName().Token(1, true)); if (pChan) { pChan->Enable(); GetModule()->PutIRC("JOIN " + pChan->GetName() + " " + pChan->GetKey()); } } }; class CRejoinMod : public CModule { private: unsigned int delay = 10; public: MODCONSTRUCTOR(CRejoinMod) { AddHelpCommand(); AddCommand("SetDelay", t_d(""), t_d("Set the rejoin delay"), [=](const CString& sLine) { OnSetDelayCommand(sLine); }); AddCommand("ShowDelay", "", t_d("Show the rejoin delay"), [=](const CString& sLine) { OnShowDelayCommand(sLine); }); } ~CRejoinMod() override {} bool OnLoad(const CString& sArgs, CString& sErrorMsg) override { if (sArgs.empty()) { CString sDelay = GetNV("delay"); if (sDelay.empty()) delay = 10; else delay = sDelay.ToUInt(); } else { int i = sArgs.ToInt(); if ((i == 0 && sArgs == "0") || i > 0) delay = i; else { sErrorMsg = t_s("Illegal argument, must be a positive number or 0"); return false; } } return true; } void OnSetDelayCommand(const CString& sCommand) { int i; i = sCommand.Token(1).ToInt(); if (i < 0) { PutModule(t_s("Negative delays don't make any sense!")); return; } delay = i; SetNV("delay", CString(delay)); if (delay) PutModule(t_p("Rejoin delay set to 1 second", "Rejoin delay set to {1} seconds", delay)(delay)); else PutModule(t_s("Rejoin delay disabled")); } void OnShowDelayCommand(const CString& sCommand) { if (delay) PutModule(t_p("Rejoin delay is set to 1 second", "Rejoin delay is set to {1} seconds", delay)(delay)); else PutModule(t_s("Rejoin delay is disabled")); } void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& pChan, const CString& sMessage) override { if (GetNetwork()->GetCurNick().Equals(sKickedNick)) { if (!delay) { PutIRC("JOIN " + pChan.GetName() + " " + pChan.GetKey()); pChan.Enable(); return; } AddTimer(new CRejoinJob(this, delay, 1, "Rejoin " + pChan.GetName(), "Rejoin channel after a delay")); } } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("kickrejoin"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s( "You might enter the number of seconds to wait before rejoining.")); } NETWORKMODULEDEFS(CRejoinMod, t_s("Autorejoins on kick")) znc-1.7.5/modules/perform.cpp0000644000175000017500000001323313542151610016370 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include class CPerform : public CModule { void Add(const CString& sCommand) { CString sPerf = sCommand.Token(1, true); if (sPerf.empty()) { PutModule(t_s("Usage: add ")); return; } m_vPerform.push_back(ParsePerform(sPerf)); PutModule(t_s("Added!")); Save(); } void Del(const CString& sCommand) { u_int iNum = sCommand.Token(1, true).ToUInt(); if (iNum > m_vPerform.size() || iNum <= 0) { PutModule(t_s("Illegal # Requested")); return; } else { m_vPerform.erase(m_vPerform.begin() + iNum - 1); PutModule(t_s("Command Erased.")); } Save(); } void List(const CString& sCommand) { CTable Table; unsigned int index = 1; Table.AddColumn(t_s("Id", "list")); Table.AddColumn(t_s("Perform", "list")); Table.AddColumn(t_s("Expanded", "list")); for (const CString& sPerf : m_vPerform) { Table.AddRow(); Table.SetCell(t_s("Id", "list"), CString(index++)); Table.SetCell(t_s("Perform", "list"), sPerf); CString sExpanded = ExpandString(sPerf); if (sExpanded != sPerf) { Table.SetCell(t_s("Expanded", "list"), sExpanded); } } if (PutModule(Table) == 0) { PutModule(t_s("No commands in your perform list.")); } } void Execute(const CString& sCommand) { OnIRCConnected(); PutModule(t_s("perform commands sent")); } void Swap(const CString& sCommand) { u_int iNumA = sCommand.Token(1).ToUInt(); u_int iNumB = sCommand.Token(2).ToUInt(); if (iNumA > m_vPerform.size() || iNumA <= 0 || iNumB > m_vPerform.size() || iNumB <= 0) { PutModule(t_s("Illegal # Requested")); } else { std::iter_swap(m_vPerform.begin() + (iNumA - 1), m_vPerform.begin() + (iNumB - 1)); PutModule(t_s("Commands Swapped.")); Save(); } } public: MODCONSTRUCTOR(CPerform) { AddHelpCommand(); AddCommand( "Add", t_d(""), t_d("Adds perform command to be sent to the server on connect"), [=](const CString& sLine) { Add(sLine); }); AddCommand("Del", t_d(""), t_d("Delete a perform command"), [=](const CString& sLine) { Del(sLine); }); AddCommand("List", "", t_d("List the perform commands"), [=](const CString& sLine) { List(sLine); }); AddCommand("Execute", "", t_d("Send the perform commands to the server now"), [=](const CString& sLine) { Execute(sLine); }); AddCommand("Swap", t_d(" "), t_d("Swap two perform commands"), [=](const CString& sLine) { Swap(sLine); }); } ~CPerform() override {} CString ParsePerform(const CString& sArg) const { CString sPerf = sArg; if (sPerf.Left(1) == "/") sPerf.LeftChomp(); if (sPerf.Token(0).Equals("MSG")) { sPerf = "PRIVMSG " + sPerf.Token(1, true); } if ((sPerf.Token(0).Equals("PRIVMSG") || sPerf.Token(0).Equals("NOTICE")) && sPerf.Token(2).Left(1) != ":") { sPerf = sPerf.Token(0) + " " + sPerf.Token(1) + " :" + sPerf.Token(2, true); } return sPerf; } bool OnLoad(const CString& sArgs, CString& sMessage) override { GetNV("Perform").Split("\n", m_vPerform, false); return true; } void OnIRCConnected() override { for (const CString& sPerf : m_vPerform) { PutIRC(ExpandString(sPerf)); } } CString GetWebMenuTitle() override { return t_s("Perform"); } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName != "index") { // only accept requests to index return false; } if (WebSock.IsPost()) { VCString vsPerf; WebSock.GetRawParam("perform", true).Split("\n", vsPerf, false); m_vPerform.clear(); for (const CString& sPerf : vsPerf) m_vPerform.push_back(ParsePerform(sPerf)); Save(); } for (const CString& sPerf : m_vPerform) { CTemplate& Row = Tmpl.AddRow("PerformLoop"); Row["Perform"] = sPerf; } return true; } private: void Save() { CString sBuffer = ""; for (const CString& sPerf : m_vPerform) { sBuffer += sPerf + "\n"; } SetNV("Perform", sBuffer); } VCString m_vPerform; }; template <> void TModInfo(CModInfo& Info) { Info.AddType(CModInfo::UserModule); Info.SetWikiPage("perform"); } NETWORKMODULEDEFS( CPerform, t_s("Keeps a list of commands to be executed when ZNC connects to IRC.")) znc-1.7.5/modules/send_raw.cpp0000644000175000017500000001320213542151610016514 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::vector; using std::map; class CSendRaw_Mod : public CModule { void SendClient(const CString& sLine) { CUser* pUser = CZNC::Get().FindUser(sLine.Token(1)); if (pUser) { CIRCNetwork* pNetwork = pUser->FindNetwork(sLine.Token(2)); if (pNetwork) { pNetwork->PutUser(sLine.Token(3, true)); PutModule(t_f("Sent [{1}] to {2}/{3}")(sLine.Token(3, true), pUser->GetUserName(), pNetwork->GetName())); } else { PutModule(t_f("Network {1} not found for user {2}")( sLine.Token(2), sLine.Token(1))); } } else { PutModule(t_f("User {1} not found")(sLine.Token(1))); } } void SendServer(const CString& sLine) { CUser* pUser = CZNC::Get().FindUser(sLine.Token(1)); if (pUser) { CIRCNetwork* pNetwork = pUser->FindNetwork(sLine.Token(2)); if (pNetwork) { pNetwork->PutIRC(sLine.Token(3, true)); PutModule(t_f("Sent [{1}] to IRC server of {2}/{3}")( sLine.Token(3, true), pUser->GetUserName(), pNetwork->GetName())); } else { PutModule(t_f("Network {1} not found for user {2}")( sLine.Token(2), sLine.Token(1))); } } else { PutModule(t_f("User {1} not found")(sLine.Token(1))); } } void CurrentClient(const CString& sLine) { CString sData = sLine.Token(1, true); GetClient()->PutClient(sData); } public: ~CSendRaw_Mod() override {} bool OnLoad(const CString& sArgs, CString& sErrorMsg) override { if (!GetUser()->IsAdmin()) { sErrorMsg = t_s("You must have admin privileges to load this module"); return false; } return true; } CString GetWebMenuTitle() override { return t_s("Send Raw"); } bool WebRequiresAdmin() override { return true; } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "index") { if (WebSock.IsPost()) { CUser* pUser = CZNC::Get().FindUser( WebSock.GetParam("network").Token(0, false, "/")); if (!pUser) { WebSock.GetSession()->AddError(t_s("User not found")); return true; } CIRCNetwork* pNetwork = pUser->FindNetwork( WebSock.GetParam("network").Token(1, false, "/")); if (!pNetwork) { WebSock.GetSession()->AddError(t_s("Network not found")); return true; } bool bToServer = WebSock.GetParam("send_to") == "server"; const CString sLine = WebSock.GetParam("line"); Tmpl["user"] = pUser->GetUserName(); Tmpl[bToServer ? "to_server" : "to_client"] = "true"; Tmpl["line"] = sLine; if (bToServer) { pNetwork->PutIRC(sLine); } else { pNetwork->PutUser(sLine); } WebSock.GetSession()->AddSuccess(t_s("Line sent")); } const map& msUsers = CZNC::Get().GetUserMap(); for (const auto& it : msUsers) { CTemplate& l = Tmpl.AddRow("UserLoop"); l["Username"] = it.second->GetUserName(); vector vNetworks = it.second->GetNetworks(); for (const CIRCNetwork* pNetwork : vNetworks) { CTemplate& NetworkLoop = l.AddRow("NetworkLoop"); NetworkLoop["Username"] = it.second->GetUserName(); NetworkLoop["Network"] = pNetwork->GetName(); } } return true; } return false; } MODCONSTRUCTOR(CSendRaw_Mod) { AddHelpCommand(); AddCommand("Client", t_d("[user] [network] [data to send]"), t_d("The data will be sent to the user's IRC client(s)"), [=](const CString& sLine) { SendClient(sLine); }); AddCommand("Server", t_d("[user] [network] [data to send]"), t_d("The data will be sent to the IRC server the user is " "connected to"), [=](const CString& sLine) { SendServer(sLine); }); AddCommand("Current", t_d("[data to send]"), t_d("The data will be sent to your current client"), [=](const CString& sLine) { CurrentClient(sLine); }); } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("send_raw"); } USERMODULEDEFS(CSendRaw_Mod, t_s("Lets you send some raw IRC lines as/to someone else")) znc-1.7.5/modules/stripcontrols.cpp0000644000175000017500000000364113542151610017645 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include class CStripControlsMod : public CModule { public: MODCONSTRUCTOR(CStripControlsMod) {} EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override { sMessage.StripControls(); return CONTINUE; } EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) override { sMessage.StripControls(); return CONTINUE; } EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override { sMessage.StripControls(); return CONTINUE; } EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) override { sMessage.StripControls(); return CONTINUE; } EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override { sMessage.StripControls(); return CONTINUE; } EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override { sMessage.StripControls(); return CONTINUE; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("stripcontrols"); Info.AddType(CModInfo::UserModule); } NETWORKMODULEDEFS(CStripControlsMod, t_s("Strips control codes (Colors, Bold, ..) from channel " "and private messages.")) znc-1.7.5/modules/imapauth.cpp0000644000175000017500000001131513542151610016525 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include using std::map; class CIMAPAuthMod; class CIMAPSock : public CSocket { public: CIMAPSock(CIMAPAuthMod* pModule, std::shared_ptr Auth) : CSocket((CModule*)pModule), m_spAuth(Auth) { m_pIMAPMod = pModule; m_bSentReply = false; m_bSentLogin = false; EnableReadLine(); } ~CIMAPSock() override { if (!m_bSentReply) { m_spAuth->RefuseLogin( "IMAP server is down, please try again later"); } } void ReadLine(const CString& sLine) override; private: protected: CIMAPAuthMod* m_pIMAPMod; bool m_bSentLogin; bool m_bSentReply; std::shared_ptr m_spAuth; }; class CIMAPAuthMod : public CModule { public: MODCONSTRUCTOR(CIMAPAuthMod) { m_Cache.SetTTL(60000); m_sServer = "localhost"; m_uPort = 143; m_bSSL = false; } ~CIMAPAuthMod() override {} bool OnBoot() override { return true; } bool OnLoad(const CString& sArgs, CString& sMessage) override { if (sArgs.Trim_n().empty()) { return true; // use defaults } m_sServer = sArgs.Token(0); CString sPort = sArgs.Token(1); m_sUserFormat = sArgs.Token(2); if (sPort.Left(1) == "+") { m_bSSL = true; sPort.LeftChomp(); } unsigned short uPort = sPort.ToUShort(); if (uPort) { m_uPort = uPort; } return true; } EModRet OnLoginAttempt(std::shared_ptr Auth) override { CUser* pUser = CZNC::Get().FindUser(Auth->GetUsername()); if (!pUser) { // @todo Will want to do some sort of && !m_bAllowCreate in the // future Auth->RefuseLogin("Invalid User - Halting IMAP Lookup"); return HALT; } if (pUser && m_Cache.HasItem(CString(Auth->GetUsername() + ":" + Auth->GetPassword()).MD5())) { DEBUG("+++ Found in cache"); Auth->AcceptLogin(*pUser); return HALT; } CIMAPSock* pSock = new CIMAPSock(this, Auth); pSock->Connect(m_sServer, m_uPort, m_bSSL, 20); return HALT; } void OnModCommand(const CString& sLine) override {} void CacheLogin(const CString& sLogin) { m_Cache.AddItem(sLogin); } // Getters const CString& GetUserFormat() const { return m_sUserFormat; } // !Getters private: // Settings CString m_sServer; unsigned short m_uPort; bool m_bSSL; CString m_sUserFormat; // !Settings TCacheMap m_Cache; }; void CIMAPSock::ReadLine(const CString& sLine) { if (!m_bSentLogin) { CString sUsername = m_spAuth->GetUsername(); m_bSentLogin = true; const CString& sFormat = m_pIMAPMod->GetUserFormat(); if (!sFormat.empty()) { if (sFormat.find('%') != CString::npos) { sUsername = sFormat.Replace_n("%", sUsername); } else { sUsername += sFormat; } } Write("AUTH LOGIN " + sUsername + " " + m_spAuth->GetPassword() + "\r\n"); } else if (sLine.Left(5) == "AUTH ") { CUser* pUser = CZNC::Get().FindUser(m_spAuth->GetUsername()); if (pUser && sLine.StartsWith("AUTH OK")) { m_spAuth->AcceptLogin(*pUser); // Use MD5 so passes don't sit in memory in plain text m_pIMAPMod->CacheLogin(CString(m_spAuth->GetUsername() + ":" + m_spAuth->GetPassword()).MD5()); DEBUG("+++ Successful IMAP lookup"); } else { m_spAuth->RefuseLogin("Invalid Password"); DEBUG("--- FAILED IMAP lookup"); } m_bSentReply = true; Close(); } } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("imapauth"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s("[ server [+]port [ UserFormatString ] ]")); } GLOBALMODULEDEFS(CIMAPAuthMod, t_s("Allow users to authenticate via IMAP.")) znc-1.7.5/modules/crypt.cpp0000644000175000017500000004244513542151610016066 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //! @author prozac@rottenboy.com // // The encryption here was designed to be compatible with mircryption's CBC // mode. // // Latest tested against: // MircryptionSuite - Mircryption ver 1.19.01 (dll v1.15.01 , mirc v7.32) CBC // loaded and ready. // // TODO: // // 1) Encrypt key storage file // 2) Some way of notifying the user that the current channel is in "encryption // mode" verses plain text // 3) Temporarily disable a target (nick/chan) // // NOTE: This module is currently NOT intended to secure you from your shell // admin. // The keys are currently stored in plain text, so anyone with access to // your account (or root) can obtain them. // It is strongly suggested that you enable SSL between ZNC and your // client otherwise the encryption stops at ZNC and gets sent to your // client in plain text. // #include #include #include #include #include #include #define REQUIRESSL 1 // To be removed in future versions #define NICK_PREFIX_OLD_KEY "[nick-prefix]" #define NICK_PREFIX_KEY "@nick-prefix@" class CCryptMod : public CModule { private: /* * As used in other implementations like KVIrc, fish10, Quassel, FiSH-irssi, * ... all the way back to the original located at * http://mircryption.sourceforge.net/Extras/McpsFishDH.zip */ static constexpr const char* m_sPrime1080 = "FBE1022E23D213E8ACFA9AE8B9DFADA3EA6B7AC7A7B7E95AB5EB2DF858921FEADE95E6" "AC7BE7DE6ADBAB8A783E7AF7A7FA6A2B7BEB1E72EAE2B72F9FA2BFB2A2EFBEFAC868BA" "DB3E828FA8BADFADA3E4CC1BE7E8AFE85E9698A783EB68FA07A77AB6AD7BEB618ACF9C" "A2897EB28A6189EFA07AB99A8A7FA9AE299EFA7BA66DEAFEFBEFBF0B7D8B"; /* Generate our keys once and reuse, just like ssh keys */ std::unique_ptr m_pDH; CString m_sPrivKey; CString m_sPubKey; #if OPENSSL_VERSION_NUMBER < 0X10100000L || defined(LIBRESSL_VERSION_NUMBER) static int DH_set0_pqg(DH* dh, BIGNUM* p, BIGNUM* q, BIGNUM* g) { /* If the fields p and g in dh are nullptr, the corresponding input * parameters MUST be non-nullptr. q may remain nullptr. */ if (dh == nullptr || (dh->p == nullptr && p == nullptr) || (dh->g == nullptr && g == nullptr)) return 0; if (p != nullptr) { BN_free(dh->p); dh->p = p; } if (g != nullptr) { BN_free(dh->g); dh->g = g; } if (q != nullptr) { BN_free(dh->q); dh->q = q; dh->length = BN_num_bits(q); } return 1; } static void DH_get0_key(const DH* dh, const BIGNUM** pub_key, const BIGNUM** priv_key) { if (dh != nullptr) { if (pub_key != nullptr) *pub_key = dh->pub_key; if (priv_key != nullptr) *priv_key = dh->priv_key; } } #endif bool DH1080_gen() { /* Generate our keys on first call */ if (m_sPrivKey.empty() || m_sPubKey.empty()) { int len; const BIGNUM* bPrivKey = nullptr; const BIGNUM* bPubKey = nullptr; BIGNUM* bPrime = nullptr; BIGNUM* bGen = nullptr; if (!BN_hex2bn(&bPrime, m_sPrime1080) || !BN_dec2bn(&bGen, "2") || !DH_set0_pqg(m_pDH.get(), bPrime, nullptr, bGen) || !DH_generate_key(m_pDH.get())) { /* one of them failed */ if (bPrime != nullptr) BN_clear_free(bPrime); if (bGen != nullptr) BN_clear_free(bGen); return false; } /* Get our keys */ DH_get0_key(m_pDH.get(), &bPubKey, &bPrivKey); /* Get our private key */ len = BN_num_bytes(bPrivKey); m_sPrivKey.resize(len); BN_bn2bin(bPrivKey, (unsigned char*)m_sPrivKey.data()); m_sPrivKey.Base64Encode(); /* Get our public key */ len = BN_num_bytes(bPubKey); m_sPubKey.resize(len); BN_bn2bin(bPubKey, (unsigned char*)m_sPubKey.data()); m_sPubKey.Base64Encode(); } return true; } bool DH1080_comp(CString& sOtherPubKey, CString& sSecretKey) { long len; unsigned char* key = nullptr; BIGNUM* bOtherPubKey = nullptr; /* Prepare other public key */ len = sOtherPubKey.Base64Decode(); bOtherPubKey = BN_bin2bn((unsigned char*)sOtherPubKey.data(), len, nullptr); /* Generate secret key */ key = (unsigned char*)calloc(DH_size(m_pDH.get()), 1); if ((len = DH_compute_key(key, bOtherPubKey, m_pDH.get())) == -1) { sSecretKey = ""; if (bOtherPubKey != nullptr) BN_clear_free(bOtherPubKey); if (key != nullptr) free(key); return false; } /* Get our secret key */ sSecretKey.resize(SHA256_DIGEST_SIZE); sha256(key, len, (unsigned char*)sSecretKey.data()); sSecretKey.Base64Encode(); sSecretKey.TrimRight("="); if (bOtherPubKey != nullptr) BN_clear_free(bOtherPubKey); if (key != nullptr) free(key); return true; } CString NickPrefix() { MCString::iterator it = FindNV(NICK_PREFIX_KEY); /* * Check for different Prefixes to not confuse modules with nicknames * Also check for overlap for rare cases like: * SP = "*"; NP = "*s"; "tatus" sends an encrypted message appearing at * "*status" */ CString sStatusPrefix = GetUser()->GetStatusPrefix(); if (it != EndNV()) { size_t sp = sStatusPrefix.size(); size_t np = it->second.size(); int min = std::min(sp, np); if (min == 0 || sStatusPrefix.CaseCmp(it->second, min) != 0) return it->second; } return sStatusPrefix.StartsWith("*") ? "." : "*"; } public: /* MODCONSTRUCTOR(CLASS) is of form "CLASS(...) : CModule(...)" */ MODCONSTRUCTOR(CCryptMod), m_pDH(DH_new(), DH_free) { AddHelpCommand(); AddCommand("DelKey", t_d("<#chan|Nick>"), t_d("Remove a key for nick or channel"), [=](const CString& sLine) { OnDelKeyCommand(sLine); }); AddCommand("SetKey", t_d("<#chan|Nick> "), t_d("Set a key for nick or channel"), [=](const CString& sLine) { OnSetKeyCommand(sLine); }); AddCommand("ListKeys", "", t_d("List all keys"), [=](const CString& sLine) { OnListKeysCommand(sLine); }); AddCommand("KeyX", t_d(""), t_d("Start a DH1080 key exchange with nick"), [=](const CString& sLine) { OnKeyXCommand(sLine); }); AddCommand( "GetNickPrefix", "", t_d("Get the nick prefix"), [=](const CString& sLine) { OnGetNickPrefixCommand(sLine); }); AddCommand( "SetNickPrefix", t_d("[Prefix]"), t_d("Set the nick prefix, with no argument it's disabled."), [=](const CString& sLine) { OnSetNickPrefixCommand(sLine); }); } bool OnLoad(const CString& sArgsi, CString& sMessage) override { MCString::iterator it = FindNV(NICK_PREFIX_KEY); if (it == EndNV()) { /* Don't have the new prefix key yet */ it = FindNV(NICK_PREFIX_OLD_KEY); if (it != EndNV()) { SetNV(NICK_PREFIX_KEY, it->second); DelNV(NICK_PREFIX_OLD_KEY); } } return true; } EModRet OnUserTextMessage(CTextMessage& Message) override { FilterOutgoing(Message); return CONTINUE; } EModRet OnUserNoticeMessage(CNoticeMessage& Message) override { FilterOutgoing(Message); return CONTINUE; } EModRet OnUserActionMessage(CActionMessage& Message) override { FilterOutgoing(Message); return CONTINUE; } EModRet OnUserTopicMessage(CTopicMessage& Message) override { FilterOutgoing(Message); return CONTINUE; } EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override { FilterIncoming(Nick.GetNick(), Nick, sMessage); return CONTINUE; } EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override { CString sCommand = sMessage.Token(0); CString sOtherPubKey = sMessage.Token(1); if ((sCommand.Equals("DH1080_INIT") || sCommand.Equals("DH1080_INIT_CBC")) && !sOtherPubKey.empty()) { CString sSecretKey; CString sTail = sMessage.Token(2); /* For fish10 */ /* remove trailing A */ if (sOtherPubKey.TrimSuffix("A") && DH1080_gen() && DH1080_comp(sOtherPubKey, sSecretKey)) { PutModule( t_f("Received DH1080 public key from {1}, sending mine...")( Nick.GetNick())); PutIRC("NOTICE " + Nick.GetNick() + " :DH1080_FINISH " + m_sPubKey + "A" + (sTail.empty() ? "" : (" " + sTail))); SetNV(Nick.GetNick().AsLower(), sSecretKey); PutModule(t_f("Key for {1} successfully set.")(Nick.GetNick())); return HALT; } PutModule(t_f("Error in {1} with {2}: {3}")( sCommand, Nick.GetNick(), (sSecretKey.empty() ? t_s("no secret key computed") : sSecretKey))); return CONTINUE; } else if (sCommand.Equals("DH1080_FINISH") && !sOtherPubKey.empty()) { /* * In theory we could get a DH1080_FINISH without us having sent a * DH1080_INIT first, but then to have any use for the other user, * they'd already have our pub key */ CString sSecretKey; /* remove trailing A */ if (sOtherPubKey.TrimSuffix("A") && DH1080_gen() && DH1080_comp(sOtherPubKey, sSecretKey)) { SetNV(Nick.GetNick().AsLower(), sSecretKey); PutModule(t_f("Key for {1} successfully set.")(Nick.GetNick())); return HALT; } PutModule(t_f("Error in {1} with {2}: {3}")( sCommand, Nick.GetNick(), (sSecretKey.empty() ? t_s("no secret key computed") : sSecretKey))); return CONTINUE; } FilterIncoming(Nick.GetNick(), Nick, sMessage); return CONTINUE; } EModRet OnPrivAction(CNick& Nick, CString& sMessage) override { FilterIncoming(Nick.GetNick(), Nick, sMessage); return CONTINUE; } EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override { FilterIncoming(Channel.GetName(), Nick, sMessage); return CONTINUE; } EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) override { FilterIncoming(Channel.GetName(), Nick, sMessage); return CONTINUE; } EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) override { FilterIncoming(Channel.GetName(), Nick, sMessage); return CONTINUE; } EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sMessage) override { FilterIncoming(Channel.GetName(), Nick, sMessage); return CONTINUE; } EModRet OnNumericMessage(CNumericMessage& Message) override { if (Message.GetCode() != 332) { return CONTINUE; } CChan* pChan = GetNetwork()->FindChan(Message.GetParam(1)); if (pChan) { CNick* Nick = pChan->FindNick(Message.GetParam(0)); CString sTopic = Message.GetParam(2); FilterIncoming(pChan->GetName(), *Nick, sTopic); Message.SetParam(2, sTopic); } return CONTINUE; } template void FilterOutgoing(T& Msg) { CString sTarget = Msg.GetTarget(); sTarget.TrimPrefix(NickPrefix()); Msg.SetTarget(sTarget); CString sMessage = Msg.GetText(); if (sMessage.TrimPrefix("``")) { return; } MCString::iterator it = FindNV(sTarget.AsLower()); if (it != EndNV()) { sMessage = MakeIvec() + sMessage; sMessage.Encrypt(it->second); sMessage.Base64Encode(); Msg.SetText("+OK *" + sMessage); } } void FilterIncoming(const CString& sTarget, CNick& Nick, CString& sMessage) { if (sMessage.TrimPrefix("+OK *")) { MCString::iterator it = FindNV(sTarget.AsLower()); if (it != EndNV()) { sMessage.Base64Decode(); sMessage.Decrypt(it->second); sMessage.LeftChomp(8); sMessage = sMessage.c_str(); Nick.SetNick(NickPrefix() + Nick.GetNick()); } } } void OnDelKeyCommand(const CString& sCommand) { CString sTarget = sCommand.Token(1); if (!sTarget.empty()) { if (DelNV(sTarget.AsLower())) { PutModule(t_f("Target [{1}] deleted")(sTarget)); } else { PutModule(t_f("Target [{1}] not found")(sTarget)); } } else { PutModule(t_s("Usage DelKey <#chan|Nick>")); } } void OnSetKeyCommand(const CString& sCommand) { CString sTarget = sCommand.Token(1); CString sKey = sCommand.Token(2, true); // Strip "cbc:" from beginning of string incase someone pastes directly // from mircryption sKey.TrimPrefix("cbc:"); if (!sKey.empty()) { SetNV(sTarget.AsLower(), sKey); PutModule( t_f("Set encryption key for [{1}] to [{2}]")(sTarget, sKey)); } else { PutModule(t_s("Usage: SetKey <#chan|Nick> ")); } } void OnKeyXCommand(const CString& sCommand) { CString sTarget = sCommand.Token(1); if (!sTarget.empty()) { if (DH1080_gen()) { PutIRC("NOTICE " + sTarget + " :DH1080_INIT " + m_sPubKey + "A"); PutModule(t_f("Sent my DH1080 public key to {1}, waiting for reply ...")(sTarget)); } else { PutModule(t_s("Error generating our keys, nothing sent.")); } } else { PutModule(t_s("Usage: KeyX ")); } } void OnGetNickPrefixCommand(const CString& sCommand) { CString sPrefix = NickPrefix(); if (sPrefix.empty()) { PutModule(t_s("Nick Prefix disabled.")); } else { PutModule(t_f("Nick Prefix: {1}")(sPrefix)); } } void OnSetNickPrefixCommand(const CString& sCommand) { CString sPrefix = sCommand.Token(1); if (sPrefix.StartsWith(":")) { PutModule( t_s("You cannot use :, even followed by other symbols, as Nick " "Prefix.")); } else { CString sStatusPrefix = GetUser()->GetStatusPrefix(); size_t sp = sStatusPrefix.size(); size_t np = sPrefix.size(); int min = std::min(sp, np); if (min > 0 && sStatusPrefix.CaseCmp(sPrefix, min) == 0) PutModule( t_f("Overlap with Status Prefix ({1}), this Nick Prefix " "will not be used!")(sStatusPrefix)); else { SetNV(NICK_PREFIX_KEY, sPrefix); if (sPrefix.empty()) PutModule(t_s("Disabling Nick Prefix.")); else PutModule(t_f("Setting Nick Prefix to {1}")(sPrefix)); } } } void OnListKeysCommand(const CString& sCommand) { CTable Table; Table.AddColumn(t_s("Target", "listkeys")); Table.AddColumn(t_s("Key", "listkeys")); for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { if (!it->first.Equals(NICK_PREFIX_KEY)) { Table.AddRow(); Table.SetCell(t_s("Target", "listkeys"), it->first); Table.SetCell(t_s("Key", "listkeys"), it->second); } } if (Table.empty()) PutModule(t_s("You have no encryption keys set.")); else PutModule(Table); } CString MakeIvec() { CString sRet; time_t t; time(&t); int r = rand(); sRet.append((char*)&t, 4); sRet.append((char*)&r, 4); return sRet; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("crypt"); } NETWORKMODULEDEFS(CCryptMod, t_s("Encryption for channel/private messages")) znc-1.7.5/modules/modpython.cpp0000644000175000017500000004142213542151610016740 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include "modpython/swigpyrun.h" #include "modpython/module.h" #include "modpython/ret.h" using std::vector; using std::set; class CModPython : public CModule { PyObject* m_PyZNCModule; PyObject* m_PyFormatException; vector m_vpObject; public: CString GetPyExceptionStr() { PyObject* ptype; PyObject* pvalue; PyObject* ptraceback; PyErr_Fetch(&ptype, &pvalue, &ptraceback); CString result; if (!pvalue) { Py_INCREF(Py_None); pvalue = Py_None; } if (!ptraceback) { Py_INCREF(Py_None); ptraceback = Py_None; } PyErr_NormalizeException(&ptype, &pvalue, &ptraceback); PyObject* strlist = PyObject_CallFunctionObjArgs( m_PyFormatException, ptype, pvalue, ptraceback, nullptr); Py_CLEAR(ptype); Py_CLEAR(pvalue); Py_CLEAR(ptraceback); if (!strlist) { return "Couldn't get exact error message"; } if (PySequence_Check(strlist)) { PyObject* strlist_fast = PySequence_Fast(strlist, "Shouldn't happen (1)"); PyObject** items = PySequence_Fast_ITEMS(strlist_fast); Py_ssize_t L = PySequence_Fast_GET_SIZE(strlist_fast); for (Py_ssize_t i = 0; i < L; ++i) { PyObject* utf8 = PyUnicode_AsUTF8String(items[i]); result += PyBytes_AsString(utf8); Py_CLEAR(utf8); } Py_CLEAR(strlist_fast); } else { result = "Can't get exact error message"; } Py_CLEAR(strlist); return result; } MODCONSTRUCTOR(CModPython) { CZNC::Get().ForceEncoding(); Py_Initialize(); m_PyFormatException = nullptr; m_PyZNCModule = nullptr; } bool OnLoad(const CString& sArgsi, CString& sMessage) override { CString sModPath, sTmp; #ifdef __CYGWIN__ CString sDllPath = "modpython/_znc_core.dll"; #else CString sDllPath = "modpython/_znc_core.so"; #endif if (!CModules::FindModPath(sDllPath, sModPath, sTmp)) { sMessage = sDllPath + " not found."; return false; } sTmp = CDir::ChangeDir(sModPath, ".."); PyObject* pyModuleTraceback = PyImport_ImportModule("traceback"); if (!pyModuleTraceback) { sMessage = "Couldn't import python module traceback"; return false; } m_PyFormatException = PyObject_GetAttrString(pyModuleTraceback, "format_exception"); if (!m_PyFormatException) { sMessage = "Couldn't get traceback.format_exception"; Py_CLEAR(pyModuleTraceback); return false; } Py_CLEAR(pyModuleTraceback); PyObject* pySysModule = PyImport_ImportModule("sys"); if (!pySysModule) { sMessage = GetPyExceptionStr(); return false; } PyObject* pySysPath = PyObject_GetAttrString(pySysModule, "path"); if (!pySysPath) { sMessage = GetPyExceptionStr(); Py_CLEAR(pySysModule); return false; } Py_CLEAR(pySysModule); PyObject* pyIgnored = PyObject_CallMethod(pySysPath, const_cast("append"), const_cast("s"), sTmp.c_str()); if (!pyIgnored) { sMessage = GetPyExceptionStr(); Py_CLEAR(pyIgnored); return false; } Py_CLEAR(pyIgnored); Py_CLEAR(pySysPath); m_PyZNCModule = PyImport_ImportModule("znc"); if (!m_PyZNCModule) { sMessage = GetPyExceptionStr(); return false; } return true; } EModRet OnModuleLoading(const CString& sModName, const CString& sArgs, CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) override { PyObject* pyFunc = PyObject_GetAttrString(m_PyZNCModule, "load_module"); if (!pyFunc) { sRetMsg = GetPyExceptionStr(); DEBUG("modpython: " << sRetMsg); bSuccess = false; return HALT; } PyObject* pyRes = PyObject_CallFunction( pyFunc, const_cast("ssiNNNN"), sModName.c_str(), sArgs.c_str(), (int)eType, (eType == CModInfo::GlobalModule ? Py_None : SWIG_NewInstanceObj(GetUser(), SWIG_TypeQuery("CUser*"), 0)), (eType == CModInfo::NetworkModule ? SWIG_NewInstanceObj(GetNetwork(), SWIG_TypeQuery("CIRCNetwork*"), 0) : Py_None), CPyRetString::wrap(sRetMsg), SWIG_NewInstanceObj(reinterpret_cast(this), SWIG_TypeQuery("CModPython*"), 0)); if (!pyRes) { sRetMsg = GetPyExceptionStr(); DEBUG("modpython: " << sRetMsg); bSuccess = false; Py_CLEAR(pyFunc); return HALT; } Py_CLEAR(pyFunc); long int ret = PyLong_AsLong(pyRes); if (PyErr_Occurred()) { sRetMsg = GetPyExceptionStr(); DEBUG("modpython: " << sRetMsg); Py_CLEAR(pyRes); return HALT; } Py_CLEAR(pyRes); switch (ret) { case 0: // Not found return CONTINUE; case 1: // Error bSuccess = false; return HALT; case 2: // Success bSuccess = true; return HALT; } bSuccess = false; sRetMsg += " unknown value returned by modpython.load_module"; return HALT; } EModRet OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) override { CPyModule* pMod = AsPyModule(pModule); if (pMod) { CString sModName = pMod->GetModName(); PyObject* pyFunc = PyObject_GetAttrString(m_PyZNCModule, "unload_module"); if (!pyFunc) { sRetMsg = GetPyExceptionStr(); DEBUG("modpython: " << sRetMsg); bSuccess = false; return HALT; } PyObject* pyRes = PyObject_CallFunctionObjArgs(pyFunc, pMod->GetPyObj(), nullptr); if (!pyRes) { sRetMsg = GetPyExceptionStr(); DEBUG("modpython: " << sRetMsg); bSuccess = false; Py_CLEAR(pyFunc); return HALT; } if (!PyObject_IsTrue(pyRes)) { // python module, but not handled by modpython itself. // some module-provider written on python loaded it? return CONTINUE; } Py_CLEAR(pyFunc); Py_CLEAR(pyRes); bSuccess = true; sRetMsg = "Module [" + sModName + "] unloaded"; return HALT; } return CONTINUE; } EModRet OnGetModInfo(CModInfo& ModInfo, const CString& sModule, bool& bSuccess, CString& sRetMsg) override { PyObject* pyFunc = PyObject_GetAttrString(m_PyZNCModule, "get_mod_info"); if (!pyFunc) { sRetMsg = GetPyExceptionStr(); DEBUG("modpython: " << sRetMsg); bSuccess = false; return HALT; } PyObject* pyRes = PyObject_CallFunction( pyFunc, const_cast("sNN"), sModule.c_str(), CPyRetString::wrap(sRetMsg), SWIG_NewInstanceObj(&ModInfo, SWIG_TypeQuery("CModInfo*"), 0)); if (!pyRes) { sRetMsg = GetPyExceptionStr(); DEBUG("modpython: " << sRetMsg); bSuccess = false; Py_CLEAR(pyFunc); return HALT; } Py_CLEAR(pyFunc); long int x = PyLong_AsLong(pyRes); if (PyErr_Occurred()) { sRetMsg = GetPyExceptionStr(); DEBUG("modpython: " << sRetMsg); bSuccess = false; Py_CLEAR(pyRes); return HALT; } Py_CLEAR(pyRes); switch (x) { case 0: return CONTINUE; case 1: bSuccess = false; return HALT; case 2: bSuccess = true; return HALT; } bSuccess = false; sRetMsg = CString("Shouldn't happen. ") + __PRETTY_FUNCTION__ + " on " + __FILE__ + ":" + CString(__LINE__); DEBUG(sRetMsg); return HALT; } void TryAddModInfo(const CString& sPath, const CString& sName, set& ssMods, set& ssAlready, CModInfo::EModuleType eType) { if (ssAlready.count(sName)) { return; } PyObject* pyFunc = PyObject_GetAttrString(m_PyZNCModule, "get_mod_info_path"); if (!pyFunc) { CString sRetMsg = GetPyExceptionStr(); DEBUG("modpython tried to get info about [" << sPath << "] (1) but: " << sRetMsg); return; } CModInfo ModInfo; PyObject* pyRes = PyObject_CallFunction( pyFunc, const_cast("ssN"), sPath.c_str(), sName.c_str(), SWIG_NewInstanceObj(&ModInfo, SWIG_TypeQuery("CModInfo*"), 0)); if (!pyRes) { CString sRetMsg = GetPyExceptionStr(); DEBUG("modpython tried to get info about [" << sPath << "] (2) but: " << sRetMsg); Py_CLEAR(pyFunc); return; } Py_CLEAR(pyFunc); long int x = PyLong_AsLong(pyRes); if (PyErr_Occurred()) { CString sRetMsg = GetPyExceptionStr(); DEBUG("modpython tried to get info about [" << sPath << "] (3) but: " << sRetMsg); Py_CLEAR(pyRes); return; } Py_CLEAR(pyRes); if (x && ModInfo.SupportsType(eType)) { ssMods.insert(ModInfo); ssAlready.insert(sName); } } void OnGetAvailableMods(set& ssMods, CModInfo::EModuleType eType) override { CDir Dir; CModules::ModDirList dirs = CModules::GetModDirs(); while (!dirs.empty()) { set already; Dir.Fill(dirs.front().first); for (unsigned int a = 0; a < Dir.size(); a++) { CFile& File = *Dir[a]; CString sName = File.GetShortName(); CString sPath = File.GetLongName(); sPath.TrimSuffix(sName); if (!File.IsDir()) { if (sName.WildCmp("*.pyc")) { sName.RightChomp(4); } else if (sName.WildCmp("*.py") || sName.WildCmp("*.so")) { sName.RightChomp(3); } else { continue; } } TryAddModInfo(sPath, sName, ssMods, already, eType); } dirs.pop(); } } ~CModPython() override { if (!m_PyZNCModule) { DEBUG( "~CModPython(): seems like CModPython::OnLoad() didn't " "initialize python"); return; } PyObject* pyFunc = PyObject_GetAttrString(m_PyZNCModule, "unload_all"); if (!pyFunc) { CString sRetMsg = GetPyExceptionStr(); DEBUG("~CModPython(): couldn't find unload_all: " << sRetMsg); return; } PyObject* pyRes = PyObject_CallFunctionObjArgs(pyFunc, nullptr); if (!pyRes) { CString sRetMsg = GetPyExceptionStr(); DEBUG( "modpython tried to unload all modules in its destructor, but: " << sRetMsg); } Py_CLEAR(pyRes); Py_CLEAR(pyFunc); Py_CLEAR(m_PyFormatException); Py_CLEAR(m_PyZNCModule); Py_Finalize(); CZNC::Get().UnforceEncoding(); } }; CString CPyModule::GetPyExceptionStr() { return m_pModPython->GetPyExceptionStr(); } #include "modpython/pyfunctions.cpp" VWebSubPages& CPyModule::GetSubPages() { VWebSubPages* result = _GetSubPages(); if (!result) { return CModule::GetSubPages(); } return *result; } void CPyTimer::RunJob() { CPyModule* pMod = AsPyModule(GetModule()); if (pMod) { PyObject* pyRes = PyObject_CallMethod( m_pyObj, const_cast("RunJob"), const_cast("")); if (!pyRes) { CString sRetMsg = m_pModPython->GetPyExceptionStr(); DEBUG("python timer failed: " << sRetMsg); Stop(); } Py_CLEAR(pyRes); } } CPyTimer::~CPyTimer() { CPyModule* pMod = AsPyModule(GetModule()); if (pMod) { PyObject* pyRes = PyObject_CallMethod( m_pyObj, const_cast("OnShutdown"), const_cast("")); if (!pyRes) { CString sRetMsg = m_pModPython->GetPyExceptionStr(); DEBUG("python timer shutdown failed: " << sRetMsg); } Py_CLEAR(pyRes); Py_CLEAR(m_pyObj); } } #define CHECKCLEARSOCK(Func) \ if (!pyRes) { \ CString sRetMsg = m_pModPython->GetPyExceptionStr(); \ DEBUG("python socket failed in " Func ": " << sRetMsg); \ Close(); \ } \ Py_CLEAR(pyRes) #define CBSOCK(Func) \ void CPySocket::Func() { \ PyObject* pyRes = PyObject_CallMethod( \ m_pyObj, const_cast("On" #Func), const_cast("")); \ CHECKCLEARSOCK(#Func); \ } CBSOCK(Connected); CBSOCK(Disconnected); CBSOCK(Timeout); CBSOCK(ConnectionRefused); void CPySocket::ReadData(const char* data, size_t len) { PyObject* pyRes = PyObject_CallMethod(m_pyObj, const_cast("OnReadData"), const_cast("y#"), data, (int)len); CHECKCLEARSOCK("OnReadData"); } void CPySocket::ReadLine(const CString& sLine) { PyObject* pyRes = PyObject_CallMethod(m_pyObj, const_cast("OnReadLine"), const_cast("s"), sLine.c_str()); CHECKCLEARSOCK("OnReadLine"); } Csock* CPySocket::GetSockObj(const CString& sHost, unsigned short uPort) { CPySocket* result = nullptr; PyObject* pyRes = PyObject_CallMethod(m_pyObj, const_cast("_Accepted"), const_cast("sH"), sHost.c_str(), uPort); if (!pyRes) { CString sRetMsg = m_pModPython->GetPyExceptionStr(); DEBUG("python socket failed in OnAccepted: " << sRetMsg); Close(); } int res = SWIG_ConvertPtr(pyRes, (void**)&result, SWIG_TypeQuery("CPySocket*"), 0); if (!SWIG_IsOK(res)) { DEBUG( "python socket was expected to return new socket from OnAccepted, " "but error=" << res); Close(); result = nullptr; } if (!result) { DEBUG("modpython: OnAccepted didn't return new socket"); } Py_CLEAR(pyRes); return result; } CPySocket::~CPySocket() { PyObject* pyRes = PyObject_CallMethod( m_pyObj, const_cast("OnShutdown"), const_cast("")); if (!pyRes) { CString sRetMsg = m_pModPython->GetPyExceptionStr(); DEBUG("python socket failed in OnShutdown: " << sRetMsg); } Py_CLEAR(pyRes); Py_CLEAR(m_pyObj); } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("modpython"); } GLOBALMODULEDEFS(CModPython, t_s("Loads python scripts as ZNC modules")) znc-1.7.5/modules/certauth.cpp0000644000175000017500000002133213542151610016534 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define REQUIRESSL #include #include using std::map; using std::vector; using std::set; using std::pair; class CSSLClientCertMod : public CModule { public: MODCONSTRUCTOR(CSSLClientCertMod) { AddHelpCommand(); AddCommand("Add", t_d("[pubkey]"), t_d("Add a public key. If key is not provided " "will use the current key"), [=](const CString& sLine) { HandleAddCommand(sLine); }); AddCommand("Del", t_d("id"), t_d("Delete a key by its number in List"), [=](const CString& sLine) { HandleDelCommand(sLine); }); AddCommand("List", "", t_d("List your public keys"), [=](const CString& sLine) { HandleListCommand(sLine); }); AddCommand("Show", "", t_d("Print your current key"), [=](const CString& sLine) { HandleShowCommand(sLine); }); } ~CSSLClientCertMod() override {} bool OnBoot() override { const vector& vListeners = CZNC::Get().GetListeners(); // We need the SSL_VERIFY_PEER flag on all listeners, or else // the client doesn't send a ssl cert for (CListener* pListener : vListeners) pListener->GetRealListener()->SetRequireClientCertFlags( SSL_VERIFY_PEER); for (MCString::const_iterator it = BeginNV(); it != EndNV(); ++it) { VCString vsKeys; if (CZNC::Get().FindUser(it->first) == nullptr) { DEBUG("Unknown user in saved data [" + it->first + "]"); continue; } it->second.Split(" ", vsKeys, false); for (const CString& sKey : vsKeys) { m_PubKeys[it->first].insert(sKey.AsLower()); } } return true; } void OnPostRehash() override { OnBoot(); } bool OnLoad(const CString& sArgs, CString& sMessage) override { OnBoot(); return true; } bool Save() { ClearNV(false); for (const auto& it : m_PubKeys) { CString sVal; for (const CString& sKey : it.second) { sVal += sKey + " "; } if (!sVal.empty()) SetNV(it.first, sVal, false); } return SaveRegistry(); } bool AddKey(CUser* pUser, const CString& sKey) { const pair pair = m_PubKeys[pUser->GetUserName()].insert(sKey.AsLower()); if (pair.second) { Save(); } return pair.second; } EModRet OnLoginAttempt(std::shared_ptr Auth) override { const CString sUser = Auth->GetUsername(); Csock* pSock = Auth->GetSocket(); CUser* pUser = CZNC::Get().FindUser(sUser); if (pSock == nullptr || pUser == nullptr) return CONTINUE; const CString sPubKey = GetKey(pSock); DEBUG("User: " << sUser << " Key: " << sPubKey); if (sPubKey.empty()) { DEBUG("Peer got no public key, ignoring"); return CONTINUE; } MSCString::const_iterator it = m_PubKeys.find(sUser); if (it == m_PubKeys.end()) { DEBUG("No saved pubkeys for this client"); return CONTINUE; } SCString::const_iterator it2 = it->second.find(sPubKey); if (it2 == it->second.end()) { DEBUG("Invalid pubkey"); return CONTINUE; } // This client uses a valid pubkey for this user, let them in DEBUG("Accepted pubkey auth"); Auth->AcceptLogin(*pUser); return HALT; } void HandleShowCommand(const CString& sLine) { const CString sPubKey = GetKey(GetClient()); if (sPubKey.empty()) { PutModule(t_s("You are not connected with any valid public key")); } else { PutModule(t_f("Your current public key is: {1}")(sPubKey)); } } void HandleAddCommand(const CString& sLine) { CString sPubKey = sLine.Token(1); if (sPubKey.empty()) { sPubKey = GetKey(GetClient()); } if (sPubKey.empty()) { PutModule( t_s("You did not supply a public key or connect with one.")); } else { if (AddKey(GetUser(), sPubKey)) { PutModule(t_f("Key '{1}' added.")(sPubKey)); } else { PutModule(t_f("The key '{1}' is already added.")(sPubKey)); } } } void HandleListCommand(const CString& sLine) { CTable Table; Table.AddColumn(t_s("Id", "list")); Table.AddColumn(t_s("Key", "list")); MSCString::const_iterator it = m_PubKeys.find(GetUser()->GetUserName()); if (it == m_PubKeys.end()) { PutModule(t_s("No keys set for your user")); return; } unsigned int id = 1; for (const CString& sKey : it->second) { Table.AddRow(); Table.SetCell(t_s("Id", "list"), CString(id++)); Table.SetCell(t_s("Key", "list"), sKey); } if (PutModule(Table) == 0) { // This double check is necessary, because the // set could be empty. PutModule(t_s("No keys set for your user")); } } void HandleDelCommand(const CString& sLine) { unsigned int id = sLine.Token(1, true).ToUInt(); MSCString::iterator it = m_PubKeys.find(GetUser()->GetUserName()); if (it == m_PubKeys.end()) { PutModule(t_s("No keys set for your user")); return; } if (id == 0 || id > it->second.size()) { PutModule(t_s("Invalid #, check \"list\"")); return; } SCString::const_iterator it2 = it->second.begin(); while (id > 1) { ++it2; id--; } it->second.erase(it2); if (it->second.size() == 0) m_PubKeys.erase(it); PutModule(t_s("Removed")); Save(); } CString GetKey(Csock* pSock) { CString sRes; long int res = pSock->GetPeerFingerprint(sRes); DEBUG("GetKey() returned status " << res << " with key " << sRes); // This is 'inspired' by charybdis' libratbox switch (res) { case X509_V_OK: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: return sRes.AsLower(); default: return ""; } } CString GetWebMenuTitle() override { return "certauth"; } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { CUser* pUser = WebSock.GetSession()->GetUser(); if (sPageName == "index") { MSCString::const_iterator it = m_PubKeys.find(pUser->GetUserName()); if (it != m_PubKeys.end()) { for (const CString& sKey : it->second) { CTemplate& row = Tmpl.AddRow("KeyLoop"); row["Key"] = sKey; } } return true; } else if (sPageName == "add") { AddKey(pUser, WebSock.GetParam("key")); WebSock.Redirect(GetWebPath()); return true; } else if (sPageName == "delete") { MSCString::iterator it = m_PubKeys.find(pUser->GetUserName()); if (it != m_PubKeys.end()) { if (it->second.erase(WebSock.GetParam("key", false))) { if (it->second.size() == 0) { m_PubKeys.erase(it); } Save(); } } WebSock.Redirect(GetWebPath()); return true; } return false; } private: // Maps user names to a list of allowed pubkeys typedef map> MSCString; MSCString m_PubKeys; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("certauth"); } GLOBALMODULEDEFS( CSSLClientCertMod, t_s("Allows users to authenticate via SSL client certificates.")) znc-1.7.5/modules/cyrusauth.cpp0000644000175000017500000002002513542151610016742 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * Copyright (C) 2008 Heiko Hund * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @class CSASLAuthMod * @author Heiko Hund * @brief SASL authentication module for znc. */ #include #include #include class CSASLAuthMod : public CModule { public: MODCONSTRUCTOR(CSASLAuthMod) { m_Cache.SetTTL(60000 /*ms*/); m_cbs[0].id = SASL_CB_GETOPT; m_cbs[0].proc = reinterpret_cast(CSASLAuthMod::getopt); m_cbs[0].context = this; m_cbs[1].id = SASL_CB_LIST_END; m_cbs[1].proc = nullptr; m_cbs[1].context = nullptr; AddHelpCommand(); AddCommand("Show", "", t_d("Shows current settings"), [=](const CString& sLine) { ShowCommand(sLine); }); AddCommand("CreateUsers", t_d("yes|clone |no"), t_d("Create ZNC users upon first successful login, " "optionally from a template"), [=](const CString& sLine) { CreateUsersCommand(sLine); }); } ~CSASLAuthMod() override { sasl_done(); } void OnModCommand(const CString& sCommand) override { if (GetUser()->IsAdmin()) { HandleCommand(sCommand); } else { PutModule(t_s("Access denied")); } } bool OnLoad(const CString& sArgs, CString& sMessage) override { VCString vsArgs; VCString::const_iterator it; sArgs.Split(" ", vsArgs, false); for (it = vsArgs.begin(); it != vsArgs.end(); ++it) { if (it->Equals("saslauthd") || it->Equals("auxprop")) { m_sMethod += *it + " "; } else { CUtils::PrintError( t_f("Ignoring invalid SASL pwcheck method: {1}")(*it)); sMessage = t_s("Ignored invalid SASL pwcheck method"); } } m_sMethod.TrimRight(); if (m_sMethod.empty()) { sMessage = t_s("Need a pwcheck method as argument (saslauthd, auxprop)"); return false; } if (sasl_server_init(nullptr, nullptr) != SASL_OK) { sMessage = t_s("SASL Could Not Be Initialized - Halting Startup"); return false; } return true; } EModRet OnLoginAttempt(std::shared_ptr Auth) override { const CString& sUsername = Auth->GetUsername(); const CString& sPassword = Auth->GetPassword(); CUser* pUser(CZNC::Get().FindUser(sUsername)); sasl_conn_t* sasl_conn(nullptr); bool bSuccess = false; if (!pUser && !CreateUser()) { return CONTINUE; } const CString sCacheKey(CString(sUsername + ":" + sPassword).MD5()); if (m_Cache.HasItem(sCacheKey)) { bSuccess = true; DEBUG("saslauth: Found [" + sUsername + "] in cache"); } else if (sasl_server_new("znc", nullptr, nullptr, nullptr, nullptr, m_cbs, 0, &sasl_conn) == SASL_OK && sasl_checkpass(sasl_conn, sUsername.c_str(), sUsername.size(), sPassword.c_str(), sPassword.size()) == SASL_OK) { m_Cache.AddItem(sCacheKey); DEBUG("saslauth: Successful SASL authentication [" + sUsername + "]"); bSuccess = true; } sasl_dispose(&sasl_conn); if (bSuccess) { if (!pUser) { CString sErr; pUser = new CUser(sUsername); if (ShouldCloneUser()) { CUser* pBaseUser = CZNC::Get().FindUser(CloneUser()); if (!pBaseUser) { DEBUG("saslauth: Clone User [" << CloneUser() << "] User not found"); delete pUser; pUser = nullptr; } if (pUser && !pUser->Clone(*pBaseUser, sErr)) { DEBUG("saslauth: Clone User [" << CloneUser() << "] failed: " << sErr); delete pUser; pUser = nullptr; } } if (pUser) { // "::" is an invalid MD5 hash, so user won't be able to // login by usual method pUser->SetPass("::", CUser::HASH_MD5, "::"); } if (pUser && !CZNC::Get().AddUser(pUser, sErr)) { DEBUG("saslauth: Add user [" << sUsername << "] failed: " << sErr); delete pUser; pUser = nullptr; } } if (pUser) { Auth->AcceptLogin(*pUser); return HALT; } } return CONTINUE; } const CString& GetMethod() const { return m_sMethod; } void ShowCommand(const CString& sLine) { if (!CreateUser()) { PutModule(t_s("We will not create users on their first login")); } else if (ShouldCloneUser()) { PutModule( t_f("We will create users on their first login, using user " "[{1}] as a template")(CloneUser())); } else { PutModule(t_s("We will create users on their first login")); } } void CreateUsersCommand(const CString& sLine) { CString sCreate = sLine.Token(1); if (sCreate == "no") { DelNV("CloneUser"); SetNV("CreateUser", CString(false)); PutModule(t_s("We will not create users on their first login")); } else if (sCreate == "yes") { DelNV("CloneUser"); SetNV("CreateUser", CString(true)); PutModule(t_s("We will create users on their first login")); } else if (sCreate == "clone" && !sLine.Token(2).empty()) { SetNV("CloneUser", sLine.Token(2)); SetNV("CreateUser", CString(true)); PutModule( t_f("We will create users on their first login, using user " "[{1}] as a template")(sLine.Token(2))); } else { PutModule( t_s("Usage: CreateUsers yes, CreateUsers no, or CreateUsers " "clone ")); } } bool CreateUser() const { return GetNV("CreateUser").ToBool(); } CString CloneUser() const { return GetNV("CloneUser"); } bool ShouldCloneUser() { return !GetNV("CloneUser").empty(); } protected: TCacheMap m_Cache; sasl_callback_t m_cbs[2]; CString m_sMethod; static int getopt(void* context, const char* plugin_name, const char* option, const char** result, unsigned* len) { if (CString(option).Equals("pwcheck_method")) { *result = ((CSASLAuthMod*)context)->GetMethod().c_str(); return SASL_OK; } return SASL_CONTINUE; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("cyrusauth"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s( "This global module takes up to two arguments - the methods of " "authentication - auxprop and saslauthd")); } GLOBALMODULEDEFS( CSASLAuthMod, t_s("Allow users to authenticate via SASL password verification method")) znc-1.7.5/modules/adminlog.cpp0000644000175000017500000001565613542151610016523 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include class CAdminLogMod : public CModule { public: MODCONSTRUCTOR(CAdminLogMod) { AddHelpCommand(); AddCommand("Show", "", t_d("Show the logging target"), [=](const CString& sLine) { OnShowCommand(sLine); }); AddCommand("Target", t_d(" [path]"), t_d("Set the logging target"), [=](const CString& sLine) { OnTargetCommand(sLine); }); openlog("znc", LOG_PID, LOG_DAEMON); } ~CAdminLogMod() override { Log("Logging ended."); closelog(); } bool OnLoad(const CString& sArgs, CString& sMessage) override { CString sTarget = GetNV("target"); if (sTarget.Equals("syslog")) m_eLogMode = LOG_TO_SYSLOG; else if (sTarget.Equals("both")) m_eLogMode = LOG_TO_BOTH; else if (sTarget.Equals("file")) m_eLogMode = LOG_TO_FILE; else m_eLogMode = LOG_TO_FILE; SetLogFilePath(GetNV("path")); Log("Logging started. ZNC PID[" + CString(getpid()) + "] UID/GID[" + CString(getuid()) + ":" + CString(getgid()) + "]"); return true; } void OnIRCConnected() override { Log("[" + GetUser()->GetUserName() + "/" + GetNetwork()->GetName() + "] connected to IRC: " + GetNetwork()->GetCurrentServer()->GetName()); } void OnIRCDisconnected() override { Log("[" + GetUser()->GetUserName() + "/" + GetNetwork()->GetName() + "] disconnected from IRC"); } EModRet OnRawMessage(CMessage& Message) override { if (Message.GetCommand().Equals("ERROR")) { // ERROR :Closing Link: nick[24.24.24.24] (Excess Flood) // ERROR :Closing Link: nick[24.24.24.24] Killer (Local kill by // Killer (reason)) Log("[" + GetUser()->GetUserName() + "/" + GetNetwork()->GetName() + "] disconnected from IRC: " + GetNetwork()->GetCurrentServer()->GetName() + " [" + Message.GetParamsColon(0) + "]", LOG_NOTICE); } return CONTINUE; } void OnClientLogin() override { Log("[" + GetUser()->GetUserName() + "] connected to ZNC from " + GetClient()->GetRemoteIP()); } void OnClientDisconnect() override { Log("[" + GetUser()->GetUserName() + "] disconnected from ZNC from " + GetClient()->GetRemoteIP()); } void OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) override { Log("[" + sUsername + "] failed to login from " + sRemoteIP, LOG_WARNING); } void SetLogFilePath(CString sPath) { if (sPath.empty()) { sPath = GetSavePath() + "/znc.log"; } CFile LogFile(sPath); CString sLogDir = LogFile.GetDir(); struct stat ModDirInfo; CFile::GetInfo(GetSavePath(), ModDirInfo); if (!CFile::Exists(sLogDir)) { CDir::MakeDir(sLogDir, ModDirInfo.st_mode); } m_sLogFile = sPath; SetNV("path", sPath); } void Log(CString sLine, int iPrio = LOG_INFO) { if (m_eLogMode & LOG_TO_SYSLOG) syslog(iPrio, "%s", sLine.c_str()); if (m_eLogMode & LOG_TO_FILE) { time_t curtime; tm* timeinfo; char buf[23]; time(&curtime); timeinfo = localtime(&curtime); strftime(buf, sizeof(buf), "[%Y-%m-%d %H:%M:%S] ", timeinfo); CFile LogFile(m_sLogFile); if (LogFile.Open(O_WRONLY | O_APPEND | O_CREAT)) LogFile.Write(buf + sLine + "\n"); else DEBUG("Failed to write to [" << m_sLogFile << "]: " << strerror(errno)); } } void OnModCommand(const CString& sCommand) override { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied")); } else { HandleCommand(sCommand); } } void OnTargetCommand(const CString& sCommand) { CString sArg = sCommand.Token(1, false); CString sTarget; CString sMessage; LogMode mode; if (sArg.Equals("file")) { sTarget = "file"; sMessage = t_s("Now logging to file"); mode = LOG_TO_FILE; } else if (sArg.Equals("syslog")) { sTarget = "syslog"; sMessage = t_s("Now only logging to syslog"); mode = LOG_TO_SYSLOG; } else if (sArg.Equals("both")) { sTarget = "both"; sMessage = t_s("Now logging to syslog and file"); mode = LOG_TO_BOTH; } else { if (sArg.empty()) { PutModule(t_s("Usage: Target [path]")); } else { PutModule(t_s("Unknown target")); } return; } if (mode != LOG_TO_SYSLOG) { CString sPath = sCommand.Token(2, true); SetLogFilePath(sPath); sMessage += " [" + sPath + "]"; } Log(sMessage); SetNV("target", sTarget); m_eLogMode = mode; PutModule(sMessage); } void OnShowCommand(const CString& sCommand) { CString sTarget; switch (m_eLogMode) { case LOG_TO_FILE: sTarget = t_s("Logging is enabled for file"); break; case LOG_TO_SYSLOG: sTarget = t_s("Logging is enabled for syslog"); break; case LOG_TO_BOTH: sTarget = t_s("Logging is enabled for both, file and syslog"); break; } PutModule(sTarget); if (m_eLogMode != LOG_TO_SYSLOG) PutModule(t_f("Log file will be written to {1}")(m_sLogFile)); } private: enum LogMode { LOG_TO_FILE = 1 << 0, LOG_TO_SYSLOG = 1 << 1, LOG_TO_BOTH = LOG_TO_FILE | LOG_TO_SYSLOG }; LogMode m_eLogMode = LOG_TO_FILE; CString m_sLogFile; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("adminlog"); } GLOBALMODULEDEFS(CAdminLogMod, t_s("Log ZNC events to file and/or syslog.")) znc-1.7.5/modules/sasl.cpp0000644000175000017500000002570213542151610015664 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #define NV_REQUIRE_AUTH "require_auth" #define NV_MECHANISMS "mechanisms" class Mechanisms : public VCString { public: void SetIndex(unsigned int uiIndex) { m_uiIndex = uiIndex; } unsigned int GetIndex() const { return m_uiIndex; } bool HasNext() const { return size() > (m_uiIndex + 1); } void IncrementIndex() { m_uiIndex++; } CString GetCurrent() const { return at(m_uiIndex); } CString GetNext() const { if (HasNext()) { return at(m_uiIndex + 1); } return ""; } private: unsigned int m_uiIndex = 0; }; class CSASLMod : public CModule { const struct { const char* szName; CDelayedTranslation sDescription; bool bDefault; } SupportedMechanisms[2] = { {"EXTERNAL", t_d("TLS certificate, for use with the *cert module"), true}, {"PLAIN", t_d("Plain text negotiation, this should work always if the " "network supports SASL"), true}}; public: MODCONSTRUCTOR(CSASLMod) { AddCommand("Help", t_d("search"), t_d("Generate this output"), [=](const CString& sLine) { PrintHelp(sLine); }); AddCommand("Set", t_d("[ []]"), t_d("Set username and password for the mechanisms that need " "them. Password is optional. Without parameters, " "returns information about current settings."), [=](const CString& sLine) { Set(sLine); }); AddCommand("Mechanism", t_d("[mechanism[ ...]]"), t_d("Set the mechanisms to be attempted (in order)"), [=](const CString& sLine) { SetMechanismCommand(sLine); }); AddCommand("RequireAuth", t_d("[yes|no]"), t_d("Don't connect unless SASL authentication succeeds"), [=](const CString& sLine) { RequireAuthCommand(sLine); }); AddCommand("Verbose", "yes|no", "Set verbosity level, useful to debug", [&](const CString& sLine) { m_bVerbose = sLine.Token(1, true).ToBool(); PutModule("Verbose: " + CString(m_bVerbose)); }); m_bAuthenticated = false; } void PrintHelp(const CString& sLine) { HandleHelpCommand(sLine); CTable Mechanisms; Mechanisms.AddColumn(t_s("Mechanism")); Mechanisms.AddColumn(t_s("Description")); for (const auto& it : SupportedMechanisms) { Mechanisms.AddRow(); Mechanisms.SetCell(t_s("Mechanism"), it.szName); Mechanisms.SetCell(t_s("Description"), it.sDescription.Resolve()); } PutModule(t_s("The following mechanisms are available:")); PutModule(Mechanisms); } void Set(const CString& sLine) { if (sLine.Token(1).empty()) { CString sUsername = GetNV("username"); CString sPassword = GetNV("password"); if (sUsername.empty()) { PutModule(t_s("Username is currently not set")); } else { PutModule(t_f("Username is currently set to '{1}'")(sUsername)); } if (sPassword.empty()) { PutModule(t_s("Password was not supplied")); } else { PutModule(t_s("Password was supplied")); } return; } SetNV("username", sLine.Token(1)); SetNV("password", sLine.Token(2)); PutModule(t_f("Username has been set to [{1}]")(GetNV("username"))); PutModule(t_f("Password has been set to [{1}]")(GetNV("password"))); } void SetMechanismCommand(const CString& sLine) { CString sMechanisms = sLine.Token(1, true).AsUpper(); if (!sMechanisms.empty()) { VCString vsMechanisms; sMechanisms.Split(" ", vsMechanisms); for (const CString& sMechanism : vsMechanisms) { if (!SupportsMechanism(sMechanism)) { PutModule("Unsupported mechanism: " + sMechanism); return; } } SetNV(NV_MECHANISMS, sMechanisms); } PutModule(t_f("Current mechanisms set: {1}")(GetMechanismsString())); } void RequireAuthCommand(const CString& sLine) { if (!sLine.Token(1).empty()) { SetNV(NV_REQUIRE_AUTH, sLine.Token(1)); } if (GetNV(NV_REQUIRE_AUTH).ToBool()) { PutModule(t_s("We require SASL negotiation to connect")); } else { PutModule(t_s("We will connect even if SASL fails")); } } bool SupportsMechanism(const CString& sMechanism) const { for (const auto& it : SupportedMechanisms) { if (sMechanism.Equals(it.szName)) { return true; } } return false; } CString GetMechanismsString() const { if (GetNV(NV_MECHANISMS).empty()) { CString sDefaults = ""; for (const auto& it : SupportedMechanisms) { if (it.bDefault) { if (!sDefaults.empty()) { sDefaults += " "; } sDefaults += it.szName; } } return sDefaults; } return GetNV(NV_MECHANISMS); } void CheckRequireAuth() { if (!m_bAuthenticated && GetNV(NV_REQUIRE_AUTH).ToBool()) { GetNetwork()->SetIRCConnectEnabled(false); PutModule(t_s("Disabling network, we require authentication.")); PutModule(t_s("Use 'RequireAuth no' to disable.")); } } void Authenticate(const CString& sLine) { if (m_Mechanisms.GetCurrent().Equals("PLAIN") && sLine.Equals("+")) { CString sAuthLine = GetNV("username") + '\0' + GetNV("username") + '\0' + GetNV("password"); sAuthLine.Base64Encode(); PutIRC("AUTHENTICATE " + sAuthLine); } else { /* Send blank authenticate for other mechanisms (like EXTERNAL). */ PutIRC("AUTHENTICATE +"); } } bool OnServerCapAvailable(const CString& sCap) override { return sCap.Equals("sasl"); } void OnServerCapResult(const CString& sCap, bool bSuccess) override { if (sCap.Equals("sasl")) { if (bSuccess) { GetMechanismsString().Split(" ", m_Mechanisms); if (m_Mechanisms.empty()) { CheckRequireAuth(); return; } GetNetwork()->GetIRCSock()->PauseCap(); m_Mechanisms.SetIndex(0); PutIRC("AUTHENTICATE " + m_Mechanisms.GetCurrent()); } else { CheckRequireAuth(); } } } EModRet OnRawMessage(CMessage& msg) override { if (msg.GetCommand().Equals("AUTHENTICATE")) { Authenticate(msg.GetParam(0)); return HALT; } return CONTINUE; } EModRet OnNumericMessage(CNumericMessage& msg) override { if (msg.GetCode() == 903) { /* SASL success! */ if (m_bVerbose) { PutModule( t_f("{1} mechanism succeeded.")(m_Mechanisms.GetCurrent())); } GetNetwork()->GetIRCSock()->ResumeCap(); m_bAuthenticated = true; DEBUG("sasl: Authenticated with mechanism [" << m_Mechanisms.GetCurrent() << "]"); } else if (msg.GetCode() == 904 || msg.GetCode() == 905) { DEBUG("sasl: Mechanism [" << m_Mechanisms.GetCurrent() << "] failed."); if (m_bVerbose) { PutModule( t_f("{1} mechanism failed.")(m_Mechanisms.GetCurrent())); } if (m_Mechanisms.HasNext()) { m_Mechanisms.IncrementIndex(); PutIRC("AUTHENTICATE " + m_Mechanisms.GetCurrent()); } else { CheckRequireAuth(); GetNetwork()->GetIRCSock()->ResumeCap(); } } else if (msg.GetCode() == 906) { /* CAP wasn't paused? */ DEBUG("sasl: Reached 906."); CheckRequireAuth(); } else if (msg.GetCode() == 907) { m_bAuthenticated = true; GetNetwork()->GetIRCSock()->ResumeCap(); DEBUG("sasl: Received 907 -- We are already registered"); } else { return CONTINUE; } return HALT; } void OnIRCConnected() override { /* Just incase something slipped through, perhaps the server doesn't * respond to our CAP negotiation. */ CheckRequireAuth(); } void OnIRCDisconnected() override { m_bAuthenticated = false; } CString GetWebMenuTitle() override { return t_s("SASL"); } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName != "index") { // only accept requests to index return false; } if (WebSock.IsPost()) { SetNV("username", WebSock.GetParam("username")); CString sPassword = WebSock.GetParam("password"); if (!sPassword.empty()) { SetNV("password", sPassword); } SetNV(NV_REQUIRE_AUTH, WebSock.GetParam("require_auth")); SetNV(NV_MECHANISMS, WebSock.GetParam("mechanisms")); } Tmpl["Username"] = GetNV("username"); Tmpl["Password"] = GetNV("password"); Tmpl["RequireAuth"] = GetNV(NV_REQUIRE_AUTH); Tmpl["Mechanisms"] = GetMechanismsString(); for (const auto& it : SupportedMechanisms) { CTemplate& Row = Tmpl.AddRow("MechanismLoop"); CString sName(it.szName); Row["Name"] = sName; Row["Description"] = it.sDescription.Resolve(); } return true; } private: Mechanisms m_Mechanisms; bool m_bAuthenticated; bool m_bVerbose = false; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("sasl"); } NETWORKMODULEDEFS(CSASLMod, t_s("Adds support for sasl authentication " "capability to authenticate to an IRC server")) znc-1.7.5/modules/raw.cpp0000644000175000017500000000237513542151610015514 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include class CRawMod : public CModule { public: MODCONSTRUCTOR(CRawMod) {} ~CRawMod() override {} EModRet OnRaw(CString& sLine) override { PutModule("IRC -> [" + sLine + "]"); return CONTINUE; } void OnModCommand(const CString& sCommand) override { PutIRC(sCommand); } EModRet OnUserRaw(CString& sLine) override { PutModule("YOU -> [" + sLine + "]"); return CONTINUE; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("raw"); Info.AddType(CModInfo::UserModule); } NETWORKMODULEDEFS(CRawMod, t_s("View all of the raw traffic")) znc-1.7.5/modules/clientnotify.cpp0000644000175000017500000001241213542151610017423 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::set; class CClientNotifyMod : public CModule { protected: CString m_sMethod; bool m_bNewOnly{}; bool m_bOnDisconnect{}; set m_sClientsSeen; void SaveSettings() { SetNV("method", m_sMethod); SetNV("newonly", m_bNewOnly ? "1" : "0"); SetNV("ondisconnect", m_bOnDisconnect ? "1" : "0"); } void SendNotification(const CString& sMessage) { if (m_sMethod == "message") { GetUser()->PutStatus(sMessage, nullptr, GetClient()); } else if (m_sMethod == "notice") { GetUser()->PutStatusNotice(sMessage, nullptr, GetClient()); } } public: MODCONSTRUCTOR(CClientNotifyMod) { AddHelpCommand(); AddCommand("Method", t_d(""), t_d("Sets the notify method"), [=](const CString& sLine) { OnMethodCommand(sLine); }); AddCommand("NewOnly", t_d(""), t_d("Turns notifications for unseen IP addresses on or off"), [=](const CString& sLine) { OnNewOnlyCommand(sLine); }); AddCommand( "OnDisconnect", t_d(""), t_d("Turns notifications for clients disconnecting on or off"), [=](const CString& sLine) { OnDisconnectCommand(sLine); }); AddCommand("Show", "", t_d("Shows the current settings"), [=](const CString& sLine) { OnShowCommand(sLine); }); } bool OnLoad(const CString& sArgs, CString& sMessage) override { m_sMethod = GetNV("method"); if (m_sMethod != "notice" && m_sMethod != "message" && m_sMethod != "off") { m_sMethod = "message"; } // default = off for these: m_bNewOnly = (GetNV("newonly") == "1"); m_bOnDisconnect = (GetNV("ondisconnect") == "1"); return true; } void OnClientLogin() override { CString sRemoteIP = GetClient()->GetRemoteIP(); if (!m_bNewOnly || m_sClientsSeen.find(sRemoteIP) == m_sClientsSeen.end()) { SendNotification(t_p("", "Another client authenticated as your user. " "Use the 'ListClients' command to see all {1} " "clients.", GetUser()->GetAllClients().size())( GetUser()->GetAllClients().size())); // the set<> will automatically disregard duplicates: m_sClientsSeen.insert(sRemoteIP); } } void OnClientDisconnect() override { if (m_bOnDisconnect) { SendNotification(t_p("", "A client disconnected from your user. Use " "the 'ListClients' command to see the {1} " "remaining clients.", GetUser()->GetAllClients().size())( GetUser()->GetAllClients().size())); } } void OnMethodCommand(const CString& sCommand) { const CString sArg = sCommand.Token(1, true).AsLower(); if (sArg != "notice" && sArg != "message" && sArg != "off") { PutModule(t_s("Usage: Method ")); return; } m_sMethod = sArg; SaveSettings(); PutModule(t_s("Saved.")); } void OnNewOnlyCommand(const CString& sCommand) { const CString sArg = sCommand.Token(1, true).AsLower(); if (sArg.empty()) { PutModule(t_s("Usage: NewOnly ")); return; } m_bNewOnly = sArg.ToBool(); SaveSettings(); PutModule(t_s("Saved.")); } void OnDisconnectCommand(const CString& sCommand) { const CString sArg = sCommand.Token(1, true).AsLower(); if (sArg.empty()) { PutModule(t_s("Usage: OnDisconnect ")); return; } m_bOnDisconnect = sArg.ToBool(); SaveSettings(); PutModule(t_s("Saved.")); } void OnShowCommand(const CString& sLine) { PutModule( t_f("Current settings: Method: {1}, for unseen IP addresses only: " "{2}, notify on disconnecting clients: {3}")( m_sMethod, m_bNewOnly, m_bOnDisconnect)); } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("clientnotify"); } USERMODULEDEFS(CClientNotifyMod, t_s("Notifies you when another IRC client logs into or out of " "your account. Configurable.")) znc-1.7.5/modules/Makefile.in0000644000175000017500000000716113542151610016262 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # all: SHELL := @SHELL@ # Support out-of-tree builds srcdir := @srcdir@ VPATH := @srcdir@ prefix := @prefix@ exec_prefix := @exec_prefix@ datarootdir := @datarootdir@ bindir := @bindir@ datadir := @datadir@ sysconfdir := @sysconfdir@ libdir := @libdir@ sbindir := @sbindir@ localstatedir := @localstatedir@ CXX := @CXX@ # CXXFLAGS are for the main binary, so don't use them here, use MODFLAGS instead MODFLAGS := -I$(srcdir)/../include -I../include @CPPFLAGS@ @MODFLAGS@ MODLINK := @MODLINK@ LDFLAGS := @LDFLAGS@ ISCYGWIN := @ISCYGWIN@ # LIBS are not and should not be used in here. # The znc binary links already against those. # ...but not on cygwin! LIBS := ifeq "$(ISCYGWIN)" "1" LIBS += @LIBS@ endif PERL_ON := @PERL@ PERL := @PERL_BINARY@ PYTHON_ON:= @PYTHON@ PY_CFLAGS:= @python_CFLAGS@ PY_LDFLAGS:=@python_LIBS@ SWIG := @SWIG@ MODDIR := @MODDIR@ DATADIR := @DATADIR@ LIBZNC := @LIBZNC@ LIBZNCDIR:= @LIBZNCDIR@ INSTALL := @INSTALL@ INSTALL_PROGRAM := @INSTALL_PROGRAM@ INSTALL_SCRIPT := @INSTALL_SCRIPT@ INSTALL_DATA := @INSTALL_DATA@ SED := @SED@ TCL_FLAGS:= @TCL_FLAGS@ ifneq "$(V)" "" VERBOSE=1 endif ifeq "$(VERBOSE)" "" Q=@ E=@echo C=-s else Q= E=@\# C= endif ifneq "$(LIBZNC)" "" LIBS += -L.. -lznc -Wl,-rpath,$(LIBZNCDIR) endif CLEAN := FILES := $(notdir $(wildcard $(srcdir)/*.cpp)) include $(srcdir)/modperl/Makefile.inc include $(srcdir)/modpython/Makefile.inc include $(srcdir)/modtcl/Makefile.inc FILES := $(basename $(FILES)) ifeq "@NOSSL@" "1" FILES := $(foreach file, $(FILES), \ $(if $(shell grep REQUIRESSL $(srcdir)/$(file).cpp), \ , \ $(basename $(file)) \ )) endif ifeq "@CYRUS@" "" FILES := $(shell echo $(FILES) | sed -e "s:cyrusauth::") endif cyrusauthLDFLAGS := -lsasl2 TARGETS := $(addsuffix .so, $(sort $(FILES))) CLEAN += *.so *.o .PHONY: all clean install install_datadir uninstall .SECONDARY: all: $(TARGETS) install: all install_datadir $(INSTALL_PROGRAM) $(TARGETS) $(DESTDIR)$(MODDIR) install_datadir: rm -rf $(DESTDIR)$(DATADIR)/modules test -d $(DESTDIR)$(MODDIR) || $(INSTALL) -d $(DESTDIR)$(MODDIR) test -d $(DESTDIR)$(DATADIR)/modules || $(INSTALL) -d $(DESTDIR)$(DATADIR)/modules rm -rf $(DESTDIR)$(MODDIR)/*.so cp -R $(srcdir)/data/* $(DESTDIR)$(DATADIR)/modules find $(DESTDIR)$(DATADIR)/modules -type d -exec chmod 0755 '{}' \; find $(DESTDIR)$(DATADIR)/modules -type f -exec chmod 0644 '{}' \; clean: rm -rf $(CLEAN) %.o: %.cpp Makefile @mkdir -p .depend $(E) Building module $(notdir $(basename $@))... $(Q)$(CXX) $(MODFLAGS) -c -o $@ $< $($(notdir $(basename $@))CXXFLAGS) -MD -MF .depend/$(notdir $@).dep %.so: %.o Makefile $(E) "Linking module" $(notdir $(basename $@))... $(Q)$(CXX) $(MODFLAGS) $(LDFLAGS) $(MODLINK) -o $@ $< $($(notdir $(basename $@))LDFLAGS) $(LIBS) uninstall: # Yes, we are lazy, just remove everything in there rm -rf $(DESTDIR)$(MODDIR)/* rm -rf $(DESTDIR)$(DATADIR)/* rmdir $(DESTDIR)$(MODDIR) rmdir $(DESTDIR)$(DATADIR) -include $(wildcard .depend/*.dep) znc-1.7.5/modules/autovoice.cpp0000644000175000017500000002514613542151610016722 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include using std::map; using std::set; class CAutoVoiceUser { public: CAutoVoiceUser() {} CAutoVoiceUser(const CString& sLine) { FromString(sLine); } CAutoVoiceUser(const CString& sUsername, const CString& sHostmask, const CString& sChannels) : m_sUsername(sUsername), m_sHostmask(sHostmask) { AddChans(sChannels); } virtual ~CAutoVoiceUser() {} const CString& GetUsername() const { return m_sUsername; } const CString& GetHostmask() const { return m_sHostmask; } bool ChannelMatches(const CString& sChan) const { for (const CString& s : m_ssChans) { if (sChan.AsLower().WildCmp(s, CString::CaseInsensitive)) { return true; } } return false; } bool HostMatches(const CString& sHostmask) { return sHostmask.WildCmp(m_sHostmask, CString::CaseInsensitive); } CString GetChannels() const { CString sRet; for (const CString& sChan : m_ssChans) { if (!sRet.empty()) { sRet += " "; } sRet += sChan; } return sRet; } void DelChans(const CString& sChans) { VCString vsChans; sChans.Split(" ", vsChans); for (const CString& sChan : vsChans) { m_ssChans.erase(sChan.AsLower()); } } void AddChans(const CString& sChans) { VCString vsChans; sChans.Split(" ", vsChans); for (const CString& sChan : vsChans) { m_ssChans.insert(sChan.AsLower()); } } CString ToString() const { CString sChans; for (const CString& sChan : m_ssChans) { if (!sChans.empty()) { sChans += " "; } sChans += sChan; } return m_sUsername + "\t" + m_sHostmask + "\t" + sChans; } bool FromString(const CString& sLine) { m_sUsername = sLine.Token(0, false, "\t"); m_sHostmask = sLine.Token(1, false, "\t"); sLine.Token(2, false, "\t").Split(" ", m_ssChans); return !m_sHostmask.empty(); } private: protected: CString m_sUsername; CString m_sHostmask; set m_ssChans; }; class CAutoVoiceMod : public CModule { public: MODCONSTRUCTOR(CAutoVoiceMod) { AddHelpCommand(); AddCommand("ListUsers", "", t_d("List all users"), [=](const CString& sLine) { OnListUsersCommand(sLine); }); AddCommand("AddChans", t_d(" [channel] ..."), t_d("Adds channels to a user"), [=](const CString& sLine) { OnAddChansCommand(sLine); }); AddCommand("DelChans", t_d(" [channel] ..."), t_d("Removes channels from a user"), [=](const CString& sLine) { OnDelChansCommand(sLine); }); AddCommand("AddUser", t_d(" [channels]"), t_d("Adds a user"), [=](const CString& sLine) { OnAddUserCommand(sLine); }); AddCommand("DelUser", t_d(""), t_d("Removes a user"), [=](const CString& sLine) { OnDelUserCommand(sLine); }); } bool OnLoad(const CString& sArgs, CString& sMessage) override { // Load the chans from the command line unsigned int a = 0; VCString vsChans; sArgs.Split(" ", vsChans, false); for (const CString& sChan : vsChans) { CString sName = "Args"; sName += CString(a); AddUser(sName, "*", sChan); } // Load the saved users for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { const CString& sLine = it->second; CAutoVoiceUser* pUser = new CAutoVoiceUser; if (!pUser->FromString(sLine) || FindUser(pUser->GetUsername().AsLower())) { delete pUser; } else { m_msUsers[pUser->GetUsername().AsLower()] = pUser; } } return true; } ~CAutoVoiceMod() override { for (const auto& it : m_msUsers) { delete it.second; } m_msUsers.clear(); } void OnJoin(const CNick& Nick, CChan& Channel) override { // If we have ops in this chan if (Channel.HasPerm(CChan::Op) || Channel.HasPerm(CChan::HalfOp)) { for (const auto& it : m_msUsers) { // and the nick who joined is a valid user if (it.second->HostMatches(Nick.GetHostMask()) && it.second->ChannelMatches(Channel.GetName())) { PutIRC("MODE " + Channel.GetName() + " +v " + Nick.GetNick()); break; } } } } void OnOp2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override { if (Nick.NickEquals(GetNetwork()->GetNick())) { const map& msNicks = Channel.GetNicks(); for (const auto& it : msNicks) { if (!it.second.HasPerm(CChan::Voice)) { CheckAutoVoice(it.second, Channel); } } } } bool CheckAutoVoice(const CNick& Nick, CChan& Channel) { CAutoVoiceUser* pUser = FindUserByHost(Nick.GetHostMask(), Channel.GetName()); if (!pUser) { return false; } PutIRC("MODE " + Channel.GetName() + " +v " + Nick.GetNick()); return true; } void OnAddUserCommand(const CString& sLine) { CString sUser = sLine.Token(1); CString sHost = sLine.Token(2); if (sHost.empty()) { PutModule(t_s("Usage: AddUser [channels]")); } else { CAutoVoiceUser* pUser = AddUser(sUser, sHost, sLine.Token(3, true)); if (pUser) { SetNV(sUser, pUser->ToString()); } } } void OnDelUserCommand(const CString& sLine) { CString sUser = sLine.Token(1); if (sUser.empty()) { PutModule(t_s("Usage: DelUser ")); } else { DelUser(sUser); DelNV(sUser); } } void OnListUsersCommand(const CString& sLine) { if (m_msUsers.empty()) { PutModule(t_s("There are no users defined")); return; } CTable Table; Table.AddColumn(t_s("User")); Table.AddColumn(t_s("Hostmask")); Table.AddColumn(t_s("Channels")); for (const auto& it : m_msUsers) { Table.AddRow(); Table.SetCell(t_s("User"), it.second->GetUsername()); Table.SetCell(t_s("Hostmask"), it.second->GetHostmask()); Table.SetCell(t_s("Channels"), it.second->GetChannels()); } PutModule(Table); } void OnAddChansCommand(const CString& sLine) { CString sUser = sLine.Token(1); CString sChans = sLine.Token(2, true); if (sChans.empty()) { PutModule(t_s("Usage: AddChans [channel] ...")); return; } CAutoVoiceUser* pUser = FindUser(sUser); if (!pUser) { PutModule(t_s("No such user")); return; } pUser->AddChans(sChans); PutModule(t_f("Channel(s) added to user {1}")(pUser->GetUsername())); SetNV(pUser->GetUsername(), pUser->ToString()); } void OnDelChansCommand(const CString& sLine) { CString sUser = sLine.Token(1); CString sChans = sLine.Token(2, true); if (sChans.empty()) { PutModule(t_s("Usage: DelChans [channel] ...")); return; } CAutoVoiceUser* pUser = FindUser(sUser); if (!pUser) { PutModule(t_s("No such user")); return; } pUser->DelChans(sChans); PutModule( t_f("Channel(s) Removed from user {1}")(pUser->GetUsername())); SetNV(pUser->GetUsername(), pUser->ToString()); } CAutoVoiceUser* FindUser(const CString& sUser) { map::iterator it = m_msUsers.find(sUser.AsLower()); return (it != m_msUsers.end()) ? it->second : nullptr; } CAutoVoiceUser* FindUserByHost(const CString& sHostmask, const CString& sChannel = "") { for (const auto& it : m_msUsers) { CAutoVoiceUser* pUser = it.second; if (pUser->HostMatches(sHostmask) && (sChannel.empty() || pUser->ChannelMatches(sChannel))) { return pUser; } } return nullptr; } void DelUser(const CString& sUser) { map::iterator it = m_msUsers.find(sUser.AsLower()); if (it == m_msUsers.end()) { PutModule(t_s("No such user")); return; } delete it->second; m_msUsers.erase(it); PutModule(t_f("User {1} removed")(sUser)); } CAutoVoiceUser* AddUser(const CString& sUser, const CString& sHost, const CString& sChans) { if (m_msUsers.find(sUser) != m_msUsers.end()) { PutModule(t_s("That user already exists")); return nullptr; } CAutoVoiceUser* pUser = new CAutoVoiceUser(sUser, sHost, sChans); m_msUsers[sUser.AsLower()] = pUser; PutModule(t_f("User {1} added with hostmask {2}")(sUser, sHost)); return pUser; } private: map m_msUsers; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("autovoice"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s( "Each argument is either a channel you want autovoice for (which can " "include wildcards) or, if it starts with !, it is an exception for " "autovoice.")); } NETWORKMODULEDEFS(CAutoVoiceMod, t_s("Auto voice the good people")) znc-1.7.5/modules/buffextras.cpp0000644000175000017500000001052213542151610017065 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::vector; class CBuffExtras : public CModule { public: MODCONSTRUCTOR(CBuffExtras) {} ~CBuffExtras() override {} void AddBuffer(CChan& Channel, const CString& sMessage, const timeval* tv = nullptr, const MCString& mssTags = MCString::EmptyMap) { // If they have AutoClearChanBuffer enabled, only add messages if no // client is connected if (Channel.AutoClearChanBuffer() && GetNetwork()->IsUserOnline()) return; Channel.AddBuffer(":" + GetModNick() + "!" + GetModName() + "@znc.in PRIVMSG " + _NAMEDFMT(Channel.GetName()) + " :{text}", sMessage, tv, mssTags); } void OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) override { const CString sNickMask = pOpNick ? pOpNick->GetNickMask() : t_s("Server"); AddBuffer(Channel, t_f("{1} set mode: {2} {3}")(sNickMask, sModes, sArgs)); } void OnKickMessage(CKickMessage& Message) override { const CNick& OpNick = Message.GetNick(); const CString sKickedNick = Message.GetKickedNick(); CChan& Channel = *Message.GetChan(); const CString sMessage = Message.GetReason(); AddBuffer(Channel, t_f("{1} kicked {2} with reason: {3}")( OpNick.GetNickMask(), sKickedNick, sMessage), &Message.GetTime(), Message.GetTags()); } void OnQuitMessage(CQuitMessage& Message, const vector& vChans) override { const CNick& Nick = Message.GetNick(); const CString sMessage = Message.GetReason(); const CString sMsg = t_f("{1} quit: {2}")(Nick.GetNickMask(), sMessage); for (CChan* pChan : vChans) { AddBuffer(*pChan, sMsg, &Message.GetTime(), Message.GetTags()); } } void OnJoinMessage(CJoinMessage& Message) override { const CNick& Nick = Message.GetNick(); CChan& Channel = *Message.GetChan(); AddBuffer(Channel, t_f("{1} joined")(Nick.GetNickMask(), " joined"), &Message.GetTime(), Message.GetTags()); } void OnPartMessage(CPartMessage& Message) override { const CNick& Nick = Message.GetNick(); CChan& Channel = *Message.GetChan(); const CString sMessage = Message.GetReason(); AddBuffer(Channel, t_f("{1} parted: {2}")(Nick.GetNickMask(), sMessage), &Message.GetTime(), Message.GetTags()); } void OnNickMessage(CNickMessage& Message, const vector& vChans) override { const CNick& OldNick = Message.GetNick(); const CString sNewNick = Message.GetNewNick(); const CString sMsg = t_f("{1} is now known as {2}")(OldNick.GetNickMask(), sNewNick); for (CChan* pChan : vChans) { AddBuffer(*pChan, sMsg, &Message.GetTime(), Message.GetTags()); } } EModRet OnTopicMessage(CTopicMessage& Message) override { const CNick& Nick = Message.GetNick(); CChan& Channel = *Message.GetChan(); const CString sTopic = Message.GetTopic(); AddBuffer(Channel, t_f("{1} changed the topic to: {2}")( Nick.GetNickMask(), sTopic), &Message.GetTime(), Message.GetTags()); return CONTINUE; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("buffextras"); Info.AddType(CModInfo::NetworkModule); } USERMODULEDEFS(CBuffExtras, t_s("Adds joins, parts etc. to the playback buffer")) znc-1.7.5/modules/autoop.cpp0000644000175000017500000004701613542151610016233 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::map; using std::set; using std::vector; class CAutoOpMod; #define AUTOOP_CHALLENGE_LENGTH 32 class CAutoOpTimer : public CTimer { public: CAutoOpTimer(CAutoOpMod* pModule) : CTimer((CModule*)pModule, 20, 0, "AutoOpChecker", "Check channels for auto op candidates") { m_pParent = pModule; } ~CAutoOpTimer() override {} private: protected: void RunJob() override; CAutoOpMod* m_pParent; }; class CAutoOpUser { public: CAutoOpUser() {} CAutoOpUser(const CString& sLine) { FromString(sLine); } CAutoOpUser(const CString& sUsername, const CString& sUserKey, const CString& sHostmasks, const CString& sChannels) : m_sUsername(sUsername), m_sUserKey(sUserKey) { AddHostmasks(sHostmasks); AddChans(sChannels); } virtual ~CAutoOpUser() {} const CString& GetUsername() const { return m_sUsername; } const CString& GetUserKey() const { return m_sUserKey; } bool ChannelMatches(const CString& sChan) const { for (const CString& s : m_ssChans) { if (sChan.AsLower().WildCmp(s, CString::CaseInsensitive)) { return true; } } return false; } bool HostMatches(const CString& sHostmask) { for (const CString& s : m_ssHostmasks) { if (sHostmask.WildCmp(s, CString::CaseInsensitive)) { return true; } } return false; } CString GetHostmasks() const { return CString(",").Join(m_ssHostmasks.begin(), m_ssHostmasks.end()); } CString GetChannels() const { return CString(" ").Join(m_ssChans.begin(), m_ssChans.end()); } bool DelHostmasks(const CString& sHostmasks) { VCString vsHostmasks; sHostmasks.Split(",", vsHostmasks); for (const CString& s : vsHostmasks) { m_ssHostmasks.erase(s); } return m_ssHostmasks.empty(); } void AddHostmasks(const CString& sHostmasks) { VCString vsHostmasks; sHostmasks.Split(",", vsHostmasks); for (const CString& s : vsHostmasks) { m_ssHostmasks.insert(s); } } void DelChans(const CString& sChans) { VCString vsChans; sChans.Split(" ", vsChans); for (const CString& sChan : vsChans) { m_ssChans.erase(sChan.AsLower()); } } void AddChans(const CString& sChans) { VCString vsChans; sChans.Split(" ", vsChans); for (const CString& sChan : vsChans) { m_ssChans.insert(sChan.AsLower()); } } CString ToString() const { return m_sUsername + "\t" + GetHostmasks() + "\t" + m_sUserKey + "\t" + GetChannels(); } bool FromString(const CString& sLine) { m_sUsername = sLine.Token(0, false, "\t"); sLine.Token(1, false, "\t").Split(",", m_ssHostmasks); m_sUserKey = sLine.Token(2, false, "\t"); sLine.Token(3, false, "\t").Split(" ", m_ssChans); return !m_sUserKey.empty(); } private: protected: CString m_sUsername; CString m_sUserKey; set m_ssHostmasks; set m_ssChans; }; class CAutoOpMod : public CModule { public: MODCONSTRUCTOR(CAutoOpMod) { AddHelpCommand(); AddCommand("ListUsers", "", t_d("List all users"), [=](const CString& sLine) { OnListUsersCommand(sLine); }); AddCommand("AddChans", t_d(" [channel] ..."), t_d("Adds channels to a user"), [=](const CString& sLine) { OnAddChansCommand(sLine); }); AddCommand("DelChans", t_d(" [channel] ..."), t_d("Removes channels from a user"), [=](const CString& sLine) { OnDelChansCommand(sLine); }); AddCommand("AddMasks", t_d(" ,[mask] ..."), t_d("Adds masks to a user"), [=](const CString& sLine) { OnAddMasksCommand(sLine); }); AddCommand("DelMasks", t_d(" ,[mask] ..."), t_d("Removes masks from a user"), [=](const CString& sLine) { OnDelMasksCommand(sLine); }); AddCommand("AddUser", t_d(" [,...] [channels]"), t_d("Adds a user"), [=](const CString& sLine) { OnAddUserCommand(sLine); }); AddCommand("DelUser", t_d(""), t_d("Removes a user"), [=](const CString& sLine) { OnDelUserCommand(sLine); }); } bool OnLoad(const CString& sArgs, CString& sMessage) override { AddTimer(new CAutoOpTimer(this)); // Load the users for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { const CString& sLine = it->second; CAutoOpUser* pUser = new CAutoOpUser; if (!pUser->FromString(sLine) || FindUser(pUser->GetUsername().AsLower())) { delete pUser; } else { m_msUsers[pUser->GetUsername().AsLower()] = pUser; } } return true; } ~CAutoOpMod() override { for (const auto& it : m_msUsers) { delete it.second; } m_msUsers.clear(); } void OnJoin(const CNick& Nick, CChan& Channel) override { // If we have ops in this chan if (Channel.HasPerm(CChan::Op)) { CheckAutoOp(Nick, Channel); } } void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) override { MCString::iterator it = m_msQueue.find(Nick.GetNick().AsLower()); if (it != m_msQueue.end()) { m_msQueue.erase(it); } } void OnNick(const CNick& OldNick, const CString& sNewNick, const vector& vChans) override { // Update the queue with nick changes MCString::iterator it = m_msQueue.find(OldNick.GetNick().AsLower()); if (it != m_msQueue.end()) { m_msQueue[sNewNick.AsLower()] = it->second; m_msQueue.erase(it); } } EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override { if (!sMessage.Token(0).Equals("!ZNCAO")) { return CONTINUE; } CString sCommand = sMessage.Token(1); if (sCommand.Equals("CHALLENGE")) { ChallengeRespond(Nick, sMessage.Token(2)); } else if (sCommand.Equals("RESPONSE")) { VerifyResponse(Nick, sMessage.Token(2)); } return HALTCORE; } void OnOp2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override { if (Nick.GetNick() == GetNetwork()->GetIRCNick().GetNick()) { const map& msNicks = Channel.GetNicks(); for (const auto& it : msNicks) { if (!it.second.HasPerm(CChan::Op)) { CheckAutoOp(it.second, Channel); } } } } void OnModCommand(const CString& sLine) override { CString sCommand = sLine.Token(0).AsUpper(); if (sCommand.Equals("TIMERS")) { // for testing purposes - hidden from help ListTimers(); } else { HandleCommand(sLine); } } void OnAddUserCommand(const CString& sLine) { CString sUser = sLine.Token(1); CString sHost = sLine.Token(2); CString sKey = sLine.Token(3); if (sHost.empty()) { PutModule( t_s("Usage: AddUser [,...] " "[channels]")); } else { CAutoOpUser* pUser = AddUser(sUser, sKey, sHost, sLine.Token(4, true)); if (pUser) { SetNV(sUser, pUser->ToString()); } } } void OnDelUserCommand(const CString& sLine) { CString sUser = sLine.Token(1); if (sUser.empty()) { PutModule(t_s("Usage: DelUser ")); } else { DelUser(sUser); DelNV(sUser); } } void OnListUsersCommand(const CString& sLine) { if (m_msUsers.empty()) { PutModule(t_s("There are no users defined")); return; } CTable Table; Table.AddColumn(t_s("User")); Table.AddColumn(t_s("Hostmasks")); Table.AddColumn(t_s("Key")); Table.AddColumn(t_s("Channels")); for (const auto& it : m_msUsers) { VCString vsHostmasks; it.second->GetHostmasks().Split(",", vsHostmasks); for (unsigned int a = 0; a < vsHostmasks.size(); a++) { Table.AddRow(); if (a == 0) { Table.SetCell(t_s("User"), it.second->GetUsername()); Table.SetCell(t_s("Key"), it.second->GetUserKey()); Table.SetCell(t_s("Channels"), it.second->GetChannels()); } else if (a == vsHostmasks.size() - 1) { Table.SetCell(t_s("User"), "`-"); } else { Table.SetCell(t_s("User"), "|-"); } Table.SetCell(t_s("Hostmasks"), vsHostmasks[a]); } } PutModule(Table); } void OnAddChansCommand(const CString& sLine) { CString sUser = sLine.Token(1); CString sChans = sLine.Token(2, true); if (sChans.empty()) { PutModule(t_s("Usage: AddChans [channel] ...")); return; } CAutoOpUser* pUser = FindUser(sUser); if (!pUser) { PutModule(t_s("No such user")); return; } pUser->AddChans(sChans); PutModule(t_f("Channel(s) added to user {1}")(pUser->GetUsername())); SetNV(pUser->GetUsername(), pUser->ToString()); } void OnDelChansCommand(const CString& sLine) { CString sUser = sLine.Token(1); CString sChans = sLine.Token(2, true); if (sChans.empty()) { PutModule(t_s("Usage: DelChans [channel] ...")); return; } CAutoOpUser* pUser = FindUser(sUser); if (!pUser) { PutModule(t_s("No such user")); return; } pUser->DelChans(sChans); PutModule( t_f("Channel(s) Removed from user {1}")(pUser->GetUsername())); SetNV(pUser->GetUsername(), pUser->ToString()); } void OnAddMasksCommand(const CString& sLine) { CString sUser = sLine.Token(1); CString sHostmasks = sLine.Token(2, true); if (sHostmasks.empty()) { PutModule(t_s("Usage: AddMasks ,[mask] ...")); return; } CAutoOpUser* pUser = FindUser(sUser); if (!pUser) { PutModule(t_s("No such user")); return; } pUser->AddHostmasks(sHostmasks); PutModule(t_f("Hostmasks(s) added to user {1}")(pUser->GetUsername())); SetNV(pUser->GetUsername(), pUser->ToString()); } void OnDelMasksCommand(const CString& sLine) { CString sUser = sLine.Token(1); CString sHostmasks = sLine.Token(2, true); if (sHostmasks.empty()) { PutModule(t_s("Usage: DelMasks ,[mask] ...")); return; } CAutoOpUser* pUser = FindUser(sUser); if (!pUser) { PutModule(t_s("No such user")); return; } if (pUser->DelHostmasks(sHostmasks)) { PutModule(t_f("Removed user {1} with key {2} and channels {3}")( pUser->GetUsername(), pUser->GetUserKey(), pUser->GetChannels())); DelUser(sUser); DelNV(sUser); } else { PutModule(t_f("Hostmasks(s) Removed from user {1}")( pUser->GetUsername())); SetNV(pUser->GetUsername(), pUser->ToString()); } } CAutoOpUser* FindUser(const CString& sUser) { map::iterator it = m_msUsers.find(sUser.AsLower()); return (it != m_msUsers.end()) ? it->second : nullptr; } CAutoOpUser* FindUserByHost(const CString& sHostmask, const CString& sChannel = "") { for (const auto& it : m_msUsers) { CAutoOpUser* pUser = it.second; if (pUser->HostMatches(sHostmask) && (sChannel.empty() || pUser->ChannelMatches(sChannel))) { return pUser; } } return nullptr; } bool CheckAutoOp(const CNick& Nick, CChan& Channel) { CAutoOpUser* pUser = FindUserByHost(Nick.GetHostMask(), Channel.GetName()); if (!pUser) { return false; } if (pUser->GetUserKey().Equals("__NOKEY__")) { PutIRC("MODE " + Channel.GetName() + " +o " + Nick.GetNick()); } else { // then insert this nick into the queue, the timer does the rest CString sNick = Nick.GetNick().AsLower(); if (m_msQueue.find(sNick) == m_msQueue.end()) { m_msQueue[sNick] = ""; } } return true; } void DelUser(const CString& sUser) { map::iterator it = m_msUsers.find(sUser.AsLower()); if (it == m_msUsers.end()) { PutModule(t_s("No such user")); return; } delete it->second; m_msUsers.erase(it); PutModule(t_f("User {1} removed")(sUser)); } CAutoOpUser* AddUser(const CString& sUser, const CString& sKey, const CString& sHosts, const CString& sChans) { if (m_msUsers.find(sUser) != m_msUsers.end()) { PutModule(t_s("That user already exists")); return nullptr; } CAutoOpUser* pUser = new CAutoOpUser(sUser, sKey, sHosts, sChans); m_msUsers[sUser.AsLower()] = pUser; PutModule(t_f("User {1} added with hostmask(s) {2}")(sUser, sHosts)); return pUser; } bool ChallengeRespond(const CNick& Nick, const CString& sChallenge) { // Validate before responding - don't blindly trust everyone bool bValid = false; bool bMatchedHost = false; CAutoOpUser* pUser = nullptr; for (const auto& it : m_msUsers) { pUser = it.second; // First verify that the person who challenged us matches a user's // host if (pUser->HostMatches(Nick.GetHostMask())) { const vector& Chans = GetNetwork()->GetChans(); bMatchedHost = true; // Also verify that they are opped in at least one of the user's // chans for (CChan* pChan : Chans) { const CNick* pNick = pChan->FindNick(Nick.GetNick()); if (pNick) { if (pNick->HasPerm(CChan::Op) && pUser->ChannelMatches(pChan->GetName())) { bValid = true; break; } } } if (bValid) { break; } } } if (!bValid) { if (bMatchedHost) { PutModule(t_f( "[{1}] sent us a challenge but they are not opped in any " "defined channels.")(Nick.GetHostMask())); } else { PutModule( t_f("[{1}] sent us a challenge but they do not match a " "defined user.")(Nick.GetHostMask())); } return false; } if (sChallenge.length() != AUTOOP_CHALLENGE_LENGTH) { PutModule(t_f("WARNING! [{1}] sent an invalid challenge.")( Nick.GetHostMask())); return false; } CString sResponse = pUser->GetUserKey() + "::" + sChallenge; PutIRC("NOTICE " + Nick.GetNick() + " :!ZNCAO RESPONSE " + sResponse.MD5()); return false; } bool VerifyResponse(const CNick& Nick, const CString& sResponse) { MCString::iterator itQueue = m_msQueue.find(Nick.GetNick().AsLower()); if (itQueue == m_msQueue.end()) { PutModule( t_f("[{1}] sent an unchallenged response. This could be due " "to lag.")(Nick.GetHostMask())); return false; } CString sChallenge = itQueue->second; m_msQueue.erase(itQueue); for (const auto& it : m_msUsers) { if (it.second->HostMatches(Nick.GetHostMask())) { if (sResponse == CString(it.second->GetUserKey() + "::" + sChallenge) .MD5()) { OpUser(Nick, *it.second); return true; } else { PutModule( t_f("WARNING! [{1}] sent a bad response. Please " "verify that you have their correct password.")( Nick.GetHostMask())); return false; } } } PutModule( t_f("WARNING! [{1}] sent a response but did not match any defined " "users.")(Nick.GetHostMask())); return false; } void ProcessQueue() { bool bRemoved = true; // First remove any stale challenges while (bRemoved) { bRemoved = false; for (MCString::iterator it = m_msQueue.begin(); it != m_msQueue.end(); ++it) { if (!it->second.empty()) { m_msQueue.erase(it); bRemoved = true; break; } } } // Now issue challenges for the new users in the queue for (auto& it : m_msQueue) { it.second = CString::RandomString(AUTOOP_CHALLENGE_LENGTH); PutIRC("NOTICE " + it.first + " :!ZNCAO CHALLENGE " + it.second); } } void OpUser(const CNick& Nick, const CAutoOpUser& User) { const vector& Chans = GetNetwork()->GetChans(); for (CChan* pChan : Chans) { if (pChan->HasPerm(CChan::Op) && User.ChannelMatches(pChan->GetName())) { const CNick* pNick = pChan->FindNick(Nick.GetNick()); if (pNick && !pNick->HasPerm(CChan::Op)) { PutIRC("MODE " + pChan->GetName() + " +o " + Nick.GetNick()); } } } } private: map m_msUsers; MCString m_msQueue; }; void CAutoOpTimer::RunJob() { m_pParent->ProcessQueue(); } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("autoop"); } NETWORKMODULEDEFS(CAutoOpMod, t_s("Auto op the good people")) znc-1.7.5/modules/modperl.cpp0000644000175000017500000002746013542151610016367 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "modperl/module.h" #include "modperl/swigperlrun.h" #include #include #include #if defined(__APPLE__) && defined(__MACH__) #include // for _NSGetEnviron #endif #include "modperl/pstring.h" using std::set; using std::vector; // Allows perl to load .so files when needed by .pm // For example, it needs to load ZNC.so extern "C" { void boot_DynaLoader(pTHX_ CV* cv); static void xs_init(pTHX) { newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__); } } class CModPerl : public CModule { PerlInterpreter* m_pPerl; public: MODCONSTRUCTOR(CModPerl) { m_pPerl = nullptr; } #define PSTART \ dSP; \ I32 ax; \ int ret = 0; \ ENTER; \ SAVETMPS; \ PUSHMARK(SP) #define PCALL(name) \ PUTBACK; \ ret = call_pv(name, G_EVAL | G_ARRAY); \ SPAGAIN; \ SP -= ret; \ ax = (SP - PL_stack_base) + 1 #define PEND \ ax += 0; \ PUTBACK; \ FREETMPS; \ LEAVE #define PUSH_STR(s) XPUSHs(PString(s).GetSV()) #define PUSH_PTR(type, p) \ XPUSHs(SWIG_NewInstanceObj(const_cast(p), SWIG_TypeQuery(#type), \ SWIG_SHADOW)) bool OnLoad(const CString& sArgsi, CString& sMessage) override { CString sModPath, sTmp; if (!CModules::FindModPath("modperl/startup.pl", sModPath, sTmp)) { sMessage = "startup.pl not found."; return false; } sTmp = CDir::ChangeDir(sModPath, ".."); int argc = 6; char* pArgv[] = {"", "-T", "-w", "-I", const_cast(sTmp.c_str()), const_cast(sModPath.c_str()), nullptr}; char** argv = pArgv; char*** const pEnviron = #if defined(__APPLE__) && defined(__MACH__) _NSGetEnviron(); #else &environ; #endif PERL_SYS_INIT3(&argc, &argv, pEnviron); m_pPerl = perl_alloc(); perl_construct(m_pPerl); if (perl_parse(m_pPerl, xs_init, argc, argv, *pEnviron)) { sMessage = "Can't initialize perl. "; if (SvTRUE(ERRSV)) { sMessage += PString(ERRSV); } perl_free(m_pPerl); PERL_SYS_TERM(); m_pPerl = nullptr; DEBUG(__PRETTY_FUNCTION__ << " can't init perl"); return false; } PL_exit_flags |= PERL_EXIT_DESTRUCT_END; return true; } EModRet OnModuleLoading(const CString& sModName, const CString& sArgs, CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) override { EModRet result = HALT; PSTART; PUSH_STR(sModName); PUSH_STR(sArgs); mXPUSHi(eType); PUSH_PTR(CUser*, GetUser()); PUSH_PTR(CIRCNetwork*, GetNetwork()); PCALL("ZNC::Core::LoadModule"); if (SvTRUE(ERRSV)) { sRetMsg = PString(ERRSV); bSuccess = false; result = HALT; DEBUG("Perl ZNC::Core::LoadModule died: " << sRetMsg); } else if (ret < 1 || 2 < ret) { sRetMsg = "Error: Perl ZNC::Core::LoadModule returned " + CString(ret) + " values."; bSuccess = false; result = HALT; } else { ELoadPerlMod eLPM = static_cast(SvUV(ST(0))); if (Perl_NotFound == eLPM) { result = CONTINUE; // Not a Perl module } else { sRetMsg = PString(ST(1)); result = HALT; bSuccess = eLPM == Perl_Loaded; } } PEND; return result; } EModRet OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) override { CPerlModule* pMod = AsPerlModule(pModule); if (pMod) { EModRet result = HALT; CString sModName = pMod->GetModName(); PSTART; XPUSHs(pMod->GetPerlObj()); PCALL("ZNC::Core::UnloadModule"); if (SvTRUE(ERRSV)) { bSuccess = false; sRetMsg = PString(ERRSV); } else if (ret < 1 || 2 < ret) { sRetMsg = "Error: Perl ZNC::Core::UnloadModule returned " + CString(ret) + " values."; bSuccess = false; result = HALT; } else { int bUnloaded = SvUV(ST(0)); if (bUnloaded) { bSuccess = true; sRetMsg = "Module [" + sModName + "] unloaded"; result = HALT; } else { result = CONTINUE; // module wasn't loaded by modperl. // Perhaps a module-provider written in // perl did that. } } PEND; DEBUG(__PRETTY_FUNCTION__ << " " << sRetMsg); return result; } return CONTINUE; } EModRet OnGetModInfo(CModInfo& ModInfo, const CString& sModule, bool& bSuccess, CString& sRetMsg) override { PSTART; PUSH_STR(sModule); PUSH_PTR(CModInfo*, &ModInfo); PCALL("ZNC::Core::GetModInfo"); EModRet result = CONTINUE; if (SvTRUE(ERRSV)) { bSuccess = false; sRetMsg = PString(ERRSV); DEBUG("Perl ZNC::Core::GetModInfo died: " << sRetMsg); } else if (0 < ret) { switch (static_cast(SvUV(ST(0)))) { case Perl_NotFound: result = CONTINUE; break; case Perl_Loaded: result = HALT; if (1 == ret) { bSuccess = true; } else { bSuccess = false; sRetMsg = "Something weird happened"; } break; case Perl_LoadError: result = HALT; bSuccess = false; if (2 == ret) { sRetMsg = PString(ST(1)); } else { sRetMsg = "Something weird happened"; } } } else { result = HALT; bSuccess = false; sRetMsg = "Something weird happened"; } PEND; return result; } void OnGetAvailableMods(set& ssMods, CModInfo::EModuleType eType) override { unsigned int a = 0; CDir Dir; CModules::ModDirList dirs = CModules::GetModDirs(); while (!dirs.empty()) { Dir.FillByWildcard(dirs.front().first, "*.pm"); dirs.pop(); for (a = 0; a < Dir.size(); a++) { CFile& File = *Dir[a]; CString sName = File.GetShortName(); CString sPath = File.GetLongName(); CModInfo ModInfo; sName.RightChomp(3); PSTART; PUSH_STR(sPath); PUSH_STR(sName); PUSH_PTR(CModInfo*, &ModInfo); PCALL("ZNC::Core::ModInfoByPath"); if (SvTRUE(ERRSV)) { DEBUG(__PRETTY_FUNCTION__ << ": " << sPath << ": " << PString(ERRSV)); } else if (ModInfo.SupportsType(eType)) { ssMods.insert(ModInfo); } PEND; } } } ~CModPerl() override { if (m_pPerl) { PSTART; PCALL("ZNC::Core::UnloadAll"); PEND; perl_destruct(m_pPerl); perl_free(m_pPerl); PERL_SYS_TERM(); } } }; #include "modperl/perlfunctions.cpp" VWebSubPages& CPerlModule::GetSubPages() { VWebSubPages* result = _GetSubPages(); if (!result) { return CModule::GetSubPages(); } return *result; } void CPerlTimer::RunJob() { CPerlModule* pMod = AsPerlModule(GetModule()); if (pMod) { PSTART; XPUSHs(GetPerlObj()); PCALL("ZNC::Core::CallTimer"); PEND; } } CPerlTimer::~CPerlTimer() { CPerlModule* pMod = AsPerlModule(GetModule()); if (pMod) { PSTART; XPUSHs(sv_2mortal(m_perlObj)); PCALL("ZNC::Core::RemoveTimer"); PEND; } } #define SOCKSTART \ PSTART; \ XPUSHs(GetPerlObj()) #define SOCKCBCHECK(OnSuccess) \ PCALL("ZNC::Core::CallSocket"); \ if (SvTRUE(ERRSV)) { \ Close(); \ DEBUG("Perl socket hook died with: " + PString(ERRSV)); \ } else { \ OnSuccess; \ } \ PEND #define CBSOCK(Func) \ void CPerlSocket::Func() { \ CPerlModule* pMod = AsPerlModule(GetModule()); \ if (pMod) { \ SOCKSTART; \ PUSH_STR("On" #Func); \ SOCKCBCHECK(); \ } \ } CBSOCK(Connected); CBSOCK(Disconnected); CBSOCK(Timeout); CBSOCK(ConnectionRefused); void CPerlSocket::ReadData(const char* data, size_t len) { CPerlModule* pMod = AsPerlModule(GetModule()); if (pMod) { SOCKSTART; PUSH_STR("OnReadData"); XPUSHs(sv_2mortal(newSVpvn(data, len))); mXPUSHi(len); SOCKCBCHECK(); } } void CPerlSocket::ReadLine(const CString& sLine) { CPerlModule* pMod = AsPerlModule(GetModule()); if (pMod) { SOCKSTART; PUSH_STR("OnReadLine"); PUSH_STR(sLine); SOCKCBCHECK(); } } Csock* CPerlSocket::GetSockObj(const CString& sHost, unsigned short uPort) { CPerlModule* pMod = AsPerlModule(GetModule()); Csock* result = nullptr; if (pMod) { SOCKSTART; PUSH_STR("_Accepted"); PUSH_STR(sHost); mXPUSHi(uPort); SOCKCBCHECK(result = SvToPtr("CPerlSocket*")(ST(0));); } return result; } CPerlSocket::~CPerlSocket() { CPerlModule* pMod = AsPerlModule(GetModule()); if (pMod) { PSTART; XPUSHs(sv_2mortal(m_perlObj)); PCALL("ZNC::Core::RemoveSocket"); PEND; } } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("modperl"); } GLOBALMODULEDEFS(CModPerl, t_s("Loads perl scripts as ZNC modules")) znc-1.7.5/modules/modperl/0000755000175000017500000000000013542151622015655 5ustar somebodysomebodyznc-1.7.5/modules/modperl/Makefile.inc0000644000175000017500000000551113542151610020064 0ustar somebodysomebody# vim: filetype=make ifeq "$(PERL_ON)" "yes" # We execute this now so that we see the 'beauty' of these flags in make's output PERL_CXX := $(shell $(PERL) -MExtUtils::Embed -e perl_inc) PERL_LD := $(shell $(PERL) -MExtUtils::Embed -e ldopts) # Perl API is ugly, casting string literals to char* and redeclaring functions :( PERL_CXX += -Wno-write-strings -Wno-redundant-decls -Wno-missing-declarations PERL_CXX += -Wno-type-limits -Wno-sign-compare -Wno-strict-overflow -Wno-unused-value # perl 5.20 will fix this warning: https://rt.perl.org/Public/Bug/Display.html?id=120670 PERL_CXX += -Wno-reserved-user-defined-literal -Wno-literal-suffix # This is for SWIG PERL_CXX += -DSWIG_TYPE_TABLE=znc PERLCEXT_EXT := $(shell $(PERL) -MConfig -e'print $$Config::Config{dlext}') modperlCXXFLAGS := $(PERL_CXX) -Wno-unused-function modperlLDFLAGS := $(PERL_LD) # Find additional headers for out-of-tree build modperlCXXFLAGS += -I. ifeq "$(ISCYGWIN)" "1" PERLDEPONMOD := modperl.so else PERLDEPONMOD := endif PERLHOOK := modperl_install CLEAN += modperl/ZNC.$(PERLCEXT_EXT) modperl/ZNC.o modperl/gen ifneq "$(SWIG)" "" # Only delete these files if we can regenerate them CLEAN += modperl/ZNC.pm modperl/swigperlrun.h modperl/modperl_biglib.cpp modperl/perlfunctions.cpp endif all: modperl_all else FILES := $(shell echo $(FILES) | sed -e "s/modperl//") endif .PHONY: modperl_install modperl_all install: $(PERLHOOK) modperl_all: modperl/ZNC.$(PERLCEXT_EXT) modperl/swigperlrun.h modperl/perlfunctions.cpp modperl/ZNC.$(PERLCEXT_EXT): modperl/ZNC.o Makefile modperl.so $(E) Linking ZNC Perl bindings library... $(Q)$(CXX) $(MODFLAGS) $(LDFLAGS) $(MODLINK) -o $@ $< $(PERL_LD) $(PERLDEPONMOD) $(LIBS) modperl/ZNC.o: modperl/modperl_biglib.cpp Makefile @mkdir -p modperl @mkdir -p .depend $(E) Building ZNC Perl bindings library... $(Q)$(CXX) $(MODFLAGS) -I$(srcdir) -MD -MF .depend/modperl.library.dep $(PERL_CXX) -Wno-unused-variable -Wno-shadow -o $@ $< -c ifneq "$(SWIG)" "" include $(srcdir)/modperl/Makefile.gen else modperl/swigperlrun.h modperl/ZNC.pm modperl/perlfunctions.cpp: modperl/modperl_biglib.cpp modperl/modperl_biglib.cpp: modperl/generated.tar.gz @mkdir -p modperl $(E) Unpacking ZNC Perl bindings... $(Q)tar -xf $^ -C modperl endif modperl.o: modperl/perlfunctions.cpp modperl/swigperlrun.h modperl_install: install_datadir modperl_all for i in $(wildcard $(srcdir)/*.pm); do \ $(INSTALL_DATA) $$i $(DESTDIR)$(MODDIR); \ done mkdir -p $(DESTDIR)$(MODDIR)/modperl $(INSTALL_PROGRAM) modperl/ZNC.$(PERLCEXT_EXT) $(DESTDIR)$(MODDIR)/modperl if test -e modperl/ZNC.pm ; then \ $(INSTALL_DATA) modperl/ZNC.pm $(DESTDIR)$(MODDIR)/modperl || exit 1 ; \ else \ $(INSTALL_DATA) $(srcdir)/modperl/ZNC.pm $(DESTDIR)$(MODDIR)/modperl || exit 1 ; \ fi $(INSTALL_DATA) $(srcdir)/modperl/startup.pl $(DESTDIR)$(MODDIR)/modperl znc-1.7.5/modules/modperl/CMakeLists.txt0000644000175000017500000001007413542151610020414 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # TODO: consider switching to swig_add_library() after bumping CMake # requirements to 3.8, when that command started using IMPLICIT_DEPENDS set(modinclude_modperl PUBLIC ${PERL_INCLUDE_DIRS} "${CMAKE_CURRENT_BINARY_DIR}/.." PARENT_SCOPE) set(modcompile_modperl PUBLIC "${PERL_CFLAGS}" PARENT_SCOPE) set(modlink_modperl PUBLIC ${PERL_LIBRARIES} PARENT_SCOPE) set(modprop_modperl LINK_FLAGS "${PERL_LDFLAGS}" PARENT_SCOPE) set(moddef_modperl PUBLIC "SWIG_TYPE_TABLE=znc" PARENT_SCOPE) set(moddepend_modperl modperl_functions modperl_swigruntime PARENT_SCOPE) if(APPLE) set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS "${CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS} -undefined dynamic_lookup") endif() if(SWIG_FOUND) add_custom_command( OUTPUT perlfunctions.cpp COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl" "${CMAKE_CURRENT_SOURCE_DIR}/functions.in" "perlfunctions.cpp" VERBATIM DEPENDS codegen.pl functions.in) add_custom_command( OUTPUT swigperlrun.h COMMAND "${SWIG_EXECUTABLE}" -perl -c++ -shadow -external-runtime "swigperlrun.h" VERBATIM) add_custom_command( OUTPUT modperl_biglib.cpp ZNC.pm COMMAND "${SWIG_EXECUTABLE}" -perl -c++ -shadow "-I${PROJECT_BINARY_DIR}/include" "-I${PROJECT_SOURCE_DIR}/include" "-I${CMAKE_CURRENT_SOURCE_DIR}/.." "-I${CMAKE_CURRENT_SOURCE_DIR}/include" -DZNC_EXPORT_LIB_EXPORT -outdir "${CMAKE_CURRENT_BINARY_DIR}" -o "${CMAKE_CURRENT_BINARY_DIR}/modperl_biglib.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/modperl.i" DEPENDS "modperl.i" copy_csocket_h IMPLICIT_DEPENDS CXX "${CMAKE_CURRENT_SOURCE_DIR}/modperl.i" VERBATIM) else() add_custom_command( OUTPUT swigperlrun.h ZNC.pm modperl_biglib.cpp perlfunctions.cpp COMMAND "${CMAKE_COMMAND}" -E tar xz "${CMAKE_CURRENT_SOURCE_DIR}/generated.tar.gz" VERBATIM) endif() add_custom_target(modperl_functions DEPENDS "perlfunctions.cpp") add_custom_target(modperl_swigruntime DEPENDS "swigperlrun.h") add_custom_target(modperl_swig DEPENDS "modperl_biglib.cpp" "ZNC.pm") execute_process(COMMAND "${PERL_EXECUTABLE}" -MConfig "-eprint $Config::Config{dlext}" OUTPUT_VARIABLE perl_ext) znc_add_library(modperl_lib MODULE modperl_biglib.cpp) add_dependencies(modperl_lib modperl_swig) target_include_directories(modperl_lib PRIVATE "${PROJECT_BINARY_DIR}/include" "${PROJECT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/.." "${CMAKE_CURRENT_SOURCE_DIR}/.." ${PERL_INCLUDE_DIRS}) target_link_libraries(modperl_lib ${znc_link}) set_target_properties(modperl_lib PROPERTIES PREFIX "" SUFFIX ".${perl_ext}" OUTPUT_NAME "ZNC" NO_SONAME true LINK_FLAGS "${PERL_LDFLAGS}") target_compile_options(modperl_lib PRIVATE "${PERL_CFLAGS}") target_compile_definitions(modperl_lib PRIVATE "SWIG_TYPE_TABLE=znc") if(CYGWIN) target_link_libraries(modperl_lib module_modperl) endif() install(TARGETS modperl_lib LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/znc/modperl") install(FILES "startup.pl" "${CMAKE_CURRENT_BINARY_DIR}/ZNC.pm" DESTINATION "${CMAKE_INSTALL_LIBDIR}/znc/modperl") function(add_perl_module mod modpath) install(FILES "${modpath}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/znc") endfunction() # This target is used to generate tarball which doesn't depend on SWIG. add_custom_target(modperl_dist COMMAND "${CMAKE_COMMAND}" -E tar cz "${CMAKE_CURRENT_SOURCE_DIR}/generated.tar.gz" "swigperlrun.h" "ZNC.pm" "modperl_biglib.cpp" "perlfunctions.cpp" DEPENDS swigperlrun.h ZNC.pm modperl_biglib.cpp perlfunctions.cpp VERBATIM) add_dependencies(modperl_dist copy_csocket_h) znc-1.7.5/modules/modperl/functions.in0000644000175000017500000001257713542151610020226 0ustar somebodysomebodybool OnBoot() bool WebRequiresLogin() bool WebRequiresAdmin() CString GetWebMenuTitle() bool OnWebPreRequest(CWebSock& WebSock, const CString& sPageName) bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) bool ValidateWebRequestCSRFCheck(CWebSock& WebSock, const CString& sPageName) VWebSubPages* _GetSubPages()=nullptr void OnPreRehash() void OnPostRehash() void OnIRCDisconnected() void OnIRCConnected() EModRet OnIRCConnecting(CIRCSock *pIRCSock) void OnIRCConnectionError(CIRCSock *pIRCSock) EModRet OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) EModRet OnBroadcast(CString& sMessage) void OnChanPermission2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) void OnOp2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) void OnDeop2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) void OnVoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) void OnDevoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) void OnMode2(const CNick* pOpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) void OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) EModRet OnRaw(CString& sLine) EModRet OnStatusCommand(CString& sCommand) void OnModCommand(const CString& sCommand) void OnModNotice(const CString& sMessage) void OnModCTCP(const CString& sMessage) void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) void OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans) void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) EModRet OnJoining(CChan& Channel) void OnJoin(const CNick& Nick, CChan& Channel) void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) EModRet OnInvite(const CNick& Nick, const CString& sChan) EModRet OnChanBufferStarting(CChan& Chan, CClient& Client) EModRet OnChanBufferEnding(CChan& Chan, CClient& Client) EModRet OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) EModRet OnPrivBufferPlayLine(CClient& Client, CString& sLine) void OnClientLogin() void OnClientDisconnect() EModRet OnUserRaw(CString& sLine) EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage) EModRet OnUserCTCP(CString& sTarget, CString& sMessage) EModRet OnUserAction(CString& sTarget, CString& sMessage) EModRet OnUserMsg(CString& sTarget, CString& sMessage) EModRet OnUserNotice(CString& sTarget, CString& sMessage) EModRet OnUserJoin(CString& sChannel, CString& sKey) EModRet OnUserPart(CString& sChannel, CString& sMessage) EModRet OnUserTopic(CString& sChannel, CString& sTopic) EModRet OnUserTopicRequest(CString& sChannel) EModRet OnUserQuit(CString& sMessage) EModRet OnCTCPReply(CNick& Nick, CString& sMessage) EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) EModRet OnPrivAction(CNick& Nick, CString& sMessage) EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) EModRet OnPrivMsg(CNick& Nick, CString& sMessage) EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) EModRet OnPrivNotice(CNick& Nick, CString& sMessage) EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) bool OnServerCapAvailable(const CString& sCap) void OnServerCapResult(const CString& sCap, bool bSuccess) EModRet OnTimerAutoJoin(CChan& Channel) bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) EModRet OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet) EModRet OnDeleteNetwork(CIRCNetwork& Network) EModRet OnSendToClient(CString& sLine, CClient& Client) EModRet OnSendToIRC(CString& sLine) EModRet OnRawMessage(CMessage& Message) EModRet OnNumericMessage(CNumericMessage& Message) void OnQuitMessage(CQuitMessage& Message, const std::vector& vChans) void OnNickMessage(CNickMessage& Message, const std::vector& vChans) void OnKickMessage(CKickMessage& Message) void OnJoinMessage(CJoinMessage& Message) void OnPartMessage(CPartMessage& Message) EModRet OnChanBufferPlayMessage(CMessage& Message) EModRet OnPrivBufferPlayMessage(CMessage& Message) EModRet OnUserRawMessage(CMessage& Message) EModRet OnUserCTCPReplyMessage(CCTCPMessage& Message) EModRet OnUserCTCPMessage(CCTCPMessage& Message) EModRet OnUserActionMessage(CActionMessage& Message) EModRet OnUserTextMessage(CTextMessage& Message) EModRet OnUserNoticeMessage(CNoticeMessage& Message) EModRet OnUserJoinMessage(CJoinMessage& Message) EModRet OnUserPartMessage(CPartMessage& Message) EModRet OnUserTopicMessage(CTopicMessage& Message) EModRet OnUserQuitMessage(CQuitMessage& Message) EModRet OnCTCPReplyMessage(CCTCPMessage& Message) EModRet OnPrivCTCPMessage(CCTCPMessage& Message) EModRet OnChanCTCPMessage(CCTCPMessage& Message) EModRet OnPrivActionMessage(CActionMessage& Message) EModRet OnChanActionMessage(CActionMessage& Message) EModRet OnPrivTextMessage(CTextMessage& Message) EModRet OnChanTextMessage(CTextMessage& Message) EModRet OnPrivNoticeMessage(CNoticeMessage& Message) EModRet OnChanNoticeMessage(CNoticeMessage& Message) EModRet OnTopicMessage(CTopicMessage& Message) EModRet OnSendToClientMessage(CMessage& Message) EModRet OnSendToIRCMessage(CMessage& Message) znc-1.7.5/modules/modperl/CString.i0000644000175000017500000003262513542151610017405 0ustar somebodysomebody/* SWIG-generated sources are used here. This file is generated using: echo '%include ' > foo.i swig -perl -c++ -shadow -E foo.i > string.i Remove unrelated stuff from top of file which is included by default s/std::string/CString/g s/std_string/CString/g */ %fragment(""); %feature("naturalvar") CString; class CString; /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,70,%typemaps_CString@*/ /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,4,%CString_asptr@*/ %fragment("SWIG_" "AsPtr" "_" {CString},"header",fragment="SWIG_AsCharPtrAndSize") { SWIGINTERN int SWIG_AsPtr_CString SWIG_PERL_DECL_ARGS_2(SV * obj, CString **val) { char* buf = 0 ; size_t size = 0; int alloc = SWIG_OLDOBJ; if (SWIG_IsOK((SWIG_AsCharPtrAndSize(obj, &buf, &size, &alloc)))) { if (buf) { if (val) *val = new CString(buf, size - 1); if (alloc == SWIG_NEWOBJ) delete[] buf; return SWIG_NEWOBJ; } else { if (val) *val = 0; return SWIG_OLDOBJ; } } else { static int init = 0; static swig_type_info* descriptor = 0; if (!init) { descriptor = SWIG_TypeQuery("CString" " *"); init = 1; } if (descriptor) { CString *vptr; int res = SWIG_ConvertPtr(obj, (void**)&vptr, descriptor, 0); if (SWIG_IsOK(res) && val) *val = vptr; return res; } } return SWIG_ERROR; } } /*@SWIG@*/ /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,48,%CString_asval@*/ %fragment("SWIG_" "AsVal" "_" {CString},"header", fragment="SWIG_" "AsPtr" "_" {CString}) { SWIGINTERN int SWIG_AsVal_CString SWIG_PERL_DECL_ARGS_2(SV * obj, CString *val) { CString* v = (CString *) 0; int res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2(obj, &v); if (!SWIG_IsOK(res)) return res; if (v) { if (val) *val = *v; if (SWIG_IsNewObj(res)) { delete v; res = SWIG_DelNewMask(res); } return res; } return SWIG_ERROR; } } /*@SWIG@*/ /*@SWIG:/swig/3.0.8/typemaps/CStrings.swg,38,%CString_from@*/ %fragment("SWIG_" "From" "_" {CString},"header",fragment="SWIG_FromCharPtrAndSize") { SWIGINTERNINLINE SV * SWIG_From_CString SWIG_PERL_DECL_ARGS_1(const CString& s) { return SWIG_FromCharPtrAndSize(s.data(), s.size()); } } /*@SWIG@*/ /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,201,%typemaps_asptrfromn@*/ /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,190,%typemaps_asptrfrom@*/ /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,160,%typemaps_asptr@*/ %fragment("SWIG_" "AsVal" "_" {CString},"header",fragment="SWIG_" "AsPtr" "_" {CString}) { SWIGINTERNINLINE int SWIG_AsVal_CString SWIG_PERL_CALL_ARGS_2(SV * obj, CString *val) { CString *v = (CString *)0; int res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2(obj, &v); if (!SWIG_IsOK(res)) return res; if (v) { if (val) *val = *v; if (SWIG_IsNewObj(res)) { delete v; res = SWIG_DelNewMask(res); } return res; } return SWIG_ERROR; } } /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,28,%ptr_in_typemap@*/ %typemap(in,fragment="SWIG_" "AsPtr" "_" {CString}) CString { CString *ptr = (CString *)0; int res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, &ptr); if (!SWIG_IsOK(res) || !ptr) { SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } $1 = *ptr; if (SWIG_IsNewObj(res)) delete ptr; } %typemap(freearg) CString ""; %typemap(in,fragment="SWIG_" "AsPtr" "_" {CString}) const CString & (int res = SWIG_OLDOBJ) { CString *ptr = (CString *)0; res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, &ptr); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } if (!ptr) { SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } $1 = ptr; } %typemap(freearg,noblock=1) const CString & { if (SWIG_IsNewObj(res$argnum)) delete $1; } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,53,%ptr_varin_typemap@*/ %typemap(varin,fragment="SWIG_" "AsPtr" "_" {CString}) CString { CString *ptr = (CString *)0; int res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, &ptr); if (!SWIG_IsOK(res) || !ptr) { SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in variable '""$name""' of type '""$type""'"); } $1 = *ptr; if (SWIG_IsNewObj(res)) delete ptr; } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,68,%ptr_directorout_typemap@*/ %typemap(directorargout,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString *DIRECTOROUT ($*ltype temp, int swig_ores) { CString *swig_optr = 0; swig_ores = $result ? SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($result, &swig_optr) : 0; if (!SWIG_IsOK(swig_ores) || !swig_optr) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ArgError((swig_optr ? swig_ores : SWIG_TypeError))), "in output value of type '""$type""'"); } temp = *swig_optr; $1 = &temp; if (SWIG_IsNewObj(swig_ores)) delete swig_optr; } %typemap(directorout,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString { CString *swig_optr = 0; int swig_ores = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, &swig_optr); if (!SWIG_IsOK(swig_ores) || !swig_optr) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ArgError((swig_optr ? swig_ores : SWIG_TypeError))), "in output value of type '""$type""'"); } $result = *swig_optr; if (SWIG_IsNewObj(swig_ores)) delete swig_optr; } %typemap(directorout,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString},warning= "473:Returning a pointer or reference in a director method is not recommended." ) CString* { CString *swig_optr = 0; int swig_ores = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, &swig_optr); if (!SWIG_IsOK(swig_ores)) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ArgError(swig_ores)), "in output value of type '""$type""'"); } $result = swig_optr; if (SWIG_IsNewObj(swig_ores)) { swig_acquire_ownership(swig_optr); } } %typemap(directorfree,noblock=1) CString* { if (director) { director->swig_release_ownership(SWIG_as_voidptr($input)); } } %typemap(directorout,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString},warning= "473:Returning a pointer or reference in a director method is not recommended." ) CString& { CString *swig_optr = 0; int swig_ores = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, &swig_optr); if (!SWIG_IsOK(swig_ores)) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ArgError(swig_ores)), "in output value of type '""$type""'"); } else { if (!swig_optr) { Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(SWIG_ValueError), "invalid null reference " "in output value of type '""$type""'"); } } $result = swig_optr; if (SWIG_IsNewObj(swig_ores)) { swig_acquire_ownership(swig_optr); } } %typemap(directorfree,noblock=1) CString& { if (director) { director->swig_release_ownership(SWIG_as_voidptr($input)); } } %typemap(directorout,fragment="SWIG_" "AsPtr" "_" {CString}) CString &DIRECTOROUT = CString /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/ptrtypes.swg,143,%ptr_typecheck_typemap@*/ %typemap(typecheck,noblock=1,precedence=135,fragment="SWIG_" "AsPtr" "_" {CString}) CString * { int res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, (CString**)(0)); $1 = SWIG_CheckState(res); } %typemap(typecheck,noblock=1,precedence=135,fragment="SWIG_" "AsPtr" "_" {CString}) CString, const CString& { int res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, (CString**)(0)); $1 = SWIG_CheckState(res); } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,254,%ptr_input_typemap@*/ /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,117,%_ptr_input_typemap@*/ %typemap(in,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString *INPUT(int res = 0) { res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, &$1); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } res = SWIG_AddTmpMask(res); } %typemap(in,noblock=1,fragment="SWIG_" "AsPtr" "_" {CString}) CString &INPUT(int res = 0) { res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, &$1); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } if (!$1) { SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "$symname" "', argument " "$argnum"" of type '" "$type""'"); } res = SWIG_AddTmpMask(res); } %typemap(freearg,noblock=1,match="in") CString *INPUT, CString &INPUT { if (SWIG_IsNewObj(res$argnum)) delete $1; } %typemap(typecheck,noblock=1,precedence=135,fragment="SWIG_" "AsPtr" "_" {CString}) CString *INPUT, CString &INPUT { int res = SWIG_AsPtr_CString SWIG_PERL_CALL_ARGS_2($input, (CString**)0); $1 = SWIG_CheckState(res); } /*@SWIG@*/ /*@SWIG@*/; /*@SWIG@*/ /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,183,%typemaps_from@*/ /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,55,%value_out_typemap@*/ %typemap(out,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString, const CString { $result = SWIG_From_CString SWIG_PERL_CALL_ARGS_1(static_cast< CString >($1)); argvi++ ; } %typemap(out,noblock=1,fragment="SWIG_" "From" "_" {CString}) const CString& { $result = SWIG_From_CString SWIG_PERL_CALL_ARGS_1(static_cast< CString >(*$1)); argvi++ ; } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,79,%value_varout_typemap@*/ %typemap(varout,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString, const CString& { sv_setsv($result,SWIG_From_CString SWIG_PERL_CALL_ARGS_1(static_cast< CString >($1))) ; } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,87,%value_constcode_typemap@*/ %typemap(constcode,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString { /*@SWIG:/swig/3.0.8/perl5/perltypemaps.swg,65,%set_constant@*/ do { SV *sv = get_sv((char*) SWIG_prefix "$symname", TRUE | 0x2 | GV_ADDMULTI); sv_setsv(sv, SWIG_From_CString SWIG_PERL_CALL_ARGS_1(static_cast< CString >($value))); SvREADONLY_on(sv); } while(0) /*@SWIG@*/; } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,98,%value_directorin_typemap@*/ %typemap(directorin,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString *DIRECTORIN { $input = SWIG_From_CString SWIG_PERL_CALL_ARGS_1(static_cast< CString >(*$1)); } %typemap(directorin,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString, const CString& { $input = SWIG_From_CString SWIG_PERL_CALL_ARGS_1(static_cast< CString >($1)); } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/valtypes.swg,153,%value_throws_typemap@*/ %typemap(throws,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString { sv_setsv(get_sv("@", GV_ADD), SWIG_From_CString SWIG_PERL_CALL_ARGS_1(static_cast< CString >($1))); SWIG_fail ; } /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,258,%value_output_typemap@*/ /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,175,%_value_output_typemap@*/ %typemap(in,numinputs=0,noblock=1) CString *OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ), CString &OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ) { $1 = &temp; } %typemap(argout,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString *OUTPUT, CString &OUTPUT { if (SWIG_IsTmpObj(res$argnum)) { if (argvi >= items) EXTEND(sp,1); $result = SWIG_From_CString SWIG_PERL_CALL_ARGS_1((*$1)); argvi++ ; } else { int new_flags = SWIG_IsNewObj(res$argnum) ? (SWIG_POINTER_OWN | $shadow) : $shadow; if (argvi >= items) EXTEND(sp,1); $result = SWIG_NewPointerObj((void*)($1), $1_descriptor, new_flags); argvi++ ; } } /*@SWIG@*/ /*@SWIG@*/; /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,258,%value_output_typemap@*/ /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,175,%_value_output_typemap@*/ %typemap(in,numinputs=0,noblock=1) CString *OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ), CString &OUTPUT ($*1_ltype temp, int res = SWIG_TMPOBJ) { $1 = &temp; } %typemap(argout,noblock=1,fragment="SWIG_" "From" "_" {CString}) CString *OUTPUT, CString &OUTPUT { if (SWIG_IsTmpObj(res$argnum)) { if (argvi >= items) EXTEND(sp,1); $result = SWIG_From_CString SWIG_PERL_CALL_ARGS_1((*$1)); argvi++ ; } else { int new_flags = SWIG_IsNewObj(res$argnum) ? (SWIG_POINTER_OWN | $shadow) : $shadow; if (argvi >= items) EXTEND(sp,1); $result = SWIG_NewPointerObj((void*)($1), $1_descriptor, new_flags); argvi++ ; } } /*@SWIG@*/ /*@SWIG@*/; /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,240,%_ptr_inout_typemap@*/ /*@SWIG:/swig/3.0.8/typemaps/inoutlist.swg,230,%_value_inout_typemap@*/ %typemap(in) CString *INOUT = CString *INPUT; %typemap(in) CString &INOUT = CString &INPUT; %typemap(typecheck) CString *INOUT = CString *INPUT; %typemap(typecheck) CString &INOUT = CString &INPUT; %typemap(argout) CString *INOUT = CString *OUTPUT; %typemap(argout) CString &INOUT = CString &OUTPUT; /*@SWIG@*/ %typemap(typecheck) CString *INOUT = CString *INPUT; %typemap(typecheck) CString &INOUT = CString &INPUT; %typemap(freearg) CString *INOUT = CString *INPUT; %typemap(freearg) CString &INOUT = CString &INPUT; /*@SWIG@*/; /*@SWIG@*/ ; /*@SWIG@*/; /*@SWIG@*/; znc-1.7.5/modules/modperl/module.h0000644000175000017500000002520113542151610017310 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include class ZNC_EXPORT_LIB_EXPORT CPerlModule : public CModule { SV* m_perlObj; VWebSubPages* _GetSubPages(); public: CPerlModule(CUser* pUser, CIRCNetwork* pNetwork, const CString& sModName, const CString& sDataPath, CModInfo::EModuleType eType, SV* perlObj) : CModule(nullptr, pUser, pNetwork, sModName, sDataPath, eType) { m_perlObj = newSVsv(perlObj); } SV* GetPerlObj() { return sv_2mortal(newSVsv(m_perlObj)); } bool OnBoot() override; bool WebRequiresLogin() override; bool WebRequiresAdmin() override; CString GetWebMenuTitle() override; bool OnWebPreRequest(CWebSock& WebSock, const CString& sPageName) override; bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override; bool ValidateWebRequestCSRFCheck(CWebSock& WebSock, const CString& sPageName) override; VWebSubPages& GetSubPages() override; void OnPreRehash() override; void OnPostRehash() override; void OnIRCDisconnected() override; void OnIRCConnected() override; EModRet OnIRCConnecting(CIRCSock* pIRCSock) override; void OnIRCConnectionError(CIRCSock* pIRCSock) override; EModRet OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) override; EModRet OnBroadcast(CString& sMessage) override; void OnChanPermission2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) override; void OnOp2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override; void OnDeop2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override; void OnVoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override; void OnDevoice2(const CNick* pOpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override; void OnMode2(const CNick* pOpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) override; void OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) override; EModRet OnRaw(CString& sLine) override; EModRet OnStatusCommand(CString& sCommand) override; void OnModCommand(const CString& sCommand) override; void OnModNotice(const CString& sMessage) override; void OnModCTCP(const CString& sMessage) override; void OnQuit(const CNick& Nick, const CString& sMessage, const std::vector& vChans) override; void OnNick(const CNick& Nick, const CString& sNewNick, const std::vector& vChans) override; void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) override; EModRet OnJoining(CChan& Channel) override; void OnJoin(const CNick& Nick, CChan& Channel) override; void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) override; EModRet OnInvite(const CNick& Nick, const CString& sChan) override; EModRet OnChanBufferStarting(CChan& Chan, CClient& Client) override; EModRet OnChanBufferEnding(CChan& Chan, CClient& Client) override; EModRet OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) override; EModRet OnPrivBufferPlayLine(CClient& Client, CString& sLine) override; void OnClientLogin() override; void OnClientDisconnect() override; EModRet OnUserRaw(CString& sLine) override; EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage) override; EModRet OnUserCTCP(CString& sTarget, CString& sMessage) override; EModRet OnUserAction(CString& sTarget, CString& sMessage) override; EModRet OnUserMsg(CString& sTarget, CString& sMessage) override; EModRet OnUserNotice(CString& sTarget, CString& sMessage) override; EModRet OnUserJoin(CString& sChannel, CString& sKey) override; EModRet OnUserPart(CString& sChannel, CString& sMessage) override; EModRet OnUserTopic(CString& sChannel, CString& sTopic) override; EModRet OnUserQuit(CString& sMessage) override; EModRet OnUserTopicRequest(CString& sChannel) override; EModRet OnCTCPReply(CNick& Nick, CString& sMessage) override; EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override; EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) override; EModRet OnPrivAction(CNick& Nick, CString& sMessage) override; EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) override; EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override; EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override; EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override; EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) override; EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) override; bool OnServerCapAvailable(const CString& sCap) override; void OnServerCapResult(const CString& sCap, bool bSuccess) override; EModRet OnTimerAutoJoin(CChan& Channel) override; bool OnEmbeddedWebRequest(CWebSock&, const CString&, CTemplate&) override; EModRet OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet) override; EModRet OnDeleteNetwork(CIRCNetwork& Network) override; EModRet OnSendToClient(CString& sLine, CClient& Client) override; EModRet OnSendToIRC(CString& sLine) override; EModRet OnRawMessage(CMessage& Message) override; EModRet OnNumericMessage(CNumericMessage& Message) override; void OnQuitMessage(CQuitMessage& Message, const std::vector& vChans) override; void OnNickMessage(CNickMessage& Message, const std::vector& vChans) override; void OnKickMessage(CKickMessage& Message) override; void OnJoinMessage(CJoinMessage& Message) override; void OnPartMessage(CPartMessage& Message) override; EModRet OnChanBufferPlayMessage(CMessage& Message) override; EModRet OnPrivBufferPlayMessage(CMessage& Message) override; EModRet OnUserRawMessage(CMessage& Message) override; EModRet OnUserCTCPReplyMessage(CCTCPMessage& Message) override; EModRet OnUserCTCPMessage(CCTCPMessage& Message) override; EModRet OnUserActionMessage(CActionMessage& Message) override; EModRet OnUserTextMessage(CTextMessage& Message) override; EModRet OnUserNoticeMessage(CNoticeMessage& Message) override; EModRet OnUserJoinMessage(CJoinMessage& Message) override; EModRet OnUserPartMessage(CPartMessage& Message) override; EModRet OnUserTopicMessage(CTopicMessage& Message) override; EModRet OnUserQuitMessage(CQuitMessage& Message) override; EModRet OnCTCPReplyMessage(CCTCPMessage& Message) override; EModRet OnPrivCTCPMessage(CCTCPMessage& Message) override; EModRet OnChanCTCPMessage(CCTCPMessage& Message) override; EModRet OnPrivActionMessage(CActionMessage& Message) override; EModRet OnChanActionMessage(CActionMessage& Message) override; EModRet OnPrivTextMessage(CTextMessage& Message) override; EModRet OnChanTextMessage(CTextMessage& Message) override; EModRet OnPrivNoticeMessage(CNoticeMessage& Message) override; EModRet OnChanNoticeMessage(CNoticeMessage& Message) override; EModRet OnTopicMessage(CTopicMessage& Message) override; EModRet OnSendToClientMessage(CMessage& Message) override; EModRet OnSendToIRCMessage(CMessage& Message) override; }; static inline CPerlModule* AsPerlModule(CModule* p) { return dynamic_cast(p); } enum ELoadPerlMod { Perl_NotFound, Perl_Loaded, Perl_LoadError, }; class ZNC_EXPORT_LIB_EXPORT CPerlTimer : public CTimer { SV* m_perlObj; public: CPerlTimer(CPerlModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription, SV* perlObj) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription), m_perlObj(newSVsv(perlObj)) { pModule->AddTimer(this); } void RunJob() override; SV* GetPerlObj() { return sv_2mortal(newSVsv(m_perlObj)); } ~CPerlTimer(); }; inline CPerlTimer* CreatePerlTimer(CPerlModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription, SV* perlObj) { return new CPerlTimer(pModule, uInterval, uCycles, sLabel, sDescription, perlObj); } class ZNC_EXPORT_LIB_EXPORT CPerlSocket : public CSocket { SV* m_perlObj; public: CPerlSocket(CPerlModule* pModule, SV* perlObj) : CSocket(pModule), m_perlObj(newSVsv(perlObj)) {} SV* GetPerlObj() { return sv_2mortal(newSVsv(m_perlObj)); } ~CPerlSocket(); void Connected() override; void Disconnected() override; void Timeout() override; void ConnectionRefused() override; void ReadData(const char* data, size_t len) override; void ReadLine(const CString& sLine) override; Csock* GetSockObj(const CString& sHost, unsigned short uPort) override; }; inline CPerlSocket* CreatePerlSocket(CPerlModule* pModule, SV* perlObj) { return new CPerlSocket(pModule, perlObj); } inline bool HaveIPv6() { #ifdef HAVE_IPV6 return true; #endif return false; } inline bool HaveSSL() { #ifdef HAVE_LIBSSL return true; #endif return false; } inline bool HaveCharset() { #ifdef HAVE_ICU return true; #endif return false; } inline int _GetSOMAXCONN() { return SOMAXCONN; } inline int GetVersionMajor() { return VERSION_MAJOR; } inline int GetVersionMinor() { return VERSION_MINOR; } inline double GetVersion() { return VERSION; } inline CString GetVersionExtra() { return ZNC_VERSION_EXTRA; } znc-1.7.5/modules/modperl/pstring.h0000644000175000017500000000454013542151610017514 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once class PString : public CString { public: enum EType { STRING, INT, UINT, NUM, BOOL }; PString() : CString() { m_eType = STRING; } PString(const char* c) : CString(c) { m_eType = STRING; } PString(const CString& s) : CString(s) { m_eType = STRING; } PString(int i) : CString(i) { m_eType = INT; } PString(u_int i) : CString(i) { m_eType = UINT; } PString(long i) : CString(i) { m_eType = INT; } PString(u_long i) : CString(i) { m_eType = UINT; } PString(long long i) : CString(i) { m_eType = INT; } PString(unsigned long long i) : CString(i) { m_eType = UINT; } PString(double i) : CString(i) { m_eType = NUM; } PString(bool b) : CString((b ? "1" : "0")) { m_eType = BOOL; } PString(SV* sv) { STRLEN len = SvCUR(sv); char* c = SvPV(sv, len); char* c2 = new char[len + 1]; memcpy(c2, c, len); c2[len] = 0; *this = c2; delete[] c2; } virtual ~PString() {} EType GetType() const { return m_eType; } void SetType(EType e) { m_eType = e; } SV* GetSV(bool bMakeMortal = true) const { SV* pSV = nullptr; switch (GetType()) { case NUM: pSV = newSVnv(ToDouble()); break; case INT: pSV = newSViv(ToLongLong()); break; case UINT: case BOOL: pSV = newSVuv(ToULongLong()); break; case STRING: default: pSV = newSVpvn(data(), length()); SvUTF8_on(pSV); break; } if (bMakeMortal) { pSV = sv_2mortal(pSV); } return pSV; } private: EType m_eType; }; znc-1.7.5/modules/modperl/startup.pl0000644000175000017500000004655313542151610017726 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # use 5.010; use strict; use warnings; use ZNC; # From http://search.cpan.org/dist/perl5lib/lib/perl5lib.pm use Config; use lib map { /(.*)/ } split /$Config{path_sep}/ => $ENV{PERL5LIB}; BEGIN { if ($ENV{ZNC_MODPERL_COVERAGE}) { # Can't use DEVEL_COVER_OPTIONS because perl thinks it's tainted: # https://github.com/pjcj/Devel--Cover/issues/187 my ($opts) = $ENV{ZNC_MODPERL_COVERAGE_OPTS} =~ /(.+)/; require Devel::Cover; Devel::Cover->import(split ',', $opts); } } use IO::File; use feature 'switch', 'say'; package ZNC::String; use overload '""' => sub { my $self = shift; my @caller = caller; # When called from internal SWIG subroutines, return default stringification (e.g. 'ZNC::String=SCALAR(0x6210002fe090)') instead of the stored string. # Otherwise, ZNC crashes with use-after-free. # SWIG uses it as key for a hash, so without the number in the returned string, different strings which happen to represent the same value, collide. return $self if $caller[0] eq 'ZNC::String'; return $self->GetPerlStr; }; package ZNC::CMessage; sub As { # e.g. $msg->As('CNumericMessage') my ($self, $name) = @_; my $method = "As_$name"; $self->$method; } package ZNC::Core; my %modrefcount; my @allmods; sub UnloadModule { my ($pmod) = @_; my @newallmods = grep {$pmod != $_} @allmods; if ($#allmods == $#newallmods) { return 0 } @allmods = @newallmods; $pmod->OnShutdown; my $cmod = $pmod->{_cmod}; my $modpath = $cmod->GetModPath; my $modname = $cmod->GetModName; given ($cmod->GetType()) { when ($ZNC::CModInfo::NetworkModule) { $cmod->GetNetwork->GetModules->removeModule($cmod); } when ($ZNC::CModInfo::UserModule) { $cmod->GetUser->GetModules->removeModule($cmod); } when ($ZNC::CModInfo::GlobalModule) { ZNC::CZNC::Get()->GetModules->removeModule($cmod); } } delete $pmod->{_cmod}; delete $pmod->{_nv}; unless (--$modrefcount{$modname}) { say "Unloading $modpath from perl"; ZNC::_CleanupStash($modname); delete $INC{$modpath}; } return 1 # here $cmod is deleted by perl (using DESTROY) } sub UnloadAll { while (@allmods) { UnloadModule($allmods[0]); } } sub IsModule { my $path = shift; my $modname = shift; my $f = IO::File->new($path); grep {/package\s+$modname\s*;/} <$f>; } sub LoadModule { my ($modname, $args, $type, $user, $network) = @_; $modname =~ /^\w+$/ or return ($ZNC::Perl_LoadError, "Module names can only contain letters, numbers and underscores, [$modname] is invalid."); my $container; given ($type) { when ($ZNC::CModInfo::NetworkModule) { $container = $network; } when ($ZNC::CModInfo::UserModule) { $container = $user; } when ($ZNC::CModInfo::GlobalModule) { $container = ZNC::CZNC::Get(); } } return ($ZNC::Perl_LoadError, "Uhm? No container for the module? Wtf?") unless $container; $container = $container->GetModules; return ($ZNC::Perl_LoadError, "Module [$modname] already loaded.") if defined $container->FindModule($modname); my $modpath = ZNC::String->new; my $datapath = ZNC::String->new; ZNC::CModules::FindModPath("$modname.pm", $modpath, $datapath) or return ($ZNC::Perl_NotFound); $modpath = $modpath->GetPerlStr; return ($ZNC::Perl_LoadError, "Incorrect perl module [$modpath]") unless IsModule $modpath, $modname; my $pmod; my @types = eval { require $modpath; $pmod = bless {}, $modname; $pmod->module_types(); }; if ($@) { # modrefcount was 0 before this, otherwise it couldn't die in the previous time. # so can safely remove module from %INC delete $INC{$modpath}; die $@; } return ($ZNC::Perl_LoadError, "Module [$modname] doesn't support the specified type.") unless $type ~~ @types; $modrefcount{$modname}++; $datapath = $datapath->GetPerlStr; $datapath =~ s/\.pm$//; my $cmod = ZNC::CPerlModule->new($user, $network, $modname, $datapath, $type, $pmod); my %nv; tie %nv, 'ZNC::ModuleNV', $cmod; $pmod->{_cmod} = $cmod; $pmod->{_nv} = \%nv; $cmod->SetDescription($pmod->description); $cmod->SetArgs($args); $cmod->SetModPath($modpath); push @allmods, $pmod; $container->push_back($cmod); my $x = ''; my $loaded = 0; eval { $loaded = $pmod->OnLoad($args, $x); }; if ($@) { $x .= ' ' if '' ne $x; $x .= $@; } if (!$loaded) { UnloadModule $pmod; if ($x) { return ($ZNC::Perl_LoadError, "Module [$modname] aborted: $x"); } return ($ZNC::Perl_LoadError, "Module [$modname] aborted."); } if ($x) { return ($ZNC::Perl_Loaded, "[$x] [$modpath]"); } return ($ZNC::Perl_Loaded, "[$modpath]") } sub GetModInfo { my ($modname, $modinfo) = @_; $modname =~ /^\w+$/ or return ($ZNC::Perl_LoadError, "Module names can only contain letters, numbers and underscores, [$modname] is invalid."); my $modpath = ZNC::String->new; my $datapath = ZNC::String->new; ZNC::CModules::FindModPath("$modname.pm", $modpath, $datapath) or return ($ZNC::Perl_NotFound, "Unable to find module [$modname]"); $modpath = $modpath->GetPerlStr; return ($ZNC::Perl_LoadError, "Incorrect perl module.") unless IsModule $modpath, $modname; ModInfoByPath($modpath, $modname, $modinfo); return ($ZNC::Perl_Loaded) } sub ModInfoByPath { my ($modpath, $modname, $modinfo) = @_; die "Incorrect perl module." unless IsModule $modpath, $modname; eval { require $modpath; my $translation = ZNC::CTranslationDomainRefHolder->new("znc-$modname"); my $pmod = bless {}, $modname; my @types = $pmod->module_types(); $modinfo->SetDefaultType($types[0]); $modinfo->SetDescription($pmod->description); $modinfo->SetWikiPage($pmod->wiki_page); $modinfo->SetArgsHelpText($pmod->args_help_text); $modinfo->SetHasArgs($pmod->has_args); $modinfo->SetName($modname); $modinfo->SetPath($modpath); $modinfo->AddType($_) for @types; }; if ($@) { # modrefcount was 0 before this, otherwise it couldn't die in the previous time. # so can safely remove module from %INC delete $INC{$modpath}; die $@; } unless ($modrefcount{$modname}) { ZNC::_CleanupStash($modname); delete $INC{$modpath}; } } sub CallModFunc { my $pmod = shift; my $func = shift; my @arg = @_; my $res = $pmod->$func(@arg); (defined $res, $res//0, @arg) } sub CallTimer { my $timer = shift; $timer->RunJob; } sub CallSocket { my $socket = shift; my $func = shift; say "Calling socket $func"; $socket->$func(@_) } sub RemoveTimer { my $timer = shift; $timer->OnShutdown; } sub RemoveSocket { my $socket = shift; $socket->OnShutdown; } package ZNC::ModuleNV; sub TIEHASH { my $name = shift; my $cmod = shift; bless {cmod=>$cmod, last=>-1}, $name } sub FETCH { my $self = shift; my $key = shift; return $self->{cmod}->GetNV($key) if $self->{cmod}->ExistsNV($key); return undef } sub STORE { my $self = shift; my $key = shift; my $value = shift; $self->{cmod}->SetNV($key, $value); } sub DELETE { my $self = shift; my $key = shift; $self->{cmod}->DelNV($key); } sub CLEAR { my $self = shift; $self->{cmod}->ClearNV; } sub EXISTS { my $self = shift; my $key = shift; $self->{cmod}->ExistsNV($key) } sub FIRSTKEY { my $self = shift; my @keys = $self->{cmod}->GetNVKeys; $self->{last} = 0; return $keys[0]; return undef; } sub NEXTKEY { my $self = shift; my $last = shift; my @keys = $self->{cmod}->GetNVKeys; if ($#keys < $self->{last}) { $self->{last} = -1; return undef } # Probably caller called delete on last key? if ($last eq $keys[$self->{last}]) { $self->{last}++ } if ($#keys < $self->{last}) { $self->{last} = -1; return undef } return $keys[$self->{last}] } sub SCALAR { my $self = shift; my @keys = $self->{cmod}->GetNVKeys; return $#keys + 1 } package ZNC::Module; sub description { "< Placeholder for a description >" } sub wiki_page { '' } sub module_types { $ZNC::CModInfo::NetworkModule } sub args_help_text { '' } sub has_args { 0 } # Default implementations for module hooks. They can be overriden in derived modules. sub OnLoad {1} sub OnBoot {} sub OnShutdown {} sub WebRequiresLogin {} sub WebRequiresAdmin {} sub GetWebMenuTitle {} sub OnWebPreRequest {} sub OnWebRequest {} sub GetSubPages {} sub _GetSubPages { my $self = shift; $self->GetSubPages } sub OnPreRehash {} sub OnPostRehash {} sub OnIRCDisconnected {} sub OnIRCConnected {} sub OnIRCConnecting {} sub OnIRCConnectionError {} sub OnIRCRegistration {} sub OnBroadcast {} sub OnChanPermission {} sub OnOp {} sub OnDeop {} sub OnVoice {} sub OnDevoice {} sub OnMode {} sub OnRawMode {} sub OnRaw {} sub OnStatusCommand {} sub OnModCommand {} sub OnModNotice {} sub OnModCTCP {} sub OnQuit {} sub OnNick {} sub OnKick {} sub OnJoining {} sub OnJoin {} sub OnPart {} sub OnInvite {} sub OnChanBufferStarting {} sub OnChanBufferEnding {} sub OnChanBufferPlayLine {} sub OnPrivBufferPlayLine {} sub OnClientLogin {} sub OnClientDisconnect {} sub OnUserRaw {} sub OnUserCTCPReply {} sub OnUserCTCP {} sub OnUserAction {} sub OnUserMsg {} sub OnUserNotice {} sub OnUserJoin {} sub OnUserPart {} sub OnUserTopic {} sub OnUserTopicRequest {} sub OnUserQuit {} sub OnCTCPReply {} sub OnPrivCTCP {} sub OnChanCTCP {} sub OnPrivAction {} sub OnChanAction {} sub OnPrivMsg {} sub OnChanMsg {} sub OnPrivNotice {} sub OnChanNotice {} sub OnTopic {} sub OnServerCapAvailable {} sub OnServerCapResult {} sub OnTimerAutoJoin {} sub OnEmbeddedWebRequest {} sub OnAddNetwork {} sub OnDeleteNetwork {} sub OnSendToClient {} sub OnSendToIRC {} # Deprecated non-Message functions should still work, for now. sub OnRawMessage {} sub OnNumericMessage {} sub OnQuitMessage { my ($self, $msg, @chans) = @_; $self->OnQuit($msg->GetNick, $msg->GetReason, @chans) } sub OnNickMessage { my ($self, $msg, @chans) = @_; $self->OnNick($msg->GetNick, $msg->GetNewNick, @chans) } sub OnKickMessage { my ($self, $msg) = @_; $self->OnKick($msg->GetNick, $msg->GetKickedNick, $msg->GetChan, $msg->GetReason) } sub OnJoinMessage { my ($self, $msg) = @_; $self->OnJoin($msg->GetNick, $msg->GetChan) } sub OnPartMessage { my ($self, $msg) = @_; $self->OnPart($msg->GetNick, $msg->GetChan, $msg->GetReason) } sub OnChanBufferPlayMessage { my ($self, $msg) = @_; my $old = $msg->ToString($ZNC::CMessage::ExcludeTags); my $modified = $old; my ($ret) = $self->OnChanBufferPlayLine($msg->GetChan, $msg->GetClient, $modified); $msg->Parse($modified) if $old ne $modified; return $ret; } sub OnPrivBufferPlayMessage { my ($self, $msg) = @_; my $old = $msg->ToString($ZNC::CMessage::ExcludeTags); my $modified = $old; my ($ret) = $self->OnPrivBufferPlayLine($msg->GetClient, $modified); $msg->Parse($modified) if $old ne $modified; return $ret; } sub OnUserRawMessage {} sub OnUserCTCPReplyMessage { my ($self, $msg) = @_; my $target = $msg->GetTarget; my $text = $msg->GetText; my ($ret) = $self->OnUserCTCPReply($target, $text); $msg->SetTarget($target); $msg->SetText($text); return $ret; } sub OnUserCTCPMessage { my ($self, $msg) = @_; my $target = $msg->GetTarget; my $text = $msg->GetText; my ($ret) = $self->OnUserCTCP($target, $text); $msg->SetTarget($target); $msg->SetText($text); return $ret; } sub OnUserActionMessage { my ($self, $msg) = @_; my $target = $msg->GetTarget; my $text = $msg->GetText; my ($ret) = $self->OnUserAction($target, $text); $msg->SetTarget($target); $msg->SetText($text); return $ret; } sub OnUserTextMessage { my ($self, $msg) = @_; my $target = $msg->GetTarget; my $text = $msg->GetText; my ($ret) = $self->OnUserMsg($target, $text); $msg->SetTarget($target); $msg->SetText($text); return $ret; } sub OnUserNoticeMessage { my ($self, $msg) = @_; my $target = $msg->GetTarget; my $text = $msg->GetText; my ($ret) = $self->OnUserNotice($target, $text); $msg->SetTarget($target); $msg->SetText($text); return $ret; } sub OnUserJoinMessage { my ($self, $msg) = @_; my $chan = $msg->GetTarget; my $key = $msg->GetKey; my ($ret) = $self->OnUserJoin($chan, $key); $msg->SetTarget($chan); $msg->SetKey($key); return $ret; } sub OnUserPartMessage { my ($self, $msg) = @_; my $chan = $msg->GetTarget; my $reason = $msg->GetReason; my ($ret) = $self->OnUserPart($chan, $reason); $msg->SetTarget($chan); $msg->SetReason($reason); return $ret; } sub OnUserTopicMessage { my ($self, $msg) = @_; my $chan = $msg->GetTarget; my $topic = $msg->GetTopic; my ($ret) = $self->OnUserTopic($chan, $topic); $msg->SetTarget($chan); $msg->SetTopic($topic); return $ret; } sub OnUserQuitMessage { my ($self, $msg) = @_; my $reason = $msg->GetReason; my ($ret) = $self->OnUserQuit($reason); $msg->SetReason($reason); return $ret; } sub OnCTCPReplyMessage { my ($self, $msg) = @_; my $text = $msg->GetText; my ($ret) = $self->OnCTCPReply($msg->GetNick, $text); $msg->SetText($text); return $ret; } sub OnPrivCTCPMessage { my ($self, $msg) = @_; my $text = $msg->GetText; my ($ret) = $self->OnPrivCTCP($msg->GetNick, $text); $msg->SetText($text); return $ret; } sub OnChanCTCPMessage { my ($self, $msg) = @_; my $text = $msg->GetText; my ($ret) = $self->OnChanCTCP($msg->GetNick, $msg->GetChan, $text); $msg->SetText($text); return $ret; } sub OnPrivActionMessage { my ($self, $msg) = @_; my $text = $msg->GetText; my ($ret) = $self->OnPrivAction($msg->GetNick, $text); $msg->SetText($text); return $ret; } sub OnChanActionMessage { my ($self, $msg) = @_; my $text = $msg->GetText; my ($ret) = $self->OnChanAction($msg->GetNick, $msg->GetChan, $text); $msg->SetText($text); return $ret; } sub OnPrivTextMessage { my ($self, $msg) = @_; my $text = $msg->GetText; my ($ret) = $self->OnPrivMsg($msg->GetNick, $text); $msg->SetText($text); return $ret; } sub OnChanTextMessage { my ($self, $msg) = @_; my $text = $msg->GetText; my ($ret) = $self->OnChanMsg($msg->GetNick, $msg->GetChan, $text); $msg->SetText($text); return $ret; } sub OnPrivNoticeMessage { my ($self, $msg) = @_; my $text = $msg->GetText; my ($ret) = $self->OnPrivNotice($msg->GetNick, $text); $msg->SetText($text); return $ret; } sub OnChanNoticeMessage { my ($self, $msg) = @_; my $text = $msg->GetText; my ($ret) = $self->OnChanNotice($msg->GetNick, $msg->GetChan, $text); $msg->SetText($text); return $ret; } sub OnTopicMessage { my ($self, $msg) = @_; my $topic = $msg->GetTopic; my ($ret) = $self->OnTopic($msg->GetNick, $msg->GetChan, $topic); $msg->SetTopic($topic); return $ret; } sub OnSendToClientMessage {} sub OnSendToIRCMessage {} # In Perl "undefined" is allowed value, so perl modules may continue using OnMode and not OnMode2 sub OnChanPermission2 { my $self = shift; $self->OnChanPermission(@_) } sub OnOp2 { my $self = shift; $self->OnOp(@_) } sub OnDeop2 { my $self = shift; $self->OnDeop(@_) } sub OnVoice2 { my $self = shift; $self->OnVoice(@_) } sub OnDevoice2 { my $self = shift; $self->OnDevoice(@_) } sub OnMode2 { my $self = shift; $self->OnMode(@_) } sub OnRawMode2 { my $self = shift; $self->OnRawMode(@_) } # Functions of CModule will be usable from perl modules. our $AUTOLOAD; sub AUTOLOAD { my $name = $AUTOLOAD; $name =~ s/^.*:://; # Strip fully-qualified portion. my $sub = sub { my $self = shift; $self->{_cmod}->$name(@_) }; no strict 'refs'; *{$AUTOLOAD} = $sub; use strict 'refs'; goto &{$sub}; } sub DESTROY {} sub BeginNV { die "Don't use BeginNV from perl modules, use GetNVKeys or NV instead!"; } sub EndNV { die "Don't use EndNV from perl modules, use GetNVKeys or NV instead!"; } sub FindNV { die "Don't use FindNV from perl modules, use GetNVKeys/ExistsNV or NV instead!"; } sub NV { my $self = shift; $self->{_nv} } sub CreateTimer { my $self = shift; my %a = @_; my $ptimer = {}; my $ctimer = ZNC::CreatePerlTimer( $self->{_cmod}, $a{interval}//10, $a{cycles}//1, "perl-timer", $a{description}//'Just Another Perl Timer', $ptimer); $ptimer->{_ctimer} = $ctimer; if (ref($a{task}) eq 'CODE') { bless $ptimer, 'ZNC::Timer'; $ptimer->{job} = $a{task}; $ptimer->{context} = $a{context}; } else { bless $ptimer, $a{task}; } $ptimer; } sub CreateSocket { my $self = shift; my $class = shift; my $psock = bless {}, $class; my $csock = ZNC::CreatePerlSocket($self->{_cmod}, $psock); $psock->{_csock} = $csock; $psock->Init(@_); $psock; } sub t_s { my $self = shift; my $module = ref $self; my $english = shift; my $context = shift//''; ZNC::CTranslation::Get->Singular("znc-$module", $context, $english); } sub t_f { my $self = shift; my $fmt = $self->t_s(@_); return sub { sprintf $fmt, @_ } } sub t_p { my $self = shift; my $module = ref $self; my $english = shift; my $englishes = shift; my $num = shift; my $context = shift//''; my $fmt = ZNC::CTranslation::Get->Plural("znc-$module", $context, $english, $englishes, $num); return sub { sprintf $fmt, @_ } } # TODO is t_d needed for perl? Maybe after AddCommand is implemented package ZNC::Timer; sub GetModule { my $self = shift; ZNC::AsPerlModule($self->{_ctimer}->GetModule)->GetPerlObj() } sub RunJob { my $self = shift; if (ref($self->{job}) eq 'CODE') { &{$self->{job}}($self->GetModule, context=>$self->{context}, timer=>$self->{_ctimer}); } } sub OnShutdown {} our $AUTOLOAD; sub AUTOLOAD { my $name = $AUTOLOAD; $name =~ s/^.*:://; # Strip fully-qualified portion. my $sub = sub { my $self = shift; $self->{_ctimer}->$name(@_) }; no strict 'refs'; *{$AUTOLOAD} = $sub; use strict 'refs'; goto &{$sub}; } sub DESTROY {} package ZNC::Socket; sub GetModule { my $self = shift; ZNC::AsPerlModule($self->{_csock}->GetModule)->GetPerlObj() } sub Init {} sub OnConnected {} sub OnDisconnected {} sub OnTimeout {} sub OnConnectionRefused {} sub OnReadData {} sub OnReadLine {} sub OnAccepted {} sub OnShutdown {} sub _Accepted { my $self = shift; my $psock = $self->OnAccepted(@_); return $psock->{_csock} if defined $psock; return undef; } our $AUTOLOAD; sub AUTOLOAD { my $name = $AUTOLOAD; $name =~ s/^.*:://; # Strip fully-qualified portion. my $sub = sub { my $self = shift; $self->{_csock}->$name(@_) }; no strict 'refs'; *{$AUTOLOAD} = $sub; use strict 'refs'; goto &{$sub}; } sub DESTROY {} sub Connect { my $self = shift; my $host = shift; my $port = shift; my %arg = @_; $self->GetModule->GetManager->Connect( $host, $port, "perl-socket", $arg{timeout}//60, $arg{ssl}//0, $arg{bindhost}//'', $self->{_csock} ); } sub Listen { my $self = shift; my %arg = @_; my $addrtype = $ZNC::ADDR_ALL; if (defined $arg{addrtype}) { given ($arg{addrtype}) { when (/^ipv4$/i) { $addrtype = $ZNC::ADDR_IPV4ONLY } when (/^ipv6$/i) { $addrtype = $ZNC::ADDR_IPV6ONLY } when (/^all$/i) { } default { die "Specified addrtype [$arg{addrtype}] isn't supported" } } } if (defined $arg{port}) { return $arg{port} if $self->GetModule->GetManager->ListenHost( $arg{port}, "perl-socket", $arg{bindhost}//'', $arg{ssl}//0, $arg{maxconns}//ZNC::_GetSOMAXCONN, $self->{_csock}, $arg{timeout}//0, $addrtype ); return 0; } $self->GetModule->GetManager->ListenRand( "perl-socket", $arg{bindhost}//'', $arg{ssl}//0, $arg{maxconns}//ZNC::_GetSOMAXCONN, $self->{_csock}, $arg{timeout}//0, $addrtype ); } 1 znc-1.7.5/modules/modperl/codegen.pl0000755000175000017500000001055613542151610017625 0ustar somebodysomebody#!/usr/bin/env perl # # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # use strict; use warnings; use IO::File; use feature 'switch', 'say'; open my $in, $ARGV[0] or die; open my $out, ">", $ARGV[1] or die; print $out <<'EOF'; /* * Copyright (C) 2004-2016 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * This file is generated automatically using codegen.pl from functions.in * * Don't change it manually. * ***************************************************************************/ namespace { template struct SvToPtr { CString m_sType; SvToPtr(const CString& sType) { m_sType = sType; } T* operator()(SV* sv) { T* result; int res = SWIG_ConvertPtr(sv, (void**)&result, SWIG_TypeQuery(m_sType.c_str()), 0); if (SWIG_IsOK(res)) { return result; } return nullptr; } }; CModule::EModRet SvToEModRet(SV* sv) { return static_cast(SvUV(sv)); } } #define PSTART_IDF(Func) PSTART; XPUSHs(GetPerlObj()); PUSH_STR(#Func) #define PCALLMOD(Error, Success) PCALL("ZNC::Core::CallModFunc"); if (SvTRUE(ERRSV)) { DEBUG("Perl hook died with: " + PString(ERRSV)); Error; } else if (SvIV(ST(0))) { Success; } else { Error; } PEND EOF while (<$in>) { my ($type, $name, $args, $default) = /(\S+)\s+(\w+)\((.*)\)(?:=(\w+))?/ or next; $type =~ s/(EModRet)/CModule::$1/; $type =~ s/^\s*(.*?)\s*$/$1/; my @arg = map { my ($t, $v) = /^\s*(.*\W)\s*(\w+)\s*$/; $t =~ s/^\s*(.*?)\s*$/$1/; my ($tt, $tm) = $t =~ /^(.*?)\s*?(\*|&)?$/; {type=>$t, var=>$v, base=>$tt, mod=>$tm//''} } split /,/, $args; unless (defined $default) { $default = "CModule::$name(" . (join ', ', map { $_->{var} } @arg) . ")"; } say $out "$type CPerlModule::$name($args) {"; say $out "\t$type result{};" if $type ne 'void'; say $out "\tPSTART_IDF($name);"; for my $a (@arg) { given ($a->{type}) { when (/(vector\s*<\s*(.*)\*\s*>)/) { my ($vec, $sub) = ($1, $2); my $dot = '.'; $dot = '->' if $a->{mod} eq '*'; say $out "\tfor (${vec}::const_iterator i = $a->{var}${dot}begin(); i != $a->{var}${dot}end(); ++i) {"; #atm sub is always "...*" so... say $out "\t\tPUSH_PTR($sub*, *i);"; say $out "\t}"; } when (/CString/) { say $out "\tPUSH_STR($a->{var});" } when (/\*$/) { my $t=$a->{type}; $t=~s/^const//; say $out "\tPUSH_PTR($t, $a->{var});" } when (/&$/) { my $b=$a->{base}; $b=~s/^const//; say $out "\tPUSH_PTR($b*, &$a->{var});" } when (/unsigned/){ say $out "\tmXPUSHu($a->{var});" } default { say $out "\tmXPUSHi($a->{var});" } } } say $out "\tPCALLMOD("; print $out "\t\t"; print $out "result = " if $type ne 'void'; say $out "$default;,"; my $x = 1; say $out "\t\tresult = ".sv($type)."(ST(1));" if $type ne 'void'; for my $a (@arg) { $x++; say $out "\t\t$a->{var} = PString(ST($x));" if $a->{base} eq 'CString' && $a->{mod} eq '&'; } say $out "\t);"; say $out "\treturn result;" if $type ne 'void'; say $out "}\n"; } sub sv { my $type = shift; given ($type) { when (/^(.*)\*$/) { return "SvToPtr<$1>(\"$type\")" } when ('CString') { return 'PString' } when ('CModule::EModRet') { return 'SvToEModRet' } when (/unsigned/) { return 'SvUV' } default { return 'SvIV' } } } znc-1.7.5/modules/modperl/generated.tar.gz0000644000175000017500000075613013542151622020756 0ustar somebodysomebody‹’Óˆ]ì½{w7’>¼ÿÆŸ¢ÇÉŒ)Ev,'ÎwiŠ¢¹ÖmEINvÏþZdKê1ÕÍa7%+3y?û‹ªÂ¥pkR¶“q¤Ñ™‰%ÔS¸P…P@W×ùù,›Oç‹âÉÅ¿ý:?OŸ>ýö›oñïæ¿?Êÿ?›Ïà¿Éæ×Ï¿y¶ù|óÛÍo“§›Ï¿ÞÜü·äé¯TëgQÕé\T¥*/³ÓrrÃ-£ccT£Ä¿¿“Ÿ¯Ö“ÇñçA²ž]äUr–O³ä:­’tQ——iÓéô&9ÏŠlžÖÙ$9½I†oý¤uQ׳ï¾úêúúúI%ã“r~¾öò9ÉæU^É×Ož>Ù|&RìÌÅ¿EY'yQgÅDdX—Éi–di•‹ræY:IO*-&ɸ,ê4/D]’bqyšÍ“ò ò—“¼8òUVÔ¢¨*™dU~^Pnùål^^eɬœ×éi>ÍëÌ.;;ËÇyVŒož$[%Vâ2}›aŽiqžUÀ]ëŠ.ŠiVUÉM¹HÞåur}‘ÖøW:Ï’I)ªðøñ¥¨ÊÙ`ÊP*4l~–Ž3ÙÜ¢ªE£P2³Ç'ë_=x𑇎ê«*ƒhM'àÈÇÔûÓô4› 9•óä2«/ÊÉWWé<‡žÃ&ÙxšŠñ}óUZ×óütQgÕöC)¤5ù^΄|æ;ƒPÔ2Ó_ORuv9›ŠAœ\—ó·é¼\ˆÊ@ TUDÿCÓÆÆ¸œÏ… Ä jš]B ¡Ÿ»_~™ÛSLÒùrþø<ÉÏD3Ïr1@[£ÑðxïàpÔí®%úSÂ’ïHž¾{þíÓ5Á#9âùêöp6µŠxu0JEþÐè½,-Ë„ª$×y}‘ü?AIw:Ä€iôçÉ#¡z 0Uòê éì ØÎ—_ÿyóéˤóäé×Ož?‡ÖŠgÉ5 n!½Thлürq™\I¥G γ¿-ò9è“I(5Ñûµûb:mW5„ýü¹°»Ð¬˜[7¿ÊVáh!4öÁçô4'/¦À£G©Û§ƒ½Á^ÏíÄñlº¨àÿkÉ?þ‘´ ¡¿wܰkÿÀúüèpÐ=`»—W–ÊUaíñ1¡˜ª‹[žyEv¦>>¸Ë$½*óIòhQ,D €t^3V¹M>Þ;ö¶Ü&Ë–a½á­4H œ¼H¾¶~²‘ »ƒ½ýCÀý|#Åb5šj"кÜÙQ´,µÀÜ ¡¹Š2-ùü}Ê u‘.Ïî".ÚÑî°;:Þö†ÃÑ7ÏŸ>w ˆ“Þ!Õk6OÏ/SÕS­I^áôø]Œk‰èýE1Ïβ¹˜×D¯OK1_'g‹‚Œ÷…˜ÈO3¡åóìRL‰d¯jG 8èîb ™un¸¹€nÍšE"1ɬIL_ɹ³-ÀI†f_z‡{‚ÛÒ H³\ËJ•È[*üÒ"´ÂyIue%s5EfïÀ¤‚¯Bå(E +•HgŠ ±ºêÐØ—Mèw»£Waw§3ž †ƒ—ƒÁÑOR=Tkš@JYFJïǃýÃ#gä¾ì}ý kmˆi`­ÔîO}A`ÖD‘†G£Aw$$ùº·0ºÜ˜Î@ |j–[“é”:bͱ’=Ô g•–T´nžá¸Ê«œÜÐÖCNÓúáZ£ÝâTµuUür× †Iô˜—ËkϤ¶ºÔa¬®2cÑꪞ@¥"†ÀTÀkÊV&´}“Ý|ý'¯ªEV}µùçg´,aIœWãE«È»˜#wFÝý݃ÁN|pÛ©I”SóüÏÏ”€…|“Þ|^ÎQ pª†eß‘'u\À²¼@ÐÏÄÿo: Á¾¦kÌ3sHvDóµ›°¤ïLVˆùÆÁÝÌ2Vbž;˜­¦ƒ²xyó¿Ù¼$Ì·f_Œ’³iy-óBÌ¿;˜áX–¿³Ûþæ$.2§Îöò©„ rdøÔuÔ|F8¹’Þ.æüÆÉÉõÞb:=TîªÂ>ÞüúÁ¯³•cvH«ësoÊÛØè&ƒ55³T‹88Æg%zI-::_dã·Jc>jÍÕ~íÃ\ࢹ,¦7°r΋ñ÷"„ñÀõ{–ãv LÓô¦\ÔIy†íA-GyqVªí­BØ¢%ÐØÌBk4ÏÒª,h‘®š­¶ÃDa¦‰IétzÃõ´æxïh°«-fòð›‡XkŽ9úé 7:ê¼Æ{¯³ÛK„ |è2Sál×{ô?ÇûG=\Iïõ[ïÖ’Ïß9á6uö¶FðÊÀávëÚ˜¥Ã!ò’>OCŽlòñS¹€&2ærûPŠwÉØßr¹q‰³&ôž`£€œ…T­zD§NnŠôRüªœœ]Uæ¦wËI&­˜À’?ÿùÉŸÿ@b‚-:ÄâüPdÙ· h;ëy }øˆŠ|ôäÈæ% 9¹y*f¿JØ Ü:+²qVU¢.Ižm 6P/RØž—Âè_Š ÜA`»‚¢5Õb|1Íߊº‚>pgVÊÅ·_#.–Lƒ9°Õ§»¼KúÒrœ.΄IóéÏÞîÑèåñövïp4ü¯;ž%Ù|úìžõö4=¯¸Ù!?÷Ø*Oö±Á£­ÁpÿÍžšëž¾Û´aÝÎðh´×{3Úííîþ¤aÏœ"‹ìZ[žþ5×ñ"Yy²H9¾)¿¯”/ ùγzA3>ŒŸ¬Âá#¬œŸ¦…ÊÞ€ÁÖÅäú žoÈ„~àjþ¬qBî‹ðŦ8ôp$›œÀí FáÙb ê(ë'IGh˜‹ßÑ(Š 3œŒ@7P-O3Y˜°³­*ËФ"¦‚ÙÛCEM²jZr,Uù¬œŠÙ=yTÙ¯ÎP´B‘ª¬†*ˆ¡"›«„9p¹õ,…á×^Ò€Ú :‚r€tìò µ‹jG6×ó\,/Šï03Ú] Q åÙ»q5‚­ož`×’?ü ¦ãµäïd~õ•–KÉ¿à ƒÎÒ|ÊXè^yê.å‰N¢X‰Oóq^Ëj‰nL`£ø‡dyÝÚ¬v ªý×-Á»fjª¬SW±ëJUÕ>7.¸Ä:æE!Å ¡Û²†¤ÓJÄ’ª_².jÙ^¡5-Ü|]__kýIp¬}hÃ,޽ìzÿô¯Èeº%yòäɃÏ&Ù4«y-ýþC $ÝBhƒ'Ù“ ŽÓ\”ÔU0&ʈÀ¼&åü9œú¨ã3˜}P§oá/1Vä¼4ž(Çxšô$Ù?ÕXÌ+Z¶ òBè#·*uÉk"‹i-–FÂ3æEjÑ%PÑ¡žK` qÙ‚ð¿D4åÛœ$‰0}²æ;{D •ïgTK@ʆ >ÉÓ¶8dCÈ“î½Ùùßœîõj °(K³ÞßÙr³Ö¿ á¬/;6ë/zXÁ/ºï6Ø\]ŒëæäÑÓ–åk_=ÞlÁ[{$lb>â‘]EÚhL äiY8õ09³mHwîðpÿ,pZÜÈáyàôCÆ]zG8å™9«è9ô°³÷z´»¿Õƒ¾Ï X»N¤MÃKé tçuņ `ájžomà4’½Ká€ÑöŽÀ“RÃÇåYYNZ“r! [sÒó–øEXšÉ”ŠM§ŠY…QGEÖ¥'6%Ik3yü"Ù|òtÍ€óøé#ÌC:“IWÀZk_‘€`Y4„y¬µFŽwö_'ŸxZž<ö“3“#S¹æâæ°)îæÙ™Ÿã‚ÓÆ·ø?°R×’ÿLæÉwΊ~M.ȲÚz($²“_ŠñV¥7Ur!,à%Œ¨ÓŒÜwh&ÆEÐBt(5˜v»ƒ#S¥Íäûï“ÿXS% Û¾›Vo…îJFSé0Î÷¸/eQÁ fä«K´#k^yd3v;C«Z¡ºˆlê]ΰ9ùqyñ¬3a}y™Îä©9މìR,—ÓiÔk<Ú=ˆV€UN>Ä£w¦Òd¸½|IɽñÂzÕ†;qüþëµÔbàä®l×Bm^Æn$ƒ G-îïd‚-æp1ÂDðs$kpO&r˜ðáݲ”ä?A1üÚŠ±>wª¼•MWËíOÉÿ·BvÆ=Yó$ ²ƒHÈÏÍÎUâÉDÆÕÚÉÄnçj¹©v6g7¨Dn·i'ËŽ —Ç`]’]pò}p’ç†fµ  øéLɆ’bÂE!榥X€|ÎNþ¬#ëΪTÎŒ›ýxœE&g;uÆì”Ì¢õlÍ*3dm[Ñ Øªµ§‡]Zi§+´äyök¼“]íªÉ ={r฻ÃIË+÷{¯ér4})¬›šaäœ#SûÁ/ aÓêÒºx5ŠžB ¸O]W”ØkqbºT£Í–¢j½È¢5÷elª§XâšÞÓ¹O¢˜ïas¨8rñâ9"01Ù;8¦OvŠ*n˜jH+¨Ö:îoÒ*_ Gp¸&—W(³uá)&QÞB̕Ξ¨Êerb°²fœ}q1ÇÓ–ªGXç—¸Iðm Ù5½%*,Ôd|‘Îþ³^ˆõfû³Ï>E 7â| ËX‚¢ƒ kRYB<Q¦Ìàbq‰k/FÉÇm¹Êh)mÌHí%¢j뀒Iy-–ÀÉEžÍÓùøâFfÇšŒyb““u™d7Í‹·`gò 7¨¡*&ÜŽ ýVºÅñÖÇÓ\¬'iRm§Bn‹ô\¬ÝgÙ8?õÆ<@Á üˆæ˜L`5®œýJ÷½€ÏeÊ„,qz8:dRªŠ hUûRZ¢ÚU€‹JF®WhF—– $I‰«<*T… ±Pn†3zò(f¬“¤¤TíëR^ ù`_ÉR«æQ-÷« ©j(X¦1¯Ù<» 4V•‚’—‹Šò4}¦¹Ý>þÐ'Œâbj©<œôôÒñ…"©¨è 2°k-cqGƒ­”Ó)¸ÆxX+Öµ´­7m“`*ÚqÏAåÆù|¼˜¦óé Í“Èh¡ ./8`*êÔÎ|žâªX÷!ˆÂfdµÄñ”¢M¤Q$…B•ÿœ|ƒdQó öT`·4 ÁÌ" SÃHdsàŒ¢LìŠì‚cÃ=&–‘<¨o[‘‰VL<ê S%3PuÞ2mż•Yp³XFß4îx¦QÊÖ±dL²m¹‡ß…Ó?°e×Ò†ÀtR%ÕÛ|6S[7Õ BÝaJJÇ0hp#dž -‡@X±køk"~‡áý°;M«ê{Ñi/ˆ¨ÿN^<ÜH²zŒ{0‡äß<¥£NŒ#UÁI† ÔÎ4ÝHÔ_/Ä_Ùuú°8µû§>%yÀÃÊ&?$Øj‚û"µ>M Þ.Ó\.¦Lq ɲ3(;!ä§ÐÂF©žÅ± */ðYÐý†,;2=ùÑ“§Â{Û–îð_US¼BûŠl…TgìDˇbœ.Ŭ~¥¾ƒÛ²ÿ6u_6vWÊ\©ÃøŠGu4`þÈü?ÍZÇjÚ™ ¨´[ÇR¯³a¼V½ÆÞB¢¾‘cIˆ[ýî™ÿõ¦'1œn¿@·˜ë/Ðìa œ0_HxüÊzüj.dBÍtO"(w“½Þ"N´Èb6æÅİ —¤ræ/ÕåL¹x3¥, ë~•¨̳?È$œ‰½Q:¯‹I¥ltèÅ=ðažÈìjòS»\-Íg•dÀŠìòRDzÝ6ÿbë|<ₘ|!c{X‰YîÝ8›Õ õ5¸æól6M!Œ"Rvöóp^ ôvC—\Û–;b!.ä·ÇfÃè„rÿ5r#·‹[zz.fu!|»¼NanÐ{Θ”;W´•ÂÆ#l$¹ƒ©¾Ù@8a¥›"»¾ÄPBËà·Z€1 "þ€íW Ò5ðZàtó;1ÙÙ”fjò3K¶äî†Ö0ò²ábèu±jK= 2­•ù›F[z¦ ­^ ­ÏÖ…7\×78„ÚR%E³¡ùØú uªxÃÜР”Âav$""€x˜§âuŠe#ƒ(F‚‡æ@ýá½—ãW,h¼ô¾Bxtð)Õv¿ål3NºÉ4!+$”ZÑ\/ˆûQ["†W¨­7½Ð!ïÿc% 9n©I“³¨²¹·˜7ëëÓØ¸™tåÛC1'Ý|öõ7Ï¿ý÷ÿøsz:ždgÍ~¾Ž…¢20;:ik‰ ¢rdÀ’,à¸àgÉ>^ àй 5¨mÎ0®/Hæë­±X²ˆ¨uKþ”<}wö§èoþÀ(È_œû˜Iþ¸˜¹²Ç»aQÙ{ëXÊúÀÞ÷ÄÇ‘èJEüĈ¢i¥lö:Zp•=•Çe˜“ýùÑšZ*.üº®ÓcâùþûäY†öd–©•åÙ*Y¶Óãͧk^¾’Sí€)‰I#â¶vÅvýï…j×í[ÉL·hÕ¶àØ ŠŒ`´h¬=² ‡¼~çoÆ8äD0ÃJ&kðºÓ¡Χj< %0«¹ªõl€å™Œƒp;áh¿ >cAm礶FГSÓ£6oó ¸´aç§gEy IsÄô½HZ¢ø\ü*%Œ¾U$øá³‘¯ž^%•Z Ä»ŠÚkÉ…4?,=s”°>}Mær}0ÞxÛ?ÝC-ykEKTÏ›ê*Üšñî£ð¶{»Û®!ûòËñFPÜ®X3íæ…G’6ƒï7¨ÔbP®¿°¿“ÿL¬Þ‡ØJ>†A'þ?%ò{>ÆÏ:ã©éHQ¡‡ÒÒ¾Ü\óœ2lÊSG“o5ÚŒx—O4{à]f—UVãÁÁS%Š_oÜýLc-û‹ } ÐÌ£~eAo¼]Ë7.SXÕdÕãÇiO`wW«n*X¤7É9.×ä>¸ðq…w Λpñ*1YÂïðÄ F«`]áÑ]@¨.ßLóSH …êjÜÃÞÇüäâ!Kƒk픇Ç/!ZÕ™L`Ï]-¨R|¹ó2¯pÁ‘ãuXQE~!öòKv០rÿ;M+ΖXOÀð–å,-ž¨× ´ƒÞáÎè°¯:íïmПò=ù—¨žzà@ UvÉÛÊB>ãÅž¨9èu_íôNz;£W£Á^wçx«·¥^²Ñ/è”õP)\½'㯱P;ë݃Awp$S5‡| bÀN´üyù¬áöƒ†¬ ¼f¬ÂªjºÌ1섌Äò~oDŽ FMõ‹Ñn«¢È5[ëy@ªŸä©¢e½ ?æÏà£gºÕò¹,.Èmÿå÷ºGöãDÐêÁþˆÛàª.©uv±q6]KZðÇúšøsͺàj°ÿzt|ÂÞ)­êJÝqha&àJñêøäGüK9A¢?ÖB™ï¿æ9Ë\Ì/Í’MË<É÷êÙ:;ù|Î*åÊ_8•ÏåRòÙUW£ÖÌþQÉ6¸H?K?Ejòùüüʇa²WzQúHLö7Âv"Ù†^¦ó·bi:~;ßFÿXÉ^Ç Nä»ò1Æý½¾JљȢ™gålÌ7°hï$§p ø|‘UòF-íkÁ­´s Ï"?‘÷AÂOöŽžªg eö¢—E"üJ}}ì%Ûªxtxâ‹Ç8«9•ÔJ‹›‰‘ð§Xk¬ÙU‘A™¶°KõîAY/ó­Âé<œ¸Rõ!?Ý)_͸w¼k1ú,¦VÏ'ðº&ý¨'3wÀp{ §*²‡8ÙãQ1³LS•IË’ï½êR›IÕÏâ•U僆ô$8±^й:8+œfnÚT¾ $þj½Û@â[Åó¬ Î$C 81#Etxz‡‡ÃÆ‚KÆÖÃÿz¸±ÝÙöü²fG¯~éBþEÍK’ðå©&¯ñ×xK‹H¹L‹|¶˜êëµì>sŽÚÊÕˆ/dÃh‹Îœ&æN8-“€OJÐþ³y›ì;¾«üh+P³È‡ãl¸Lt üý8Ï)nþúA9§î0è»è6^';pû¡9›R=Äk=@g³Z$‡½Ig31‚Ãbž¨³9LºW†~¯Î-Cûõ:›Ë¦!ã„î´.éÈ_hkêã«™ú¨Gã“uüF£ôC{Ñ #8]#ÓA/[Ðki‘žÃ2æ|Zž¦SýP$Ý<úß¹“fŒ9ÒÎCS†0Úêuw’.4rÿô¯É:ÐùûÒ@XÛˆ³ã;µˆÚPïµ5•Ôœ­«KÏtß”+L|ó*½¶îÄÙï?¸ÏÌÌ6dô–|ÉüóǘÂ- f+¸SLö¯‹`ñåu±,X2­^üÜ¢tŸUÈ®å­-¸2o¹Õx›)ÒÑ–㱨Žê~à†‚ÕÂKnˆº6(B¤47’Šjb·Æ(15IÓdå˹¥Ê[ÙÔ,Qêâ”Æp? _å£ËxËÆô ¨0xV,صs;8¢.Ôk²Êʘ7Úf^æª]hlé»­Ëš¸-ª¯YUhj¢ûJ¨.Ëת²ûÌMs󞲦‰V]fxÏRµ‰žc”‰±GEd½weÂÂmWˆÇuëR†÷JëzÌogh¨[xzªs üÙgÕÕ¨ÊêÙÕY‹­i’þɨ³µµ¶‘<üc•ü±z¸¬+åg—†ÏÊE~>û켬K|yî3üÁÊ‚  QõuVkÚµrßMßf uÕ•‰«L1Š)lƒYJÕC–Ù)p‰Ivrñ!õZU{oa…ƽ¥ËØvоßîШsØŽ6[éü|3\Š_wtØ!)4ì}2EÄ255}†™nò™÷BX¼¦’¡±¾·ËZ×Weý묤eÿ ý“_™/Æ ku*î5|œ@½Mß[Ã8娛±½»½ƒ#Ü|ºú0ö^oöz‡Z‹Ì[´Žb¼êlí¿I8 <-æZ‰ÎO/{¼Ç"Ë|+l ­²è5f) ü¢*9-’‡Æ—`F?÷öù÷1d’<ÛÅsNøµ…û@I÷d=³]w^<ó.ËYT%þK;;?[#*ÿi¯6h•Èw‚ØÍîñÎрΘ~JüžÂÙ­%j£oE¬q¿w4-ßHt¸¦6Ä׌»þ ;:RÂ–ŠØ,8L7Ikx^Ø^yªg6`ÓIgóÝwëC±¬Øëéñ6>!4<7ˆ°ø QÓ6;O+Ý8…Ç”D.©ÎæÔ6Gø%š})çyщ÷6Ÿ ™H¢Ù>¤,ïù[Ôø½äúaÒT’°Æªï°ZËÕ šN¸P•aà;ü!|˜_¥E¡©¬[´Sí{» 5o0¨#$Ki\•V%};*Ói‹¯üY2Ù‡r¸ ©2c&Ìâh¡ÙûoÊ„×ÄìøãE!ªlQ&´­N¤œCÉo!h ól=üã^™Ï ,ƒÓ06äj”Wôte èèF\n£#ÙTVèëš3äj›úþBŽ=°l‘˜á­Pz_½6w”N³ú:ÃPô9~6îð‰s1£ã«¯ðP>Å«—b•5-Süªb¤G„èQ”r<^Ì+|Ñþ„o(ÓC}ð²Núã)j¸Ô'«"~›•U•C¨óé ñ¦ÍSzN—]`ä‰Î›Åàñ–™7áKDôÉÃ!'ïBø<=îO \ªÕ%ä¡>ÿâ¾(»¡ªª¤ÄÛ+CÿRŒ®—Ÿ‡­ü`+µI?¢Ž×&!üZ1¿ÁGÊé•%ë™7<òWøÍ Eò5ó"­ðÞéu*_ —OøâCá8®sŠÍ¿Î¦Ó $üÇyF1aì`Œb´> –'~ÈËyK·Ãëx—†#‡{.$wx¤»‚+¨c1 ÒÈõõ†õüÙÞâ/@«ïo¨çÅßÒÁ€å§}o›ã;ó´`08iI¨)ºœ[¾[ínî*wZÙIçj«Ž|5gZk‰ËDÑtÒÐØŒüÆ©9~Xå}‰3Úµƒ7&ÌCÉÊI €þÙ¡ÄúÌ\kXû×Û(N5>é&µË‰ÃSÌäòc6êA|èYŸ{5H–sÂc€ ¯ìŽÝQMÏOÈã |‰Ï?BW¬ë1´²ƒÿÚÑÊ(t(³®dHÀ3 ä¬)ôEåKðáŤt6Kgœ]0Íܧ^õÑAìì`æty‘ð·ÊK>wßÉè1K Š3’|4\gÈýÈQêÍà$©…­Ð£‡š!\ñuˆ˜8<¡ÒÔ˜Õ‚ïµjgvRN^°¯WH·öòœßò^©ÆÔ¬lj“(N4 ¢¸ñèàÑš=/Ïí)` /Ï¿l¢Am®Uá†~æ´Ìn˜Ö”„Îa-9‘}A)‚ûiþ‹ïü:WÔm|°,Bš1¦‚bä[·‚‡G`ã %² è=ÑLÞ=6@á(ºNZ¯u| $oo}âµSìwÖí‡'X¤ULZ©eyXM!p]ͺ†Â_Õúó'›ÏÐ †|Ï7döª Á‰Pàz}¬¾(Ÿ;œæÚi&ûñ$1šªÙÊÛ+Æ—µoH5Þø’ÈŒN–—ú€ýÁ.>jSü*N)xÿü4ˆi«‘OØ\¦3õÅPø~ÊžÀKS² ‘ð6y Ὶըo°ƒÙ ·2õ‡ƒ,?‡Ïd²Á4Ÿá?ÿVÝÞÜK#$1) ~4y]¬žéËfø9xØ‘ßÁ’¿²“bØLr¾˜/pWT>ù—ãü¸XÕ“Ø||"¿Éõ'{™ŠYc#žê½ßrÇn„Á™Ý$3Ñ¡™Œ§k”§ÙT}‰­"¯FfA¿¾ôƒ°^$”W'x‰»º@ëÏtEÀ”®ôæü /üõOÖ××.®Fg»!ãFò7·n$Ï7’£Ã㛟óªÒ:ç& ¼€ÌúW¯N  ©Þ¡«vÔà#ùµ²ëB,¬/ò} [*\íFþð$¿‚Oňþ |Œ ì $&“W`7è8ðz“.Ç壺Èã‰æäV[46{'œíj$@⯠ŠxJóøè?dãP7ä )gÔ=ð ï/«ù˜Í»ô² {³ú¨¸¥_úÔ¿fž¯ñ/—Õ6XY¿®Ð 3yý\éM‹Ÿ°üÃükzÀa‰Ùô¬ÍÇÿ8|Zª‹pHŠ‘ ɯNZkŽfПtö,æÜÑ슢 b†¾^CÉÉl0‹bªm Úh„£3j<½§:ÊùFk¤¶ çWø´HÜHYP̰ÊãâêOqEðÁp[ŒŠeøE‰-Ü`_»À"éwä÷Fßê_V!¹ÞvwïHèÛ%(Å+úúí6Aó‚ç¹Æ;®ºÂ ðP†ÄŨ‚ v=+âªUvê5.µ»À W¿8:¤¾øybíbÍ|}º•Aòa?àu1ã—ó:Òˆ·b§‚ T¤AÛX¬dìà‚•ŒÔlâÛaèéQ%þ>_Šï˜Û¬ªzöÕMó˜r´£ „5¸ÃºùôéSý.Ùƒ[_aÕwŸ›KB¨ kÁD5÷ m`x,ì­ºÊèô©5PtLTx `¬*N3à2Q<#í´èý–åS! W %4!+5½i{…ëd}lm¤´þæ‡ÅÕ.Úóµ°ÛŽË sD£ ûh€ü¨ùÁøä^‘—6¥ðfl5†íE²»ÅáB¿üR— þ|†{ÍÚl•ÚK"¹çºQß°© W+Ñ[ÀµÑáôí6á¾=Æ{˜rwvà.„ã?U×Z½ã@Ü®«ž%±CïÄ:D‡tµÁ×ç *¼NBa$½™ÃûXsö‰‡’¬; °(°¿ÕA©åå%}2ôtúÏßa¤¼Kµ‹î—’$×ô{[,„Ê`ß °oQ-0µ6Õp> ¶Gßös¾Æ¼½³ßÂ3ç˜?0ž$_cg’oœß ö:ð%ççJ·©&ü3Eæ°Ø—e$—ùZHàs9æ‘FW ëæR<Üв¸¦¨ZD¤SLFœ0¢û5‹õ#ºvCX¬Í/ú·Ɖºà°ú@±†ˆ>½Go§%ŸS²û=úˆ®©ªL˜‰©àØ|ö­ðOëý sÆG¢ÀoAJß®ÚH7N7„¹…hØ\´ºßãaÔ‹Vº†p8”7óÞ3ënñ å½ÈPD‰ë¼„òT Hƒ¢+D¸Q"Št®IŠ‚ÑDظP¨ÈáÅqX5‰ãíêÉÙéºã¢+5Ö ÒØÐ>¡ÿ‚‰ï:÷Ak*¢ Ã:¬C½>5€€ãGôê'E묀2Ï®òy½H1ðk·rôrö`éë¨-ùê ¥¯¸¿¨®j8^Á3+ŠGé{ˆ¡ 2TqÑ"µ{"…2oœÍ³Œè0éz‡ºÖCuÌ3Ñí䪙¼MÅBÞ­wÕŒ6Níƒ޾$IJÑ’´-—ëL%éػџ°µŸŽé0zš“Lq*ðÛ'ïÁ ªß}ÇÊë™$  DÖO½ÑQçåNo»Ôr‘üC¡…bn—*ûO¢ãU5³CàHDÔxs×ñè ø)©ñà=®YE,[÷™;~Nô‡Yt8E½A[|öÑͯÛ°SèZ›åWJdêÆ»lÆò7t>v¸5=ö-\Ž >cH0\?Às58+ª|BÄ˯‰SÁ¨H•Z_êœäól\ÃwÆ…)Ö‰\ÎÒõIÏnê áÉ=¦`C¡÷Râ€èL«rªD^êô ö¬–V“qUÂ×(„ÑÀê|l‰˜‹œ´.Üß:ýÚÝôö޶:GìíО˒gO[ Ù%üÊͪO3Ë7ah¸Ä–Îve$”²ØHÔ¿òiµà–ÒjW ­Œ<Ño,¹(ïÑ¥ÚŒªú'tÒ¯Rï÷;Ú´ÿÝë>™]þÛ¯úóôéÓo¿ù&ÿnþûó§ü_ñóÍóo¾~þM²)þólóùæ·Ïž%OÅÿþìß’§¿nµèg;5¢*ðÚi9¹‰á–ѱ1ªQâßßÉÏçìY€ë´JÒE]‚ì|>òô†l뢮gß}õÕõõõ²OÊùùÚ±Â8‘¤ýúÉÓ'›Ï|.’¶J|œ^‚á^œg•þT,¸(0Ð"]MHü7_&bš>üXŒÜüìF䦧œ½Ïàk‘˜‰|—þɃ°5¨cºýfPxÀ-ùÛu«‡OdáNO†ëì”ðv 0æqûÁiYÖb‘Î(3+çÿêýx°x$SäñRŸ³I0yÙîßnïèÕþÖО >¨§ÉÑ ÷ª3|%½¿Ë›¤õÞÆUʸ;ùCò_#+ŒO3’/pwÔ Q©!ËîN¯s˜ü=‘n‡G¯{?™”½ÞvÂvï¨kUNO6¾ÀW¬yù‚ö]õ¥úþßöÅßú ¬q³xü‚Ã[kºŠÃ£ýÃ^¤À/„»x•NoUpÕX°ÊQ—#Pÿ TùYm ºÎ³Ië_Ði¬‰tG'ÛÇ{]¼yöæ°7bLW»½¼.<èíIwZVÙ~Ñ{—Aí×a}÷Ki?XïÁÐw&“9ì¨.€â¯nUŽß‡;ƒÉ;´ÓpP䔂ËI‰b‰2¼XÔðAnæ¨Ø¡ønóBuªmoþ·w¸o*E‡½#›&$i0ôˆ˜$ÉÝC›(i‹«J*E/óé4Ç{šª“¹SÁBgWM¶ÁS¡_p-IG‚‹•ã,èЧKàWéU68¸úÖ€TŠ$Š~´i"A’ºÂƒ¨xþ,d½²¿Ûù±»¿·ÇÓ©G¥éÞMÿêt*'ØÐ¼ˆ@`AC( Ð{'ìl…hÈÉAšÏ!êÿÙ°æ]l¥ü&;.N@ Ö%!|š‰•Ìl(ƒf4”%ƒuç? ~_8ù”û»ïN‡Ý½¬¾.ço«ÄÂ}n™I“Еè'˜@þk0ì$¤K¥õ;ž–üQ¬gŸßÚíí¾æE âœY&"Erý€ie¼”†VÞÌν=·í$‚½©Ôvñª¶þk$7䤃†šrbïY~!Û…Ä7¬0yf#ü6Áƒõìr†ß† A&0j³*„AšÀ̼Û,QÎb€r&èç\{,:îË­WQ:ªHx«7<:Üÿɾc!ýš/Fÿ÷ô/_äUÚz³¼Š>fb§)æïˆüe­ÈDʘ8ä …;}¡{üïHüÅl3QœSòIåQÔ"ïduø,r‚—ÅsR[Mr6•1uwÛæ 4šeåœÊJqJ°_ôDÝéþÏñ€» ·Ì›gš¨Ïd5j´°ŸE!V¤KÔYÁ>u]VõüpEV9Å´XÓc*¬ýÕô òj@s51¤¶¦âwIguÇÞ{…ÒMÂ%úJ¨O^]©šA[)£¨²JrTW%=¦ª’ÖTE )ª¤õTUùN©©ìÐ{®¥¸–ZIS9ò×V^ÕÖXžYDk-HDs-ŒÒ^K-D@íŠ ] ¥]Pý"­Fo³XM%õÎè´Õí÷\¯WÓéªÏŽ1ùU5üýµûŽŒõsé?î¡ÁYȲu¡Æ}âs—©è‡ûš:«˜·i1Ó "§}NFx†ò;Yõï’çi:øžëîËÅÙ|̪Ysê7Ò[WGTñJCÞW¯U>÷vÆÒ¸å¨_#&?/=B0×é,@‡ä¶k •LâeúnA(’@ͳ†q6/‹:ÀtA‡g4dH–FuËÂ2’™¦‘Žg¨hËN’üiACØB&¯³ËBRȸG0•ƈ±ÁH •UMóq¨7‰J‹¡*ƒ¹ÆPŠÔ¾sv÷äd¥¹“ßÅZ_Uóý¥“湓%;s'Í;s'M;s' ;s' ;s'wqgîä_+пîÑ<-*zLCNµÕEÿVÞR?«YÉ•›n…F§í\ Ý¡\ÖYÃÞc·p>sµ"³Ö”÷±5n¾÷Ö—óñ/]ÕòX]OC ëè$D™ k»˜òÉÌ)²@Lñ1Ô0Žˆ€SÜN*˜¬@Ë ÀQΖ1„Àïeׇúe®0‡Ž­lºŒƒC>Žø—}!ÜwÛ Æíp\β%ÖÁÂ~âž·]Ùû;Öm1Ü÷ÑÎ4«¼LóBØÔWô]÷•'F‡ñS׃xÍï¯R4Èä¾kˆð3Ò›l²ºËè3|êá×ø=¶g3zÅßxk~¶# º3»!ÑÝw…ÙÇGŒÒéêàøÔU&På¢3|ïžÒ„„wßµ¦[Î3&Ýü]¾LmB,ŸºÞ„ê|Ý® 4î»&×ù²k#„ùÔÇ:VòþnjþmÃúY=8`"æ2ÂTÚÝ)‹ó0‚(°?9ϋڹZ+a†¤p»BöF&CJ¢ÂÌËËY†M!;ô-• ’h 9¬ÓzQ…‘D“×…ÓiM^¥ÕÅhK ý6Âp۰—Œ,»[Ï_YW7%΢jôðUçÙóo €ê«¯©å ˜-‚ÕDa^–å4ŠÓDÂî-.£PE“§aÖufƒ:¢;ÍðXH>ÆPŠ·•ƒ˜®¤nãëAˆ!iÜ0›_eó´À(‚‹Ê ,Ý´û碹"G"a{ŸœàØXMÀ{bÝÁÖ¡/E‘2%µ:JÃy2rïý7á‡þÎ͇=ý.lóœ¨q¿ÕAUïÇ‘zØ€õŠ®ÆˆÑ -2øšo,É0ãêìîï¬kDð3/¼zìI»ƒÚu„ϼ6kb>uo+yÇ=5ÿ¶c¾€YN—Ü€aN#Mi#ê°¼AD2ÍPÝl:õ2]ú­ðl¬‹éò,ïM>©/B@F†¹ÖŽg“°.E³Ý9-í–ÅY~ÞÃïÚ,ÛÑÈO]cYUï¯Þr!ÜV{é©¿Ñl¸8¥lœ 4–·k‡Ø«ÕØMüæÝÓ±•Ôë÷¡Yï±!ÿ2;Ï èñÜZÉ~çTðh‹Ijhm™«>±Œ €ònb°È4C½ÎnNà‰~xËÉgpÄ¢³â5Ö¥¹(ã|O²q] pîi¯‘Öò š,áǃ¢n€k²‚/Êy#ƒH–-üPB ¨fÇ%k‘ýÀuSqë¸z÷ɘ,Èoæy còÝ90’ú|ßwƇð(ÝËÅÙÙÒè†üÔm5«êýõ‚¸nëFðÆìhĬËn¤ÈwÐcÂóð–ç2mP¸O^TEï±&hÜV;Û£ÎÞO\ T^#Ikj°ÇŸFu`@¤(ûíô2ŸÞšJȃÒÚÕ´p@£=û}RŽ"š< ‰¡ú¥Rw²"f›g¡›%êÝÙ>Ìþ¶ÈçY¬a smÄ÷-ü³WüEâf‹e½QüiÛ,VÕûkµ¸nk·à i¦ ,«ðœ¸gÖ*I*­[úŠ,àÓG01Á9ânú®{3žÚ»3€±© D!‘ßýV4¼ù}.ìµ9Ð0Q‹ Y&·1ø3óJÅDQgó+ëþBIž¦ÇÊiòˆßÉμ‚-¢çÕI:Í'.L&Ë0‹ôÒkŸL&ï j@³wõ¡ß‹†rZÿ]žz‚ÂÔ;hΆ»¥°úå|{kÙªF?uÓfjz “Á­æÓú"ŒÕv9 ìØZkè|G>|‚­êè"­æùùy6Ï&aV¥‚yDz˜AQi#9Œ4s—¥âÎDƒû¾¢ÿĈ”0ØÆ¦AÕ+ %R¼&ßE#!VLÝòòr©çc€Ÿ¼‘Ð5½ÇFÂÈà¶FB~læFKeuŽ#Žhk†í-©1Í\&‰x9Š eÌ­Xž-zäÅH"=‡I¢½¼q÷.<0A"VŽÕ’Y9|½,ŠÔd5xʦí;g—àûFK,@>Ò¶Ü þºÆ *ýÇÉrS >ãl†ä52”»sJ‡Bº­ÝÚî†ÿÐʈ‘@SËÙ‹€4AÚ?>z¹¼·å’Uº€ì †G=D¥ƒ;±ÌD&ƒ'ÓëlzûÛ.B¥kÈ¡WŒJ×N¿3Ø £¤€ðq©ÃÞ6|:ˆftÅÒÜMâÖg½ÑþkE©’ è@NŒ$áöŠ‚ù’‘Ép´3t‰" 8‡;Ͼöø QC4"…ؾ¦²6…mJR¦ˆ^q˜1[£½²ðƱJ—Q…+/M` ¯òš A¢à+¯ªšÀA£8ldƒ5“$S·HÍ@M‡G£áQçÐ4š A[{^wËd x9ØÛ:yµ? 椉*7a?c9IAazÝ`ž’dµ©îk¥yGTbÏ/S¦KÈÞþ›B$K@g[ê7‡Â\‡p†ªŠì à þ¿× â¹ ‡ÈSœ­cdÄ ᢰןÒc²ù»H`ñYåÎP4, ¯l ê.™R59Ð…š@f¢‹ŸaŠ s0ŒJpºLƒ3ªHhiŠÚ‚ X@•õAº ô«ìtâÒ MÆ—ãtj]šSNˆ¤ –ãuÄ).»eÍ3¯DF’Gžq¬M•Ÿ(TúFÈ1ˆ@¿‰äòÆä„ -HaЉ”"Ýt: |áSv='ª­`÷ƒ˜²Eí7‡zZ̾sÆHØð ¦:ÒÐ`ÚÛÝG÷Á›ùdº„m“&HP§Ûíx¶ÐPlÇS™LÝ2)žêŠs.¶8PºÚ¢®Åríó\û¹öÝ\q É—ÓÚôDíxÝ+ÓÙ¹@‘N¡‡d0˜_d3£ÝXÊÍP$ÎÝôýyt1Ϫ‹rRk¤Ï)–0AíÐÕ$-kò0 f¬oAᜠ®³æÔ"Z@Áöª¬Ü#•£"QŽ1àÐBEÐÜçáJ*š2Q°M¥œ_ÞÔY2 œ¦rŽ‚m*ËFJ`¢vÈVþ G®Î#µ— ΓŒÄç:'pÇžíd䎚%#XM#he¢€B€¡àW¬=3‰rß ~肦Ñ$ …fhL±$y9iyq>ØwqQŽMß…¡T©5>y¨È¯ÒªÁàØT¹59o`péPj:¨zUžNóê"àm8tã™ Š¬öàœf ÛÞ¨ ²oÓ9xŠqûaäˆidòÒ Jý1.“åø¿¡…†·¢hÄæ(’‘/ZîÃmåÕ8†ã4˜äÃS¢™ A©·Ò:õ ¥Kˆs¯NCä½::Šmj[DÅð™†v ÌHT×±xz~ ÔÙ¢C?ÇüGî;Jñçe±=//##©zAŸ®©ð ,ÏÃì,äzÙaoÒò%¥ƒ4Ì‹q¶“V5t%¾“ºOfp*—öYšü¬¤­ã–0º©´Y1 ÑP¤¹. xÃ#h­%‰ô9Z@úø:ô~°Eœ¨¦’–Ñä,žðEB3¸$QMcÀ¡ÜÚŽ‚›7š A°;Â@:AvÊò­¿ÐÖªÕbv©”¤´CÁµÚߥ¸Z?FW¯T5 ÀªP<Öµ3–×AWÄPäÄù6ŸEöUlj[ÇåbiÀÃÑ!£ ÁWÙSìÈA¥¾Œª½s('4_(Ò<°K¶ôJF~òG馪÷ø, áÖ7´.+lŒå8bˆèêÒÁÛ^_ÀŒ:xfMýu…ƒ5ë"s Ö46¨l·ÝÁ"¹Ü·ÑÜü —JphI0¼ìvð¶ ¼D‚Cwâjà/К%èn05Iph$»*a£ïòå‡!줯ll-ðG `åÿÊتÿ=6¶îý^õ1ÑeÃ_á>yOCUôq-‚ÛzÂàoeµXõó Aå6ÒTš}éÎsgü„Ðlˑ˽޶}oNäPæS–Ô¬;"ž [~Mp®åhÇW‰ÊÌò e¶’ÂѶw—™íE4ÊlhÉ,ìËp°åÉ4Ëì®{'¢ë@x…0ÂK­3ÇþîB­Úßc³m‰á¶¦Ûùš¨›þ¦¨ŒŽâ$Ýd;PÔóˆÑõáq·+FT,ém »ëu Änÿ0g ÃãGÿ¹¬H@L8üÉ  3J\;WäHJï€yA6PG½J+?XÛàˆ ù•e¼ƒ€›7b•šéNM#ƒ‡lÓCK¥*bóHz[¾$~}y<´ÙB`+Сe, ~ˆiRݹ.Â,§<“àE¾‡¸pãYýY­XXå•V©ö»SmŒß IïzóyQ6i¤Žb¿&UOS9P:+ñºÀ6Þj ‰n5°‘ÇQ†kêvΈu0y¯GY\Õ²añPO‚«„ÙLà˜™Æ’@bÝ {¬6î··àhÎ…âƒNC/LÎ2¼‚Ü=Küç.–‹þ˜N–©Â¯êg¹M¸·ž–'ˆ÷ØŒ÷|#7Sÿ>ÍÒ®lí’e‰D},]ÿ_y)"k|oUC àÖ—=c§»2Cÿ€Wž¶•'Ù²"„sÓ{·P]MÀaBhòq"S*š† )µ­?޲Œ$µ>rAjšŒ<ô-$¥b”ÅÄ]!@¥·å…ï ÈPÚô ú«ò2;H­¯R ­-og„‘Œt7ÐÍþöʧíî‰*Þ_oëÈ;æ1G"—‘LÅHkˆ$)/oÞäÓÉ8OC Ì XŠœ¼iˆzÂÃ×yÝ©ë¹aò¶²jìÝœ 'µå£) ÅsÑ)ï¼ZYTħÅyf[*BÊt˜+Ó·„L•“ý›-¿"ñÚùÍô%öD¢>u›"«ù/t‚ã,&Ø·…ýs™áˆ“ÛÝ]w -ÉíÜjwÀò;ýuÞD‘‚¦pÝt–žæÓ¼Ž¢ Bóu¢hAS8w¦¶€j²Æ?Å•íTYP¢*ì—yT@S¸×¹åþX8 )Ün9‰– 4…ÛkÈoå·WÖù8š#Q5vq™ÍóqLd…>°?-aAè ô»mmEú½lÀ•÷?‹6Æg¬V`¬Œ½wõ<]¥X Œd±B4ÐdÑ-/gù4ÛŸA cÕXͦ©.>Tes6ƒûä ï–4TÅÃ…3ˆWÂÃ}X„Ê÷þš;.„ûníàRÞ²'6ó±¼îüWÿÞÖ÷þojþ-6~hÍ}=s Íã™ô¿j<ÏgÎ edöÊ•=ÉIû‹çÚwr½sJ¸}°ŠJÔG[`‘¿®&Ê*ß_]TxmÜ>è¦Óéij¿Žu ÍÐï FHog¹NÆF”WÙ|Z¦,ñá÷“^$Pù¿«Á2MëѨ%þÚüËÚ/„ûá  c¬Æb¤œµo­-¿CZ¦%ŠýLvæ²ù[­úÓò4z†U¹ˆœ,ÐÇU6b Q åsQ°Eÿ0/ò»¿fA à¶f†p gˆôb6+çuå>3"qœÜÆõE€’Haoáw $ÜÉ8Uû½==B3öÚžóªØ×ïÂîƒznÇ›üm~à\B7pE%lg~^½Ê¦3÷eƒçây•V†Kb[¾P˜N¬§hªgébê=ÃÛ¨2®7,Ý¡–î0*Ý¡–nÔ¥cP[ºÃFé-é—JwèIwØ$Ý!—î°AºC&Ýá2é]éÖ£Pá"õnN¶êE›¥ó­~ÝæM×ô=^HÃÇ7Åp´€Ìo¤¨d>ã8IŒ¾-dÖóBâíEá=¡f¡ÀX¯(Ô˜¡¨’3´­çà_†¡@¹COw˜Árß·ƒ¤ë·Ê¾÷ïÀ,îó3û²ý·u1»û{Gƒ½ãž·=Ra^uvŽ|¤JâîþÖ0 Šu÷Å( ¬\övö;[>„Òi^‡Œ„èwe½…ç¿\§qúáºã™:aºì;A¥#àeYJ¡tx“f[äó¬Ú)Ï󇺛©3¹\„é'g§»Y±8ÊkwÉ· ×¥9@³ø^¥A¯]üoTWMh @Éû<ƒjfUPD@±4ã ø$æ“´ÎLbwx¸í~¢Xò6€iê.N}8 ­-_S—V¥âd’Z̈ØôÞåi6™d“fø(dF1^¤U g‘ eU7`5ÁƒÃîV^é»MYPˆbë.áéF¼%©ËAËQ+¥,¼g_|¥˜³saç©ïCiN!]Ÿ ­§á®ÑD„“–Ùü2¯àøóëƒ °=[Îö,À¶œ ™ögÁüE²$‡©HÜÊÊ074$†@ÀI™³`&D1 (FtÍIÑ8°‡0¸wÌ C à0½Žf£hØ€S°Dç’yïôñŒTø‘Ç8T Þë†ûŰNëE\úPBjÀóõ§ËWª›y<*Ç™£ß?¦B—¤y}è!éý"òÀ¢‚Ú¯+Òß1I<ü0¤·õ*$ýÃ! òФ½vòsŸ¥æ8ÀkÃ+IÖP¬ýÔ'ýÃÑT~ûRÏEÖ×ôw GVÝ{Ò[sõœ7BúꉱóØ|ã£æžû€kO}€'LÓ›†F,àã1ÑéÁEØWã–þE~µ\h>ÊaŽ ÍÅ8ŒK„²ˆ -‹°¯ÆMÇeFÄë·È n|©8Áé‹£Èü IÖ F¡™À,âSdKX]œŸÁRN‹e…âB%5á50úH2çp_Iæ©Í<yv—sØïîRÚnÔIÒ°èÇœÁ}㘧6óhðÃï@,¶&¼.™ˆÅÖ„7½yÈØê+J›36rØÐ†•›‹ÑŒKœ b±5áɦ¬ ºAµmTY[]Áú-QWb±5áõĵ$b±5áuE–šä°6óè --Ç9¬Í<ºRKÌŽÑl³#Iº*Krw š-’»$éJ,5jÈamæÑÕYZŽrX›y¼ÌðxF'jpŒ±fó+1›¥³ÎUšOÓÓÐV_e3fÕb4 „ªJE]ÆLº@–ÎdÝ«åT¹2‡ì¼-)&G%9D À<öe|ŒapØ]Z˜ÁØŒ´]¸µ³Ü)ép°¨ƒÙP:Â[è’@Z©AD"¥aô›†ÅÔSÛ*~Ôsm”4 ®Z M·Ò:µ¿Œfa%™öy)P2´Ë+ã1׳ËHQÚxpo#8FlÃWìŠX©š$`/3±À?=ÈÚ“\ & ØN^Õ1œ¡Éíoúè|p÷[~gƒi’M É©R81¨¡)ñÐ_1ùH* ( 54)¢(’Û:< º9eÓ‰¡ l€BxQ ¡IaE‘ŒØ†›“i[d olŸñ•éDî‘üDNàaz•ÅÁœÚ¦ÇÁœÚ¦SÁ“@–LF"DîKò«´ ‘1Y =D§tl!zO’qh†’ÐÆ¯S†˜Ü–‡N!€$PA€Ñ£9E„ê¾›‰Î Åþa­•$ëÇXIٚȵh0ŠDzg‚®ª¡µu´Ye"aÂõëëú5˨ÉÕ 7 kàD›ÐçMèÇŽ´ûúH»ßp¤Ý_úÑ6ãßbÛM á{DæC¢)-\;Mb¾Y i¨l«»l«Ë¶¯p¬S×Ùå,ÈÁéȰ-ÚlÝWcä6;YhÚ%³¦¦åyÈE‘ÎvƒÉ"·áSúoÖ:9 ¡ì²6 \L[ˆ*˜êÈÆ¬`,"ÑȤ!ÈFŠá|.^sªëu‹H ÐÅ(Sÿ:» k/‘ÐBìMÐjKÊÝ -¬V «~Ãx°»žU½OÄá„ÃUï ²ªV‹²ªV ³ªÜ„FJ]i"¬V +k*$ûÓqã^§iíh We‚¸šlªÛDØT·±©Þ'Ʀº}Ír‹(‡ñ6a6Õ­ãlª[ÚTïiãó­jã³µc±6Us°Mµ,Ú¦Zn£ í†x›j•€ j7FÜT«†Ü0`»1^¦Z5`†•›Én·9ŒGATi±’tm"ΡªÐê‘7Õû„ÞT·½©üà›Ýè^µrÊ–ÇÐAúpªéàK—†ÅT<.¦)ÎF—ÆT<2¦)ÒFݘ—˜uuCi¢ h*Ù=p †V<<¦é”UyŽ‘pšêÖñ4Ê&¾O@ͨ GvØÌ·Ž‡ ³·W ˆ©> "Ææ†ÄÄ[ý-aö€ÌšÆR<Œiµ ¿þÒ:¼P½OhaZ1¶¦º]p ƒ¯£˜ÂÑ1ÇúëJ2œËB®RÌŠa2ŠÅ‰“i>·™V –QÔ`íœ šåÁ:6ÓŠQ4ªr· ×±™–GÔTVHÍR;äÇé4ÄT·ˆ©nS-‰ /ÃQ-ÍQ4.ãjÁ-†‹bSVˆ ±XìR–†÷œ-ª‹‘óºœbÐ4›g—åUµ(œ|O@qÿ°ùø“vÿuöyËï¤þfŸXØíO=ŤnEB6#LJ!±Uæ1‘f™WeU秊ûÅÝ#µõ»@%z¡U˨©½¿-Ò©5”vä(aî9là›À#™L€ÁÄv Ó Í ¹p¨åd2ú+—!€L&ÁoÃz¤˜U ¤6†î… ”É”SH.}-—~D.}#—~X.}-™[dˆ(RùÊÂh˜x- ô%Æ ¿Õ+›î©&”=Rš¯Òé™u‹TJ…yÙ#íÓƒaöË,HQ±ì_–Il(ˆ»#X§µW!M@Ð0Ï-³%1”Ž1WgóÔöœ$J“H6û…µ1%‘††Ð½R:u•54„îÏÜÕµÄI‚vòË<Ð LFÀë,P)‘(‹厤`Ÿîê^ݽL½þÁD$öÞ³Y ^”þoUA>÷÷¥*lýmß©rçgì 5?•bu–Ÿ»t•°¬H—–u½{3žúDHDØœqÖ{HWé çuŽ/B CiCw f(è俹(=Émí+žJoã ®¤û#_Sh²Þµƒ¤yÂdš¬C™¬××™)Ž0‹hÀÛå®ðxõwÈmÔ.&@k(rCÀ™Á¤Ò©¥Á|TºD$Œ@&CuQ®!Œ¡èÀ2 "pP·\Þ¨·©4&àC>(.²yÞÄâ#ÚR˜\:I5ÜXMPý†16³ˆdg(1R θ¾g(§tåúάªzÔ™UCB¤N¾†Íˆ¾"MzßÕ~ÉL‚”Ú~KÜvý‹ÈÀ[„ÓÚü±Ý˜aâdb€Moì\à  Ìð]!‹8R ç2‰áTËÁpûÎ#ÉÞ-ÂS#°;Ï0Ê1"yN†)EÌö§þÜ%“Ûp÷(D§Tææ±£yî÷§)EÁ6µ ÖUjhÖ¥ƒ*ª"ŒDúšd2(?Û(PRÌ<Ô™Çf,Aa+L°d¡ á«®Ô[ÿQt-~“5:!Ê*t¿¯t¿Ñý¾ý¾¨î÷Ýï7è~ßÖý~³î÷=Ý—ËÝRMÅò×ØÔ§i`¢—«oĆT1Å5ÔŽ°Ò2í7klßÓXQ)g¨hI¡|£ºÖ·5M¨›v‡¾›ìˆ) š0sÈzsëÎÑܶ@ÿ½yÛ‚ùOû½d¨ãý]ƒbëo»Å_Ï"@V#Få-ííïõ\˜&(ÐîÖó F¤+ÈðUçÙóoƒ(")àVo»sl=Ôl’.F:­³É+ûê  %¼¤F_RÃÛ¸ôý £ äEw¦ÓòZdlo‘"Ò¦’OÝ·©jíÀ’üª¸´Àð›Lt,"‚ña`†É€{öDÏŠ ËóômÕ*b,@{ pç¢ wÂ!ˆtƒA‚Á&ª[ ìü"H‹¨Vãa(#Yîa¨EŠDÕPXWÜÈ®#yAíÐk'¤­ü­Ñ׌¤´ÃO¢(…~÷¢–l¨ŽZ ½ ¢ :h#ò~ ÃéüFÀÖžg#G"§¶éCQ¡ûaˆ¶ˆ¹„¦ñδ>|‘eœN·ºÝÁA “ ±}t±Î“ò%–ªN/g‘«ij×/6Î,b`‹Ð€ñ¥pÆ™/àeæÒåîÇMU‡YꉋÓôX®ÖYCKr;tœG&œçu¦1Œ¤´ƒ§~ ÄNýD-§!KÅHrJèxÈp3’\7w» XFm˯ù³ŒL–û,b‘GºÆ!«…{q#¯B0T)Kç$GKRæHžf8b#›p0>Ï»'[›-Ìé,ºLA6¤ÍîáöŠq9 (™ &Œ^®BhI¡Ñ jVC—‡4‹9( å´¦]M=¢ÜMP¶<É V ˜Ío¹Ä*;XzxÄö4eÞÄÏ`”ÁNZœ/ì,ŤHR†™èKšúC#“徟²Ÿb2½LC‚w[g6ËŠPQÂaC|Ÿ„h ^ÀäIž†'ÑÆ”ùsÀÖ3C+p…ä+p°0é;H I’úþ6/"¶T‘tޱ™Ë¦j8$޳Hy4OÏÎò1´¼\„ºÛ…´õmýˆÁµ©ÏœÑä’#É­—&?Ú¥·CÑÚãÔÇ3‘i³Ï§Í@Pˆ± Ø´Ù·¦Í~|Îè[“E¿qÚì»Óf? œ"0,;KhØ^c M¶èž§5‚OJ؇‡†#åÜd·´bÅ8 ÍÙ6õ8ýíSg_ÚîE¹5í8MSÀ ’iËDåÀ¸—éC—hh‡›cPû½¹h#‡N,…sJb×Ôœ•øg|7¾†n_D·¡Ü!vo8•·@P\V”²+LŒ‘×À&±Ë»,™\¨[š š¬&ºwuÜ‚È.ZÌçY±ŒËBÉ#’ÃnGHcµ¤rC§rƒj'­98B®]æ‹JÌBÚçÙ|6Ï›ìsK÷ QáûPêÞU³BÛò åÆÄк£äüKŽ‘Y.„”»z«eBê à‹Ml@7àæÁÈÇýéìMzpv°×r0úÆœ%Ǫ t®ÓˆUÔd]‰8ÖÐax·äy·ë ò˜ÿOÌÆv?#áë°ú˜Ä eØ%Äßhµy'CeLV‘ÆÛ và3/¶›AÏi ª¦×ÞŠ«NC6a G†ã|5{ Òl½wé¸^‰×FªÖí–µ%Àmžµå­—f& ¢«ºŒËE©*RtÆÒJrUs9£ÒU]ÎéãTuûnnmí}7ÿTÅ™‡ÎVldã ‹cêÏYlìÒÓn¢Îl¸}¶àoóº®Úìõc8¡!’ÃF6Æs8F®1ªÃÆ.í°áv\C³Ø†ÙÒ8mí‘oOËR¡:ÞãÁ^.æ n T¡%e í2†ËË:eÈ(náŦGŽhë醡ǀžl˜dó˜G墘wÙÌè¢X‰¯Í… +' ï[ðÐ><ßZ¾ï¢Íž|$X˶¶«…lxL9‘87ÆãD»©½€QTBD¾ƒçp’ø2­²%Ûæ ö¯WYnµ­Ävëh1‚·¤œ'‹T~#NEÃmy÷u*fä6Ÿ‰NŒ‚Ùìö¦ÁŒÜÖÁ Bi&°"ËÍw±À¡z€ÎÅeYgV„+‡*2¬Š+8I±ç5Ô;¨Ê´ã m]öâ‡~uæVdeí~¿7tÅïïé“ÁmJP7L~–vH“â?yÇðD–&ޏ³¸’ö},Í3[.¿…êÝwµ{y¼˜À£‡ù<›¨¹Ï»gByâØè /9W™ß%Ô›ÝÝ×4fí(ÞÕ²aæñ5\úæg¹}IXƒ ™Dºé Zxvã£9•À°‡Ù€6d !&«‰ƒ#ˆ©÷N,!&ÙÄyOØðp±à[*ï‚`"ìø•÷&‹ÆIî¼:;¹Déü b§‚™2Á_¦õø"ˆDŠl÷ø¢ôŸeÍ6tU‰éY£·u LÓèð mu{Êý~Žd`D =(çu#œ`!MŸë±ŸWWº¨im81Ù?;ó†F½çŸü›äÁð- x^/¿ ˆÐEЗ ícK,ÿ\9%ÙÕ˜¦rp2r¢o`+\çsÁú xÙ•> É.õ SãFé®0T¥ç `C•›5é¹|27Ø_†,àdŠHƒ·0¸™ÞÍ ˆ1 U»Ì+åCâ4’Nœ/Óè9„(mšß`?><›ÌE69a ÊPHJ›bžÃ E1çW!Áóƒ"?lX‚L°pä IâÜ$ýQ=éÀF‹7’ èûnúÎ7CKÒBw¬ÍXa»ÕÁYB̲=8 ³x/&‘•¥/øö€ý,ôEÈÀ@³˜‚g¸ÌKàç·Û‹©»ƒnŠx×J@KÃYIT¿¯Õ„,çþ.'”n»žØ…ØÏ*ÉœF’"}ß „`kçço.²bèÔ#ÊqB g…éáIBAØ,9æG·ÛñÓ}„ÞÂ*;¹[fî7T^Ó‚³ˆB™i¤ÁÄ39¸6ž\/ÛÝRpM‹„ 0FüÏÂ;¹d0¤¶åãb(BYËÊD:gRùY¦ƒTR8 ¡%‰J[\F`šw§tEJ÷ŸãPù÷ÚÒÜу‹BH;î"-z[¿&æÜçãhImë'ζç¥ûÎ'Ãs„9r/d1~kP^é6ÒcïtÓ‘j¢©u¤t$TC=59ºÀÀöF‚Ïqæ¬!R°îÙൠ•v]Bëxf6›ò hVò± nŒWܱà,+oY0&Ï"¸…À8¬=é26ô³&ÓXøë]&å©v… Ë–#Ô*M¥³gtéeÆ-£bÞ7p0/ëØìãBî Ï >DV,}zMÁ~«Tn·wp4²§BU‰‘¡è«££ƒ, ¸³³Ó€ÔptUn÷×ÓÕ¸õiU5; Ò†L&sgÖ0F–Ó…m8ð€¬@8pí°5ÞÒ:fàiKÞ mΡéÜL65RäÖ@#ÃÐa BI¿(¿qYS=Ð4– šM¤-‰³8ÿÅ_wiÎk~­–%…[ß"Õ‹Nðê™¶ð\G6ÊÄìŸþ5Æb‘e¬…fkÙ;§Šƒb\^æÅ¹â²2á÷¥–~ýï¯rdqûOøûV^®| «i£'ÈèìùÜ9 z… jûXÚvÛíé»0Þ• ßk”o¥uÊ«Êk¤háM\ Ö°‹«q|78‘i¤5‰m—󱪢¡†ÚÖ_m á$ Abìùß"eP€ÍL¸Ù¸Oƒ×Ķz‰¹ 窉t$Z¿R³l„Fª*<Žeä6ÃÇ¡šHkÑÂp¬¡*²WÖÛå¢v¯À!3Éçöe:6dˆ¦òEäÀ±3Öˆ¶|ýBü'µ¶ ÞX,˜¢HAS{…áò%‰@Î×8È|Œ!‹Ì,ÿÂÖ-Ë·y,k #ÏÔã †J]½UŽË2؆ÚVåçÙdT!FV³^7±†š ª¦ UÊ6^Ï>¯§rÍqæAgó×®Ÿy{O ï"ˆÕ¹õÞ¬:}WuhÅ«®~¡E¿Ô‹þA33DaMkj”€éuR‘i[8ŠT4Vt\øR7Õï'ét‘5¢ q}¤£ìr6†ã(=•“éÒmŸáSÿÄ…_ãû». Èâ¶ñX‡y~¶# k+A\…E$h–ÁÙ*ƒ³¶©–ÐÓÕ*&€wXŸÕ7°VSfý]¬ß‡&ËêþK• n«Ãî—ÌüøGÍ{Õ8eÎ.¡‹·pœï¨\…먼Ú¸S–3ôÇÞ-»vàø×eÖ÷Ò &ÁÛêÆ'^ö­ ¬„'ë숲`;ô0^„żãpX^ŠIön9B¶ñ;‘+ò1$DÍe«ò1$Õö6Ä’"Ç ô¥uåhZ0¬ J#ÇþJrìó—oQ¿¾W¿þÊýзúþrŸ{Žó±§ŸÅ_ÕJ<::éüµ‚HØVïH­ÄD8]³•*F蘧çàﺟ·â”ò‘ö¶w»r§â^Î*¿ùTòó¼Ðg–ò¾zŒ,©’ù;dF6‚¢-ÊéU¶“×Ù<†XlNyÈR ]oÄdAk6ÒĶz7ÅÙ ×HC5sG'I*øÖÚEä ¹‹_â‹¡ w’ñzR ÉȰU>kÂj[}y/5Ô¶¼U¿;ÒPÕ¾··ïÈj«É … ]Œ ­ÖG’¤@¢‚ãR)àz4î#¢ÐÌ–>„‘¤æi‚Í øØ]pî¥iz²æ¤X$©Mé.æ|I€{ =§.aô@šQOQ.3S(¯&â Y€«,X• îfܹYWüwåR û±Î–Ûµ¿î–‹ÕŠû»áb‹áý¶LíýO+G¾õyç”æMv:Ý´<Ê?õHSÓû«L·Õ|fƒé‚ÉŠ^à7#âƒà1¬ 2±ðf¶÷ 6ر1Ã[Çþg¸,¤ú½µº¬&.ªú6Ûo#зôœxU˜ÁƒA„K>.çtQä8¹áŒAQ 8\ŒÇYÉÛÐï¨ý[œbtÇrûGÀ߃ý£šÞoû'ep[û·=êlíö] ÌF’ÜÕe0k3÷(¯§qRI Ýð TT\qâOAÃ&Ñ$¸sÊÀÖ†iC]û¦®¡©¢8 »¸›ÎVv™váªò§o5teßcok;/ò ßY‘Ù„g‘ùȇÞíH[Œï±'yç´eyŒ·D}¬e¸Ž,_IaÖ:ýÞhoÿh{ÿxo˳Êé p8Ø;Š‘¨[½íÞáa/š³¢küþ^/Š´Tñ{ýjŠÀ­]‚P”¹ê™%Aæ ¶<ÆÜ !æ=B=48Ýl§u>vöØ-ƒhÓ÷¢ŽD¡öI’ Ì—›>Îc!ü©#øûôTgC%U^g½Jó)$¹Ó‹ºó¯é&ï€ïÃò6ÎO,Øš1¬k­ðV¨õÒùQÊÚ›q“xx¸wµÒdµ/B‹‡¹ƒŽÿ¥{ÀŸºS&~½¿Ö[KÝëîïmú0_¿ìõí-Ý‘Cm3|¯·5:ì8b<áò½9MnbC€ËuÒ;|¹?ì-ç¶€,—­ÞNç§%Å[·B%š :‹ ™ƒQª4£œsÀy°ŸÖÈr÷hœ¤Ë C-äšæµ˜|»ùt²SZ†svȸo/t¦ÓòÚº…p‹ëqø-z8y˜¾•{¢RÉ8ÿ¿´/²õ!:}t×™±ƒ²’î^ví}ÆWËW:Õ¸ðW„g>ø0»H«‹ “ò¥°¾‹ý¹_ŒÝîuÉòˆXŒ-Û߬!è A±êxáær&†ŒŒlõŽÕ%<„’Ù"éÒ­®NWÛ»êi·çm"íô^ Áe(ZÁ1JÛþ8ãÁ¼|gaUWÁF´ù§%!íÆ¯ §R}ðú{^¦“qêÕ^§·£ŸôQÂXé[>l>âËv…/i˜É †Ó<=;ËÇà6»òu¨*6kf €ÚÁ·l±‘æ![º)4XÜ¡i ðƒ%”ùÀð¾–ìÝ5SXF%¼¾¢>Ìdn‘‰£S”Åà`'¿ÌÝae}è%±‹yY×ÞŒàÑeÐ=±e¶b\Á1Äû*Ÿda›ce[DìÓ›“<õ•V-r!º÷`Þp?fºOS¥†;Ý|váÏÁMc¡y帜†ÑšjòÎæn@Ë\ù¸ÃÉ"^{ ¡¬pl¼öÝñÚ‡SOÝÕChG¾$®Púâá5 „Ù뿆±ß÷Æ>æfhC Ô«òÒ“0E!œH Ã$ÁH1R¨¤˜Ã×0NQ´Ã0I»ýÙ¥p¡Ò:83"¡_g7q4#zëÄ9M!kÑ´ï™]F}O"µ­×»#ŠÏà}ýµæð|ëÑåI·|Y'פ6½+Û¼ö|TFQZ·¾.YîŸD­oßµ¾ýF+Õ÷¬TËÄH=‰ZÞ¾kyûË-o"µž: µ{÷°-€¸fw¢óÁåˆ%K0óŠÙMƦFgÐßKªÕh$¡QÔÌb„Ï6!A§Ù:ÚäS\vˆRÐÀûÆÀŠÙç[HjæÛ6lúߺËaDS¶ò¬Gù‰b|Nc˜›Û³a½ÏÉ–øCâòÝ/Q=‡g »_±–Ũ'ð¢ÅªÃ@.«ñ"Ø~›M~8‹Tbq\í³ÛéFíu‚X `°Þì$‘„•<@ ïÃà‚bôf/8µèç2>ÌoWWwmTYšy[µª–¡™®$Ú.(^"-©V(¦ Ñö?ƒÐ°L (VÀ”ò_:½VØwÉ2W5ß×kPUö¨žÕ8ÅK6E8×x‰ô±²AkhP™ ?fŒþ£6úÞÑ”£ÿèýG9úÞÑ£ˆòëb¤UIDË_xéuñ-[•øüÇ•]t¿aˤ Ì´Õh"É ¥Ê$àî—°îs Zðëa¾‡¦ U™Ovr(‘öÚ¼®ååü–v/Ùmuû7ér^ .]Òô™I7ìÈA&ºÑJÕp=À à'UŽ£^“ßfK8­³ïv¶¢F {‚Ãùvôšæ#ÕbM•o:¼Z5@éÜú[t.Þ¦Úïd4pʬh¿{uWÔž¾Â׃¨=°Ÿ¶šÑh6ðá¸çx¥cLËÕF×QÄK õÑõnC«ŸQ¼Ù#ÜÄ;S@åѣ—®o´€w’þx AöN¶=I™Z˜¨êÊb×ÛöT2­þžZÌþo|é´í¨ ¾ºR4p]Â&س˜ìÚ:[67Ysíhþ²GmÌÝ‹yqcòY÷U²À¨êQ× E²uü@TH`g¸yáX)oo˜ *Ê SÀz!©ÀNÂëLHQ.€3à„9ö¥U}Ø£QGAˆ ˜w·îB€l¿º}œÕ8¨•oÛ€ãI·ÚVFdˆçD>jÿšô«Â<ÀË‹KÐ,8&UžwøXÆVX{÷½¨c¥rp¯7t•ËhÒj`·ÝÈUÁY•›á¥zª H.‘ãa¾ÒlÍ8j÷3¶WD«¢$pv=G•щ)c•ñb ŠL{u›7Y$QmT ¼UÏ BV8H¼TæÅ4{ +Y!k ˆr œµD¹®vºq= š$x–”åfÛ#4ŽñÒ(úš´E&΢­(—‹+ X”Ë–³AAÈÖ³+(ÙCçðbÙv(/–­f3™‚mgWPT!“oÏ0ç̉.H½›c Òl]Éš^6²ÀØуjkÐïd­ˆªí¶Î£F#jŒÖÂÓÔ€òôUT\ÁÁãìˆ:GM»Qí0yêÇ‹‚Ñ*™iÌ5X&s¦¥Œ½)MIš|A >ãúˆJ&”Ô?FÔÒ@¤62ª#"u“U~µª cŒ¨¢HedD ıç¨ìvìü£ÆàÖ÷ãõM¨ôº k4’³¾]•Iו @µkE_Fϳöõ• @c—ÏQÙæ6±§ç¨jsÜ}óLXƒ3ôuí•›—Eœì!¶óÜm³‡ØÜs¬/»ªÚèsô›æ,µíçè;]ÍÁ˜˜ì9GU ÌR#rô›æi¥2äè;]=c¦˜RßðFÔu€š[d®ú îá¸MhßoÝ•QÁ|õGÛö¹Ëþ”S§³·ìS?öO öœ[kƒ«±¢Í ã?ƒÓmÿié0”>®œ^“gJ½tà]%hŸxñ°Ž¦y-ÆZ|°Kƒ#lÜk{ß%Ç–~“qUÄ¡­["\­}‚æ°¼pSô²“èØ4{( l“å¶·²”i5D)tXk5@åg²ŒŽ÷Ð “)Sijœ…öáaƒœ\xTúÚ #k¬¦ŠŒÜàhúÆ·SÀÂqÐB9Ðâó=ŽrÆO®ãËÚEÜKúµK=$oQm°‰6Q°I»BÃݰ*³ M«²‡´‰fßø*<½ÏîÁ <›tý.‡gŒÙ™Ãadº²²ˆ»ÖMWCVX玆Ýî ÄÊðÛ&½ÂH•P0Hc‘²¾6Óiž=.B «J‘ŒX‹ä¢/Im¨·_™Zc¾ªƒøÖ©ãY®:ˆsÕŽÅ«—»Ö°1•‡´”u‚+:XaÁÙÖÉÞ¬´ R=ýPŸWŒÅ» L}Yû}Ù‰/c=–šöOå•ÚÞáÙÖþÞN­r´ý«v6 è‡}øgeï¿w 8ù€¶vvNj{Çg¯Ž÷µ Æg ì{7Ø÷:ØÖþ¾_ ÏiµÃNÿ—Î@wÿ3> °ýN؈l öQ±¼NÍï€Ñ'‚Ÿ ­Y¬--ƒÕŸOŸ<âþ£¶¢Rð÷°wY„&ÿwm“üGWdíù(ú“ýúúòåŸ_À°‹JÒ;MZy"‹¯¯0*YÚÿÝ€L†Ml> ëWÁßyÛEĪ϶<|ž±:h5õTml÷+ïú¢Éž4­áGþë/é[é·Þ¼š`ÝÒBÛí·º<‰W ýbqS´Œ–V×…Ñ.4Camÿ)áxõUIR`QãÑœCZ€ K ­ª¹ab;)òVª:Ø‹E4e™LB™ ΄]V*‰Hò8®3QÜ Ï£&-ÀJ+ê_u/‡a/F1J-4"XhìZò2ì÷aúQR"¡ØÑÕƒv)#F`»(•Û}ÞèŒÄ`J¢Õ˰GÇ+œ c”·õ°‚ºÞéõ°C€toF-! Ýí/ Ü{ lY—xÕ݃ãý­ê.œÁ·>ì}9ªmoƒgÏýCð–æ—×߯¡N ÉGg»r>5.>×Bh'}E¸åE°o×qÿ*ø¿P¬lm=‡Ý¾±ŸgÏÁp÷J‚OÇÁÖaeæùaã§òÚ‡`kumcõõkœ-´¸w\ãNØ a;û·­`Èw`Â`¿“¥­DX룻üugÐlàÖ+FˆÞxý” ¤ƒÖÍØÓO¢ìíïUÿÁ—‡˜MX,œ²ûûñÑIÕâÜßö7ÖiÔj‚ô ¢ñuû¡@“&¢¨Rݪîmד¿îî8‚ì×·æ u¤Õ f“¢hI^ÝEijøèÆ”wl)Á1Œ“˜ Kšý¥b¦ÜÒ')Fk/<$ÛGRÜDƒ}¹sé•êÎöÖþþ”¦•7 ³Nú ”G¨¤¦²Áª$Ýä ®÷:Iç¢ÿ<Á] ¯Ÿà¿¨"ÂÎÒJÚVÊWoЦÜiBÜÉå%7^’¸‡ ZTk•ÝíÓL¶\ÛÙÙ» ºAf)wÍ­ÛWUÉÈÄSÂ"n“ê$ç‹Y3>ï…½ïLM'©¯ª6Sˆ{¦[]P›Ÿ'rj°ý<ßJ’¨×?«Wσ Ì|¸öÎ;í•‹€è¥cJJnï例*X»€ûƒ­í“£ &»ù‹«ìV€‘«ŸŽN«°ÛîÀ'4nWô¹Œ_;XÓ'ºûI¦'2ø&•`ìa D fÇõ+2pµ#Œ]á.›¤¥Å Ù‚0@¨g¨•8|Œ6(h²Ûx܈M¼(Àûj4:ÁP­L羦“Ú‰Âkú_5€8i?ïc­Æ*œ›;ØÄè1acvVŸitúªDÑ›mÉ›—//–ƒóUÊK4¯°ÿ‰“d%/Ë?­³3`íSqRPDl䥲áà¹_Û>:8ÞÛßEÜTj¡Ô¼þi}¦[9È 4¥L„©cîv°u¼Ç”!g’A·š1?Íc#xvê$Gàoª#§Wv*¿¢#T§ ÇÒs´ôÕ{t2V¢Ó\ÓáÅF3¼AïåÎÍ»†£¬Å틎°<–Ðü3ÁÙ ‘x³…I§ÍŽlbÚÂR ‡ƒˆ:o2ù£ðNN«{rýK¯–hÔ:LõÇ»µ*^ðÖ·vXKVÁ’Æ8V‘©ˆÕþëô¨ºKçªÃ…/Åào_,ØD·wjø6¬««¶=ÖÌ&­Ðß3ZÔ8ñÎílisË.G)ÙL´ß\ùl‘ EêAõ:ÞGâR … DmÜ´ÃüSl$kE㊺FL â,øé§ÕŸþŽ ƒ@ “Ð`C°$-ÚQÔ C$3îÐ8[HÃç¬Ëç«O¡™ÈrÈ n×Y˜€6D†”vTÇq½›RG%,BÛöUˆ–ó^D@ Ä!Û< @³Ál’Aýª†±2#´Rm8^Lt äé'‡kàÔÙ‚¦ë›mÚÊ~ð‘KŽsL’ @ÜÒ° ˆí߬2w…à»wÁJYóTzùR úeŸ¿’¾¯]„qS N;×´Ü9>Ie€sY3®Ç}>, cУèr£Ç¦¼«v/9úµu‹j´®ÁZcs¬l¨R#õÍò _‹%XÛ µ‰„Íb‡ ¿ŠŠ€º'ÊžMLqËËÅÂ3¨Q¼íÄŒ‡ÑõÑùTKó2[]]}ú„ß©Q¦éG€¼h ¤í­F«%BŽ5]B_«(L„Á}ãëÇx n6q÷!€~ø¯ð}©”àÙ:Wƒ£ Æ —0%–/RD í¡ô;úH¸ÃȯZ@¼ðUôT èç¢^«•G:nùo¡™¦óù½^Ä qûÔ¦oD`•·]6J„ä…z¼Î¦QƒO„üv;úðŸzyŠªŽNP¢ŒlúhÇnZþÛщ^õÖYõ«d+ü‡¤]IÛ ÄtŠ ž¯8—_®” ÈrÅç 1?ù±Õ¨D ¶iH´«–µ•¸:wrrt‚8lßpöÂ6hûaÂkG´Åm&ø®’¾¶FÚG”y¯ÁhÆ^b 9¯æ9ýzaûóóm#Ñ—¯›Lí5)Á–Ä—N£Ðè  ³¢õ=.À?@аL,±fSÔ§ª Ôi!ËÞƒçåçAP(+ïƒòêZQÇ.àµçÔ)†ºÎŠþxÛV(¾dÂce^.™â¦« G¿Ž¿^š<Ñ);“ ÇDeц롉Ôns«wIÎ&|€¿{§õZ ~zÁ®Áƒ|§JE~ ‹œë `„å¼M›$¸ ØBŽ:G÷T”\ô(Tª‰¶%˜iï`¯ª†TÞ¾ ~,ŠA¶„Égƒ ®Dl‹bk˜ö{:  –2HéAŒ¼l‘)¦úc2ã`«bP¡à Œ ,GPmui1ÓãâöKOâEÂa=!A X­ÖÜŽ,úÕJ§ÙDÕ˜®îà\Ë¡‰V›™Ih ³¸Ç¸äêq¯>h†½æŽšU·°Žæb˜„u«× éT,iˆ¨0+j£$~ I&2.âHaÄŠÿÕÒ+Ž >y¢i‡Âçž‹gcž‰ 6‚fŽ-.Џû&4çFœÆî>´Ôøµí¦þÑx®@ëGC¶”£Ê¶ù·œm ±`7iѸŸ·–$Ó0»ÉmøÛxû‡²ìšËÜN’ ùw»Ât“tñnIa™† !½Ö š@–°`y =™èŸüÙ{‰žq¿¢½g…òwð~©Dý:Ù`N˜~³Æ®:É«†B›cht_·Ë´ë­.3Éñ>žÓe’~µ]>• 2¦ãÆI´vù¢\Ò7Þåf¹ôyØ€Y·`Ö™‚†‚½°Y¸(£‘¡YfúÿÅ:ýZ/n/^`ëð¿ëÂ:ÈßE [D ™WM©Ò¦¼n‹x]˜—Y3ËØWéÛ{ö‰©m+ÔúW¥_’}©Ph–ƒ•à&±šëøoè€^ô2n¡43Ä'’$õˆI/"­;’oñwùý_ôßõ÷1û³¤6Œ4ÂT~% ]Óœƒ2Ý?/â×{ø•IÈm‹†ís“>ýs†od8,{œ¬½Çñ‰Ày€Þß=˜LjÙ0¡«}ŽŸ91Xs€ä5$È(AYâ…6ÆIlG›X€äWÅœ@Ø Pò/ ä9¨qŸÅ[oü_1Ò4¿âüÚQ‰Ô´ê»±HJM͈vèKÏéW–´Ì$×.ö™‹`ú‰Ga±üâüguÖ1¦vÅDÚŠ%©—56ºƸê¥ÔA¢Ãy Ð-þÿË1qr³òž%ßÑÖ/–™l â‹ VÞc_+ïÙ{ã:›¦}ÁZWÍKq Qów>rëÅ2ôUèKýNWܹ¤vJÞõ*|ÇM©'Ù'Ú‰S#bßõ±¨¯¬ÙiqOÓ`)”™Ã`¼õ~%d=£',ŠS|‰k ND{Î_͵¥1ß]q¡‡6àØd+Øå¾Ô£n?`´FÕ¼u›!:u“CD¨Ýýã>' ŽÇºLµ-Ø‹~!óácÅÀÈØï#çÞÎÝ&“ždÁA—y]€n÷Cܤ ÀâIn¹b¦Ñd3Sÿ¦Äñ†•YnÚÑu+juz7†À/¾CžD÷øïhþâ@ZD­o7ßÀfg–¨QÕžš\°Ã­r…1-ßì^·óÎ4µ‚ÔlyûjÒÆ:“ÆY]ç³eІû£ƒñ0ö€iãôiö Æ'âVñFS? 5@%5ÇPÄ =š¦€èµºÕ8ƒ•( ž¨ MÒ@{ïÔc:±ð’v7wè[ª©~óÝÖ'œä”Ù†è,œEö¸ÐïG˜DÐ ¯-Loò Ã´<üc‹ r2©q‘3H¢^ê0ážÖ1'sr]®ò ·%Ø–‚‹8jjÔ±WÍx£Í2Ñî²6» ‰0‚ L w¡•s™:«­ÁoxvëtQ·íÆüÝ#Ò<`jž«U‹>œÄ ? ¢ÕIú¬¢8\®rscXœ§Øá)†º¬† ÌÕd,RDZýFJz vŠœ†ûÂD%ÌLy·ãäJƒ"£ « ¼µ1¾DpØéGo˜¯*À‘óϣ˸Mõ\†â>A¸ìÉ¿_‡7{Mb8’V:fÕÌ·Ñ0$ ÒÿkõnxžŠ´MRSæÒéJ0-fçQÆ0¯-@£*W¶¨[$z££­¦‚¡%T[Ì\ÚÔ•BþMimä^¼”µŠ¾$F-¥ù‚¹½ªñR¥ðþ=^4òØ Aáe°N.!OxË1êÍà^&"èæÓ'úc.• Ÿü3þ—zOh* O˜%¥Îí…ïø™¦À6¶IPPKBñsìKuUQîq¦×|«U¤qÈ_ÃC}‘k¼œUX™§ý÷ZûMjïojè ²ÆP¾ògì½ÏƧh®¥œ™M|/ô.VêÔÍ¿ê‡*Ü'©VZUÏ':ÈÕŒ= ­{Füâ¸8¤Gý€Â#s±ÀÝôêBù`Yã1“)ŠŒ#ÀoÃx|ž ŠÈ“ðh›]8Æ£7~TàÍ®>hw;Ù–-ÔÜÒ /Ī»ÇAùà+©ã3e†¹™Ã¢îÝpL:/S–{¼3SR3Êà .#Ø‚†ªB8rvïE|Uhî§b¨ëo³ âx|ýF¯à‰ÁJ(*CöZ]¡Ù Ê:ò—O°àa¿¢°'ŒøšÈ—‚<Ö…;»€oo5áŽö`&ÊLÓ “»8@<ÙYFSGf±ˆ"Ê#Xu]ÉoðÉ rçE'.PØ:F±ÒÜSÁqXÿ,‡ ºñæ’:Ki§(¬I•4ÂjVŽßäß|;fÏ¡4¾ü³üÿ`‚KkåõW¯¿ÿáÇŸÂóz#ºXRö|é Åúàîh}+܉ÞY#Â*Á¯ þ@œÆB܉;LmÖ`ÅåÃùr¡Gø€£.@ѳ`íËÅmѯþå€ ÿ²Nìu ó§í®{zæÅ}êËZ`40Íá~JL£¹Jð•P³éIJ²u¨*=_ã×e Ü“Ÿÿô¼(ŽŠƒôX‹Xi…Õyû6xÅûºo24š¼ÈÓd*­”׊©vyMaãBÄžmÎyý•…˜×ø3ò4&g”w.ÄŒ@&ÙñœñÚsSpðçwicŒ%@Π2¾è`ß±’Á¼öv(Ùù\ð3+CA‰•Å^UX§Û î=†îv h¿gõ”ÄeÛcËöyí9irb{”â­W§A%³=¹+ò[H¶¡Oßû  Â{ð?8(úF—¨‡wo ]¹½òR6@ože/1çZùnì©«„å:®W˜²n(àçƒzi Í?Kö¥µ"1*÷Mñ”‡›fRïQô¹§¬Û¶ {ñ¢^r¢ÛF‹c'bÖ<7'I18S‰Ã ?½ƒŸƒúè[©3à¿‘éàÿš¬xBæ#dü[6ÜT„ä’•JTö¢\L)eË=¡ç|ÛzGo4Óf¼VÔJ¢>]¬ TÌŽïþÍxÍákÄû vÙÓ¤˜5¥;ÿ‹¶1vh›Åü†?ÔïWÊÐÞ‘,—0ëÌ óR€³a·ÓnD_TSóÊ‚‘ïf´¾^[0;1†Éé´?ÜüwÔë0˜ï-˜#8M_4;×¼-‚ùÁ‚©Ü´ûásî?Z0ZÑóO©v’~Ô²p¸fm‰8? ŽÙ˜> ë&«%Õ‡ƒfóD„ñ°+å§ÞX¨<®_§Í¼]ó°?­²Q²²²Â A|Ow“àÉ´}\Ò_~ÀÁŽ4¨±ƒ^Ÿ€†„ÿÆ(3ôÔ@xhƒ…þÙºÏv#@Ã7—¶ »û;:¯cdXõ CH›_~¯œ~ è±èüÖ 8®âR$ÝVœÐ)3¦7Ð0Dý4Ʋ_ ðé¦ðl†ÿ& 9;Ñ0j®cà gÙ Û«"¤ö†1ik'»Øéè°Ä~ò ü ODµ™!£½ì7šà‘¼´(5Ç[ÕíOû»g»ûµOµ½ÃíýÓÝÌFÑSPF¬Õ¹Çù†:5›>8ÞßÛÞ«òX`‚X]<…5 DDãU‡Þ¿6q3¦¡6}dÚ€ÅÐdŸu4ÕÚ~ ÃDÖ(ß@Ö8Üh4ç*J¸Ä*¼vàCЉÿ©!¦A5ªâŸúéŒ{&gÍ#féxÀÖŽ>üçîvÕŒO„³Þ;ª±Øc¿ìQ\1»¨pqUºhƒþX.ÂÏb:^Åpïè×Úé™8‚)$Cñ°¥@ß虆§g¿Ó/ØÙ ˆý(º?=úUoù”·¢þôÞ Ü æ ÞŠÈuæçwÑeãN¯9 üì×’am@#3ÿÄg¸> íЋz½ËaŒ>§zowÒô9y²Ó ŸMÐVØûœôa߯¡B+ÿŒÏ)Âìñ`!<ãþÑáGñE6΀Œ2Y΄y…–š­àß~_¢„?£fÆLŒÑÊ® 0Lù*䎸wX]?®žˆÈ…¼y 2|Ä2ZŸ¦>›K±zr–F3ñ¸6rÖS!lß”’#ñ'0‹æda(¼#ìÓDVf¯©ÇoFp¾<5­Ø‰¹†íÉIpüÊŠ‡§FÅt5ªõ½3 °ÉþD{g¥® wê€;uÀjpb ‡Ç)îE³ÖÈ ))ø-²€¡i&5+‰ñuùPu¦D–þŽFx áñ¬X8)é¢M|£PPð«ð¥D2$-/£>,p 3ìC@y0D¡Ug÷ä¤r¦U¡ß¼baé/•~ÙÚ¯ì¦ûêV?ý^“;ÿŦîs£Ž SC†oTXXœVØŽ»ƒ¦|3Õnˆ~êå£î^ÍÏ܈{R‘ñ\Q`7 uû ZFA} @"¶þF¿KXÒ ˜XVá‡$œ´@õ³’ ¯—ØíËÓՅünU')^~¶ÀÍC•Y¿ˆrW]ã°eV5ЬjÚùˬ¤XUÔq̬¡¾§úg3»Y`U1Ojf-³Œ*6ØK愤”k3Yg(_FF*Ô’é¡ qðÛNö° /U™ð`MXÈÆ°^âAæ²Ù9›2Z${p6çð†\iª´_LÔvv·÷ÊiŽYΗ±\2Å’¿:«%¨’Ó—ÕSvCº°Ýf±:É&ƒ¡#ù“B…ׯSH3ì‡]¨[âN{<—úSòO«äž¡³)_Ç[íÆÑuÛÙ}©sÝ.:;æ•òw_Âdzv4èš?ÖÃH þ™“7+y(ì™9ÝÖÂ8ˆ«süáÃŒ §ƒ""^Ë9J ›¥ a#1g“F(«”…MÕT‡T›£P@¥ŽD&e/ew,{cdo0Gñô^;!ŸiÁYh¬µ ìY6hjÊ¢mš´«a}Ò›¥ÜÆÉ¡L>i5Å_8 cèEcYS´ƒÁpµv!ÛѲ§·¦M fÕŠèy­˜‹ÂÉ?úbÉðq”ŠFÖvtöÇâZ|j¢¬a9n–ž§‹Õ x¶ó=Z `£·QŸ»šèîšÎ?µTœ•Ìv+’À²oÝ«JÍ`7¥b§'¢´_¦èfü¹TfW%Gü‘\ÀOž$CL¸Û^´SMðñ¬¶µ³S,KO‚¿'K%çXY{foMÐó÷äÉe§ß¡€ƒO苈ÂI­ÈWÌÆ¶k´~~ŽpÕ%CΉy¶QÉ-M9z•¬J’Ùêp„H¶ZI1!£ZÒO…@sñN]J(Û‘ÓzªCµ­“•Z¹ö.Ëî^Òc'…*8ʼnMÒ(!Äרé:5ZBÈõT`8ÿHy…ÌñŽ×´¯hz6ç.Ù_’~2ûs: iuŒ{ D€p–‘ÜÓ}¡‚wßÞ=®’ù}-è3nå[Ìvᣵ0>míýèU0¢œ-%¶þñaW§˜ç8@!BPÖ°S ÂÍQAi ôÙa;ø½¢t íÊè÷ÊñÉQõHO’Á?ñ+}ºÞÆÈlŸ-uÍî®w‡ÑÝ}Y‡ª Wkÿ÷J¡Æú¤ÿêÃ;D<<”vEspº_Ýc·LÿÒq½ÜÍaêËY…Füq·Zƒ™—ٙ„I,óÌx°õqo»vŒEvT¤i¡…úT¤ÃÍÜ (¢« ÕI6óæÍ2å„ótýŠU9ÃÐS4 >•i¨³øêÂÒ9ÆÐ‚VBÙ̹)Ž(M¥ËyªyéÔÖ·B %Þfù“$Ãê”cÄáõvؘ0x5­h£æ§øŽ.¢÷øt˜™ÌÈÕ#ëkŒy Ë·=QU’bq‰d,{I‚T ?×Úƒf³ ŸüµÏL><åìB¢JñŒ»Šµ •õ?«}$ÊæOï«UQ‹*覸“²®%¿G_Ej³°ô÷–éõ0÷I$— a-NXÄÒ–3ÿFV‹yYIFÑéºêVjmªñr#!VÙahƱ,)‚2NOÓΣþuD/z”•î(²=ìèìó#°g 8e5;!¥%Yì( §S¯z òÆÿ«RèlŸ*…ŸÉ£¢o9ùPà_ÝN’Äèá~~Ã=û™õ”Eþ“}·É÷D¶­'¯XÙQû&¦#by+x¡tz€¯&XNv°¡£Z¿ƒmˆ0v á’ªÀ’>_îñÒ£ ž°9 (…2›“ŒO¯eÑ÷ÿºèÝP,«NsÈús¡R£os;`䘊±o‡ý†¹½y€x¹™âÃ_ÇìIÆuÔl–ä'Žà¿÷"æ ¨&çU#o„Ÿ”ÍËJAkÛ b\ðêÙW\àø¼‰ác³'øò¸쀾F¶®Wé÷Ö-z÷.Ò®ˆ(’ð›+Ø"O¶=n‹_TDI§{ÒCRìMvçK¾'Ùyž2kOe­ÍÒáY]j»s¢ä‚Ƭ¨?4æ÷˜‰*GX‘ fµÃÐ"*~H;~!è®ãßøh¦^³CâXÃXèÀ"°r{ÂNÎs‰8ß[^§bEe\H8Žs 1 EwS·y·ÖgQGøu ¡û×Ëú~çÆšÃÿ5Ô éØg?á4àk‚î@'ز,ai•[¨!b ¬°Û…£3í.ôM…Q¨ ?’‚¸µOŽ\ÔRë}ð·h‹G¹Â3‹aÊÜ"aGâ±âeƒº¾ƒ-òu³w†éÐ÷°i€*¾Œ>'g¬7ÁS0,LoUè O³³~íøìÓ™–´„«µ­Kýqe(&Ó×úfs‚î`bè?ˆ…¥çÇÏ‹&#·.Í4ÂÖåÊ{¨ÚÔW•{¢O¬™™“ë€ð€Îs4J½PË„!‚C÷ú¦ðÎVdÞÙƒT<&Übxˆc¨£;ÞÓM0ÿ=L@¯ýIÞÀÇüë¸ôZ¦0ŽgF._­Ž8Ý5²ŸœQ—FG¸ÊEÍû£aÂå0ŸÊ‚¾F'õ׫åuR‚1Ëw¯Ä›íÁî Õë"­8æeZ%ÊÿMãxCEuv‰ð@©'í¾Š)¥o¶üÑ’RÇPeí×K|—žé‘¨wjm‰¼Qfž6kCʦJ[ …8°m`Œ"¹¨vEÚPL›ÓÄÈôVŽ÷>+È-Jõi½áAw'2eÊ|Q†ž£ïd|Âl?£ÿüåºÅÞOí·B cAŒýØv†ÅËpzf í( Æó¥Cä<ÒQr¥Üf‚ËAo@VQé1¦xÌtX•›Ê|ŠŒJ©Øž™dÖMQãx6îeLáƒ1Ž@àto‚.4âþ4øzö¡p,±¼G˜…^5GÇqÎaì„m¬ÊšºÔ†ÉF_@ÙNj¿JÌ)bíãW¸þ±«´ÄÆY\÷4-x¿æÓ1§¦]¦ã—ºµYyÕˆµ¹^º–~”¨¢¥¯/GÖ9ØôX‘ ]u@¬›‚~ÃòWŠù‹’á¨Ç¨y±©óÿ;bŸ‚ ±$p2~þtV(Z+ƒýdwϰçÖºCæ]àôý"aŽ7CM¼ó--œ›Sà$¬5#øiÂåÈ÷¹"¥½RpøX M0¯aÑÆÕð]jáÂ(N¼¹ÔU‹á«@%. d`/^Q—ìßT4îR€ÓêWª*`n÷—íÃ*¬·:a£h‹t;A#hÜÖÛ,ê„K†ÄÑîjÕÒJ¡Z=V«/šAØ„uAg „ÌÃ_­5$½žÖ!‡¯Yz=µŽ°žî=(¿Óë‡MÆñ†ÏƒÎÂÓ`SIK˜Î¹„Žlüæ0ÒôØ þ‰Yk)ì„zÄ,†g>M.«Ú^BaE|º\^[[“á螎ýrY>yÏî‰@¹[ qyZÐ:ØcbÇBhîpÐÔ`éåfòU¥mU&æÏÈ,-ÒÞ2z+ÔÜݬD"$×Ô³Ì+zŠ›åºaH)|‡â‡Å€¥Ó.Éó¢[m§c†º¢‚KËÁsÉ1=˜"=Ñ#YT™Ñ(Eoc“:Zd¤©=)wwúâ…ì ô¨)öëze*5DÜæZêßh[V¼6‡j#ÝXÊ>PßVè%&·£î ÿ¦xØšº$s=œzFø}sˆtéÚDý]Þƒ ÷¼ ENú­‡aÑzZf&«$X¶>ã¡ÀLÑBN©V‹eŠ=oºR/ýi±‘Ð.…=ÝK\³oÊ1¬-MÌž–ú‰‚üQûjV6¸C–ÒÑJÂýËþѬ[×”W>6œ¾3Á+óó‡½Ã-LàýZ¬m6=;• üæK(Äk©$1Ž,I*6§Ðe ßhµš´´X!»ÅÔ Z¡Äd¹«Úr¤ æ«cü›O|"8ägƒEäí=i;}×çKöÙN#ÃòÇÈ‘ŠqhÌD¨ÖU¶¿vú¶>í îø*((×í’RX:/¸¨¹Êhº$ußÒeÔûBX$p¼äoó&lºÀn·ôùËH—G‰­¼¸Ú Š?…yW=l/Qt)‹D yÑä¦ÐiÚ‘#åÇaŒÄo_Èކ싀È5YËI£$uÂtàÛÊO è2 T]äÖa\Èó Œ/NŸ³`3zèڻɿÓ]À0îõ!9~|<«~ØG,KŠ[àÁ~Ø÷¢£ÖÊûdØÇëº#0¼xÄzwUHœ˜‘°ºŠë ‡ô².zQÄÊqÓM]êñ 5uNy·3UMyàÐk*ÍåݧǀIÆ ;¸ãꋉK)9”™åb™W,›WñFf.6#†×¤=Û“TwÂñ‡æÇßÁÕp¨oÞè—øûL† é ĬïÖª[öwkh¥æ‡ìà/îHDJS»DßÏž±ë14e!°0".jR{W‰]ñÈô[R¥Á9â{.FûÔƒtKì‡:tXÄbÔ`&>óêf¶@K‰ƒìlÊJâÍ;ŸF¾ÐI¿uzŸYV2¿o)œ,e.ëvšÍjL«÷•'³n“F帟÷ÂÞ zS WÛ„%Bºè`_2³c,[å]Ôíu`SoaðôÓí6Ã>êe ú[Q%l¬_^õÙù#ôo<¤ºa“í¨% ( ÍÊ6J±6¡^ÈRÂÑã×dUsýmtj¬ƒàoì®O|0]}àk½É‚þ+8ö%}‰ê}0Á’zØ { Šÿ6ÐsBÐ/€îÀûi‚ðÈò H|0Áèp¢€ØO)¢ è— 04!†ý­»û „ý4Av«ŸŽv ÿmu†)è— psÓŒ¾(öÓé†=¢âƒ ™¸L°ØBsìÂr/ºPøÃ.z9ü2®{q_0ûi‚ÀV­ð‡Å&»8¸a ,}ôÛbØK5fÀ_&Sÿmƪ»€0a²¡_V+¸]jÐOk¹EÑçF¬¯7þÁ3%C MŒvÄìÜ@ày}aå”¶rÙokÐÆÄ“ôÄa cJ²9N§É6«ý(Ò}4“øRoä¶ú Zn Ü*¿›GªZ ¿Ö@j!¨Ùµ°{‹ÜD›±˜ëDŒMzš'piF!Çþp#?»ßÔ™–æüVX+VÓøÜ´Ôøeoô¥Ûãm“’DÈÍ#Û4ãè’=ÉxŠ;¾{6ãOÄš‰þÈ)À½¾Ðf>ì~Ü;,Æk"}¤´jÛL©Õ.j½Úÿ°S~­¶]!ÔZ4N©]%ÿ\ûWº‘nm{‹6êÜ=/#¾ìô¯>`ì tÝ úap±/Ïf rà y¶øÊ ¸]Ý>vŒõµú*lë`ß{ÀH“×ÈD èÀ?z€;í‹øRü) p—îˆuü{à íôÿk ¢*ð°¶²‡jÛ^Tí…í„y—Ä_b3e ·{ÎCÀè|`̵ì! ‹FaË÷Pp'j†7QCºQËCÐØDЇœ»ÒÀ«{ȹ º\¥Ç3ÖCÑ_ŽS„Y÷PótëÕá<„ÃèV£ÑÛ£L¸‡nŸªÕc{´ëÚílFýkÐÿ h:Õ°‡x42–Öº‡f{íz§‚‹³·E•u ÿŽ<y°î!â¯qý³ ÜCG‘ºRïtM1æ¡æ>¨ê˜Ú€õPÔ1Ž 5AÐosK¾í¡'@Ûl²á!&€F®qxzÀÓ„hj2È”LÛð‘'¨‡„‡±É|ÚºIýÊC98ÑÆu.^yÈwÈ^½¸jx¨xÔea[=Â앇œÇ!F˜H÷â!)7Òtzå¡(B§×è+U:%Ù^yhJéK @Eÿk;'è!ìI6]ë쵇²Ðzi㵇®·zí!jÅ9)+vÜïô~Ù1 =”¬T*ûžÁx¨YARâ6a{ˆY‰zCkØJb«<‚“í!'B`-«q9ÓÜ÷½éhú{)ÙS,ÒGE®3ïî&õÐõßûhÉ«°ë7V%I«t‡¥z(Y {—‘kU|ï¡f5j¡õÌ„õÐSÀîw:]`°>¾”Ñ«y+ª19fëï=ÄUªáå'¼C7éöƒ‡ÐUcê?xÈœ’H?x¨\ítû‰=‚úqøN§Æí“èâ Ê­×öQ\Õ¶wï<4?M¬¦=ô>íÇMƒ\?x(ü[t^ôØóõWA„]ã@ä¡+V°TÇ=4EÐÁù±E¨=„ýïÃmÌCOKõï¡%€ºyöGùZ ºèÖ!=TKì!¸©¶»UÇÓIÕ’,?ºI·‹G]Ôæ¶z—©to`ÇŸŸÜ´CøSLÿä&BššÜOnªí2-ÅžàOnâí¦àÜ”ÛÅEzJË‚›j¤ŸZÌû“›lt¯w ƒ'~rSðÀ±ýä&ßÜNbWûnâ© Ívå57ŽÅ¨­˜Ðn*Vc/¯¹ é‚t–tÚ*R^sSR[*¯¹‰©Ã»¨T^sS¶jèU)&j¢ÜD±}q×Ñ:¤ê&¶^å8´LknZ£©Õ´ó¸©Lnœ›¾ø‚¿ÌJé.e-ˆ»'n2_ ³1Ù)¶)ÓÎà²W:>‰“lM—5÷A´ì18Í~,îWÙcѺPÃ×,EikmÙcÛB[¯Kº–›K±VÒoÔj„Lo5ë·Ù†›m/ä¹a@º™õ2nX‹ÇcýŠÛµÐ:­”=°¸mµèfRÛX·;ws)€~ÿÊu3Ñçè&½LfŽÐn-ƒƒA¯¨²ÛÚÔRö˜:µjB²êe0!«ÇÔ~ì0“›=FQ½!'I2˜UcŠßÈî3xÚ!&6ûöPYšwûH2q—o×Ï`G£¾e´›ÉàJg3Êâb·”Á‰FKÊ$e·Å}v Ìðd·ÁˆRB:YØc²µj’kAºn÷©º½Ž£× ”53TI׬/.?Rµ=¦]³6Ý¥«fpŸÚŠèò"]7ƒåRÛ˜Y3ƒÅdMÁ¨é~3ØKÖFE8]3[!e=¦âts# ÝpFÌ^Mvƒ9ø3—2ã1O“õ é±K#ä04Í+»ô u²õ˜¤ ”¿·aÝ<6pD=†i][1áÝ|$áIM1k¸Y…ž•¥Ï+uÊöiþB~æ^õ:ØOkÿÚ4àtÿ{íCð.øSÕ+åb¡+Øÿÿºi Š^…’Tá‘¢ÍÜßÿ™Ö~)0Q5³Íƒ°}ÙŒΦí²Ü=øÿvw2\ÿ( º`žw:ýÚn[Å”;– ¤þæZ2º=øñE-™Mˆ'k_Ö6ÖÖÊëVöý…‚H j!Lj:©ªè½Œv­|“?aË€ÄèæÞ|SbT½í³`¹>,iѽUe9ÑíN÷æéßxœ3öÃð1>ôÀŽð_i/d ;!+ úí^˼ôïvý%]Hš‰Žñsõ ½ªìLžþÎTøôwîN”.@‹‡£yÐÚÒ_Ѳþª4&G;¤Ã9ëàHÓB}J—ÿ=’ø^.ÍÖ;qø?úH‰JÇ žGÑ.BwEõ 9w¦K„ëdº„¹å˜ßAP⤗L`RÌâÇf£W¼¾˜qƒÀÝã½›I"ß?Õs)>å×Õ•aµsHAw1òa€üØ#6=@¦þ™?ÚÆÀy<}pðÊÙ|x¥uÃyó†Çý0D[ýTª'û»‡A3jóåô¸”MäœøîJ‹FB­y–ÿ‡AC`¢‚úþ¥×i½‹§¬Z;Ï‚¤hÄ‘é)ìR²ŠOÙ Eøl ü™†c¦µ™x›—^Ü¿j™Ÿ[a×ü ¥†þ§æ²éæ w3nÅý„çU)¨I`Õö1Ckí`ë÷"½¿Vª@Oi]«}<<Ýæ)ÊùǾ°¨Åzú ÙR‚s€í…Ue%(ïïͪB5HØ;×1öâ‹ |Êà­g®ÐbÓ;¨lãή ùûA³©¿°æŸ‚ûWüý«ôÃu*JW“µŒJbdŠ?U@•­ä,lŠ;Gú’Ê^##©p¨eP]‹OE8.X„{"ð‰ˆÙŸ† i)žiqšFóÕZ £Èž¯º›¾yzhÒ?íØËmµà­Ð,<"ÅÎÏkY@)¨E”a¹¢^¯ÝÑ1bˆ.¢KƒZ]•5`ÄãâµÞ»'[‡w)¨œÖÒozúÓTœÐ'†u >ÿ?kÏy¬Y›0æ'&îôðæ OdpYí™°Yµs>SFÁ@Ã>…B7¤QÿŠ}SlÉÃ_IæÜÛ8Œ­dS-lHflÅmõïð £ÿý£5dä'Å4ï_P |Á!<',¯qU`¸^á £ /¨cA=Š›Ö÷^¾CÛ_@|\@ïoƒµÕ׸_AKo …ÄL(ZdУXÎPÆ£è½stÀ‚Ù, ÙÎä(3*«p´Z3ª Ç7t;à\]Á(ß_´¨X *V`P[„ÿÞßW‚/&¼„á¬PÅì?8*V󅬉c„oØèK,×GŠEoƒ—w>ì×v+{ vµq,7¨­Í¬>q¾3dŸ<ºW*ìRy„43ahÒðÔ_§g´ú¡àÌ’+<-=0"ÁÚ>âÇSµ-Šù;¯M¤ d L¹»'¾g|¼N¤ Œ{yç0óI¨pA8éR$`)€§+íMÈ!ôMSê—ÖîµÜç‘1𲏠’ˉыJÌØ”=z‡žÚWÛ³FÑÀAî%ÀªÐ0©†îâYƒ W&ÿ=I©)‹…FQ¡ÚßLM}Ä–—OÈ Zü2&0… íRár°žäQ2ÍÆpðl(À™ØÕ0\óÁ)ÌÍZÌ#xÓÚ#lüæ)cÊï zàù¯”ãG'ÌW—Þ â"â™+'ÖË ©h—-ÊO,8²&®ßKQÇ IÖQÌB”wgì€C;®Š|:rXlJ†üVå˜ÅtéïÍÁR)Ppâ°9¬­óà‹ü ;ÞÄ)~Úˆy#Œ˜6ŽÌbò‘ÈÔógŠ ä'9[zGe-ø€ðsåLïE[sú Ëe¼Ó`‡ãZ¥iÜÀUZµZå²Vëvº:ƒ3°·f}àwŠ\”ʇü£LP´òžÊY²—þõ¯z”g zé úµÎE­¶/£ÂtÎD­nÿ&`CX²²>àŸ1(ÔBYϘî²àg¥ÐzÍÁ1ùÅ,ùš%½ò¨E³XGÃñ•!·±°ª_ÿaZ’´4ÀNeÎDŸÊýÖ‡òªAZÐ]hA‚KÁ]hÖ*PµÇÔvF(9ÓRlÞ¤×À"%qó>˜©š“S»™|[£4L#·µŽ#vmnxá ² 3hµûÆ>çØL(±ÃûwtŒß"˜{Ñ䨖úÏø_馤bdÿy÷P6Af#ú@æE£"{ÕMóìo4“1ÐX27é¹aU¡9w‡RÆæMrÒò+[¬Î¨Yl8³T°ÆCXz›{\À^Ô¥—® u%Aòoc¹ê4=†ø‘¬K®(©÷â.´Ê|?h#æD„6ô|àÚÓÿh™b~ –gêÈ=—Z^DKüI6ï…캚ÂÁ¢UûÕ Œ@ÁÒÖTVòlBa —ƒ:ËL@/_–ƒ.þƒ«O?¸ˆ”€ú)€¥R¤äxé¤X<¬D}8œå=ßY–%ø*fú8¶ê2ZSÔY†ÓDÝH³³^8³ìFâcV¬üB˜Ã±›:iï†fÂæ*õdú)}îþvôá?¹¶¼\ggƒ´¯!Ô˜VÔÂÌŸ?ý‡ñ/Àw" '",(.S”cJ¹öD)êª ¬Aº¸×µöw`8ú7­.Gþg3}FÒo.l¦µ¹_Œ µ*ôX¼V™yL‚Ã0›ÛÚf ¡Ÿiê*™´Àœ§ŠÏ†Ä¢vØúF’$‚xŒº‡C:“=q¡…Fò3%±ÅÞ꣠ůÃùÂC€Ì$“ `þ2zȨ£€[Ön\šÏx7µlZ‹ðŽ‹Û9ûXPpKvŽ€лÄÅ3†¦¢qˆ¿e|Z¢á­ò7íU™Z†,¡Ø?ÿ…st™\®CÈš«¾B‡#žGê{å¾±xÖÔ21ä¤×˜¶pD-KÁ²ÚÃôí@_ý®¥'ùd¨™(¬óãˆåg.¼ìƒ·aMÐz´Ð®5Â3¦X§=ñÌßTp¸S¶[•æUE•æÃ™©±ÿã¶/‹²1[ëYËyÔÃ^/¼)éBCÏk©çGtlö©¬3°îÃÅÔ­'­~*­«ªšð¼rÏŽ÷kð…etÕjªQO«¿üXëèV; o2qs¼ ›Ç"ÏpÇÐaM·Ëû.ØÓƒÍÁðÏüŸ> ™ÿxò .}r!®$¾2?ûFNDä@„¶Â®Íº›#Lbµdc×jöstãÀlºE¥7oäcÅXJÓ L1‚myðŽ Ád€ÅLŽˆ ¯1 ÜØ(IÀf7ÈǶÙXN&Är†¬àæ›d´ ¬Ýožà½0‰ ±£¥Yr ¼3ÇWa‚QBÏbEY¨Î’:2¦¥m ”ï=ýæSUwaô>5¤y™Qó#0­B¤ø¨Fd¢0­LøPXÒYá›S&¨!z4(±ùAœ°z½ˆ#|¡[DÌáÌ ²§Up·4}f}»V¹õB7ŸMB€™04M4 ÜììFo’½%ùyºª1!üÖøž>ÃÏÙ ÍŸ—ÇAmîÿteˆoeÑeÜ._¸T#çY~Zèæ8÷ÀƒÙLñ’4ãz”gàÿþ1M)Ã(ó"vý@ ?F´´æiä=#¬hÇ¡}¸'Þou ¬¸èKêîÍ %ó÷%hc•ÿò+5ü2ÈCÐÑâk<ò•<€\¦ y©öPØœPïEÂúÖº¤îPЮ4\%õ½t˵Ÿ!FlÖq4-'ó¢,| Ý[ê*nSŠ&«¯åRjjžþ¼»†§†¦<­˜åaùÖ%ÖÄ|”Þ+ÒÆ@Sõ?˼m8³NÚw}ìôLiNGPOïÏ20š:ŠÚ}<‡úP—:‚ºQWòPåÛ²o?õÝùOíëš‚îN^Oÿt=±¯Ó躔þüpçæ”ð|êˆíLF¿ï ÆzW@×rïÄåØM”èwñú…,¦VdXÉ|sn¶×î`"Cg{”¥qDƒî‘T†˜T˜.éS8.À§¹ÔãuÀø³ê‹À9ÁŒ¸ âlmíícУ¢.Àã‰cwD\ŸÇ2 Ç*hÇ£“ý­Ã Ü ü¶UÝ>:(j Ú]|}¡‡0àŸ‚šV˜Š®Àr–ú†?ñ‡Íð…Ô.ò òg¦—/SoÅôÇbA£%íçý€ÜãvÐî´ƒï_ÇýQ´²áÞýçúëï¹€OŽ ø¹XZì9ó‡Ð<ÒÔñ&Ü´ÈÂ{6¦÷ü˜fÿÄ¢½3ùòF`aßFœï^cZô2ååy‹7­÷wÜóÁ3^j fÔê㪣 k ¨=Ž2ŸÛ¢Ôæ¼b‹À±žº_‘R÷jEº!À_.a’ ZQo6lJ<¼Ãè¹ÜbNöÄp5r4~K@Ž „0Y@!ã `½IA¯O=LQ'ArÕ4˜ï£c–Ã/è´™V³œ#^‚Ú 9Ò»ði®@43ˆp릹aÔÓ¤”f2÷ ùÃ$|#/²eКv¿Ö ñ¸ZÞßÞ¾ 0ôÉÁÖaµ¶³÷Q }Á®•ä¸óDV˜Jx¿ZaÉ1¾qr(æ`š¨2qªu>ËmÏMäV?φtSË6ÛwÕØp8jØ3ÅÜg~(DdK‹‘h¸thÛmVHŠ¬Í•ÅÅŸ- |a‚€T>Ì# ›õxq@R’ ¢müÎíÙ1äzw<[ÌæG(hgA9C›Yœ\ ó}DgKüj[°ýÓOAXïu’$h šýƒ›a¬Ô‹¦U +ý^<ŒÃæj€ñ]“ ¶¡ng7D€eÑ2VYòNÙÄ*êo"ܯŒCÿ.±«6"Ji\X3ÐÌ:eûÍ€ºXÐ~PDǦjATŒRBÿ JßúZ¹¼¶±ƒ‰Âpú2AlôÚ°Ï”[DüïUÔ¿‚™šS +Ÿö©Ó{à+:¨—ÍÎ9ÐãMƒQVƒ  Ÿ{Qˆ¡;10 ¼ßáÕ»ݹEmP0ZݸQ;À4˜§!Y}оñËÁAø9bZ·lGD_â¤OM…d…m×a¯ ”— ÈhÍ/^,áð{Ñÿ â *LØ\/záe+‚¥ƒ4I º0›)d°çàOà¿óf§þù)’Í”=5zx¥´~»úþiÜn"AehEÊ&U¨ŠvƒY×è@;ÁKÔaæ‹ >qt’æeËl«æe¹B­– ÚV4ÔÊÙÉ+jPšåâ(Š.ºd—ËèÆìÅ4¦Ó²ì§ø²’­Æ—Hà ÛÈm'ƒv3‚å~ =üEù•WêWQý3®·"ýYKl §—ðߌ±þ‚HÑVÛÆöhÜ…ßAB®ü²O%äï !ùO¥š —L7Óh¿˜'h*ÃϨ݅A©ÝEêÜ_F*îùvÿ쇳Ù_ØD§¸‹cÀc—LņÒ,qdµk•‘dܰYl³efP³ e¿oÞ·D±ó7Ô5_2±ûþÒI¾Cåõ|/$mît>Ždw@ÏêÆóÈlöĨݨÚlÀ^‹4†YÅÉÔéuedž ³B§ÑAûv;Bœ“Çíþðt_7ô°9Á)…C]üZ§_ˆ¼!Áü³ü/LüPW÷ìô‹*‹4Ç‹·¬˜¿{&¬3PÁ²þ乸©Uá­¨&^bâúyp¤ÁiºÀ…²öívôsrÖsQ¤|1Zg¯5îDÍÃèú L>5”U$àœ« ãÝb®ªunÿ™8>Ñ~”4•ܮ֛“MÙ*ç¿lKö7OúŽiÃJýß{Ì4«°ýië„ÀwCÚÔ d$dß}‘šÌ¤ˆ%tu#—6 ·9Ìewó(›‹hR^êÔ»ûƒ¬åÙd- 剸$½Dc8ŽžýÝ$‘’Ùv½‘U 98“)_””…pºšzÅò]…Ï ÅMý¹Ên»Á¾½x‘ò”c­®vÉó–‰ñ-L/é;_¥ª™É¡¤ûˆ¹íÒÁz6¦f¿ßI1Ÿpµ0 cV“ø%¦/ œÌ²Z¿t°áÝ$55ñIt-Ò¥¹Ÿ„î¦ÚÕç“ÔzQ«3ŒxŠ¢ì¦‰8Äùàˆ{umêOŠp¶±$Ó“'Ìœ£lîò/Oì·\øM8Ÿ’Wüþú”ýÿÎÝž|­*OûÞ ÓŽrx<«—Ê©ÁŽÇ]˜PÖ,‹óƒ«~'µ‚ˆ£ÄւŬ¢Wf\/–ê+³Ø ~Êê†CŽêI†!ÒŽA}üŽÝÞ|pº'ÆÛ2s*òWLÅ^­ç‘TÀxãI½ÂQW|tAëÒË +³OoÇxà `˯ÚÏÔ[ò'odŒŒÄ‚W,TO·Õß­8|ÇoV%v¹0êªÒ…³s»ƒß ¯llAas< –v+Ñl®Fµà|=1µçcnAžËŽ2r¨9Fª×ðƒ“h<·Gz. ×_£¯ ü* Æù~mJB\}ÝL LØèzjºâ/„Ìx[êôvÍìb‘<`}cœ§¬o Ï&¢EÊO6-}gÇGtÊ«6?¢K™ ß–¿­½T†VÀÊКMU-{«SUÊ‹#rüœ§ÐñâY6žSòÅçGq’À”Üð"°4‚Rß– xú„[;;FÙ¼Õh¬£ÞC¿–iaˆ RAS_ΙšdŸMùÑésDr¿õÎYÌŧЫNžÚv/‚“ú’ÒÉñê6©Æý¦üLC~ Ã^ØJ¬¬%ƒ_šáe†©gN¤Ñ1Vx«qÁûïQt¡Ze ‰Y0Üm7£°=èVúar•:¨Yò`ìûjX«p¯p9„ À»Ã‚€X­cº< Oµ&Д™ŸV¹îÈô­z†Z~ñDÁCkÛû[•JP»î…]Ì \†½7ož²Ã“ñU;C‰D²>G(~§•nY —,}¨Uª[Õ½m¶`(rx×k˜êµÓnÞP–Ûä±ÊéáiewçxëäÝ–K¬åTQKyé°®q¾ô»Þ넟 KgâÖûYÁŽVÃë ¸œ£dX¸¬}оìÄ—q?!‘¬Æ‰©2GŒË• ž5m‹CAë*ÚpYY<=cÜ®Ô>ìmÿŠ®3d~g`îþ«¨èž“G¿nÚ¬sú׬B×2ø½R`jG×µ3e¿H@³Ä¹¬1 XŽ^téÔ»,›éïð)¾ãϨÞiDeßS~„ºCí5ev˜vf…ÔZhü^AIJÊ&ŒQ 0÷\™=#`?ßÃOe ¥)qÆ?M@h½ ìy³8·›Kšµ7P“ðµÍÔºM»R-¬Kd˜)k· Ú%kÛ$ËÏwÚµ‹0nòë‹Þ%Ù²E•R°·ƒVÔ¿ê4‚çKÁ’=øô¼„È;ü,/-á¾FY뱆N¹¥¥çrÖ ­DâYžÔ¼$F„Ý/b@Õ,öËü³ò£ëã…39Ëð¢e6gcÌ`¦‹¯uéÅ• ª‘) [ë—øUÁo‡»'Á_Ü?øÓÖÎÑoÅMÆ¥/^£ý^9Ù­žžòAa Òç‚P,Vk£C4÷8Äõ“Ý­„cX8A7Î>w[á·¡ ¿l”r~Ò$½LËy—‡åû¢f †^lÉ'=¼qÓ™„+°]ögÃr~–Ê ª®{pÊ E~g3Kß Ô au¶àL⛲þ«`gJ™aX}i!Òuzå¬_;>Û:SÖ"µèÄ×Ⱦ£DG¥†ïÕ`I3÷,í~éÐ;+ö¬cÊÝ@´·±Î3€„Ã>½ÃñÉŒøG.dT{‡î{oþóâ…é±Áè2Ôê±'ÔËý!kû"êׯ õRëAµK)JëÝj(“¸øGËmU7_i{Ž-ø†eÓâ猻”—lKF­ ½M¬¦AƤ¥îóÕæég4õ”ÓÖ¸Ó˜&÷é/§·]å“?ËßÚ™­Mò§5y²ôÔ˜AYn-Ò§ò$lÐøü9P)fÈüMû]þ˜û„YˈFå(oé夙ñ¡à^Ä[xË@e-†Ä@6Õʦüåp°U .;ýŽ|™ìâIcråéMÎ*ïÆú`É8ÔÁÕTuÉ3ÒqqäaáðtßÔ-Áè·_Ùž»J¬|5è4äȤǵuÎ1óP>\†iß[ô]ûhXæÝlý¾½U©žlþ:M†X¿CðÙiëp¡Äܦ^.(º°Ì™˜úY¸²‹?¿ØDåÓ¼R¥¦Y"¥æ³áÓÜÖólìœ{Ëf½ê›DO4a$ë¯]RøÉ§éiãUúÞ;Mßs„m­ƒéí¤!l­‰à›7ºMS¡wqçôì!lß°cgjr>jhôôÇždáÛArÐ؈ô¼›q÷ÕÅtG^qÍÖ%FFéŽ9UGç(ï=®¹`Õß×§Y¿=xw5¦WLkYâzcQÅõ†šáäâzÃ'®×L\/î~þj ¢¦Î…x2¦hžµÇ©%Oóšú´iŽÄÄÜç?òj ä•\ ’}H®c¾¬31z=W~Û:>­|:Ø:ùµ€ÿg†``ÌÑG›üêxS5»~ëf×\Ínܺ٠W³¯nÝìºÕ¬xõTº:v‚}ñé7š¡ÉÓ•Ðì„ PæžÛ­s㺃RiÌý…I—Ì †d]ž]…ç¿›‡ýìvålf»ÃDGxÏnW`Ï \»•{+`NQåRÞ=`¤—ÔxndT!å%•žØh7²lê9§ÊNǩ솸'•¸.ðUðïX5®|í³â{dzcûqœ7s/‘Û8nNÕ3…HZJ¥/l1áÌu--¼ófLÎÃ{SÈ¥}y0½²'§šP uº‹¹÷ÍÎÖïÑFÈCÜ—aZ‹*Iú½-Š–P†Í½Ê|M¬£SOs®y‚±ÖÑè^H=¹ žÕ¢øÝà Âp)(`••÷×Wa_¾þª­»Û;ž¥äœÜË 6¹Œú³|•¯O"†as]ûIFh·’ ·ÐG(8½_`2&¶¨2DòƒvåžyÍ^æolÖÝècíÿÆf”âD¡­†øžÖ¬ÛOk䋚õ©ŠRd`û©È· Ogªh%s”¬öáoc‡¿&oä>&o8v®Ñ;T¢ïPø?w¿MeŸßÇÙ[ro0,‚¶ãqÈ¢æ§z\wÌz'v&¶Ž(ÄUmg¯rôÛᄽc®‹*ïÙP©±¹ÖÉu£Û¶£æÆ‘AzçñPWL÷Þ‡YŒ˜1ІŽŠ¢p¦qb(Põݾ6´–Òxáa&_†‘« oT˜|ô] ÚN'ŒEÑ|`:äí!ûyçA_&ç¯ Â½RöþÇz¹3Y;Þ]!sŽ!^üXIÝ2æçnPß3FÆtÉ¿ûÌ4ŽË¤[Ð8§œIEWFø…½0+p‹ó;“ª–òk¹#íÏ=†9Eg‘Œò¼M çuóCøûîbJbwºÎ¥RfÍ!‹›dã‘mn‘WnÇ_y®äÛKF ™†WY £ÎcT•Ǩ*QUnÃßTT&'çOÅ¡a)eïÌ‘TäD#©ø#©8´>·¢Ç*SÎ1Tc÷¾G1T¸í1zÊbDOI]ªL!tJêÎs qSRö¶)MI]?L/bŠhzt¸9ˆìX))+¢ÿ\=kãœb¢ˆ™Ë[õi74ñøh8¼†Ã,šG·¹¼BŸ‡MãÄ2 >¼è&­#B›,ÐÖ0ã&&F÷„Ûï cxÜcS;BÉÝî ·à±1B’ø¶ƒ{ŒDboD$’I„ÿÂ8M[³œÃ´ºË›Ë+s>ã:E+ZMì­šX´(#5Ù!F&áçQ.÷0”ˆ­™Ä¹«•1IøY.Œv…´Yù.`t…‰¬Ð óÞ yƒ3¢Ïým‘ÿ˜¥ð¼Rç{‰õúpöp‚|(‘6'''Å™±=&YÏóŽç1™˜T˜U»DXäçáÙ8›y¸Ž‚ð„èCÎNÏÉŒÌ1¹¨ÎL·;3ݯ:~g~ã®DéQ7¾yQºha6ò-§`#©èGKO\ ãh™#¢†±•<ÆÒ0bi˜ïáè;“àêýØ O¹LÝUÌ 1ÅEÕw$£ÒïÅíË»‹‘ÁúŸ×+IÖÛý‘Áæ±2ïÊDáL#dp¾ÓgcÆ:/@ÆäK`’| 䑺 DÙ)ÅÇ0è™/<dž¸ ›(,†vãÅf¼¿sôá?g/L' …¡ Ó ã.Dª»dæç_¿‹Òå_gŠ­Ô/±8Fë EÃ}ÊWvÛ >¦îÊø¸ù‹b]©²àØó ï ™Ÿ*`h€`Юq}Ö.¢½ïZšÃ ù‡aOO²ÒQ¬`uO¯°gícÒíTóæ‚!`ߜÔ–»žCFÙÖ„"=#lˆ"L˜6D‚ù]7UKùÆÜB쨨!‚H£|<årp]™\,WÊúÒïk§ŽÐ¼>w\üh#âÞ—êÃhWOÞÊrÐ9ÿC}ÍçšÇÏÓAeòð”D~D¶ÍXZsP–a9y.C{3â"ԸĚ_tÛ±Užð ù¶£Q’b¦áAçœ÷ä1:ÈctÛ0Ä7DˆÉåÀ’KƒJí­yÔ(ßfûDNdñ£€¸U;õ7v(Ét9Ù]†N7–LQ?YŒzÆ@RÏmÆ#Xܦ~Œþq—Ñ?¬ £iÿ°îr§ûò™M#ô‡u³2ÅȬå?ø²ã~¤Ì€þó¬-„óŠû¡á%û‰÷£áÏxo«áíÑò·À–¿ JK­ù<äžcMßòê=Àø¯#Â{,Ð0ëð:BEÿø+t¬H ²ŸqG²ìw,üoÅZc„ñðIýûƃ£oDIdüÂxo›“œï¶ºq›Ï‹}:ãúi+JMì§­šX¸3Ù!<&afŸÛâXL>ŽËâ”ßçjˆ™I´Ž;Z“ë˜å »ç®Š#ð» ¾Š³µÛY1€$·ï¡W.®_ ÂkVl“y«¢ÁÙ÷fÖä®$æøQMf)0ù­‡—|ä Ê„Ôz1¹<š½r›§rŸÃd’u;ï&b÷œu…¯™1¹£%?A “Y.ù…~xŸ…²™‡0‘JbðÌ/Hnö¢•°6¯à%â¢`ÆòP?,nLzXÌ#'õø ·úL½1þ™ÚÐ$ ]©x& v¤žÞ ¹L´NÔqW´½ÏŒºâlÖ¥×8’kªÌ3þóeƒy²ÆâyÇœKæ&ÿ¬åž=㜂/%iHƒgBmô'޼0‡‰d sצcÔOEåbÏY<ž½µ°šáõøŠöþ¿¢(Aíš3Am&¿N-mí·ò vFWœ*æí¯8µ™©= Ñ[ù<ÄŠó‰È­jÄV1•3ã|^„¤P1½ã¤wÏᙚÖ44±“ck .Ÿýì!=4Ç}ƒpnçýX›³õÕOãà.Jš×ýX•º/u¾Õx?ª ú¸ª`íÍn©MÙÅza–Ú8¾Ö>ÚÍh‘ݵ׵'—«Ñ”^¿UŸ‹ ¶ìp¶nG6þØ}úçèæa­ ü^Hs^?b–ùî—Ög{4²Ôm{FžÛù<¯€sŒ«çºÛ+Óéû®}²n᛺œ©(-®£ºybÿN¤ŸØï+s‡º3‡/µr“š’Û×ÂlSùý¿·©[oS¹<Çq›šÞÀÝÛÔxÄ^XŸ·Ñ8[P¿· Üíû6ZãH²5ŽlO¸)¿>›¦ÿÚ,z[Q€Ì‘uvSÀÒ=˜ÂÌw|'ªg°ã;‘}vüé |ôÁtô†€«q¡ ÷ð™³Aî«0©¡¤{(ø·m·Ø)8êènÁg÷¸cÌkÇð"ü>ìÓ¼{ç°.YGobŽÞ@æpíº¸ûA‘vÅœþv°0w¹Ž9Ïþ2—qÒ=™ž‹õ¬„ú]?—q1¿ƒä&3û÷09Þ¨á×¹VÃ-ÙÆwMÎóI gZIÔ„…ðÑP°°’fªRÆ¢È]‰”üâDQh Ù¡*-˜ 8Û“~ÔŽzÉÝ%JC`yägÿ¸JÍùÞ§K—3Í·óH˜nRÒ‘mO˜iâtÑÜeR={u—>ýv c‚êjaäM¢>ÅŒÚÓI¨nÓ8_Ju…~B,hŸÔÞ?–¤UŠ‚#è̈x]Óä¼ R®›"ùþ']¿;Á¼îÖ¾ÊBûZ×µ/IèÑV¹ñиD£P“²°(>t*[ëNe+µËt×§¾o鑼Eœ³ƒÝNÄe¤7Qf¥7@ýi$Ìó§¿KµÒ?Q‰ÇG<.µRQäc!õÂT³¶±UmØ~Ã{—ÂÄtÞ䢂žê`t"Š|)'ø;a#¤'{e:…—Ü”‘¦±מ”N²âŸ’Âô"5ÄÛ°l&3AŠrýƧá<ÒUL‹ãò¤*o#Ê#gfš¶|ÑNYaîØ]Î,nNÔo%Ö‚3ˆ¹)›¼\ LT,7 ÈQŠ˜%,Q^>æ–•vëÑøcrs9‘ÅOnÎUÂtG^ÍП×|”†˜KAÔñkñÙhzÌn>EAý˜Ý|1vòg7Ÿ(ŠTÙEJ7ÖM+fÔc²óÛ%;O_ðL!ÝyúNv ÏÓ6¼)¤çaŒœÏM<Ýa_|pqØ4üŽH¡¾À{ÉŒSª[(zÜD¦´‰Œ•ûqYÀ]dìì °Ü’ëÆHÞµÜÏÈG$c¿Ín±0þßötg‚żQœK1kRãf]1©6qæ³™ ¨á(;MûmØ<¯KdîåpwÈé&)5Ñ7“dîwºp&Ié>u³àî#18kÈtNt[cvz´iæûÔP’•¹ü®öS­ÑÙzšˆxh;íÍç!/<‘&µ]ÈÊs(‘XiÕ1ÙùI~M8'7.52ŸßfÙÏ;úä’bbíbVIÐïTVL }²b‘³üŽ@ÞÌ“¢!0Hjô1¥æ Õ¦ÌDéS”ŸæqmãöǵŽ#1h_'4n§¼ÓÆí±ÜÇ¿œ†ËãH¼¤|ó_ nÌÊö8ƒAû½5í»Aág)Þ rQCn˜îË>QãŽ]%%Ö’ë0ýBñV{PF e^˜ÐΦùþù®7œÏ"m#c;NLro3 7Š´·ÏôïÄŸbfC÷:VŒ ¾ýœ›™Ï=bnO¹š\1ïì(:Ÿ@‹ÆäŽ-Îf‘Ýk]ñëFºÙ>”Øu’J­ðË·½èÎÂ3zp‹O’ê!-@è ¦är~ŸƒŠŽ`ߎ‰ŠáZ˜¨êbµ³9-ҹ⾙§|œ¥yJ *fªQ†ª)˜ª|8òY}t®Bú@-CÕÌÎ\“ ZŽÙŠ—ÉÍUË…\+ëúø«qèâr(´žßíÑËØˆÊóÙˆf³éÌÍBeì'»ÉãnrG»‰C®,H™ƒOë"¸kÝ'·O9¡Ù8m©ÝÖs­"ËCY|”`[ 74ÐDžmÐØ ž’o›šÕ‚­ÌE ” s‹!hF÷ú³y IØ‚Êøgþ¶P™7åQ<ŽR_yHÒqÕ–û!݈[|Ù8­qßR4ÒbZhÉØé.šíd6Ç09чs“SZ$É&Ù_â{>Ÿö¹±X†‰Ù1÷ò3ˆ-*kûÌóâlwÛÆÖSN^{×<=NÚÚ¹2ô]¥«•˜¹ŒúÈÓåçIÝÝ&ôr›…ÉyÂsGç4SÌÝõÚáSZ¤Õ³ÀŽF£mÖ©årZã‘·Š’þæâù戇ÃûŸsn¼«™õ’9ÙÛa¹[CÚ>«Yò(o'‘·^´Í9§Üø¦Ã©Wñ¢a¡£«LqÔáØáUì\xî]1±wÅ!X¾­äx’’¨yïϳ9pÌ<¤£ŸÒãV5ÞVåEÛlŽ~™&Xr4ýùßÃÀq'iÆõ)‡‚°Dÿ9ö«ó¼ `6l˜*¹gc„ž˜PkjûBŠY= ñí$¼MOÊåëxOmçU&Áƒ­ûð°áÅÆ:À0#Q¦ñ‡-N¥çjJí›L!#Ó‰12¦0»!Ÿi‘HÆÈ^""³ðÃùl=³U…“;ØX2Ú5+›PžýGuøÊììÕ­TñWæô*¿ÝÈÜJñ%{Ф¶£Ç=(S݃^¹Ö†XX¯n~3%F­ªWaåÕ´r§½š‡…mF“à[ËØâUQnY~“›K)åIšöÊ¡±ä°‹­Œ¯À¡û›èóu;\Ÿƒ˜ï–8%¦Ý™¤…õa-ÆŽss¨ü0Ö; ¡ äp½$´ŠùºVž\l%gß½ V´4ºRgÊ D<‚*`xˆ¥~ÈF[gÀûš©€ÿ*؇ڔ0¬>ާ©ßÊY¿v|¶uV|ªX0Æ# "$ `Eá{Q­Óc5XÒæ¼´û¥ ÓT†X©Þ <:Úpêi#ªÀX—ûCõaoc=hFm˜G8¬Á?h /ô8n¼•å sþ‡úŠ¡‡ HºøÝÚf¿…ªðŸ/tAȾˆð:–‚Ø nå¦2Œ°H"?ƒŽ "[„æ,­9(Kƒ@q²ª.C{ÆRñrǡ˒5°%?¡Æ%– í¥ÿ‹3ë3š–ŰÞ [éq‚§¡i• ©?êè‚ìÑc|&Ü·7Ræ'2þ”5ʹ{k!«9õ?Ãò‚£rMC0œµ…Ø¡Ö̪œk‡òògÃB*ËYÖZ® kmVyBÉâ¦Ã-÷/w£‹»yô–¬Ý­<‹Ý­<ÍÝm4e½›]Ylv6³µÙÍŠ%§¹÷)”–¿I«ÄBr¯M/ÌðÄT¶&WžÞä¬òü1”uYÄ/°nq¾Wƒ0vî‚3ˆ¹q½\P$ta™3ñôs°üÒ€È%D—ƒá¦Q+Ÿ*—Ú·'Ðç|9çÛ²9®ŠDL;ìÇÃ(HðB§]R˜É§jøPšà;MLuG ÓÛ%HCÌZ=öûþœJP‡OçîÉaû†™R“ó¡PC£§?ZAÿ* .âì­Q3"¥¡ÓnÞ¸ûÉ¥Tª?®¶ÚÚãš­=êXš@‹”Ýå×&ÇÀa@8ôUXs ýiÖoI\éÓZb– ßXT¾1 ¾á“á‹Tä~lò¯fÁ 3ØÈ4“oç*O¼s>sæßªÊÓÞªÊ[Õ˜[•Û~¯þþ?{ßÚÜ6Ž%ú}~…>õÊYß*ëå¤Ó³[厓´wò*+=¹µSS.Åf:ª‘%¯('ݳwþû%H@H<)ÔTg›¢pÎûéO75÷WFVd e4¯!쮌æ6—qpëúmâàq^9ëõÊï•ó^¯œšYB¾¹uS>wá6/ÒE•½rCa~“nvuSxãÎbCN¹Ià–BcJ& %™ ¹ÖžWë"›`ƒ(ùéÞÊyŽHevÎeß<ÆsihBù|Þí6”N‰°¤uzkIí NípîµçÝ:Õ;&É’¯x€œRW8•¸‘jœR𩨙òA·ê…?º§z f,4 ¦¹±Ðí.ºîhè[îx7§ÛsÇ{G`s¢1n€€µj>‰Û”ÙÀRK€ÑB ¡&—ýÆK¼°X©Ål=ÒÖêÂRo@À½’›Ò½-ÍF‹´,9Û:–ú;›1Xã`÷’q(À›ý B‡ÁZla)<îz€¬ê³ m}ºlÛ—C”;ŠÞUn¶?@Ý1þ:qtDê›ü¨ UÑË¿>ù[ñ‰¿£_—Z¾I¢H° z8ìá›à óø·õß ±Y|_ñÁxx»úGˆ·zꛂq‹ïÙHÓ5Ñÿ‚•mpÿÇ ê¾ûâ{@Á)8~ö.Ûd‡ìo?ÄÈ"d_qîë¿Þlwëííx\ ídÞˆ?^@6…páOá_B7ºqu†]ß²æJ¼žÂÒÇBŽ—a·‡˜D É)ÓÉÙº°älÀƒqäHs²‰†ÃpûŒ@ êŃcüè"Ó1µ›ègMm´.Z%1kKi$qŸY[ÜgÖ9î£7°Œ¼³ûjÏyÏú♋4sâ¹%ô5¥C_33¡/Àîßp©:/ô5U }M-„¾ft FvH‘/ÝÈ×ÌFäkÖRêÃ^”îe _3øb V+ðeŒ¬È¸»ÊC`6å¤Ù¤4ã87U2ÓFXÎhÌÓeØ­Ò¬pÿåÕ²ÉoÛaË©W¾G#m&°òâcÁÉùfÐyµý²»yˆå-3ú–ß׿•³§?•-G¨ní~õ€Ë)ûe›F8Yo|_@â‘~ì'Ÿ?o~TŬ]´ A¸ö¢ås-K0ŠO×<×@%Æ™ùy€oΗ…”y·ºÏXO³!–©ÍßÔÂñSçŠø#lý¿sùþçÿr”ê—c§rñúŠföËÜx}rÛEpóò5doóÂŒ?&£*Ì?Æÿ>ÁíY$‘\ä¦wµ¸‰Å±ÑÖDñ”òo”Ìñu‘ÌúΦç @£ràN«œ€EÉL¸2³…“Èø»‹‡K颡•±u•Z¨xÕµ’Ÿ*XÍwõ”Ç¿™Ç}Œ[ÌtvµÉQ`Ä NÔ*eDìŠÚ:è_ ×ÑÅ-²ü&­ðEŸU)ò­G_=qPè Y$´ØÍMœÙjÍ~§d¸5‡ÏËüwó *±JJ¤É7•Mæbr5teWè^$Úð÷÷gGâyuñÙãø~¡8÷ÀÖJ¶{4EaTjò¥“nIµ'd:É7ËBe=nèVxžÐQñ‰ÉŸÏ?ï¼RêC¿œÉ~9þR`"jŽô@r¯:â—»ûÕz{šòðý~8Í_nÛ¬ó¯&e§{KC©'#;ËÇcðÁ%8Àõ6}z¾Ç­wí3ÍkŸ¶_ûLÿÚ9 µÇ.ÕŠëÚ;j™^×>×¼öYûµÏõ¯³úSqìæÌ¸®½Óé¡Á\{mÈAwëÖ1óÖª'ã”ûãÿǼMž}CÒˆzLŽûäŒzr&yrN=973´q>m“÷Ãæq¿Úø7xÉŸ/šŽùy@vqñË…ð—…8'þYÖ–«Å^5 ësÚ°>×0¬« o1«ñ_²ütýîñ>r3»‚9Ùêm3²EÁÄ6zöã1°Eh‹Á¼6zöã1®Eh‹Á´6zv¾a­wå Í+Ÿ·_ùBÿʯ|ñ•w:;´C™+Çö¼ÉÖv…lW8—´+4Ì·öv…óŽ×x®Øµp.ìZ@€4¼JhXšð)ù?^€âéóãò7¹O.¨'ZY«¨ÀÑ÷fó¯oVÛß ¿Ç¼O_a#…èóaüDîÓ%ÏN¯­ž¯Qøwæ!à{yXó‘LÆ×:snâ¨`¼ù°{è/jƒ)Ðf¼BLJ¨¬Áñ%)1«˜u?/‘ÂJÁ×H¢$[AŽœüI¸’¥ Ž×6KAŽ×, È-ŠÅŽÆR¸Ì6IÒŠ2$IK•$­9I+Çk ’ÖrIK±Ø%-ÛXP‰9{4õs¶×ÅZ}y¥<õ¸ Àmæ@eÁc®Äqý,¾”šÏ–’‹‘Ó¾¼Ý=Ð6a• hQÉØ¢¿Ávj¦±0.®gPL4 гvƒb¢oPp¨¹ ²1‡aIX;:¤Ya½,K”•^¢é†k[L ê+êë44×̘PfÆDA·©¿FG Šå ƒr¬ Ù«W2rÅ„6äÑ€7}¨Ë‰ÌÍéèD棡iEBeWþ{árü²ÛÜe{+*RüuNô¥øëÇ‚ðÅT§ú¸ô¨u8Z•ªŒŒžKiÖÕ­ø»‡¢{¥–ìšxþió.ÃUÑ2QfØ{åQά>ûËn»£«ÛxOh:þ2Û¬þÈîÈ`æMùá³¶H[ó“Nnͯ•ÅÝx‡¬„0÷=ÆÄlóí.ƒqò›¨Xoºo­Ö^÷n5„§7?_DxÊs†d)6ñ—…híü|ËPïêƒMØ)£.ÐtÝóó“uzWl›œ2êm•³{þ·]®« Â÷ÿø #¢®“PÌu÷ÎF׆!ÏÓÆÑz˜p—Æ 6ä·ùú·mv7Úì ‚¸YƒµÑT~%Xq½Úþc¶+ü£üemU¦ÐüÇèŒ1…èO†÷÷÷äïKÞ†Gæ|ß«G)ᄎT=òS ±º¼>¼?ý¶;ìFwëü¬ø‰bÎ5›™ŽùýÚ<,°[o¾‘× Bƒ·ƒ‘‡øýÉ““âß'5fʯªü÷¯Ùí?–‡Õ!äwB#ÝÈ7ˆ¶[ðð ^· qðïr¿=)¢~~_þœøaðø¥o/þï‹‹åÇë‹w1îä¸ÀÆ® ÆžöclŽy '«äß×`£Lõeè8·«<MžÃW}øuùËۋ뿌Á…òª\\‹r€ä§â¢ûíOõÛ§¦Þ>aÞþ¯?UÿÈ+ßôÝnttõåq{[Z`Óî[¶ßìVw….ø7Á—À–X¬#Á'ºÀ•s°ë,ßm¾ÑéLžqƒ£§\ËÇè<ï½­¥ÑøÍ„Py–•“‚V1` n0çF+ÓS+>Ê£ áHo.Á/=Õèf\7O›‰Ã¢ØµÈÚóËjV¼Xš-®ò›èmâݦaóžxx_"tµiÉ<«.à|Ÿ“²Î÷ŽóÙï‡!Lj9@Ç$¶@ký—P«€–¬W p¾4öRD%Èn¿®ˆŠ€ê_'M1ôñðçÇ/ ¥ºÙìnیڠD”L_ä/ @ ¹s±½[®ÿ™a ?½ûõÍ žK˜­jÙî¼ZÞe»ªhÖê~ U m˜ªÚ¬Kâ$8¶E4‹ÎðòS¡aÇýíï#€EÖU•öªšÍ<óXË ‰a)¿¡‹Ýø·m2÷P¼Bñ‡¦Ù\¾2…ÛìÚ‚Ðă­opˆ˜ñáÀgqaéÔG΢‘ß*—ÿ¾íæð™vÙB.‘ïîÆÐ„îî™Ç‚Ð1}¶AÑÈQäµÌ|Ä@ |á ù ÆØêÏLÜùÌz¶KfUHwÉ‚~œ×ÏŒ½Þd:ó-íù4ÞÑx 5®1†Ãü|S-’”šf¢ÿ\cÑIRMš‚ÑÏ»Õi5.qHòj’¯VbMh¶ûæ9+¹5n4Ï{ùÍ®us²¹7jšÓ¼'Ø^ìöqÀ·ëß×­ÓsxŸqÒÕÃûbY_ÿ UÐBð.¾ë“à½ßǨ¶  6ÕlÜ‹5"Ú$WêM¶ñΤ Üø·ª#ÝøoH¼-³Ã«»›]ž½ß¾ü=»åH52ÿmµ!ÿY.˜pI¾ìqÇ_îX‚Åg‚îrëÞ3¸wC^«Þ§¿wƒCŽìéÛIP´tÀÇ_º#Æ,¦Ñdêó×Ãz“·éËò!' ²ü&™F„G©T zÚ˜Î+_èCÉ5®ŠÕ<\½U݆EEÞƒ7ÍTBAÁ›ÑÑ=ð#)›êH7¯³ÃÕ’éô¡rè_tP>ö#1HãÕÝÝ^E!°n–Ë›²t H;=R£¦¡è»¤t½Õ!ž?‡è”ä?ÃŽ–ÔÈ|SK»©*LŸ¼eœà ³Ü’5š2KKo+¯¤(ð„à]H)zå”%G7$£ k³’EÄàAÖO»ûP êPÞ» YaC"Ô'ço³<î<ÔÀ± ã'çK$ÊP<Ë3x~…d¯Ókñy·ÛT#.8¹|¸¸é)kõN{y^šë(šc†?ý\€ „ÿðB%ë›=;Ÿù1]~NI¿Âkœ@ßf*ñm´ÙîÛð6d¨à‚VÏõl¦¬gS‚Y:4J"¦Ì#Y©ï—P—d&¥¢Ѩ4&-£†•rIº½tÓ`è7GR”ZÁí‘Ö^O)¸²Sÿºš hà­!NUçV*e¶X¿âc™l¤0˜óí5ÁÄg>ìw÷‡¨,ÎêÈÇdpVGio=º‚¹ ‰cØÖæÅm£”8t¦­Ž|LL[A%Ó=ºÓBâ6Ó»î1ç…¿Q˜ÕkˆFà£wk]ÇÞÛ6æ¼ãÏËÇÛÛ‚éOE¬Ï«ù[ÑÎë<xÚ™B myԡС-YV@[ ãÚ­}ÅÔN‰AÈ1+ñàm’ÔpW+ ¥âD&•¥Ÿ+“†pI®‰åšˆÌÝ—X7!?’˜mÏÈÕ™ÅÈU ß&ªˆd\zdÓá/|ËØ梷Œûf¿Î:Üø,R~ítn¨×z9ºsÍ«žµ_õ\ÿªç®zéUw:74U„“£€¡@ŒªºÀ­- %¾s;ãÿx.5OK+EÅ6…Eý Sñã3êñ™äÅsêɹQ‹×Úùº›ÒJ#tMiG&sO«xF[Å3Vq²‡ãºÉNöp²‡ãáWƒö°#)nkÈÓÝr™ZKikY(=N¹m®’l¸dY²=’íAÚ}RˆšÇÓTD„/½y!ta…6DËJC^ n§ÞþNo$Óï~͈³Ä®;ƒfƒ »/§q]u€Ý— ×Ï×»Ùä ×[†=4®ÜY\àšr3‚ : ¹™ƒóFôÊHy#›Çyë¬ï[Ͷ¬£—kô«ÿ\8¦ÚõN6€¸ ÷a àßçcI9bÐ# ý™>;?üÁJ9.L®‡ÑjÒÛrÄ‘4Vð*U‹”À£„˸ú×Ép2/MQüdq’Å:©ÂT[xa-›Í¦b4%±`2?»Q}@9µ‘dro™¬”×m‹Ó¦]{âÂ4‰Ð$B;K‹À…—>9Œ£#NZ øH“€)sZ¡A~J,ñ€óKŒ!"BÿÚðÑ ‹#(dúÁeŸl”’âQÏ•ãæN-Œ±Òr™‰µbiGAø—Kp‰òzœñ¯¸z·~^PÚ¢&FÛíEÂÍMÎØô …©2M8#Ñ4DÓ\‚¦Æv4ILjÑÄNhEÓ¼MsM‹ŽhšC4-$hjè·v4-º¡i¡‹¦E;šdâ%VËÒ~B@»à9ø½4”0&ï“éæ½p'c×*%¨Úµ¡Û¯LJµ˜¤ÉM–h²D“%š,Ñd‰¶[¢ÆL¬°­+;†U/›J©À¤“MåÁvò87Jl%K(YBÉJ–Б[B&T|°Úݸbï¥Óg½uzôuü\uœ4qÒÄIW÷T1!jeiÔÒp*kp –—Ò22Í[Jó–Ž·ÔÚ/XF@ý7A­–;k«äöHëÎÓ(¦˜G1Y¾ ïƒÑ alD`¤â"IÅ)Ì]*ZF@R1$Ø”ŠÑ aL¨†9!<:«†¹›µFjÅT‹Z£ÃT‡Z£h–óâ¹ï|Cï×h|û¸¾ÏÈd'ãt(ù¶ÒJ:ÑI§3Õ¤8͘M2á 4ކ–¿o„›ßeß?ìʸ7ˆèŽ·Ùwh®"ØðW?!çJ×ÂN¡ zõîãËë›÷ŸÞþмLxZoÖ ¿]o6 ÷CG‘Ë?\:œøºÆÍƒ‘âük,³¤o@ÿ¯”Ià`FœW0uq/Ø+ôss¨jÕW‰ÖîÔyáI3ÌI73Ëò@_f;g\Â=>œæÿ[”&&sÀ´•{†²‡“ëÝPyCëIàŒöju2&u:‘g,Á±žùíp^|ÜlSh²ú|0åûdÜÌBFùÂÉ ãNt)˜jú}“ör€©>%ˆ³ÈÌŠ–Ü„Q`òÐP:‰æO!Y^1~™æ&‡åiaô yŽžÕLO©„îTAÜ«¿FC1¼Úí c ‹7e@]KˆÖÊšÑ{•²TK§êàs@¿TÿŠ]ÏÔ0E¤lº:i%#CoØjÇøÉùºGïºC_@+CZØ+hŸª²6SƒP{£ËþY_f÷IC h{~aÓfš6 €¤º}ö¸ œo2 §“eS¯d¥·yÄîÌ@ÉÀ”Þ²“T}Û5ÒSC*ç›4%`›æ§dÄD¢Õ’“ŒóF̘&°˜>T³Æm–ã š?„ æNµ*gÜZ\ »°ýE j¨Ù(ºkoudj[ Ó—~G,%ü¡q}à¦5Ñ}{ì•ZqÒKF*­8±“eKõëU«–ªO,³}ñ2^­/Ô¤:êê´ë‰…i|øi视!¾Ñ³k‡Ž"A|wѵØî¬i8VVû<ãó²©emê;ñ0Ê8/ôÄ 䨦fØ9¾prÍÝ,¹èílóZãøŽ7€Îî¶…å)/œ]vÐî}*›Ë3)—7£§•ïÃ#ô;1 'Ü—9¿ÜÞîîŠoéºð™”®‹|zØ×Uzv/®.¯Uµ(¿ÛªÀuÊ›ÌÃÂ`ó«§ùõjûÛÀ5;†86núà|m®wÙ¡§l%8 ;ckúà-ÏôT¬Z(fbu¨†v?$ËfÅtÏ/Ô3#Þf9ÙW´!aÊ‹|ë*Dƒ2Î߬·×54ı)+§Wô!ZéíB¾•ؤo[mÒ·2›´üÑò—‹Ë÷Ÿ¢ò'—Ú’å­Èî%ƒÐ\AÔ|pª5Ö†é»äˆ£ÓûîwûÃjƒb õí e¡\|ËÍ‹—è"(iŒúüùKPü@¶ÒÁÕä?Ë)ïmÙ?üÎѬ{ÑóFm?®qÃàç…v‘"‹rÇâOøLX½O,>G´ÒGWOìEqçâXéäTã~ËáøäÙ˜¼´`ÔxU7‡Ê­ò Š + Y<´öÂ/†Oaé¼¼n±u9B…*³¦•°B£Fß,Ñ·8ô˜ Ï8Ï6_:²[BvéåÕ²2Mm ¸t˜dôDGcTyÓV‘߆r½øXe*¤Ò=¥6å‡=G¾®qB>s@¶M0´è¶² Q/O¼Ã{<›ßzRJúÿóŸÿÒ  •˜[µ‘ÅAmD©R?®>oÚFÿTé'zi±ú8’a?è(•ÊEOSµå 5Ôlï„Úk@€bQ…W¡V·aD‘÷àM‘–‡PFðftDüHHʳ<ÒÍÅÝÝ‹Ýæñ~«G‹½cQåcd”D}š¿[5+­º’¶ÕʀᒖÑÙcO]¶¢0ÔÔ¥ƒ+¥.ÇÐ,ªùÇcŽó—ô£æ»ôäîõî»; ?Ü=þ-»=ìö¦ÿËsGÿùüy¾þgvs°ëÆ0j=¸±Åé]Êךåjf”òTuJ\uS¤]!q™^d› olYw D4åC›V`Q¶i«f/šÑVo³Ñ乜³u-£9Í­=å\n…Wí¢Jȟ楢:},Èðêî÷¹B•̤®f’aIfÍ7‘ô.:Üq- u‡cCÂ\4–ÑD JsáõÍ`m.I£5s{m®sºj’›e›³Y6må[&áæ Ó‡ò6NÒkÖUÏCôCÔç‹w[4¿º³…7±ká9°Ò ˜_šƒÜZͯdv%³+™]£dvÅpÑ6æŸ0 â¶žrF‘Cq¦;íëæ ‡`ý¯DïÃŽ‚783<â,„EÌ!3}#¿Ò„³8À­ÿÆ]5Ô•6χ7Ý é9ÚŸ×33×zwûP·êñ×Ù¡ltÕ ÎæËUå¯ÈŸše'Ñe€¾Øc¯2I˜grê #Ó…õpØè‹AŒ¢1£— U‘‰¼ÒßÄá{ò<Å«ê¦/#yŨú­ðé5ë¡ÒnLI ¹ëWxüæUxÐñ@(c;ÊTXw†QK‰9̆µ'Âèø™ùô—ËÌüÊ›Ÿ³ßÖ[@”kz› ›õêeñvÝ}_ÿVZ?§yÈP3þýêWoŠÛóË8åMqÇûUñËâgE@D …'“’ϩУ ÐÍJuv9Çdp] …gŠ–êuÏŸ—öíêá ·°Eô°¸¾¥ Å››‚:?âJ—ò'uÖ?<ÿ»¡©S§ƨ·tór{—8»•³k,ÅË×5 ar5ãÄÓ½xº”Ø “±©ŸPv¯Oå]#-^>g “ÙYlwáxüqU®ç}@›ó©ŸPŽbP2 ¦Ih+ù!ð?F˜ÜOc:ñ¾aÞ¿¸»ûKöGÉ„Vë½.÷Ç1ÉÌl(sÄ`}SóË|H*u™`B bŸe¦ŠËP‡šY=ÿjÐÓÍTQê˜3«ç‡Ê€¹zbì;%Pû:&ôŽlTY}¥uÖDzšG¯X94_Åœ~Üïœyþ¡±ðqõ´P2.N‹Õ̅~æ‚‘áÛ ¦,†‚oá[ ¦Ï7þ·¾Ñ9_ Î@œ·5òît®§¼‰ôJhaçÒÃO1èÈÖ€ù¾OéÁñ¹³Mž]U3óŸŒÛÅú¼žGö‰°3Vjk±V§Ç6(?|kóÕz{W!ÿ¯eú‹» ©‡åùW‘éY^‰q»SydYùõáí:Ü ´ú–¿Yç‡ÓÏ/÷«<ÎØ ]²F{X£íÈ Ü"µß*ÝëÎrãW8í¦ŒÖ|Ã×Ï”7+熺£Éäµza&¾ñv"•²[ȹ7")ãˆ5åjûŽ ÅӾè¡j6ZØ&Yý‡I“«þÀI%.cĤrlB¹Ÿúªl%³(™EÉ,JfQ2‹Záv1‚ÕÿÆU­Ÿv ùÆäöh— uºê)÷ªEê#ì›`Ó‘-"2.‚\Íí&¢˜$‚ï-EíÁ§´£(¼Em!žÛŠÚ’pfö ¾¥}ƒQãƒÂáÖVŠÓˆŸ“Y9a.²žÁô:î¾Âzðªj¿ÎòÓü2û²žUÜ‘0Í9Ê)¦Ëhâ`&Ïo( ænÓ“*6ÂZùdáÔ˜—(ä¥ÇÏsM~žµó³Ù¢µV\6Ê¿"ãçNç‡&‚Ú†vVwJ3žÜ_†›å>>§ŸW–ªu·¸ªò¦Žp cÊ¥ríÈd>&ó1™É|<^óÑ€ ¬±HÂÔÕfŽ”/eEpÊ—Z×`v+а¯:%H£)Az4" È«žÅuÕÇšm]–Ó+ *Ûðc, ª¶:‡üÜÏ…n%Zšö©AR3ý‰¯ƒ Z}ÉÏϱ'?1h)vÕ3v%Ád‘+Ó§7·<î6h%Aü)÷x• CU•ºˆ´áQ‚GÝŽµÞH­ŽZY«ÈXjŽkS^Nhà$»&Ù5É®%»r¸vMoE¬÷ž}ÃøK¹7ÿ÷”{ 4ð^)…°ï9%Þ¢çÿ ³1)ñfœÿSbp’/®\3Þb.ýÖÌpO¾á¯ÐJ½ýzµ=XI½a0 l¢~é/G#蔾&2bõRr±§ä0h)tÕ3t%Ád¡+Ó§7ºB2¢Ð3ŽÇpIÂF„(Aæ=”eðà­^Rvø—Kp•¡eï$8c³w$èjY< YªÙ¼Zå¤lžlkhËæI ­cÊê m¤d%Ó(™F£d%Ó¨¿ÂV×{Ïúaü¥¬Ÿÿ¨Êúõ§•FØ÷²ÑË”ý;.9à; ¨fJ Á ‚͹„`3ïfDçq™`5šO¥Á0›P­øõýÕ»/¯o.¯–ï?½sàѹu‹êŠÔ‰†Qm&÷Y¼ûæÅòÅ×ÕþçÇ/…ÛA’d¾þgvs¨àù‰üIá«LØÀj ù‘ß1z‚ãêxôIêda¯—ŹYŧ&t„O¨2Î`¡žÑ„z¦b€ os¨kÚúHPÏŸ2§aÑK5ô«ô‚´´*ïzHÀk±D #`}ŠoÈŒäaîÆŸ.EQ‘BõMiÉ úcAiQt¬›åzûju¿Þü9­ò@2N®nÔdô‰bMü— :ýP|M7*},àžœWŽýT—rËTZá5NYÿßi¾‰*¿.‘5‰|8¾C"RÞµ02±);Õ õc!¼ô¼†ØÌ7"rnàÆ¼„±›©¯;°r‡F=1C7{õ_„ÚõÊ£kØ£Ðþþ&Ûºg¼xß&ÛÞ\ñíX…€Æ‡ò«y¥æÁj1¸1ˆÜaB ™¢â8üË¡ƒtø&TÎܳ“^ZSc=•Ày@ å—›¨›<á0—Áè6ñ]ÂòŠ>YooV²}xd üáŸ7ðí‘|a˜'àw¸å‡ÂkºxuýÏãzŸucŠú§ÏŸ¿ÄïꪀýŸE*0<0VùéëúökÄÌD‚JàBZïë+n!ÁRsì+ÔÂæ8jr +ÊÑS„ôÑ« :rìhù±`xÝU0X ƒð¯µ-0R_‡4:ÈH%8Ruý:ˆ”µ'Т¸Ú~ÙÑlTO%"yá°¡q{îþ“§—ΪJKø#ç-1"Õ7‰õ&:°Èç¿ìòĄ̃(:½Í±ûÌ00z«Ú4v¢.Yi äYû4v’Ë»ó9‹b»¥ƒCNjÎ`oot&¥5à¸vAm¢×¹ £¤:MÄÕ'úOCªu˜íHíhiÎÂBÑËX$Ó'^‰‡#5”ls>-…«ZFRPr§ÌOÀœ‹–JʉïÕ(x䌟Pã'ZVp—ªhxT°'RòÔM`k™¾ŸðJÖ8P™1„›Ôà­ÄROýP7¦cS ©Ð’8ØÍÕv}Ù6`²@´Nü7_ŠB%.=Y’xø°ßÝfyî‡LáS–B0‡@¹_ÄKFùõ¸Hˆß¸ ^_­·ëüëС‚r|PA@ìFÆË‘=Ä`š&¯iÎC¥py|±3þh"gVŽ]ܬ G5kCJh13³çí1ª‘‘ˆƒdug4a°q%Ç,—o®î~oéýÖÔkzíÞôI$íÞàÊ[¿ÑÞÜÀ/ÏœZЬÛ, ‡gâ$—Uïô£›ªnïäå×ÇÃÝîûV ÑFñÊ|u·Íß7Ê‹ÊôF ¬-…¼gþÆçhçnòÑðyûã«Ë›ÿ~yýžÄï—»›<;ÔN=úw€áWtüÂgïÝø[éÆYGçn·¦ò5|sôÆ+ǸZñçwYެ‚¯_¾üHÚm^VoÓ3æê›ò©ÖvJGÐ32‚=^—>.‡Lysè¤uŒî†ÐÁ³·)¾Hµñsõ½³è´¼?U†5áþ QÁú}R~å;~ ¿N ~”ƒ}ŸEšà0WË8øW× ÕgèѲtyúÄÔRdØckÆS©ÉIÆçækRâÅ›ëd„q‘P€­@(ΞÄvu< œ tüÍ͇ŒõµEY®jÄ#â_8ð‘15›ÞPËþ¤É-Ì´äÛ??~ipñf³»%ˆæQy]ô‡7ÎOò–ûÖoÖÛìÝn ™,p49,ÃnÏ^]äp&êÅöLÇuµwˆ»’œ­ 51ä¬T+™ŽêÁQl«b F¶æ1;ÿäÃÄÜ-ú㣱ã 1Åý~HäQ»ý°d¤vÆ$ÒOVš«ÿÔS+àI$;QaõËO…üEÏþíï#pªQ«ß¬¢«î×›Íú°¾ÏZÃàZÎçzãYô¢Ãø$âÐ0ùˆÄ´/YDÅ´/´.[ ^ìwÛä–Ï8¦ ¾H6G¹:HÕvŸå#ºC;xŸÁÉì@ QTÁ^PžÀÐn˜ú üm†)Π`>T·¢µ¦üDHuúàD7ûG-êâ­P|ƒXò Á¯5Þí¾"`7ë]áéÝѪ’OOŠTH+.» ‘ÁZ¿ˆ~=­u5qN¡ŽyS°ÖÐzK]–‡Õþðvõû‹?n7YŽWµi¢»Ýãç 54†PKðum³d‚ˆCðPX ±» ,³ÿyôwºÆ¿N°ÑÀ¹“q¼i34„N­Ã3J¸aEIu~µé2VjšLÈn¾Fl¸üxÆ͆º¾}7AkBÚNL˜}½d.i ÍÀÀ%î!IÜa[•ºÒq '°ìÖÌ4~pm»3) Å1fð_FŽCW%ÕM¢+´ž»’ßx/5Îå÷ÑËâË_Ö‚z¸+è+¹~R¿¥×v|þàÐc¹ ìõßðªÊ2[{ç­@nbïü„ ‘Î{ç'„ŒJ²@¦žùAÅQ¶Å¾a÷' ¬@nBLMÈ‚)–èÉêù÷uñ÷qõeè8…Ù• ô>üºüåíÅõ_Æà”­P]\ŒšwüSqɇÇýö§úÕS#¯>c^ý¯?Uÿ˜+¯óÝnt@…_··À¸}ÙíG»B¦lv«»Â®ú7Þ7@«›~@´ˆŒ83AWÓV7YŸœiœ^{ * ÄtT”rãü×nðµ‘ðžÙPžsÞN¬=°8\lá7Q7Z0ñÃJˆ*á#ö–“˘ÂGÇDIt apA”£ %˜ X (Ç vQ–(×Ç7Y ìÒØ=¸sj˱À—މh²ùÃê1Ï"&¶òüqR[yt÷äVa̽ýºâ qÒ<¼{ªCXóEw×YN‹ŒêÊóÇIsåÑÝS\…1_ôö:;\ã>´+ªC¡'žÌ.”H@'=¨Re‡Š¢¨/ì­S/&6$bÜr(·„‘æLxót;kõjø«ˆÆÖ~ §ra`ÕhwÇ1º ¦¼Í>£àBAûœB—/ÇÈ*Ú5Êy¥Æ®ˆYŒv€Û þêüo²/ÎŒ‡Ô_-ù× Hÿ~ãd€5ˆÁ®ï\‘¾îÃ.dAŠ“àááý‘z9¼O@ð³RR7:Èϰ¬·ºwøÀ£¯tLjtõ¶8iÞÍ×SÊF?ˆe}‰`)é£÷¨P?zö?ÇOœqÀRŸÈ9y ¥ˆ²¨ò ñx ¤æ8ÍK ÄÆ"K=éÏèØjýˆ I¥~“ö~S*QÚ³”J„½Ær£0¦úÙ85ä_f´΀AáŽsÓªžâNP›RÔ`r»]²©¿KÏ È~?\ëMŠ#*‹× ¨Î Ÿ‡0{!ÁÒÿÚ}Ž9WS'Tg÷­©pæ>]SB\¾ÝmׇÝþÕeÛlÆúI'믓Íi$UMk¤>§"4ʵÍl¬ßêcr#ÿ’(ౄ 0žœh‚dFZ4.ÈÛ\Çú$ ²„¼-‰B~.¤Iõ¹n^¯_³â/ù«Ý~YœéöЕxóÃÝóç÷«b Àiþµ€¡ 7Ö?.ã¸ìdó3#ûìDÖÅê.E–]Aå‹ß¯××ÙêîWwùéô.ío—FyЉޖ‚ê‡û´»› â¾¹)ˆû#XàqS’uAÞÖëáŽõ}e<é§Ê-@+Q·”TXõÝÅ ¤›‹-Ìz¨d‡•2ØÓ>f;'‡ú¤yÛ•ºîd®’:ÈmJãjôRû*fóKš•~wõ_Àùñëêðq¿þí·âºî\(ë]Äv7ÁÉÐ×PÜQkkº¤«Uuu;æt›Ïæe÷@™ÒÙ<áÞàױ…Q~›’ßd‡5q‡e?`…$çµäƒ/Í|&ß5[ÓðøaoDÉ n=´sˆ¹Ê_nÁi:û7/ñÀŒŸ”1(zTÜ¡¶S‰aÚ›š_…ª=kÜÇÖæTÕ«JéÅîþ¾}Éqý¤›B:üuÒB:âP°ŽüÿBºÒá·z)¤ã^|-ÇHŒ„§†› ’Yìù+¤Ã'QaÄmi /âsAÒásݼØd«íã("Σ'[`æ‰×ÂåCã‡`q ›Ä«»±”W—Pí’€kèCÅ5HA2a¿ô FOø’ÃeBê[v[ è)±ÞçÎ>~2GèQwçHLãµõ-ºÙª-¾yrŠHÈw4ÐËTxu”°+íäÂϬwÀ‘Bh?(~¦PxV{¾7êP\ÜÝõ!Ϻ¡s:êÕЩܪb?ÅÓ@N•ãy¸-3ÅCxü½R‰)µŽY3•K 8jŒK4ÎòëyèÆY6ÕƒˆÍ®§FÆe¶)u&o厔L)cš«º¦ý{nt:LùÖ¶ÚôМ}hÞKöÌiÙ3W—=õÄ´™ÓÏ—eçb³9ýüb•gËl›¯ëoýçÐøJP?B û||†:¥ÆÚÙWÜY5¼²£’ûƒ¨:RÀ[y¯VxsH(XÄ)#c‘1— £!æÚ‘1¹*2æbdÌMŒD/ŠQYšþ˜ëhiõD:J½Ë[ûÙÛ6€Co¿žVQ'ý=Jú;é錄i•¥ ¿5T–Eme\QõÓQSÓ:*’)¥Ru“tLÒ1IÇhÎ3•‹U;ÕùyrR $hpÜ6ϰ;e/±‡6fÇÅ –ÁmÕ‡íqG[úÐ ä&„ÀÌ„˜‰„À< vÚ˜—° nÀB lÈg±AnBüÍ yÐYüͱøCOV?È¿¯‹¿«/Cǹ]åÙ:£Ñ‡_—¿¼½¸þËüqòDuq1Jñ¾ŸŠ;><î·?Õožšxó”÷晉7Oxož›xóófp=à?pKU¬ðÝnt.Ƚ/Û[q}ÙíG»Bðov«»ìnôoœ/€¡"²‚¿-óówwûΉ­A—iS(L±6U*ÙîŽ)Û…Û4ù…½å±UA ±µ&>,άõÙݤ1³Ö“äh4êù˜Y«‚±hfÖ:F(*ufÖšRëEÂ^ä ýåHÄ¢  hÔÿÀ¦%×g7”µrZŒ÷æ¨Ã·Cµ*jñLò[¹sOŒ²Ö=¹€ÃˆÔÞ«ly"(/¡mc!3»ž”ðÈ–àbAª±+ †Y—„û9±ˆêVƒ«­»:)°·üUœ:5³o©©‰U€¡çÔÄ Ã $b¨Q³¢ÁP¬h(\½UBiZÃHpÕ,>}Û2JUjàŒŸdíåš}›ÂåDÆR_p:Ä!oNèùݶ¬³eˆIùzÛS0c´?”åi|T"ý!R} '|ê¬Þ§_¸Èáf|øv.NÌ­Tœ°•Š´²H±9Ý^H5U³ÄYI–M*,Oßa¦&x§Æ4MEšîBÎ9 ÍSOK «¿†2£}ôüd¡öIJ')ãT:…n4òÖ¤¨Õ’²šÑÎÌ•ÐcÄ7  †ºþ› ´´5¶b«²ôH»kBh4ëVX~6ØîÝ–GÚ]B‹YhLà»ÇÀø†¼5BàÇÑ\ÑÌ ôk©h&Øú5R4CýÚ'š±z#Møµí­å—¿Î M[øTè¥ò»ptÃZÇ}‘¡³c)Q 'È ‹J8< ÇsÖ¼xŽv­Cå”:©r`àQ|ThÖ)m¨>1Љa­ u\˜ƒ¯”çQʇó([Á&¤‘¯F¦Ž|‰Ó ¨r….z“*û…ÀÎTJb˜y‰vIÖa05MÌ!3„ˆ §·ÕžŠauCÚÅë"ÏR \fXøFI… (L’¢;Ó†ÀõÕ]5ötJMÒá‹ÝÃZ?þ}Ä‹òÊ>¿-‘é‚C»£YínˆëµÅ\4,Ô2ŸÝ…æ+®~¦®¯Ñ'ˆ~L½;€nÀ*úq³É¿®¿Š¿ðveu DX›;î¤&„Å Œ'D'«jR¡“€“!0è‚ñƒó#Myô’y»‡l¿:ìö£?ÿY} yPÞ²óyæ|<ÑÈe?ä.?ì³Õ}qžÇôO¢Ç샇Ìx?åõz—¶†Àæ|„Õ9ôRµ?”ÄE1â—›}ÕP éè†ù·Dnë‹mR»• xâPOøùuŽ,Æ©Ž€ê³`¡«ëS%¤!ƒ´Ý]HM¤Ã’MHíXÀ2d4"ʸ¾þíÁæbpæl“gÄ!¡=ødܼbÄáµ3Ì”ëÄ">MüBs¦#4½¬¥IR3p©rË‚¾Ø1±&|™âÈ$›kšdçód’%ábÊ$Ô°IŽIVº›IVrx2ÉdBs¡k’u–šÉ$¨ÔžIÆÈ“¬äˆd’ñ¤Ë¹Žtù²Ù­º‰–ê“I¶‡l©n;JáR]M²TP&±Â+OuÄÊÝîñó&ë$WàG“`9Á¯;JÉR]M´@8“l¡pœ¶&kï÷gªyÙò¾ä rEÀ95?°ð+'þCÄK“NŽl›²an±¼G¹ä.ä8a6ìiìKäayŒYލòaÃþ ˜ÄAEØ8˜§¢$~Ðá‡ÅÑòƒÈMðÃÂ?,?tâ‡sÏü Ê·ÅV@7Áç&â<1D'†xê™!TBж8 ì&8â© Žxš8¢G<³ËÝhN¬ д® &xf‚ žÙœ¦(låì7TQØ€Õo¶¢°ˆ¸ßˆEaç絋ޯ]ð^{Þûµç¼×>íýÚ§¼×>ëýZvÊfÇ)–ìÛ‡Y2y›Ý\MVú¼Ûm`²¶ú…QK¤8Ç,ÁÃ;W3çànðð<„DQ²üÕ~wSÞ&WÍMÆTʾ|ð?QÝ~0<ý¯ÛõïAFÑe‡nÓ›0.àP”«Ã×X€‘&£tý$Á`УQÌŸ|Õ2…' KÒ‹b^J†> åÍ:?d[€*“³©ÖôrM²·vn\F·ÌF sö¡¹YÛgN û¹Š°¯ÑeýÏ…Oôj½ÉN×oW¿BÎOE[‡ƒW5pItÒ2­Œœ/ÿ^ÝÙŽs<±0SNýÍ æ<4äW;æ]ð0×iRŸ³È ›Ôçr'‰¶’ ãàyˆ‚ŽïÕå­=¬­jŠVƒ; Á€òï²MCAù'Ÿt~ÒùIç7t~/ ¬ró²7C Ò´Fî 2)ÔOI+%­”´’B$²U‡(‰}"Sg¤ï"Ë‘¡áiÃc fË ¡1epë¿ JQ[}8[u¨GÚÜ9OÜï±¹34î· n¸Üïðö ’ëÏil”*MˆÄƹ ­ÖŽs]lœ3اæbâœÅ õ0HS㺪‰›€˜ƒß-ÀèuR´uÑH$Ì©Dœý âLÆÎï×MYt©€2lÃÆh³0G´9ÚcýÍÑd†&34™¡É Mfh2C…f¨,ÛË¢ÙÕÑâÒ*Ðëaqf]yíTk1œ’½”ì¥d/%{)ÙKêÕ¡­BØÆ» £I ½ñ¹Å$ð£ú{j÷î­h\ížtzÒéI§ëͪ޹®#­;Ê`­½Ø<l}Å«»Þ)B &1šÄ¨†m—!ŽÅ‡ñUh(©ÙÇw¥³åfŸúo*`mN N}?‰Âk„ñǾ!O-@©H@ l Xø†|¨Ý@ݺ¾fqu}ØÄȽE’{i‹_ˆ{“{–Mîù¾çöZ©¨.:ü=•çIâ§=•!BîMâ[<4‰ïûžýI|ß·7dE¹ ]gx­å²Me‡ȶ”ul Á ½Oiì2±K™w`|ô‚âØ…‹[ý41Ù§-ŸÀšíréúA6_¿¯æa6äI·OÝæ7%àÛTfá Ôª‰ì:ʼˆ»¼ÿž~J#d‚2¥­ßŠ"O¥øÐËûï%£OEøMý¡‰‘òx% ‡êQÊjà¨Ë9—‡ä¼>¢PaÆ¿¾)º¾u}HpÈïO¯â«ü€æý±õ^X É.Í:º@³BqܼÁZbÃ+lÖ«ai‰ N X«f‡?i-[X¥ì¤ª™óZ´VA¶\¾Ò.M TœÛ4ññª^¡UHwuV&7j'±Y¸[væÃHœ†,N:§aðNì J£¥øe¶/îzˆO@-Å0„@ñ$Jã¤x¸çt`&L Uœ”^Ÿß;•¨Œ“—‡ÕþðñÍrHô`Š“ºÑé½Ó6Fcœ”ýi_M—ñ··_W{ŒWÿª›¯ÿ™ÝôÜ¢H~ÏçÇ/fªÍfwKþ~g ­%¢«°ìÝê°:ÝdÛ蘮„ÁODö"QBŽ‹íݲ¸h—”QåîŠJšpŒ`‚ p–Ä[5Ñ?!»°6ø!Ίä dØàGxí¬à¥y{—­¤°AÃêØj=­D•¶ÖŠÁÆ$ÊOV~6 "Ñ¿äÝËOïþ/4]ào{Õ’ç^ÚMÙŸõ²ABNç—… NBúˆÖ *Šõ æÆ˜<óJg© ¸iŸ`»tMÝžKKÓ*Á0jÎRKñp[ŠLÀwÙλ \õßµ¥*ŽXêî×3l­º”vL—Ò15ƒ%–å‹+,¯³ÕݱÆó@ùü´å¨ÀräA=BŠé Á éA0 {±<èT– Õ¶+¼³»ÓÀIo³ïÏÓ>då–Ö¿ýp(O(k >p ïàýÕ»/¯oÞzW°âÙP‚}¯³Ã›ÝíjsõÁU.yA–Ó™5`q&4ëó« c*¯`$±9¦^|Y’À¬4¬ƒ.Z%²ƒžu˜é,À¸Îîw‡lˆ¤ ‹–ö?ÆmÌÔ•Ã"œLË+½ˆ…+NÒ'ðGúUXŸÏ$†ã,qYf‡ŽÔv2kOF‹u'[ÈgÒÐW¾êçèØ„†Âï0`y'¹ëaÀm˜aýWáŠÏÆ@àzÅ'‚×¼Ñ4%Høåßn Çì~·?¬6Htèpxûn þÒ¡˜­š«;{Ÿ`‰Š·dì0ãTwèô>Ê6‰‹:ý€hãS-ÖPþh•ߊy8ì‘£ ÅÃNQÓ^ AõZõ;‰ê¥zóCûb_GÊ ZkŸ8õïÁéÔZLRš9$ª IL‰ê†k"Wݰ ¦«Ñ»3ÖKJ€«™0µ^ëâ¦ÃEhaxéµ}sº.Ñ›•³tnÛó¼sé$Cι%´2"d5ß¼¦{‘ƒ^‘S0®ù§ãpÍ?Eí¤| Î5ÿ·kNRý€]ó#¢z®¹œBwÍ?%×<',¹æ‰*’knÃ5§ \C®9m?˜uÍ?鹿„?:×¼¶oâuÍÛö1¸æ”XwÍ?äšÇ9bÆ_'¶VÈu®ˆ©_W§~¸-ê¸CpÁ¶¸cmÇj;Š÷h‹:ΖÂl!TR˜-QE ³Ù³Ùˆ²Y ²iÄØ^¬6ðx©I»˜îÐ>Až59¯Ó^,UO}OlÞi›àga…7èÌßîNóË,¿Ý¯Kk%:s‰+9øªxaÝüâìj~e«€ « 6$¦9(þš¶6œQÂ[‰š„ÓZ°ÆŽujÀ¡³C™È :Äóê)‘¨å”;æ7ŸBêáNœQg?)úš/Tw#xšHË¥f4Q„±a¡RIz$é=="*þÅÔ™ÒRߢå!¥õßÐ*2¨­!†G/IãJƒëé\ÏiUöXì +Nq±žq1¾Án":ÆJŒ‘Q_ <Ú4Ï×÷ÙÞUžÏB.¯"Ît^}~wNE=$ãNdž6™jû°zÌ3Ý»‘ †!N ÄÇwO€5æ|Ñ߯Û!P Eœ4Hàž Iìù¢Ã«|}yŽ ¬áŠ“4IB-HàXZpòlA`‡ì2¶Å¿gÓcöÛbçeø®Ã<} YÛq0ºÿ…ÿbÑñ\ UŠ´+!Å\˜7S¿¤wy ÖáD}Ø$&j“õ±à fëµéˆÕV’ÁúòÔƒ¢ä4"C,×(…Iú%é§*ý¼î?ÃX(¥}çSRz1´CJ/¦ôâàÒ‹­€·›åQA~L™FŽ­n"ÍÈ £Ì1ÖoWwAF!4¼2„£í’ ðLP> Àí—D™Ç÷ëŸÈåŸ?…ÖI‘†&ž š»+%™…á²¼f\5Îï“ЀOYÞF¢ãß×Ú±ó¹ŒâyQ*ƒ@¯4‘¡×9ì²q¸£ÂëCöX68£}¬Ì"¦ýåpK‰a) ”ÚO…Ê2AéYtü‡â#-¾úÁ)ýP‹Å§›ïÔC €ïvߣc wf:ûžXwM£g‚Ð3¥‚1Èá¡gJy•J7ÂHÄZÕù˜¦ºÑˆÿ‹fªèÊFŠn•ó¯??~ùҥΡÚ<®þUÿî'ŠÐÞÅy#£d9ò{Á®lVœÂõÚìÚj#Ð^Ç9ûм—‡>§Åó\©xÞG%šïV‡Õé&Ûž~^VûÃÅῳ}|½Š&§S±çüEA/F.¶wË‚°”TÅ$–JÒ"CÏ3—Ée12£ì™S¦)!søàIŠ( kSF!Æ [DQ\­„BIP`Î&°!_þ9ƒ¸˜KpÑàîv\Ìõq1W]û9g1Q¯ýDPàªg$rÆ$Åà¢ðÇœ£Ý„ñ€$ŠÑ˜¹—ŸÞÿü_¨}ýoêÔùt}sg}¨U³¢«ƒÑnjùª-i³¤Í’6ë®ÍT¥¸enEvë‹mÕH©üÂg5R£ò€/Ï(Œ®úo‚ê  — ­ŒZͧ‡4ÎÀ§û®£òÉé¾ao÷ã‚ü˜jÈž³‰ ²FxÚ`ýz·bõØëìp¼“íjúÁ'ÝMªÀÓ)÷næÑ7!6¿ÞÅÇv†z¼(µ›ƒgQISüN—Û<ŸöÅ‹ FÏ#,2 ‰éx¹d™Þ®~¯Àøøµ8Ñ×ÝFkÆÂ€Š‘›ˆ@5É1±qªT˜¬ ËõÉÊq¸/Sî'")ݰ~tüÎ%ÀBN¾ã¬çE©«™ñG]Áìµt¹¥|¿µp9ÐÚý¥>™cfјkGš÷V´àFe(µ ™™“TÇÙ²øÿw«{gÚÊuÁ­îBøÓ_TÐCº½²D´T—¡w©è3ô¬ËM–ËnAî<#•’~™}f=Ö’cf9ÍK,ÄÆ2K}–1×v£¶³‹Ð…Jð'í;»L6æH1ȪĠ6v™?9ägÁ¾.’e¸‹º´tP¶„'—‘c–˜‚ÏX’œF-äø÷+ò–ÛH ›AúµÌH²Â–çXá8v×±„"ù޾½„ä;&ªH¾cò ûŽ´¡cÎy¤½5ãÞcùzu÷ñ:»ß²»½³… À°žœ;© ©‹Öž«A°&„Àoœ! ov·«Í@éÃ-ùc¤þ»Ñÿ@é>j’”Ú#&ô¥>¡cbu·ÒB‹™át]b!6–Xê±Ä1„½…(á…¼«‡¼K¢•*IIÎv … ƒG_ŽÄ2ß\å/ öø¼Yç_‡Ïaa‹“XY(ÂÔ \G*ªwÛmv{¸Úf‡NãX÷ƒÜ2#8¼[R|n†pܶXD—ùf4óÍ”4IèÊ\å…iñƤäߨ⍗ƒN¬¶~eV#MiýÊ´}ýÊŒÊÙ*‘Ó¬Úf!ï_±pt( ™,¬òAæ)\éœr·²ÌÜ)!Ìh\êe,3jËì'W[ý…½TœVõŸó›®¶êTò+ÐVIG%¥©£TE–cÙd¾|¸)G¦Cò"!É‚Nþ"þãwSý²ïJÕT¿œ¨"¼úåv«'0÷+`føa–øAF³£åË7 U1¡PÅ“''}Ñ&Øf‚ýgúxþŒ‘6^À…óâ™›m“ Þ¯Ø-?òê²Kò:zSúŸ3N*eΆ•ŠŸ-˜nôà,àç¶:Ñ‹gfì3³æ«çÜ´ І-Ø7,šßrÎ>snÖ=>§Ýãs ÷øÕ%„Fl¿º<]—Iíâ/9X–r>ÙåzŸ•¤«ýê2µÒ«à„¤çV ¤Uý+˜T±0…X˜I°ÐH]¶c¡-ÃÛaa&ÄV-ã5×4Gfí¯¹~ÆkÞcóÒ]ÆÎ 5“ëÂÒ_Ù|žCŠ_H(~¡Oñ‹÷·P /ÄôÉù眿€x8—à¡¡ÔÚñpÞç‚q"¥5ÂEÈ9‹Ú€)1ƒ“ÇV ]\æB`á'Dçàw ðz£«ô¾—F:sN¥3çìó߯þŶ­VÖÔŒm© ÛÓ<]ÐæiC¢õ5O“MšlÒd“&›4Ù¤É&Ù¤f,¯Œ.‹öVwSK«°¤›©–ieÀjšÓVÓܘՔ̥d.%s)™KÉ\Ò,WW°Â6ìØÌÕwóTWâ¼ú®†¼þ› ®ÄۜȠŸÆ x·zš™µzš#-/]$±ryé°ÆãÆ ö,šØó}ÏíÁŨ.:üúéó$ðC®Ÿö&ðƒܦÀ²nÜžÀ÷}Ïþ¾oÈ[Kš¢ü[ˆô”Á>¢¾È`“Q‘o¾CàÕ¥b{Xx·ÚgÛòøW™KÒÈë‘™;2Ù¦•¹+~„Ó2m7KË#)T‰¶¼úa”ÙµHî²lµÌÊTSçNÚ3+SýÌŠte »êBʰØ:?äv&ÓB®Ð¤Š›XцËM]L©ÔôÉÚ"êïROƒ¼î#E{í¥A|…ó\èaKK§›¢2:ñØÃßüÆZ,Ž~l¥¦‘.ÍH¢7ª$%ѳÿ9~âlbG!® YwMõlJ¯©?;ŸßPuDfWW£‡Z+†ôL”.ƒ!Î`Ðϲütýv½Ù¬óâDÛ»<:„ù­þ nÝ5%¼u×€Ô×]—ÌÓZ$G‡ë: !:Ø* $ ÔJ°Ü êÓ¥d4\¢c£èÈË.’óuu¸’ý]™˜z,Oö"a‹Ö¨Àø³'„&D]©õPÊÓ¡|Ðá /Âǵ;Ó‹ 7´@‹šôR~‰Û8 ÆóÜ­°7·1ÖqÿøøîÌU¦L•?¼ßÉ6ŠËu~;$Áˆ“ IÜ"…?_´Äøîñ1Bâ¤@xx÷ć°æ‹î@ÏÕåê°Ò!¼Û¯«=΋«Õ¿Í×ÿÌ:¯pÊŒüžÏ_#Û7›Ý-ùCøa„´J«˜Ö]ñ·ÓMß(*†ÓYÎDëEqûF.¶wËâvqØ CU¬°T‚z1,YºLŒ 6„U-åЙrR‘zž$ =˜P–/l,«:¹Z$ BÉca>éÖØA²¢ùÝËOïþ/”0ûÛßGàB´do‡—ê‰ë7ëíÑU2 ¸aC‰‚*8xªXè,‚ùè ºPÁð±WÒúÌ&Ã/Kx¹]}Þd]äa`~ Hœî ƒ{/ŠÁ¡Ç€Ò@ˆ’$Nªd€ðY ‚.Yå®iÒÑZô¸ ”À_v©e!ºŒxëS°[”Šãß~ÍîÞ®~~: Jœ4ÏBá^*7ðèK,ƒªÇa=æõ^ù¬:`l¯±ñÙF ¬,þ¾Ýæ—Y~»_?D9냔…©àÄÜ 0½°Hà{% z©³ésCù'jÜÀâc¥µ¿Y^Óæâ‥f"p ªÇ&ç}s|<]Òµ0]×Ûè¢h<Â@ô/»üpºþPÐGtꇆ'¥;¥ÛthÚÊáùêð‹òÛÁ«ÍBP½6¿™TN“uÂWTe’4üX¾(ÙiÉ'Wá+ê;ͪë»7ëüm | SÕYÐlcP©ý¼ÞÞ]}8}ŒR­a`’Fë¤Ñ$ø Z™™>w¬zL‚* é¬Z†è©+ùgß §V××Ù—Ç<êZò,q™`xko 0é³Ä÷Ã*r¬ˆ“"ëó{Ix Üù¢Á×ÙTº/×…STp~ܯ¶ùªd‘.û›ÅûèÁ Ê$[?8mšêº†_©hêRëØ‚+˜y·û´@æ:Ž€"ro„·)5ö³¢ƒSk¶­rm̱6oudÆÔÈ×pÚ6Ó‚áÈ6yFÚîOÆMJ€,ŒHaZO¶üÍIm½·R]ñ‹-KäÆç‡]y,`ƒŽ Ù Eeªo¬~ó9áRbå~¼¿z÷ñåõÍûOï –>sÒ¹® Õµ6—ö1;ôÅsÇžöVñœ$³õÞwé$Þs°³f’fy§• ª˜&ªð¸ñ ä.äH¼… z€+¬ ‚V5·LŒ‡VuØ ŽwnùJÅ¡ÏÅ[À‡KútëüV}? e«hð5K‚X¯„ÉL—”ÏPœ Îþ/öYq˜eñ×üÕåÆ~Q€Å©)ܱ³¨ß˜B¨»žb£»d6»Ü5±Û mŒHI›€ÀC׉?Í. …Ìê®\_œ4JàÑ QÚ‹-ËlÆíÂC˜\¿d˜¥¯Pb"6¶Yê³M® ŽÁ Ç+˜?ùJ:Éžd›á³¿|·|³Ûýãñ¡K |äþ\j4£ý]'Æ Û 0£›·QÁ‰(jƒî_/jƒ™ƒŠÚ0ù(sjŠ“U–™ù*Š}‹ëñá¯.]¡Ÿª8úüÞƒ>*ãŒøÎÑÕ‡oçC"oRœ´ ïÏ¡–-2@˜“Ô—ú¤^±‹AX~0˜Ôf‡ÓÏÑ1ÄR!ìX}åucö QÂ}àØj†äE~J®$Ÿ0ÒqÅi.^]gÿó¸Þknoáì‹»»}aÍâ7ÄŸ”Ç ÀΩ9ò9>|rñÑÒ ñÈ\Ñ×㳈H(Ô”†d¸Ølvß?í×ze:`çù4Vu Ž“=–ܹAk¸‹¨ñ‚š+ߊN8Ô@x0Œõz)EJQcn§¶ 5¬xÀÔþC/¼öI!pSç]‰–€×,{%u|‚_DrK¾Ž5‹iùõ¤z„Î}Ä>Er…Ô1cÉ#"i* óçua‘¦ÛÕöËÎDm@m öÛ‰',¨ßÂnjØWËḀ̂ͺ,s ÐIì(Ú®î³ÓÛ¡&:9B@•JºÎ­c0èÒó'_qKöÄ®?š ¦ˆ ftÇ+5r“Yo½Ã^²ìOŠŠæÚ<, eVóÌ®ÕlðÈPœsØ—ù‡›+–ÈL/)$û*D­ä€£Zv`/Ës… þ½*>v“vûBaaÍ=nþ†þÔ&ÛÒ˜HÝ?'4.^Q~±¯®Ò! ¨ !M¡9P?4o¾mÎ}pÑ|ýQ?cA Å!T6ÆC)×àÏ7Ùö4¿úpúíVDº c6zXÎiÇ”¹ðM¦XÍÜàrÒø’¦ `%2mUŽÅLÛ(1“«{Û0ÈjG|ÈÖAb3Û6YÏ£ã“7Lj{ã«A­âëÑ"fοûºû9cÆ•ÚDnÃÍuùfÞõÖç‹VfÃÍíÚp 56φƒ:Þ þuÎÑu.H‘ˆ4~»(lh»¶+]t½Ò…`ñš@ø-„ÑáêCC áŒÖnÚ\ÄóÕ²¶Òžƒ¿.\™ÁÝBMƒNoW¿ƒ@˜– þ€U´5dudò)Áq„Øfß EW/¥ãÎó%ܪ Ï­"R*ÀgMhFLѪÛÖ¬J‡u¸$LúÝzV‡ã:´Z:;§k4Rá;½@"F¢b ñ¬=8Ñ·Z9<ʯÀ¢aÄ-² oE,“z’¯ˆu—zjG/‘-ÜÛH=Ñ;b<¼¥¹ÒR%w;sÛÂz2ÅÁÕöåV¢»íZ'` *%W¸!ÉÉ)6ÍDª‡ÔZþh•ߣ¥ Q¤eß§þZ8“õý§w/¯ _þcùËÅ%¨ºa7¼8¡Â‹Ö®“ê±./ì¡ö&}Ô^=gT‡é´é°¤º’êJª‹Ó(ØCfÇ&®MJê.BÚÁDîf/¯éIÃ"ÑÚ“''Å¿±ð q w ný7èj’æÝ¯oÞÐ*À[Cœ£·`&`3ÿ‰ ¬O˜ |CÞêFøqL[ºWý†¬ ƒ•Ff«³oo©^Y6ù¤eˆs´½ÞÀATf’M­y¹¼ZV›^lg8°©8Näé$¨2y…†Yìr!ÉC¯³rõýP¯«… -·“ĘMzî&“Qõ^4ÆóDò ß…4yð4Cæ2@Ùé»cc(ô@ %Cá»Cq§„¡ÌÓõÎP3BÃc¨èçí2—Qæt¼0¨Û+zâÀ: „Â?m,S¢]Ê.ePK…WÊÝ ÖbN-uÍ*vKù„QÔ×ë:áX;(g˜¶}»aV²˜¿Ê—Ë7~øÅò,F a—–P˜ 3‘sK…~wÃLìp ö›Cφ;"ËÑÓÞâç#oŽœÞ·sW}1k£¥‰ÐväËFø€3@"ç¸e縷1VCðÄ> D­¡Î± Àªm+ f¬Ao%aÜ?Ï1,éJ¥@† ];&A’tíŠÖH¤«aZ¥+f¬c’®ý“^Ã’®Ì¾¼ø¥kÇŒX’®]щtMõH×~P^ ²TíÚhUºâ,éé:~ÉÚ!OjLª†Ü-§†'s„¸))MW°(ÊŒÎâ w¢òkœÛWøÈŒ8è– ¶*¤m-þ‚S¬LÍ;hˆ<ï€# …& zæ°#ß3ÀC†©EÞEA—L·UAÌú5DÙÚÈVYhrÀ@v~h{ÚD2¾®Í»¤èšË?F³!mtSeQˆ8mƒ™´GåfØõ•Ç9oBAds‹lœ}éè¢\åཛྷؙ½Çˆ18ʉ–4.'ðQß<Ü!|<¥Ú¾ž®Ë(>©†KŠ-)¶¤ØäcùzŠó%¹Ÿù|piD_Ñ—Fô¥}>˜À÷ º4¢/è‹mDßù21¥ë48¨úõY}s¹™ŒÅXgvXS2à¡}ŒÛh¤©’g¾úݧíb1·§•a>Ð ¿Š Þ¬óC¶Íö¼d™´„£Š…*™°¡åâpTÊ ŸN@0¹É$ oW©ƒÕž~¾Ì«Û¯,û`,(kþ3èwOøüQ½PßïÆODí¼!u¹'r—{`5äm¨ ´rÜʱWÜzq^Ò@^»â:k F›0­42uÑ /eP‹*^ÂÒ¤Œ# Vˆ›N /Õˆ,áûh„„Û.ÎUs“®j®¿Z3¬±ºdD+iª¤©’¦2!¡ãή©¸"yÚ&’•E¯AéªçCó¤k’©r™ªÎj!ð” ÏÛAÆk@°¿5ÜÎ)d4B4`ª°œé–üšÄ•ü 0`4`&˜X·õ¢ÛÃaQ]´ öŸ™`ÿ™ýDhÃ1‘m„­8/õ|©Ñœ*z·z:•6ƒ« ]:‰J¸çO±Ïb&uÊx*þ²¦ên!ySZ¹Òúc¥I ~Yf˜ÒëD«±7u7ñ`¬§»¦r7}šMP|uØÍÜ*8²ÔË ©ËwÏ%ƒ×ýX?äM«.ÇLýºSßv˜ .dí}sûEĬtˆvQ„3ÜU$Ê›ãÐ\p‡‹eP,”àÕñf¶¹CΑ.€"Ípí‚3œíä;Ñ™\m›MØMƒž‰q'y ü ƃeà ;}²Îhâ€Ø'þ5ä%pÆÐ Íe1¹DÍ'¿(• Áa‰uu‰ð·«ßAgFîž=àS.¸9A „À#k¸SÂ"óR.Y‡·þŒÄ9w¦±+·~6uçÖ›Ý]ë“M4&ûuî•–Õïß |ºñP\¯Þä>žÑÔißY.Ü”pS¼ë6É9¿SNÑ"ó³œI IVV:b ‹ÿ{¥Bq:s ÑiÓë]}Ê€. Ó£‹O+ouE”®¢.ù"üý®$6z&}·Ñ‘‹óû}J‰n)âc3ÒG•ÉOÅÙ™³-¸‡j{çÖx룟ќ|¦2ÀŒüÆ1‡kq}48³‹ùt×å×v™ÙE¾Xcn—ôöTî wÀ‹®ED-ü<µ€º53=œûò7½€<ŒŠ§oNKŠÓ j’y´›ÛM¶ ó@³BÆn &0>iiÒ «:êÓ Ý¾(ޱ}|&åBà†B»œ¨aÖ;ýÂÍÂðá/ðÖ%eQŠž¬ˆœÑÔ<7šÅGñ©ÖEÅ3sö™yKs^€­oöÎiœkñ`}A°R¯N}”.?kP}²(*ú:eÜ[J`~5o/ˆ< ên/ˆFØ!ÒbÝÆšºX†E¤jàg13—`¦! Û13ï…™¹bšh.L!pˆèC¥Nz'„¶di øcαº%À!*Á- Aà›P«Hѱ?º¼Õ„Í2qg³86RÌ z‹Äô dw$»#ÙÉî°hwôÕ³Q¨X/ëÈ„ë` H³î+mþ­’´ø÷XyKôøŒ4%tvR¿®×x+û@þWª÷¡÷–Á­ÿÆ]Mæ¦Å/F¿Ì“PbŒ´æHä€oÈ[C:QàÒ [?Ú#$ý€´gŒ¬í~Më6ÕWm¹7•Ó‚¯GfƒDÐ%Þ öPôs»õƒÓf©ù)*l Ù AU¢Ûâ_§·à‰D‡ h>CCd¼‡ÆÚamÊ!5ÅžJ¦Ww©ò"¬-!øŠ2ùW}æD…“šø>?”¼K'Å ¼òi}å3þ•OÑ•Ï(F©#²ëÖ‹•è|Ýl(ŠF.†f| UŸ€¨Aq\CeΘwòð¼Ä¶üC±ÎöO´|T¯¢Tï†DA™U@öË÷åz%)”¤P’Bé P4¤¦ßÖ&ê„£CØ?CÊr|¶ &2+l„¦Méš â–áóGˆ˜ò}¦ !?Êø%ë ^²±A‘Køºa˪{ÕTÔ’ê׉Yâ2Œ'°r\ÿÄ{d³~­Ö/l)à×]Ó«r¿B?t]«À¨èéúP}w)Ÿ«@‹Ì­»÷;³"l5}Af¾zž¬ÉÃKÜØÆèø¢¢"LÙ ŠBÙÇÁÌ afNb ôväèè—芶4¿Ö:\ü̹ø©?QÔ,ׯ–JÁ€ÓÍ…Ê¥úæ7L1èÄ¢ÿD+'åH ezôŽGw6=ÂI—êÚ ½ò§b[!É@HB2 µŸÅg9ÿJ©»©5ug=ùª«¥zec9Z*©§¤ž’zÒPO]„°cùk/ eFÊæ†’­Š)›K Ü ü”Ë w„˜ÊtÈ!‚Ÿ2¹M2¹©¯yÌd ‡r!DðÝÈ…!Ÿq!'ò;AoB(ÎLuŠ3‡å-LðÉhu “Çá¼{fæÝv gª¯Ð­›ùe•¿ºÌûEñú aÕÂõšÊZ;”¡¬4ÚÑ·.ëîÛbpTh†¥fÉ=¼w‘+Ó_ßìv]  ‹XBZ\âT§9Ä Í^þ±]ݯo—Ù&»=€#™)—Óùœ^ŠEþ ê;¬ï³›ns‹•Vg)$k ©¯k©´YîØ¸¸rçÍî{¶ÿy÷¸½ËO׿><Ôÿx»úý:Ëw›GÀàÓ|2mØÛ¼tñÆ[ì8S}±WÉÇÔNžˆ&î)`ˆ7xOˆ!îà½C>‡Rq!é}VB’ÌM¶U«-T@[fX–Ö8‘ç®ê]œì !Ûî^}fX2ùdÜ&P«Õ%“LD€Þ´Ýõ­…’þ;îEvCÏZGU»Áƒ•àxŒ®4~ÒøI㇥ñ$|Â= ° &[öD×Il]AžfÙ¦Y¶Ã,¬ X$„ yÄcm æÎQô"lr°œÈ~æ\ìÄM¢‹s 6rÞoÓM_ÜÝ•­‚ýºXpgætÄëÌ$·$ñs-.Ü=IœþÌëÔê$ÇA ˆÚ*”§7äàÏw«ûl _ðÝ/œ¢®dYè}"«Ñ?"iÚ4PM{(`ί¶Šˆl( é‡èÛcB46zƒ\eöøPš2Û P‰Ÿ2úÂ]q¤áîšQ{„`EbÐFý…";¯ óüäç?®³ûÝ!+‡æôŽØ£µ~S+Ñys›ûzµkòPcò=ă0…à•Bðj¨ãEá…ëܸQøz[³ ’]çÆ%XY¤Ý n:2°—d{³»]m’`ë Ø0æ†*×0€I¬iŠ5 æ|IµšZ@¨•rϹü½Ìfv0'ËÂàŠåhØ|J0=G:–åÊmøcÁ²(VÜ%Ë*BºdCþ6a?[}ï¯É½dÿ«Ë~’ÿ6¿êhÊ‚Egɾº„&l»!IþW—¡Y®kÙ~Ë WÆXˆDÍd­ùIÛf-èrðÆj¥µºü¾þ­Ô¿Ÿ вýŸ‹;¿{þü[v{Øí‰ŒBñ?Wâ„Ӛ͓9kל"8.{Ö,m-#¸s†ìx›}Ⱥ¹z7ÿɈÆfZÏßÜTϬ´¨½9…tùþêÝÇ—×7ï?½+8ýl –qŽ"Û¿ìòžÁÞ¤nh…Jüu;8ÅSƒ™ÔEõ#CstJÈ80úªˆàΤBPH¯³CA`Û¿áð)'s´C‚à ijNñÁÖ¡9øDì^ŽÍ”ÁÕÌÔðœ¡9U©îÇõ}¶{ìiÇõá!ÜÃç‘(ÐÄP\!1V;OÑW"å­2k¯Â\åƒ>¸ki”»xÝùÖKblº<,z`Ò!+~Vd -{hÝK;Úl4Ô#S¿A•›Þ×ùËlSe3.îîövÛdì´Ã8”0®È¾— ¶Ôó¢iA™­Î<ˆ‚¢Æ0ÅJ?’¯ÿ™u4PàG3Q VpEî ýT0…fŒ@Ïâ‹•j6„–k ¢ LB,¿¯*ùuu÷»]ã–#Ú#Ç”M‘ZàèsºM•Â:4aÞeßÁN×ï÷¿­·«’ZÀÄ/›(h“Q£bÔ´ Ì–QÛ?Ö&½M kÁÛì*äÙc¤ oÙOJ³òjÀIkHí;©V¶pK5G4›¸ék`”ÇÃûýú·øÂ4 Ioèé ·Þð>šµÖmr¼Þšáæ!ë×Ùáç?Y~­îŽ+%‰ÁP:ÃW*²¾ŠÈÓ–Oûõ¯,>*†‚§ X²ºÈ9ëÕå2;”C-ô–%÷«¢åé4ÿºÛÎfcpýêçÏ_–‡#W«M x·-¯å/›³/ó¸ß§¾7Ô¨xwz¿^aÿÇ«»ü4˜€ ¨á -Úhã¢_ÖÚÛ½¡Fao!>Þ”ò€ÞNãÄ5’!ªM“ȱšT†wÔ°3é­•—ÛƒEèøIe;ãba©Ê>3È>s û4äe;û´ï+’a’]ò#ÖX\~š³ü$Ñx%ƒ!àq-òKϹԠ=6üh»ÁÝmŒ_Vy²1¬ØºÑØžFºÈ¡Îdt¨b|%£CQñÖ`9:£CŒI_F‡ ‚Oh€vÄz ßžSØN7ÿýŽFi¼p4ñGêáÓðó€4÷šSŒÎh-}&×ҼÎ9j^¨ì ' §Sü€0Ú¥?x†þ’7èKp‹çûOï^^·Œ¥‘Þ½Ê=Wݛҫ–¡ Ù¬R” <1  6\n½WÔº{yµ¬ºwmwhÛM;Ù­j˜y²×0&_ÝL<Ñpé̆Yü”mxÅ †æít7Ç¢ÙäåÍ\5áx åõ­ü3 ²¶ÐóÔ$·ÇŒà8}3o5©ÉøÝ…ë&¬C ëÎè°Ê;š#ä½·Z8á­¼îæ®¼­wGàµiá†õÛ Ô´jŽ×«u öÇ)Ïå"]ßÑtGç0>1WǤéòV3fÐÄ¿äØî1fÓèÕëÚ4É”I¦L2e’)ˆ)c@qÇ¢³«ëžšº¢Ba}ý¸Í׿m³»JùáÕ»hª&øZz xù˼\œM³D¾\\ªûNêW÷Ú¼leýÿŠÀÖP4ˆŸ zv ¸õß8 ûÝ.nr+¶'“t^±=aä– ó$ÂØÆ®L° nÀ2Á7ä­Q¤¨7! §„tè, §X¢'«äß×ÅßÇÕ—¡ãær6‚âs4úðëò—·×ƒ? ;´Buq1ZÁ˜ŸŠ«><î·?Õß05ù gÌ7üëOÕU¸âÝnt"åËãöx*£/»ýhWˆØÍnuW˜›ÿ&ù"èb`#ÈÖF5¾œ\ŒÑLèTÕ„ ë´¤˜»‡uô²Ï$4ã? …Ï«ÊÀgЯDÁ ž_©£iø•äñÛÃ2¢¸ïD÷mv$î#(ÏÀ¸+]I ¢rùEù‡™ì3‡Ä'-7ÝéU¿¼ã\\V#º%¯7Ô»@†s/SºŠ»ŽZ“òûÙUyQ° orÖ Z7#ÔÌ[TF«Ϧ©Œ]Ÿ>€T¼@¢7©ÅW'š&îY{|u¢_í-/ ¨Z84d^•)òFT³\V•Ê!”|Ë1ÒgK1®âP[šÙ©zo^ Yj¸‹3ËÖEö@#¦Œíi8™Ò4Ü@òäÔj4YYqÀ*ø×éüù&ÛžæWNÖ&Zbè²qëc˜ø0jp‡¹°"°×œƒÏ2•£‘øª(k¬zbe€ uüéøM1 ÊGÀéOkBBˆœÐÔ6£©Ç”&U$6æ¡s2±óш<ñŠžÊd|.“¡ÓãÃg›Â¢«O ³“OÆ| ¨”E=}‰q±Ü™ó)`†(`N‡¬+#ŸÐ¥××[~ ûÝ7'1U:Q6‹‹-w秆º7§jxÇDgò‚©st© RBbo½´ ÚåcC#¶]ï¢Çõ.¤© \\pñÅ~¢mÑH <Yå…&3оiµÏÃ>ïÒ>EßÅÇ nÀ€™ÆUÕ ì}ãÂw¸Ì íüq÷×l¿þòÇrùFß*µY›i©Ö÷õ4—{ŠQA´DGjõ5arí÷!P"oiÖÂh -ÍöaXq[š‰%ê,ƒñu9’V!Pï‚5ÙQ«%cA[Âò͇,Û¿*@l´”ÓèB³†/­¹cE ¬ášSÊÈ›ÿŒ7ª,>ú¥¦ ¢ ó=ëf¯ !¯  >îóCvÇÀÖ!Š·ìm°‘4aÍ¥á"F´aòWú¯)÷fÈÁsmÎ(…°H¯{©äv"ŒÕôK‰ªgœq¶¤ÅŠ©ba(nÉúèìFv9ÛÙ¯Ö7mtÜ?]yZûb³yQpZ•&걕%gùÁÙÖ$'…ˆJX~F?‹W`RP¹–‘¼JæòÞånœ›5 êHbe A­~Ž\'"dMpÁȄ׽eBÿDwçJwç¤Éï‘r9 ‹o—¤Zj sLhÔK}£Û Ì{#%$þruôгÀ©3Jâä& ¤.uñcSS NIvbýˆô#bëH™ùu'fö©ÂcVˆ/·…)œÝcN"T ‘õþãä$¬”8ì•£2‚Œ¡á÷¦ 1;KŽð:»ß²«Î "#7.¾ ™YQgî¯l< ©m $u2¼Œø>Ù3êXÕ˜ú“ü»é0€x­‡m¢«¢€e–pûÈ»2"²š·ä­ˆ8ŠÊ\òÆt2‹Ö1{í "vóf²-(NâÍÕ#bñÐ"ÒÕ¡w¨ó[P¬pASý9úi<Ùø8ðÓÏàÏ_‚"X´§ýG]ì0b‰ìXhøhd1;õKö\°¯g‡ŠgÎÙgιþäÓæÁžò@ƒo}ƾõYó›dŸùÑl8çGZzý¨°b¾IÚpÁ|¹ª0¼k~òŸ×Û»ròÔçåòÍéúíê÷B’móÓ‡ÛÒ¸BK O3@0f ³=ôMdøyÑLyRÆ›íOzqb ¡R`Ú0Ô¥ŠO¶¥(”P€ÕóCÈDô®~®yõ³ö«Ÿë_½h7½ êDE±\}§óC£‡7 o1ÒHŠÍ¡h\HD£^ûüH÷ûd „y±…8/¶ Ç9é’Äǹçúø8ïsÅÉ­ç,:ðäÖó:ò”owœ#»ãi·XÑS]›ãi„<Õ‹ ?U =%Iæ™ØÖ’ÏSH>Ï$äóLŸ|žõÀÖ3‘¥!¢£gB;Ô3W?j°×3ˆŸ%øiØéíøù±~~dðƒ]<.r~d‘S{„%f~¬YÊeÂ#áW‹î”¥Ÿñ\õS‚?ÎÁOÁÏÀ?Šbæs øÒÁüÌŸý$~rN=9gßÎü¡XàôLý#%“ÁGJRP¤CP¤gÀãðh(ê¥PG u¤PG u¤PG u¤PG u¤P‡ù„êpåÐÔ—ÌïïÁOãÁ'O݈óý”v¾jžó|îQò¹“Ï|îäs'Ÿ;ùÜÉçN>w¸>·?rx.d8ÞcÇqã8`—Ѐ§wN{z ymÁÓK.Þ(¹xÉÅK.^rñ’‹—\¼äâùsñ,z/ƒr\‚ðYú»+óÝ•ˆý“ž¾‡æ®¾î¾Gò8FÉãHGò8’Ç‘<Žäq8ô8¬ÙØC1¯}[ÖýêEFuxF´ûxNÛÇŬ&ìãd’iœLãd'Ó8™Æ6Mc–àŒ@ö_Ó¯"MÂ|Á ü›]q[7…•‘ý^[@åW‚׫í?F7{ð'øe deìüÇŒØ-ïô§«Šûû{ÉïÀ‡'XF”~ó|¼æºÊªüV )ü{løIì$ðÉtÖ³“úeå—WïùšÝþcYfî ?BÉ…›o'£ßv‡Ýè<|ƒÁ€Xù÷ÿ(Þ÷¤‘úù}ùs⇠žÀ/}{ñ_\,?^_¼ûKõß@w²tÞýúæ ºð5øÑÐ]ÙArëÉ““‚0"¹õnàÎâ·ú¢J>/ ¾ûÏÕË(3ɩꑟj©6!DÂø »ªó@îÖùÃêpû•†ü ¡cFËc ¸HP8¦I:@Ch0HpíI@ßDÞÃŽŠ®MÈþi GwÙ?Éþó$ûˆc–d¿4„&ûƒמì÷Mäþd¿oÈ[K#£܄қÕptWz3‘Ò{š”žqÌ“Òs€†Ð”^àÚSz¾‰ÜŸÒó ¹7¥gðN‚ýœ/Øë^ï é݄Ɵ˜ê¬ñç"ÿ,i|âX$ï ¡iü Áµ§ñ}¹?ïroß2àak|ß·®55* 0aö,rélö,DfÏÉìQ Žó€8Ä£Ùc ¡™=A‚kÏìñMäþÌß{3{,¶ÙãûÖƒ0{|#¡u­]T€›°÷Î >élïc{=Yý ÿ¾.þ>®¾ çv•g#Xû7}øuùËۋ뿌Á'?AT£Ü„÷Sq͇Çýö§úíSSoŸóÞ>3õöïísSoŸòÞ¾0õö ïíç¦Þ~ƼøP\Õû÷n7º„¬—/Û[Ð2ú²Ûv…pßìVwÙÝèß_û¸pñmÅÿ› >›Ã¶O43eN7W¢%Ôn€ó‘âv¿§ðçõÖË•ç•hðÊœ}ÜyCÛp–úôì¸Èâ»Ïy§‡o}ʾ•],Ãæ¿‚Hù]¯òu§ „A4ÄHý°úý°\´¥vØ®í°\tÆÓ kîøüfX,Ù•Ýñd޹„9SÚ™C­Ã•‹¶AT8+dβD=+dNJŽ…†§âuv ìèÑpÂÆä<œœrÎW; ¤vλ͟כ×X~ 3>Øa-ãçÏùê†?NÌS±ª‘Ï9$ž§âÑÕ?ÒYì¬þÖoO…j““l;^¸ñ¸èaâÉwÛ7¶á1»í•VáCRÖ•¾jî+{ïðãmèÂ?j^«ë¼v<®›·êx&“ïcöô{/¯ëè?&Ï1yŽÉsLžcò“ç˜<Çä9Ãs4í Eå9q‹z{DN×wñˆŽÄó a?›ž3“|˜äÃ$&ù0ɇI>Lòa‚öa æ±Øä¶ÍñÞ–¸Ó}È-–xÜ6vëÅMçd3'›9ÙÌÉfN6s²™ýÚÌìÁLA‹V`oÐé†YÖ ÛâëiÍõ^†%µæ’ —l¸dÃ%.Ùp®m¸ÞfKØ‹c¥·âti§·åœ=MŽmrÌŒ™ÉÚHÖF²6’µaßÚè£]ƒU¬Æujwuê`â, ‹ãqjZ„ÍfÀÈ!†¿0íFU!ßKÓ A®Ê‹v3`ë­·Çr¢ºèðWå¥5©*lá{—V Â0ÈÝqÑ®Ê Xú†¼µ !*ÀÃß—¦ªÈßË¥ÑA.S‹vw\ÀZÀ7äÞ´@ˆËÔi™š (\¦–Ö§ªGH{wÒ2µ,S Xú†Ü› q»˜3èûÖµ†©DEáoKKUU8Ä÷–@ì€ ×mE»],`;À7äÞì€×m9³|ßzv€o$ kÏØÑ®Û"«çoÛ"[/Û"TßµEΡ3¾j‹ûm|Ó¹ÌÊÖ¢­â;ºìÙ*ìí»þ‹¶È† ²q"Â5[ðG¸è¿Ñëa$IPKµ˜j®–ÞëµmVm-umþs!mÁR¹ãÙ±Ðà«£ÖÏAtÊ(¹_“ö~Žé‰v?‡Z{ «lL¸ Ï…6ÓÑ¡wõ1µòðQO/Áó¢u˜ãÿÂÇÇMä#$M~×ÁVZ&Çí­a´Î4X––2·¹ÒìJ±f.{GLgf£aXÚ£Éí¦œRݔӟÄOš^Gæô8µ_¤ÕJ8ñ=––åÄ'ݨ/Þ{UY_HpÓFJóBÏ7äi#eÚH™6R¦”ñn¤¼&«þ¯¤¼&{H祿&g½_JI¼ÝÂVJâíÖRo··—|I—Å”› u>ã½&¨‡xF7€ þ^jÂèb¤¸¾âœ·ƒÒìN Ôˆ¨¹ÙO‚ž9zŠS” „˜l’þQ[±Z=q´ea/ Uêh|%c~PïUü ä%(y@ÉJPò€’¡dÍÈܾ·mÚ±ê-,d3bÕÇj½‡µÖ@Ç Ovx²Ã“žìðd‡';< ;܆a¯MiÑœ4bIZXƒÕbIf#†5º_ÉôK6_²ù’Í—l¾dó9°ùLÚ2Qš1v,#Æ‹…ÍC¬ñâØZ1f‰ôžD/±D’ý‘ìd$ûøýaNÝÆ¦i+Y#úÕ¦s]Œ©Ê)­*§†TeÒ’IK&-ÙSKÑ)“z Ÿ p°Vcš¦³ðø8†=‘­ÕÏDZ1£BA.^ˆvÏDý·N£{¦iñ‚éÅ iÛŒ [¹‰ ÚÅ Kß·æ¾¢<üMi<r4´›¾!÷&þBÍ?O£ùMÈ~áhþ´…F…8‚œUíhþ€e¿oȽÉþgÕ;“ý¾o]«_6* V}ÚM£Â!AovV}À Ð7äÞ`ˆÃÛ)@ß·„ô„aM­?Úáíl-Ÿñùíl1¾ñîl«¢ñ)îìT ãƒÜÙa|Æg¹³ãÒms‡ß£7Ñt+f·{³Ü™2,¢oƒü§ÝsÁ´{œs>FN.§ÆŸ<YÂ¥Ò6R¼kÎ}ì€]°/ ‡Ÿ æ”Ö‘…Å·<å~K ÷³æGØ1u»-ŹÏèâÜgŹú`Yî/»ü°,ëV‰Ž<Ù½l²Í.Ä0xvóU Rý®:JÛêw…(¡r×ìáÕ;[šU¶R§ÒC›‹3lƒ -žÕZ]åÂ|z<2×ä‘Y;Ìõy¤­AWˆL¶57*étxhðxd¡ávÍ!W,$\¡7G~¤ãE²3dD=Ö –pµln£<ìäiX£ì˜Fa \c*iÐéðЭhv¹<ã•O‘Qù¬Ûh©†½Üv—ϺÞå3½¡RÏøÆ$;Tê„ µû ›^6iû;r ÷§àwèëÈV¡üÛÍ6û~_èíì¡éÖ‘É}|N=>'æ)õ™§ÄgŒw‘:8síÅ)v)ÑA û œŽ5\ è±ë­_ ¹ÿÉýOîrÿ“ûŸÜÿäþ'÷?¹ÿÉý7îþ;pn£õk#si{z³öz÷fîµê9¦=–ïuqL“;šÜÑäŽ&w4¹£ÉMîhrGm»£&=“À\ ‹žî‚…å-½Ý…8Ý}˿ǖ?MË?ýÉèOF2ú“ÑŸŒþdôÛ0ú ™¹áX¸¾Ûžv­…½>úvm˜†¬ž‘Úc¡š‘šlÓd›&Û4Ù¦É6M¶©AÛ´¿A„-æÑ ëj9Xû‘†œÿÄ0AZûaÜúo ƒ4°­ 8AÞú,®[ÙKšs®BiÙË1JÀ oÝžô}ë­ߨî9ü ?i̹ W¤ ?Ç(úƒ¼u{¢ß÷­{ý¾o¯ç‹ òð÷:¥Ñæ*ò íu:F¥ä­ÛSz¾oÝ›Òó ¸?¥$…ŸÇEááïïz–t¼q¤ý]Ǩーu{:Þ÷­{Óñ¾÷§ãƒ¤p{:>Ä%uO£^Rà~6Û[ZØšgƒûYØ6Aƒ›YØ%w²°“= nca7‘˜_“¿AoAÊëìp±Ýmág×àoÛƒùêw3µìœús\?ø¸9T¿h)LŸÒ…édrù½’Ât>Î`úÕ‡È+ÒùÐi¨W•©LÝžc¨Z· ¿ˆ½bu@¤8ytx«yœË/î…ä@ð–èzµßÝ7Öôq©k2æ™Wí_…EX‰´ÿ÷#« ¶”åš,ñ­%ŸbÍîe¶ÿüù‹»»}­‘£ÍVÓò±¼ëZ«úÁ)_§to·ï¡0(,Uzb»(¸|µ0‘ŸÆÙálJá,WÚ[и߾ò¾Y ј‹WLùXÊɽH|¡FšòMØ  (i”…Hñ-ñfüÝ|oww›ŒèWÝ1¬¿zôkôp‹˜ÐB ÁQ´  ?Tôæøê5n˜8¿w£+Òalô™&OCåŽoê¤8 º·Š¦ê¹PqvåMWþh•ßj),¤t›‘öìp ŽOï^^È-ÿ±üåâòý'¾Šng‡nœ0ÑåýŽcÈs߯Å3söÎd#¬«×‰Ìa]¢ù±ìA66ç(xz >œújæÏyc±!¶û‰±”SMÍ ^æ¼4ÄY;^8=ÂR¼°Ýµ¢i'sxÚÉ\C½ó»jaÇ­ ¿Ö­þ×ìœ5î¬÷µ3¦öí o†…)£aF é£m4$[!Ù ÉV%[AÍVè«)cS’Æõ£¦jt0|b2°2E¬LUwiKþ,ÑE„}Ù©?Ænüð»´‡6¢È¸4²U75hÇÝ ÝŠ†Ö8]T€Ø·k¡ä•—kîWéÊ‹¥õ+påeTˆ/n- ­<(ÚªPŽOª§ôFäãfÝi0Êr#u6ØùýðþêÝÇ—×7—WËÂv‡£!R,´É:Ô_‚Ï0¡¸Ú­ž4c Âz3¹qÄLí4S+b™6Ë–Âb=be@4K­Î ÂjÜg·tÂm•Vp–÷ªR¶ —RIË5ÍÒû›u~ȶÝÉý±ÀßäüæP…^)Ên›9>:›Þ˜Ù¿Z†Ê¾­6S6]ÃVböJ¾ÅÊöU]îï°Ž_xUZÍ·_¿]ýÈ8?Í.¬D"±þöÞµ¹Kþ>¿‚Û¼”‹3+ñâŠpu׆Jv¹Ü–%·¨²'Þ‰ -¥mŽ)Rͤ䪮­ÿþ&ÈL dH\“˜u»h2çà\žsÁÁ‹d¿¼ù¤ÈIµk&J™Ã<”šæ܆ò‚\‡(ú‰4_è’K¡ÛÌÚ¸V[(,¬*Œq~Pµ—ÆÈÆòÈ÷vÐ^B­ÊR6!ôq¬{Ã|è®{ÙKák†šµßò=C l o*ܳØ5C¥3ë‚Ñ~è¼Z”‘/^ŠÜ·Ä»VÔÊ$1G­ Úù¾ÑnÏï€pO#Ü­°ªpƒ¨4X 5‚TÒ4GAj©¤6‚T à,\f’u@cc‹hÌ3ä¥T)Üx) ª"–ŠXŠ´¦KE,±w4Œ vð6˜A ÀÂÄXp :ú}¹£b~?zûèíI½½¸·t.¬½Œ ï`™§:,³~SÜÑÌ*Œáb™Ùh\£qU2®ívŲIÑ8•«àçU²¼ù’Üf@䧇O¢¶˜GP¸m–4%vA!í5~2dÞRo0øÈ8Y!E²7f$(ñÈ@J–Eü_ö³›µå„%Ç;Ìþ¾ÙŽÒIz³[A± R3J²ÜûÇF°mß=6p†ö<¼]sŽ%Þ.ÈË®aщPvmÜž]›Èg×”žÑ1Šg 6Ý+Göʱž 2&0¤b¦ÔXAVó¤QfæjBd®&Rù0ñÊøžjŽ4Àv²(ÜqJvRc$wÑx}Ø[¤g’’ÃS2ˆ&»žJÎB{;TI”•žÎW2ºüeØ£–DycoêëXYaÆ.éO„0_‰}ŒSºçWÞ_צô7‘O“nÿÕéW‹i‰{ÛŒ^­MIþ8ŸŸBîvr´µŸÞ:T7ý³S\ŒNn>ºdovr+sèîÙ¥ÚåêìÒgÄŒ/2(ûÃ\žÔZ‡1'Ø>L^ªÔÞB\8«¶ùÒ–{ˆUæ>›t:Àt qwpç/ˆsÖTÜŠË"‹p,±Ç"ëÇ:B ¿Q†»;+ØØBºã8ZÊ0!"„ˆ"BˆÁH%%–P=a¼¦Bzy野ªçÄk*â5Úå"^Sqˆƒéã5ÑÄk*œßÏà‰5p͆ö$\P”{xOegÑ6ËÅô°ì arC±ƒ®Ùàκ¦\ª$(&èpÓŠug05yi»ôqÜùê"^I¥ÛõE¼&ÆS§]Ÿªéb$êá­—#1‡,ÈÏ-®•œÆT;Ë„Õù«ÒæR¯>5M-:YKTt;²Ÿm/ø°‡¾ô û2úAXx<¢½ÊQŸÁ¨r4 Üi†þNÜá¶AÔê>UDS?ˆ0±ß":Š®µ)µÖ!RoJmé©Í¦³ÛBý!3 èßHc,9¥H~Ô¬°uê(½˜'xŸgtyÑåyïòí¹ SnvÌœ…„qLª:hAH2µÏ3•YŠÍQ#ïF0©®ÙÐŽ‚¢Üÿ>ŒhZäÂuEÞ«tMyëäé ÷¿!¶dµÈ…O¥Y‡Á5Üa×”K¥Äƒb‚‡µùhå¬ãì`’kÊ%Ä«õæMŒõæ!W‡å›a¦@ÙòÍb‹ª¢\<;XËçšrg–Ï0á¾Y>×ûÜ~¡qP­Ãæ?«èP·ùÏx6ÿY´ùÍrñ½×aÒæ»¦Ü™Í7L¸o6ßõ>»³ù®)oNpÍB£\‡·û¾¢CÝÛ}oãÜEí.E=Ç.¨æG=§.j7òê9vAt`òг=8á¥ý™áߢ5zô*zoÞ]¾¾¸~yµxñzžm“ëU£KÀza;%cº°ŸQÖ«švR{Ã÷‰BmýyµN oßfGÀw­˜ð¢&ë‘/$7è»ÚlxžMsAïuÀ¶šãÊ1ùJ[nUUÜ:9CQm]zž…ÀË»„ÞÃâ×bCKòS ÇíCOˆ¨MÕt””Š/f…ê^1’GjJh“Š2_ž¸S\æÈÊbd剀Ћ?FÊX8kr¬/SîÁ1Š8fyªåEÚ[èa£¸Y*uKŽÕ¾–4KùØÖ K~+[óÊЙq£’oèH0ÿá,ôÐù®ÈD ù/< >réŸ'{ð¿*JH!ïz=—È‹î˜ÝÚyg*óG“Ž®!àfEI¶’¤I±'¼r¡„¿—´sÐ×ë ­œ}AqÌWö,}FHÁµeâsëuÎÀ·¯Ó«ä3+=ÃK #AÆ"‰‚b®Gãð s=TÌ#¤¼J$Œ>þš&ç`4@OS ÕÁ$ô¯™V`(in5°8•¤‰´ýãŽÝ¨ "©Æn$Pc7à{Ÿ?ÏÕ„[q¬!$Lëñ$H»-•|–š-5’d•5‹’õb–YŒÆðàŒ¡¼ðÌXL§{òbµ;P•Q~€ *£:8»¡oÍá‚(&l€( &DIÚÒ€Aa£1<8c(o<3@ÔÙ—CQå¢2ªƒ³úÖ.ˆbòÀˆjA”¤- Df1Ã3†òvÀ3àDý´þz  *£üATFupvCßšÃQLØQ@M"ˆ’´¥ƒ(Â,FcxpÆPÞxf€¨ŸWŸ¶Š¢é£ÙÁ™‹H±™`IAU‰PJÖ¢Œ¥HãMâšDcà™p€§Î7‡š”Ê(?@4•Qœåзæp±“6 P“ˆ¤$miÀ@Š0‹Ñœ1”·ž™ x:PH?@ÈÎth\t¸@ŠÍH ªJ„R²5`,EÇhÐ$*Ïì€Îu¸óq1èŒù8עైù8ïô!æãb>.æãt(•|ÒéIÇUOÔ•ÃsVz’qÕ5çâ² §â°ë”c.®¸—9ôdœàÝÅ—³~Ã;7+å¬ù8Ì‚ô,!Wƒh´¦ä _CÍÉÅǤœë˜;&åbä“r®EÁc“rÞéCLÊŤ\LÊéP+I9"®Ó“•é+-Gä¯ôäå°GjNÌ' fæ~ö§\V#sRÖE” öüùKð?à·)ž+²u“z” ßpyþâò§¿cÿØ– +²xúK½û„ Ü'";dÝ0¿XÞ%#È~>¯x^ÉØÎ Ëÿ>*-=Î2 ãþ${âaD¸a×ÀÒ.÷£eç¡ù<ò§ì*XºÈê2sÿÀõÁ•e¢‘ACLgLû”ì’ÍMbzÍH)²Uã[ÌÊMáô&5Éa™¬é¸Xš²nˆœe©·Âž{ŒØ3i`OMUÛÙ3‘dÏD4q;á'n ¨ÜbYnJ†”èAÛ;¬0›Ê-ö¦Ñ¦Ä£Å»y¶°ótâs³N|v©D’U¨»¦µÆaBüG¯{b„³¯>5Åh]4»+†Ý÷Ä‚ÝøáYχ¦vYÍçO]/;Ðæ¤â š©N•Œu”Â)€¤±ž?Y°NV5»•ÀÞC5ñ²¡OXMïª[À‚i…L(à4]õMqâNj¨E Z³(„Ôèf'H†H¡z´8VÃ{[Œ€5Û},‡×D›^<Ãk:—- Ør±ClîÊ«~Ã;Èˈï"¾‹ø.â»fQß‘í½š‰«ô"<ølqˆ÷¶7ïíá@<ѾMÏ žÎe C¼·âiƒxo#Ä‹/B¼ñzñÞš€xo B¼·rï¬7ïìp žèÑÏ žÎe C¼³ñ´A¼³ñ"Ä‹/B¼^A¼3ïÌ Ä;“ƒxÕ!9#Ïê¸C@wb§ç<Ãvú-Œì€@tÆu6Nùù ê26FH!]„tÒ5‹B@Ÿ   Ðá(J/œËž,æ^™sVOr˜;öí˜Ó·ha0÷J˜³q<Ýo0÷*‚¹æ"˜‹`®Ms¯ôƒ¹WÆÀÜ+0÷zói+‚â€GƒÒ—ôp¡]5͇ñ“–«~зLÞôƒhÏ!à(í÷-sˆØð` ÆUsqà˜í¨OйMcÂSE5Îl’»æþ@vÛèk~ v>©Ok‚‹ƒ4,ÉÄN‰.–úX©Üî ©Rõû‡²¯U*4ç"h»O9£ÃÔXê3ø^à÷½€¿ïãÐÿœ²0G´åkѦÜ?šÉ†XherS»HJöÛ ©È5Ž{j÷æfŸMTäw.6òù6^ÀA¨?#`tÀGð&Ä—™Â|Ûe N¯Eö´J8Ž%ãI;pËG.a³®vË O¨Qã’‘-`Ý éõõ»l¼}·pÐv0˜Å‹wùÐiL@§±” ’| ’Ç:Ñá±ôx(G÷ï²Oô8Ñã²Ç‘·¶>Z6VܼžmïA—€p°_ (šg%óÌf׿Yã’C Ø,°@ÛU¶ó‰'zœCö8òÖÖGCë& j_ÁÞÅRÔ¹xQÎxÞ¾ \óÉh]4·yq x _ûcƒjlP ª±AµYBiP¥ºyt4¨R IcƒjþdÁU¬66Aj¢IÛVDd¢6/ž]®oË­`¶W`Q°öæTÔ¸d6PìUB VCLA[ïIAÑ¿Hz2r˜ptf¯½U< Ãüú¤‹_W÷ãNû[x.:úåÌvôËÑ/+&ê•}R°îȺ'’sBôÑ«˜4Ÿìšì:1–ì:м§JpyO%ÿPÒ¼”äO<|Íÿä°”À0¹Õߤ‹å„.~=?Ǩ ·¢Ø:å:Ô¢Cý'>«¿oŽozX:o˜\uÞå:t~ªCç§æ+»ÄÙ@u]"ñÊxà¤Ã™•çi‡ŽuÖÁs«ÎXv¬:Þ‹ß¡}èUgÁoŸ’Ÿ—|ÙíØ†bÕÙúÁ'”áçwâǪ³³ª3æ×«êÜ좣_ÁlG¿ýr·ª³¼O Öy\u»«Î®Ë±êìG".VcÕ9VcÕ9VcÕ9VcÕ9V!×cUçŽUgb•Žª3‘xÕQu&†:ê¨:%_Ugð\Ѫó—»í­Ê¤ÊìgÉbŸ§‚òO„'~áwô_j¹ŸÇJÒð#ý( oäX¿ý™_xÆVèB›\|ð+mŒ§lÙœ¡ ù¨¼ç`€/qI^mc(]+¿ÜrµÉ:³FÕòPºöé°¾«H‹««nŽê€?ø êŠÝ9_:oíÀmŸÐH®ºÍ¾‹ÌS;ÍËÐèG9NÐ(zU®Ñ¸ææ‚\´Ýd»‹ªTNYÎÃ"œõ‰mA±bæ:ej¸b¦Dù “òÂ(úMz¬ž…˜D4\=óY ¥’f.­F$x´äÕˆ°IgÚ rªWᦤÂME°ÝjTÉYý¼^~NG«·!;Aök½8ÀÂf×X4.™}€…u°¨jc?‘Ís¥lÐçJ³%‹+´§Jÿ¨ÄwÊVüI¡øS…ŠÐT^~§r¬˜ª„¦nD·iµåbëõ ©X=h*Uˇ¾¡áŒ0øcjmè<¬ò@%,£åÞD ËØC.ŽyðAI„#ŽD8rÀpDÑUE/Õè¥Æ:¼Tзû2\Nô5Ñײ¯‘7µ>ZY7Wûb¶u"c[‘õײ–JØ¿­B]=Œ èU Ó‘ÊÙðÐv5[Ìhñàa­–]ÂÃq=[5aËŸ‹‰B¶j"ïr:"eÁlÕÄ·iZm¹Øz¶j"–­šÈg«~A/£î@¦ˆVwášÇPôí> Í>ôÈ4ÌúÔûQêyTp•ÞȾp{?,œ«ñáÊûC;W—.†Ï™TãLoi….¦†·Ê)“¨ 0ómvSœZ•À¿‰^Î|‚a•¶|lçÐå¡Ì2‹–@F*f‡å “ÛÍð™œdh„pÚ?Ó¡ý3žöO£ö7IųÃÒ~Ãäú«ý† W’ð‰Øc„t†ïÆ'eÃ÷Ìü¬ ¢Z¡cÔQÕ1•èƒÔ1•hþa>|ª•½×ëí ý¡Âé‰4]ý ´8nžÌÍKæ÷é¿~zøô)ÙV?ý¾OÂ+žR¬ÖÖ°ÒùY&7N7·ólÛÊZ9ÜÙAÉà2B®pÞÔ¢Êf]6Ï%¯œl3Ù?ã ï ðù›& Ú*Ô§ÖÞ¢‹äÛ»-d0h"n’o…¾“åÕ¼gýÓ¬ÐzD`ô…âûåë‹ë—W‹Ë™îóÛb SU,êå‡ËŸþ^4³þ×ÀFc?ë•|¨xépö|µItýÇ?gŸÃ—FÎ<¶p\o—…Ë×}’AÕöŽ¢Ó /–ûeög²^ÝeÙiÿ9n|€Ðì[$o£FŽèulŽðšÿŸÔyÂ|Ë]V‡¾Q-‹åz¯RÓËy·9û ŠÄΦ`®N(Ã0n?›¢³Q˜ÏBÚãyu>Eó²‘-;£RÚÀü ó´Šíaæ1“ qÌ5;Ũì޵œ^7ãv4"3çÉXIG‘ÌÚiÌ ¦ÏÖÛ4±5<ÞÀ¬x¸þ0‡ÅÃ¥Û‹Õ üžsŒÔÓÇEÌï¶»ýr]ü» "ǹgëd¹Ë³¦AK]IE¨²WàB+î¹’ÃëÝï/;ßf¾Cc÷tçáC¼l˜§½Ò%QÊ üJr ÷ó”ôÄ šR­^gÑt¯›Ió~šRŒßÛ\™’xys'GæwÇFƒ6Ï+EwÝQtGƒzaGÊûhƒÝ”lhË;îÓ|¤¦Sù6¾Š‘ö4ÇH ïås]—9Ðj],Y{U­s\²>”BV,Y;¿žÎ_%0Lnõ7N%ÛÙ$‡r ¡±2v=hÑQÊ®'¡tÜÇQ¯Ñh,’—,”ã ¸!^Èñ'Á]Бݯ›¾ItNQ˜¯Ý¹D#†)ÑÙ®Ü'›>ItNQ˜¯]T¢‰SuåzH<þ‰9âk˜bþ*ÙŸo7Ÿ/–wÖ:÷ŠXǰ¸c”…)óîŸ-ò8o徨kÑ/¾kWúç_¶»}?Å¿$-Xù/)ðP*î®/VÖÚgíÉ~FT°RŸ­ÝCy YÒYÞBî÷ Ò4…)êÅêý„õ%oÃöWIšì­ ¼ù®ˆS«õÛ?ñÎÕÁˆ×›Õþ—í]òn¹ÿBH!Ö*Ê‘3ø’¶PIlÉÃôçåzýqyó•¼â1b­%=‚µ¾ãöÖÆ¢’Ô1·‚‘, ¦>u7X:IªÁ¾îùsB:˜='‚ºÆl"ÏtÊ£EÁ‘IÖÀP¹š:,°˜¢2Ægl~½Pòðåk=+¹Alé¶$ Ÿ—8æ %¨Î"òµ¸°Ù lz2pÁƒb.p=ö\lÁâmɬ\jÀßä|¾ùzt\óŠ—bÓ€¡b(œGZ+’¶+gƇzZ¼Ø™Ÿ~ÿ°ZßÞ,w·ÝÍ)þùĈ™ÍþqbÎKŽ›ª³°²Æ£´dkxv¹"(Zh5 ÝÄAßmµöµ³­¶Ü–O$·|ܾåù-gM©a=©*¤-WZ;r"޳žœ)[Ì›çn9ôäÌoNˆoNôû|ñ·Š‡ô_î¶·¬’aö1º‚ëD °Ê;ú¡AHù6Lª@3B+$„ðúE¾ø-Ä[;J’Ú±@¾.Ê" ø s§oÖ¢)¬¶\l²NluÅ<Öq Ò‚ ÉPéz/ç7°áðÕg<£sÉý‡1nùŒ^t.¹ ´à>ä¼ýùóÜÖ+ÁF)Jà¥xÏb>‡C-DP áßøXÆ:ŒñÁœ¨!=HEQȳÀHÄ!‡D‚-´8¤››òßiò2J¾c,ž¯<ËX6ù]}q\÷+ ÕpëÞ&¹¡¥¶í±ÞŒ6nMIžœ<+8UûæTЩŽý°¤‚Nu,æTÇl§Ê±¹e‹Dau™×vË©`ã… ²ƒ% •ö{èî<O–Œ3†û ÈÛ{ÝøÜ‘ð;ê(=ß”>ôlܰv±ˆó†Ý“;‹Ü™2\Ow0\Ïtœ-\/¸ë+\>·}¢0øê‹üè‚Ä9á¦k'Ï{š0Ï90«Ü~Ö#8˜ãÆú×¼dž8–Ûb¿æúüx«a¨Ñ"ÞÇ–/ú†²7CzÃÀ|vìEø £#Ñ(À.ø¾HÒ›ds›©—E0|MTˆÒ¯ß•øW0Dž`o£Ìûx+A^ÒÌÜ1Äün—|Zý¦£`É;«Ü­)sFYáR¥ãÉë†)øû(=½½¥`¼uÏËùae£Í,¾ÿÐV¾ù\ 5³xvITnÓ}?ÍÜÂ7¿Ï5›Xü²ù„sqXŒtR%p•óÎzïû2Q›6yÚÚÒ:‚+¡J»•n0œ¤tÖ‡“"< ÕhFxá‘–Ž1 ž2p—èoµ+r\Ñ·ºW<¢èGÝËlñ߇#Y¾I¾áƒ‰¾I¾—äš;†u(­æŽa±ƒK-²ØE'©ˆ7ˆUªÏ¾,7ŸAZ=V)dªˆi‡WŸ@„‡zë]ö!Ý\Žùnë]ö!Ô!¸ó»¡wÙ‚µ‡ÂìǪÃÁUH˜txõ†:â‰@'$³N:+ Jþ/pGçs-íG¬"Ä*B¬"‹U„XE8rcÁß*,j©Љz•ôl±šÁÛåWÙŠA}ò|c¬:m^öôB$ŒˆGqðê-cÒ|ŸaDnXa°ÞE7Áx„ëç}.7<¢¯´Þr¹æÆèÃ3ky$\NÜõê:¹æï¬#ÒG„fá¨'a죙?@3¯ þQó-å¤âpŸ˜¤‰éI®(Ä;(üÓ‚@24zÓ¿ “ú²èÉ“yÎ>¼À᨞šú1 .ņèdK2¦‡àE·ò[  Bo­0ˆÀ€Mòmqö6I­2I"Ù xÇàiɳâQZCœžaŠþÒÓh§5˜hÀÀ¢Û¢Jö޲·—¢(d˜ûÝæ%ô†-Óð¬Ù‹ %Ç‚¢Š|¸xy5øùÌ9}qù!ŒPa#NÚ¬²²ºËgBݹ֙+N÷Ú„í&'U_¬n¾ wº½çx‹ÿÃû‡îWš§ûÛçÏ“›ýv‡y»A¶÷÷“æ¯<}œÔV1%_94ÖÔEtJŠèTBDÁŽŒÒ³íÝÝrs;zLß-wË»tt—¦×ËÏ©Òp2B áó&“´áP üÏj‰Kòu§.§y¹Kîµ\Û8·÷Þ×ÌBO»ï ,ºùAévIeÍø9Ì­ÔÓ£,¢žŒ%Á\{3S·Xä¦îºØû,ÔÎôâýmðï'8£‰~,‡Ñ¢b \ÁãU¶õð½ÄÞŸ¾ÏÌ$ˆÔ‡àoGÙ×Þ£o‘îü¬g¸|„ï¿ß/Þ½?}Dn²q ÷2HÀ¾d&¶bïpgÿ þ‚Ñü——¿ÝgdfQáüh·ü|¿Úƒ¿`+šgk}º¬>x=ÖÉ&£cù¸Èþúž³*24ƒíÇÿ©>ñèøÕߎ¬þšý4ûŸï¾ÃY4ìóJ@x¾| Vd®ƒ½ËÙ Gƒr“Ÿd/&6™Úh´ÀÑ1cgá"€ÿûû‡ôËâãòæëðiöZŒ 1‚ÄÉZýLHþD§+‘õ"ºjõµRzÐ7[†ëöç@›%=lÖy_pŽ‚´µÐÆ«AýPÍWƒz8ÜÀc%˜–&O艹ÿót Î}_ò|áÿ<ý?Ä7Ø•§,‘VPÕž±¬å²DÒ–¼äâù ¹üeIúf¹_=&ƒ4ùçÀô5ÚÅRª„çß°„gíÕ"¹Gü¹ð›@¤YnÉÝýþ÷’”ÁMöÑÇ„ËÍïyØQ#ŽÇBŒœ÷A©ì¿$ƒO«]Ldè:ÛÍúwö{Ø©ÔêÿPv–ΙÓ9Sœ- ¹Óòu 9T . —x?8f°õßšþ›ÃtÖÃðÖS¥Öm‡;­(Tw¸SžÃ¥»$¢Ã%¤bvX×0¹ÑáF‡.ñºÃu¸†m’S™0JÕ é·_Ñ6f§”ÑÆÌä`æI­n‚™Dœtzä”õÈi§GNXœuzäXÏIhüÉí'¡‹%¼Jö@5鲘ƒŠ~xy‡Y‹fà8$õü9l‹07Á‡¢r˜&ëOJÕffyéxðÿŒ×œi ¹Åfååµ§2µÜrŸ©rn½Ò—oÝÑpH¿îžvý÷ –7[²ÁDÝÔ‘uð=þquøG{MN¤ÒV²ûå?–ëT^-ˆoñz7õÅÓɇ$c &.3X»í(}Êép¦Nr+5ñ§¶…*óÛøSë ùÓÔéB×ÛôÍÓ¿h¤½›:®ÙH8'Œo‘Ñÿ.2+_×ì0³)o;ÏÖÛ¢pg:ÍXJȆð %$CÂNŒ…ä0Æk©mÍòöqˆÌ_®âÖ/}AÓÝv·_® 4iÖ~eÐõ"ÙÛî¾Z‹^_¡›hÄ 5ðàQá<>Â÷°9<*ø®±ó±zy¾­=š£¦yÍ!8‡Ì ÅÎnˆ€Ù"oÌI…Ý Sóæ*šg"4)‡5 ÐÄ£šçÅ^Æíâ¿ãx^Lô|òµgëUÆ Ë®6©M7›¿1p/›áÜÉ»×ì`Ç5ú×ü‰Î|«ª¦”ü*ÝjÉÀž¸TL¹F÷ˆMa*Ù\AÉÜøS\lúR{j®´r7Zü†ïB‘¨yåA¿,7¶ýgöJ«Þ3{_è¾3#Á½ç„ûÖâ7¯uzÍìyî|¦’n >Uþ2g[_¼e¡L™¯ì S¥æÒ*åÈO–âoÕK2YS÷‘P°¥<$üEƒÂå“w ÊÌ!ôæ½d~6Þb*7{_à^à@¥ ÿ˜ïØÑàɰò‡«ý!ê˜wàIm8‰ÚÐ3m0ƒ+h,gôMKäþ2g*=ÑÕ¶} ·™EÁhŒC™Yaâ‚/8îxÉeè¹è‹zºx‹û7çRI€r8[ºÑæA~„ ŠæÎBɆ´ö™tÚ‹ÌL¾ÔB~Á¹tæ›Ñt-™Ÿ« fÓ±Êá@#CʼÉ]íjÅ>‹éýœÎÀ£5D…󀭲ز\oì9W»Zò©ÍÃ:óŠ"2kµUvóVÍeõ1ê6[Õ½2ÍU”I‹$>¹Tˆ“ž05·ö%sŽ)^¼@:$<£”‹ ü&Š{¬ü–7Õ‘÷pFNoà0#'Â5Êx/ 3Ó)ûò?¯_^¼¦÷#ôÐÿ1]ý+VVªû òü)HÄ_ýaðÝw+½:I˜L'çï‡x²iþmõyþM¾ìáo£A‰RþkõßøWIý#íþ û Â4õô1€ƒîÓ‘ÖÐ÷NÃ-Eãæ¯<};ÀA˜Žw»‡È½²Ï”]+ â w:!‡;õÜÿ¤ó±LŸ²Æ9Ýÿrbàþ—1`v}_â-0DÎKà˜±‰[`ÆÌ[`Ú¶Kv˸wÁÁ…wÁÐÂû‡CÃ}†p‘udßêâMÞ‹À¥ } e…9ž1çóúuß-Îx@Îà.¹ÙÞ&ã†/Oè/Ošr±ES=änðã@ãÑÃëÛßFçI¨­ŽAr)(5EÁ‹Bó9{Óœ"’ÅfUþl)f¡Ÿ(±‹³q‘ÎY•sjP° Mä %øqˆQVª€ ›ÆˆM“6Õ¤¿M56MdÙ4igÓ¤r Y`FàùrºíÓDd\Bw¿0ÖçÌØ=&]1b˜ôhÍ£57f͔ͥ e¯ÆŽAôc°o—Ò1X'-jSæ¥}ÆÅ¯ççDê¡•t±ЇÒ6IiGßn9Ò¯†oû C;‚aÂ84&xxšáÎjª´®¯·šŠ»MMoHºjoÛΟ/5›<ÿÉÙ6ƒÍêM 1¬˜ †|ïYFÒ R‰ÏbnXœW¾$ˆs•>ˆ,1î54–ûœ*¦ ~´õÑÖ{–9®ìWÿÒÇ6 9ä˜*¬4Ûb9´dÈ&Òcª°M0b"=$&˜LJ5ÁJªŒWtç Éš¡Ü|‰|‚/gÁYo²ÉdÞ†bý ÂæÚM~î Oí›3QÙïËŒiÇS芕ƒyÍVòX𬹼É:HcÅç“IcU vT+&Õ·ÕŸ`THÚšj|.ÒÕêë\9²˜ücú•1Oê³êÍ瘘Gì'Ä{Ô~ è}Ä(›,¼^ÝY¾¯{Ÿ½1“›õ‘Ó$¸>¤_î\Û}Èoš“ŸÞŠÞ›3ýØÖ 5Í(y´ìË ¿RyFû€O¾Kê›1¥ ÛôÇæ µ ¹ödÔŸ¦E/yÃþJ5æûƒz1¤^á×Áçëåg…!]œû[cx•¡{÷Œ×Þ½ÚºV÷®Ï½/vv«šš¼Ås2=qõ…&îÒr%LšKk”_I¾U‡Ïd í;ß6×N<¾¦Us]~¥Ï >(È~‰wN?€Á¥VK^KÐ Ó7ÉïÚ´œ 7 A.7êÿS/}aªuÝKæøR±šP(ᩦFkxLFk¶Ék­¶Ú‹Úa´G)Ôœ@m÷\ÖvG«-ÁEß­¶Öu³­¶ÜVQ¼d²,€Ò¥¾u·.ù^XC!SÜê¬všx«”³¾Þ¢Á²Ú÷°›°`êÐùynʨ %öŠ´èð¹å¸Ÿ°”H±ˆ±¬e”l_µ+oO‹9„=‰†¤S9§]El«‡æÂMAGœ“çÁ)®=Þ¿¶ F0'Û‚;Þw`'ÛjHÓ™¶ZÀ§÷4[ñxñslï–»T¡ñ°pÂ*§µHÊê¢Ï…y3º5c¨+© 7^8V²s–úá’žW¾þÛ‘<›9©ÓÆ”éÓ2‘ÆIU¹#NÊ-—^ojý§éâì:{^²/TÉnXH¼ÛZÃ_êƒÅ1Z–Š{~©íM€EªðéåÛwç§×/_¼žŸ¾ýéõ«_O¯/¯§é_i9øQcg ùh7ý`‹N¡“w£eÄ»­jñæÐµŒ Æ¡–QÛ)®eäµjñhwZvv}öÎŽao¶ªaØ{C×/Œ‡ÚEl¤¸ná?ÓªY؃ÝéÕß³E»Ñ+ìÍVõ {oèz…‘âP¯ˆ×+ügZõ {°;½z»½MÜèöf«z…½7t½ÂHq¨WÄFŠëþ3­z…=Ø^]¬n¾ºÑ+ìÍVõ {oèz…‘âP¯ˆ×+ügZõ {°C½ÚîW7Ž<ñn»º…¿9xí‰q©_ävJhñC½:†?Ú¡–e»±[Ý8R3âåvõŒxuðŠFPãRÓ¨•P5ò—zux¶;e{ã *¾qßô*¾ñ*¾QƒŠoLAÅ7>@ÅwË£¢2öf«z…½7t½ÂHq¨WÄFŠëþ3­z…=Ø^ýãaåH¯°7[Õ+콡ëFŠC½"6R\¯ðŸiÕ+ìÁîôê:ùÍUTõf»-PÕ{C×+Œ—íOøFJ4?a?ÓÛúT=Ø¡^mï]¥2ðWÛÕ,ìÅÁ«F‹KÝ"öRB¹ðßéÕ.ìÉVÕ+ï0.e®RiUŠͪòîòõÅõË«E&—.,(E“m•©FœÔEÛ`®Éî½¶ù¨)ð!¡Tp)§µÞá0ÎsHÖ#ÊŒÞeã¶ŸC€“;¨p"™†sÉÌWÃÅà&z<™Ü‚¹5²>žQïñ/OÐA0Ä ðõm®¬o5­ )ô©_¬õuü—Y–Ì9`Äp(¨bÂS5 ‚²=a1[oà 8GÖŽI³wÜlöêË2ŒïøUöëAí×úâÒXæ>áÃÅË«–H¨q‹eâþÁE«ÓHDdàx"k¿œEG²'ù:§ñqj bíä7æQg½JI® #Zb¬G¼'ÐŒc7&9ÒLîžB¤DmC¤Ä|) 4N"Ù?ס>GILŽ1`NøZ6WÔ2úÕ—øH±¾FG&—ßÅê}dÄZ``Ì€BdDŽhˆŒh{##ú×Ú"#ÊHÚŒøÃ&¬âI#‘‘‘¬ýrÉN™0æåœFFØ©÷ŒËWÉýúwBމSú¥Sg÷uÈðÇívm0 bЩG¦kcŒÃ4)â‹o™B Dì87 ›x4²^V„BóC!( "qü¢ g;+ƒ`MSÌg¤öAYÄóV”¥QMÏàlgå ¤”%ð\ƒ:3nuJf`øÍ™¶¦}<šBf‹Ö -;Ì ¿Ô– Ì¡ýŒo0ž5th$ }ø]}—œåä¦áñbN3Ø|.€Á­»¸àãÄJÁ¥†Œ…ÖÔ)Õ#̵ gÆXÑÅ÷L!¨!¶¼!¨a¼ jÓip¦Ï;*Jà!Mïìv«NsuÒ¦H}‰gD8êk8clí­Ñ УÞ3œ·ÚgÒ*3ø,Ú†`†´é0˜!©-˜!L¡ý`†7Ø&4ÌhŸ8\ß%gÁŒÜb#.Ìi0ƒ EÀügJžÛħ¸–¢KÍv #œaѪéd'=ZÖüAh-"':±}S¹™ßö¦Û9ë¯ÁBšœña5Ðíq†ckŸf­à‘ñ)Ö ™Ô_è‘É_jóÈ„jØ÷ÈÜ9æ¶Ìš™céÚg•×vÉÝñt¹áåøŽé2eN=26NXöËõ-ø„^bt)¼Ô\è0|2›Z=B]LmÜ+³©c|ïü2±õ ~™ñÌ/ÌÓ3ÓÌÏ|Õ)¢¶'Šƒ¨ Eq æ÷@qæ'ð\=›(_9¶~ÍUõK›f䄞´媯‰{£ëoMÞŠÕû>çÎí—ô(¤ ðËyÒ¤¡‡éò—ÚÒ„i´Ÿ.à]Ïd 8Ih¿‚©¾KÎÒrw2qgnÓøÍ0ÌsÔ}6•ôÒ÷Üø°Ö$Öõ[vÌ#39"’LìžJèCnSðÃzUOÎ]ìg¼VŸÐÃGtž¿p¯eâg0¨MÖ§_½ Äëmdpù­ÐaœÅàÞÌhà*E•ˆ¸B±)¢ì}Q¿Ö‘FÒA$ĽPÓ*ž4é¿6“µ_îb"É›4y9·‘q€ÖgÛ[J”© +Y®ÝL¨C˜6éêó&¹-¾n*Bb®IΗ#šGoL‚D›ÜF•(‰n˜„ï-˜èÀ~55Á=iŒšŠG.æó‘è‰1{Qü‹aMÜäªâæÉ\›ü<­ú¹£§¯ÏÓSåÀÕóoõµl Íx{—÷27Í¿—½Ð—Þ=Ñ©ËÇî…Çü²ÿLêíSo˜Éü7ú“ùæ“¡\‚õˆyí¾V㮞K€Tã;¨àêß4¤øñt(ã5øyÍj M‰â[0×£D§D¹ÑÙâV׿tM›–õ%)*ÁX_£¦IhMŽbJÖç)íð®’eºÝ\ɉí Tɉ ¦ Ö÷¢tUš~ÁL«F)bMØÚ5WÔ®LÔ˜(ѺüV@‚ÔêÀH­¦¿PD_™s "ØÚâ ¹uŒ²FÝ”¥_Dw˘sø¡ S|¨°4èÛÄt·‰a n+Êb¡vŒ½¯©pLZvX5&Éör %cÂÚ¯s¶Ê:4R&Æ÷J?t[ Æ–âÊ‹9­ ¿[îöBfä‹°o`²K|JdÃ$VHc¶„ØÄÈ0¾s Ñ ±ñ Ñ ã5½I²â¬g'Y¥”&ð‡É ½IV·Ú%“d%¶X—^õ%Îdª¯‘ŽÉåÇ$kŒÔòFý…"ú’¬Îˆ`BÈ r’•²FÝ”¥_Dw’Õ9üPЩ>TXôˆIVÝIVŒÁmIVBY,$Y±÷5%YIË“¬ä/Ù^N!ÉJ˜CûIVÎVÙC‡F’¬ø^é‚n“¬ØR\y1§IÖ<¬Z’¬Ø70Ù%> %²a«G¤±G[ÂaLbdß9…è†Øø†è†ñšÞ$YqÖ³“¬RJx„Ãä†Þ$«[í’I²[¬K¯úç2Õ×HÇäòc’µFjy£þB}IVç@D0!ä 9ÉJY£nÊÒ/¢;Éê~(èT*, zÄ$«î$+Æà¶$+¡,’¬Øû𒬤e‡IVò—l/§d%Ì¡ý$+g«ì¡C#IV|¯ôA·IVl)®¼˜Ó$+0¡Mq öï˜äŸ†×0HÕ#ÎØƒ-a0)Ò‹ïšB\ClzC\ÃxMOâœí¬¸FJYk¼Ð׸Õ)ñ¸†Ø\]ÚÔ—¸Fˆ¥¾Æ5æã<` n‹ke±×`ïkŠkHËãò—ÚâÂÚk8[e‰kð½ÒÝÆ5ØR\y1·qÍöžð ÿ›”]ì¸ðÛ°ÈÕ$ÔØ£mA15"bŒïJ„Cì}SˆÃxã@î‡äàÌŸkМÐ?ŠPò&t ›+j˜>ÝêMÀ#ÆVoCƒËoz ^õ9ê©ûµZ©×˜D_ÂÕH"˜ò‘„œu¥­RG­éÑyõ((W#j\ ‹Äü«îü+ÆáÖ,¡062°Ø S°¤‘Ïs°äoÙNO% KXFYXΆلf±ø†@ˆŽS±ØZÜy5§ÙØ·ÛÛ‡uòr³ßý¾¸¿yŸìRÀÉ4!qö-LЉO+!¾ù²Ü•n˜ÿ—¢ˆC/Ž?õãç1­ëõö¦ö¡IœÇåYöÊ:ë ö"KxKš€zâ £Ä둆ãÎ2!ÈXvº¹¯þ•”  HÅhpñëù9`#”.›j›«à$ØDã (ÇD¼IòhÌäQ.ýo©mø”ô¤S{ø?Àtìwëd3d< ¾½|dëàK2¶}78) 1ØÌÿ±$½Tô"¾eSv—ÜÝÜÿ>p|ô_`±ÿ Y–m!øí'ø¨£§Cð_Ù{ƒÉ:MJRë 8Æ)Œ ëQ`—²€±ÀnÿõßÀo$(þ¼æùsóÜcä"! 2%³S\šõ_Œêg§F¡ôÂ;‹ s^ltRRÈ ‡¸¡8BÈÜd‰ÉÉ—¿íwËYäuªd…[àç}ѳ’Ȉ`ºðê ` ¤ß9–)Vq8€&—»D5%ὂ6%U>ãää¼9gÛ»ûÕ:¹„;“F˜#¡duÖ@‡ü—àõ®Nh;ݸÕo¸CrÀà©­ã %}‡zê¤÷öÔéòøÐNÏsèóéþçÕz}òzóiÛ ÷@=æ]ðKà‘ƒ'€æ!ú7âs+ÙЦƚ×®U5]©TAÚsŠ…??ln•ˆ•€*(QO3zåhTø´Ø- 9[À–††f#ù^£î<¥qK;X­;âØ&s…Õ!^™ñk†ñî‚¶E‡q戋‘u¥Ì“y·\ãB|r(÷™íg†LEièŒÂ èŽÊ›=•ÕŲ6æœ7lÃxÑÖ¸F°ÍBßö¾¦¶5RÃa×ùKîÖÈ6­*b¿g³Uö Ÿ‘†5|¯ô2·íjØR\Ù3—½jy÷éê.Ù1äµ&ª¸”>lÒÕçMr[Há˜óù„qaŠ 1þùLå|ñÂÇåzŒ}5¹ÙÞ&ã†/Oè/Oê/›rO>dÿ8ãþ#m›!—å­òŒTÙ™H71xÓð>ß³ÑÃk Œ­£‡³ßoÖI:JÏ—“õ(}‘¤7»TM*m–TD «¬Š¶Öµ”&”Š}¿\/ ZÌç °ë¹5ã„âÉfMþl)æ ŸH±‡ŽEp}Às°ƒ‚Cc˜>ÅNCô㣨ÔöŒ{& ì™È³g"Çž‰,{&íì™PA¯ØA›iÅG¡ƒ6“öƒ6Sùàw*Ǿ©Ÿ§k´/¹0êHÜÏ$7xÚ¾Á3ù žÉmð,¼ VZ2Â"ÔãqrgŽNà@ ÜÉVm€]1TMÙÏtÛ‹‘ˆ}¨?˜'¯¦ÄÉ«éüoΈoÎÂ+ ï—‰àêXmu …‹­÷7^ËåQÏÉ"LšÜ)„zhg¤å?ñ("Ë—΀æ(TNñÈm̉܄åµú"Ýp‚Z¬j(ž –]ÒmçÔ7I‚MqÆHH¾œ|+sZIZS;õÜÒ±»F讈Y°cÐH´–’Çže<œœþãṜ|äƒhäC˜ÑaSíåâ';ñÑÛÉæV¿l›ì€+PŸ< &¿RÃLæJ~ÅpÓE VpoѾ’†?*S¤x ˆ,G‚ ï| 6B ñY{i2gwk@®5–xÕKèºfM9hÀ¦†¨ÀjR„Á“EÁyÞÔÿ¨8r­èá1Þeñó»XµQE|¶REïê{)‘‹¡¼b(—A±Ú X+ˆrèsITï¢û_åòË粨ÞE·FK÷ž—F ìIq-'–GUË£,”\ny “+!ð·HZH¦–8‘”+g…Rq Xî ,äS¹- dX~w¶\¯?.o¾ÊËgñ˜}ò†å'>ž\cR­«,ZJ³•¼“Û"\P¡éDZbì´s6M›tàS ;ÿ VWÀDÎu¹´8†’ŸÇ¿88% Y:!ÞÕr:&_Ny2ýBìA´y"†±/'„UÆò]¸åäÕ®‹g=þ2׬k ºXb ³ÂÜ,¿ -’Ó&FRŒjq|ƒ¥Ë»d”¾[ h¹’‹·N$ã­ãöxëDÞŒñòZˆh_àQ¼¥wÑH;:ÕÞVö›ùåiAßÀ¢Ùu|VþЧœ!—tÎiºÅ’‡l«OdÛ)3«pÂN6äù §®—¸ŸûIÃ7™Mí>ÝØ[eÁB.Ÿ˜-!C™I^o³]Ëtá6ù­rÇð=@<®–›¯ƒÅü þ±ò¿¹¿ýÛßÇ”¿Â\<óßïð‡:†–|:zÂ_ó¯V²XRþ•*ÊQRùãÐ÷Ð·ûíàv•Þ/÷7_~ lÇŸuâ&úˆ£þý~…/˜¢Å#þõŠT*Š’…R‚Èêøè¨â |U“}In¾Î3+‘ÀˆdH±#ˆm7àË‹qñ%ăï2æ>>Í">¿ƒŸcf?E/}{úŸg§óë«Ó‹7ºÈ= •Üêo Ò…¼S‡+@nE°uÂu¨ø¸›Š#êÊø¸øfþAúm•ý}˜¿¬XNæ?“ÁÉsô¨w¿Îy{zõfþÈ¡´ËàÓv7Ø>&»õvy›Ùÿÿ?ÁˆÒ¹e«æÎf¨üËT‡wx áoêº 5ÍbÀŠË9 ‚aS¹C’M ù|J]—º±Xï yÁ$¾¥ÔèŸð©eJÄúãv»–¹KU~.Ƙ<­­kþZ.춦'adHˆ¶B7OÀ…Îþ°#ã'ÚøÃ:øƒñçI?p¡&å©õóë_ô²éб©ãZÌ ´1S’Sôgnï“ÝrŸyϿ־Ã?™[6¡š‹ôkÂ/¶Ü+h9åÍçüáþ>³Ñ)L‡*ÑZby¬âþÛ/ÝÙRœK¹Eeæ1©85n +«ÿÑ“žGA.ñ,U{ž®ÖÙ§“¶Y„ öÄDÞÞjÌ#Äðí"ÄvØ‚ñá²Æ®Ý)Ú ‘sݰPò§Zðõ6ϲÌCMñOH}>¡õYðL–à„Ë¡oÈÔôrÕ¢²|Œdù¤A–å”ý„/ËuZÄ5¾]¬O$ĺvN«ú.ƒáPö›Ü§Ú¡, g²JÖ¿Jö çÁnÚÎÖÉEŠHÍ=«ž‘à,ËÁ>µÈÁ˜¿=°ˆ3´õ^9‘+ !å€üîrð޽÷QG´~w¦*ràýИƒÇ·àÃêëê]&b½×š‚ÐÀU¦ #})ùÞeÉö)ý%Yß_'¿Õî»éÂàÄ®48)Á(Áÿ(Ï/ËdWodknêê‚È \S®•¤¥r„±Û^ÍH¿Fœƒ.·Ú "ÃŽÏ"æ °£ù»Wœ×ÚÁØÃfeA¼o8í w3Zö¦_–›ÛüÔë¯i²ÿûúêì"ÙÛî¾.v‹.à*…ob}TuØ`ÉïEu¤Ö^îàÓ2#R­n«Gñì¿mÄh\%1JüÑKl?›5߇FWÄGÄ“å×l:²¹jÝ&ðéÕýºW;j³’.êhÑbýŸomg£§g\ -|Ù6¯*L¯UcŒU+ÜõÇ:–5½­£dU/ZG6`5.¼Õ:B…9ëØ©rÛ#ià g¶R­¬M¦7°œñ:+vT½ß#JÔøC¶  Uþh>eY€íÔ¼øVÃY*СXÍÓNý±œ§t³GÈÖóT­Ý#ZPv`E ÐjI …:kŠš2XãyÅ *ìÃX*z…?ôæÔëœl} ×–Ê7;÷ ÷¸Ù4Z>ußÀÚª€Å‹uE½HŒ“­˜XÉÚAÓ AëOìöP˜é˜÷¢ŸÏú2$VFZõw(ͧFgŽžx0–3W¨Çz–ÿ^âÈ]ðΔ¨ã£êA¦V–$ø6¼±ã|VD…´JÁ 'UEÁðmœi;ÀˆóL½›gÚ„Dº5mŠl´L7e¼ uÈ)þÕþqV8B¢ÌÞb¯Eªq!´>¡‹×¤̵&­4]Šd«=·sÄ®h¹`I`WøŽJåºf ‰°OA]§¦xvc»J^Ç«afózß|Ð3ÍæªÝó3Ú¬Cn&œQrèÙØ/:¤~¹÷aŸãu髱eÿ8áþ#eX¦ªÉ]†3â^n>¯Wé—Qš™’=¨S†im2‚ÜÐ)(èKIŽÉHßËpúÍ.½ÉmòDr“Çí›<‘ßdÆ…[Íüª]¸Â&+-{îõãÜ3uÀlr.üb~̽ÌÔÔDñê+ó›⛓¹‰·*b…‘õ>7¯SÔÜ|ôîÑ»Gï®Óðûkáõêd̲P ¯š:Ú(…þÁ#Òù}…Zùõá¦N¿õ ÞÛéžÜqXäXuŸ4•µñt­ÞzvöäÖBvqµçÙöîn¹¹e%Ž9#“Ð/äga“!ÚqsˆF-pḚ̀¹?å¢Ê+ɫ߱á§Úãè©׌7‚LÔÈÞ)2ŒÇt<îF¥Ú2p–ÅBôhX7=»»ç<Tÿ§œÚÀŒ¨‡ûøU˜Ì õÑ´©p0Î(tÜ)¸39ÁM3ŽŽî³F@sG°Ïd”‚3²´HËÅÒ'’æ¸=–>‘¥I Šy ?Âi3ëF*Y¨Û¯ ¥lO¦¸íY%†¶2‚Uw…fEòÒMøêÎÍbñldü6¹û˜ì ¼D[í'0£<¤«%ÛOCŽi;ª{W0v±øÄj‚O6ÜéÒÊíZŸM¿ÕEήL%íʤݮLåù4U`Ô4P»¢´nä‹;Õáf’[=mßê™üV϶zèV+­Á+nR¶3³²'#X“ö’]˜›²?ž¹†ÓÌŒì ‘‘=Ápÿ7Sâ7Ó†§ÏˆoÎ`½/‹T/Æ"áÅüÛê3T“Ùƒî“Ý_é>sIE€ú×ë×ä(ƒÐ?â݈g—P÷–ëë,îO×KÜÒýFÜ/MUnÐQ}iRoQªiZUZ+!S2™*!0þ€áGŒ>Âs£?ª}lBp›éw†”‘~_Có¾øT€å;_ý¼Ø°Å\ÍV)L)35ø¢ó¸ÄÝ–‹P®?Y§ ¶`~=²0úaX4F¥–KÌ1a ̸˜ éäf{ÔÀÖ4Ú¸äC*–wa(ÖŸÕ¢!­K5#Ý@¾•!L/‹d¢èÕÂcDR&…L; AÍ»Y Õ„`êLº€°“¤L+!è} ›œ· |gbH¢=|P‡úº!°ÜL îãí~5¼m öÊM aïvÿEñ8"W,L·ôÉã@Œ½íÖŠžà¿Š¬»±!±ªÆ+AšlS} ¹}rmRÚm„ªÒ[è;;Ö×oãAsQÿç‹”âéw?‘‡'”lÐHÐ…l¨5k>š˜…ŽªpÂTá܆65ñ‘7c¶™`Fp½fĤ7ŒÐa8'×” ç„g8gÑpÖDaê¡N° gÕ›ÒgÚY†Q¨}$¾¨©À$TP#w¹:ŒÿSeã?5Ù§ÍëfîÖªÍË—1ž:éúÔ1ë©Ó®O¥›Õ;Ë©‡ MI+òz³ÚƒIÜD–ñzùµ%óŒÎÑÒëÂ5wÏ%ÂǘO#²HÈÉåã$¨{ÅüÔ!’>*kHÔCË]ç¥- Ï-˜qz{[S FšžJvV3•²)Þ—jØ—ÓJùCûOò³ûêšÉÍ„Y:»O‘£’4—=Åß4—ë±d:ºÑ…øTë”h7dôñh#†LÂùô¤+Ç”1Êå1ýBo¤oÀ´mJîU²'ªò6® r(ûÛÌ–&Ùk›oïÌtU´8¶^EɯlW_ºšÿ¨ÞVk€hu’ôƒ "¦zñzž‡U¦md29+©Ë>ÖoX,'\ت‚jã˜Ä¾-n *(–Ÿ`^\%„’Êÿû÷ꊡòôöø D&Jµ3o´yFk ­V-5+ü¼w틌§Qe_i.>yÖ^¼EóqdÓÒÏH½&vb&{ÕðþÅùùèìëèmÚ(Íþíby—ŒÒËýòÅj§påü´:'QLêºz\uG™=N“Ñ×®ö¥Ô×U^¨<†>ÈF«ãš˜$Ö|~®¶2e¦üT•Iè$0ÎÊ´sEç`&WjÇgq3%s^ÿuLV{?u‰ÉGÏ'.é[óò¦-1Ùåù¤%}k^2§,•®í\ë5i3tMÚ3¶uËŸ'MÚ3Ém{¦|5 Vôj´gµ$Z [ÊÓ–Y,;Lœ?yÆK¸©È„Ýê9R=ŒÙJvÔ$õ-,B-š8 *šðž~=ç.‡œ˜ë3åœÙl „~ߎ2{I®¹£ÌzÓܳhÜí]³æ±q÷‘r›ÆÝË öÌw/É5gÜ “[ýAºPùåâ×ósŒXr+‚ãX;£:ð’žáxK“ÖaÙƒ[]`½eeø˜3¨Là €ÔÕ{>6ÿ„†®Æ¿*á²éO(í_îŽd³ßc„ËF¿B#æÉ`Y‰l«Ê…94cHÞìK[Ú$ÜV£?F†]ö¸ðÕÊSÅ/˜õ=ú÷ ¹Zz0O1áyiݧ*îㆊ{ÐvуLAÁ­@­Z¾çA¦ò«Ù,pT³ ­`Ž}`€V¢: ÅÙz•ñBÚNä?ÃlDñAOìCN2ˆGZ‡|õž‡|‘Ö 75»Pˆ·ŒM(~÷HÊ|1¿n@ülK’¡7‚µ©³ùúí*l!”ˆw2Ò¨7h½Üœ+È ï4:þ9ûöÎ.§Ô¥zA)Éÿ¸Ý®eÆFLHU¨µÆ±U!ç&:Ýž‰_º¥o“|)HÕÈ鱫ÅÚ{p¦½‰…Ÿh×¾ì%ó<»P/+Q8Ëßeþ.Ë6&ÔúXœÜ[©q±ü†ÛB÷ê×R¢6=`_ ¯†Ì {Á:^œæ5S‡©Q.ð‹-s\ÄǺWÉÊy㟶[éè° "”õ‹j1§+\ˆ˜¯ßzLÇÖ-ÈJ{ú£o~H>^%ÿ|Xe¯<ß~^Õ¦ˆ…/ë4…áJ=M‰ò_co4áôö®çš)ì…&@J|Ó„œ½¡j«dŸÑò6Ù<\¯öv[:¬ ”dЮ*P„¸Ò„e9#’`k£ x=$²âí»åþKuºø¼|ÈÌ>ýÏ«u’ö\òKCÿ’/t bkØŠp¹ ½K¨KRùì×óíÍWýE©†<«Û6fÃVQ†àk^AÌe‚ó936‚TGŠ4›ˆü}Átk-­ü©•3 %rv‹•öe/¹ ¥Á :& âÄ*p¥¶ VàÆí¸‰|®±ŠÓÂM^…Ä›Rœ‰õ#gÀ»@%Išr˜õ‹•R+kÕ˜ QA© vðˆ?PÚ¹Ûòìg×ÉÝýz¹Ojã¹,ûüê)ÓúOè:‚ƒ) ¦à Œ®3f† "6PaŽÇÀ ¢áíoCACKx`ÊÖãI¡ÇSê†Zäzš¹fF¤‰1£6w¬ôMš)ÎzŽÍÓ"•$j2Å1a$ NooçÓ’Å œ{ÁÓ/Ë]r»Èöi{þtx84 €C#h p‘#¤·Ðá›û‚y!zûŠ7Go¤<¼â»°ë&`àfïŠqæÜ41v•×Õ2)8àË¥œ¾)ƒÞiéåÊ“uš`KE.ÿé°.Ø30¿O $C—O"#)ÚRò­ÞjùÙ:YîÐRj×¶w†– &Üö‚ »¶«P’“îäóU²w!ï+•Nå¯/Qîn _t1"\u5‘{w4x‚õ95I4$S~z=tÚÉÍ~›9ìf¾@£"àc›FÛëîˆzy÷1¹½MncñÔÏâi}zXD­snJLò3Ù¦íŸec©çé5ƒD„\laŠ·EWí‹×Y|e8ÓX„íZ„½ÜÀ¾Å/ËÔêÑCcJZ ´0"Üdp.º¼õn›îû#˜%1AKfI…3ѬøèR6__½X¥™»Ù$7û$ü…5ŠB–RŠW¢JsÔ±¼žõKXÏz"©gˆé™g2šAy•IñDsX}by4ZÝóç/³¿\%{™<£ZuŸâè^52Š<Ì'âBœ¶;.º•E¬aò¹BHN’gfäª(–÷#–mbÉ)ˆWá8P&‘h|O$70“š i»°­2oŽúf“YÑ0©òɬubš B9vÈú|{¸¸«äó*Ýï–`y¦ÇŒãŸO9ŸÏŒt…G” w«/Îê_¤?ÒˆÔf¤iœI˜F|ËQ;æ»ešŽÒ‹( ¿¾WO¤WÉrìyŒJ¢R$2:[»‘lfo”¸ãb°Îuó ;5PCÞÏDoe§ãÑu®9©Ié’µ]‘Õ[ÙmeP­2*°±Šº:×½äÖs©Åª¹3öÆN‹ÉolÍݶmì¬ÓÆÎ6væÁÆJ¬A¿öI&´ƒÝp—çáŸ3«Y5`ß çÿ”}ñ¬RÂïm"³äÆaßTRá¯k<¾zV¬yÛíl¥6Oû‘e=û²Ü¼Kvw«4Í6q"m7A(åWóÿdý;‘o­eGn¾,w¹{Ìÿö‚eÿýŒúïï­dMºgL =™ðϰ¯$7ÛÛÏ–@¢²/=£¿ôŒñ¥ïé/}ß)ëü=é;¾õ”Ì ”óå=L«À?À76Ézt“ý&}<Ý„£[ðy°N†"ÛCWƒóîƒå|t+‡jöš‡¼›T*›•ÎI‹œIöR­ ª…þƒ§-t¯Ÿº 6W=ql3mÑÊ Zøݠ㤅¾UóS¹»§¥+̹œft, ËdA¦q™È•½¡ù¥¶ý¤Ë¦Ò¡? ;ÿçú ܉ýqˆT:~Œ%Ð÷sY2C,yÖÀ’gò,yÖ‰%Ï(–˜,yF³µÿc•0G˜%ÏK¾o`I ê´³äûN,ù^”%ßóYRTE#4þôh™ŸÙÀÍ0~bc„üñ üñ=#–i®ÔjÎôè‰`Æ.#˜‡Mºú¼In{Ê„õ?¦7Ä4ýiÆ1¦‘çPŒiZLLÓ}í=i ¦é²j 1Má;ó¹÷ñ ƒUt|C@±@‡DÁG< &zÄÃ`‰ˆg#…fV"àñ?̉!Ž‘'p,Àñ0¾‘Äî&ƒ¹ØÆq—€æ¥÷<, 8*‹A™,ˆÉbH¦Î©‘µóèÐ27ñØz@=+î' GF)ÈQd‘BL1ˆ!{›ð{‘<Æ”_Ø ²ØÂ'ý =Ä–®Ó~|ÖzâÏ!›¶E÷µñ9ã%pÓ°Ü^b7>_L•k{DôÅ4`xˆ­¿‰@D ‡pÍqχ-'u­¹¯ð2DtÁ¥0c|Æ–Z ²Å(²ìmj0û‹¼`‰%q WÌBŸßÂn¯M_ºº ªöÅ ™œLiˆÉ€¦¥&]ž¿¸üéïH i,:”2ñHNBO3ýíË8tH¬‡˜Öu ’Ãßòí˜B/@ä°¥µZ…`Øu­|@Hà‰ Ž'¦$žhž%=AxbÚ€'ä !ú‰üÒ ‹;9zJ£‰j`tAF±ÜÒáÝïwÐoÿ}„ì÷€ð§i&ë‹âKÍ ,{âQñŒºÈãLPè1‡g4+–Έ0 ‘B«ËY¡PZ7-ÙÊq'Ælpo$8‡f&ç0Š•¡Î7 )áƒA…ž à€¡ˆŸÉ·ËÿS˜†Ûdì(Ñô¯¥C•—ÈG,šáþ…)1DQQˆL{¿ã§9w6OcF;ÖKÕÓ¤¤Š86°–ß饬ƒŠÉ¥4­'fwž­ä!=ÛÞÝ-7·1Žo±¶·PD_ð.LkKPä»±µÞ·°ÇÓ@_ߪ̈́ü¤õÄ’fqeF1ƒ©£·@Õ:Vè…i¬È±kå*Zå¦ V´NÚ+ZcùŠVÛÙEi[äMQKûâ‘’sëZ˜1 U,SÉ-T1‹>c¢è3-:‰?KÎpþºùºÙ~‹ö³Îˆ^˜ÑUÑšv²¦üôÞ¨š¢¡Í¶Ö5ì0Llö—‹í^e¾vOLkÉdRÃN‘–ÔDSÚ˜òøè½ Õ½vXŠ4è`LæÙõÙ»6˜€ü¾˜K@K4–£x&C0•W.¿Í9 3ù‡Õ^µfý¶f/ÓýíóçÉÍ~»Ãýk'ÃôWš8/Îìgy… ome3=!ÍtíÀÏLc,$jÿ£G°¬POqaTù^’–j³.ÕÈ¡šYÃÍqiJëÂùÕ)´P%ª‚D¤üÜÃ^ÃÜfdëÉ#yä+3‹En®óó_Ù‡ûÑ1á‰Ý'|1²a“âë’ušä¿z¼Ê~@üæô}f½%;ʾö}ë‡ò;ùïÁ‡ËÇ£ÁÿÊ{¿_¼{úþˆô±Èš\>'`+3^T1{Àܱÿü¥|Ð`ð——¿Ýg¬2›u„¿ÛÙ¯Gµ-ÎOõQhÜUðÐKüÇýCúeñqyó•¬NVÇÕ'GăÑþ“ÏÝ©¿¿p”í?êßÞ¾ ûàCRüÒLIò.åíO&,Ã=%ºÛ„ãljËNÔNÉœà‘Ç[šŽÚc‘êD yM»"/.êÂNÓ×£ÞH6mƒdSeH6%!Ym”d$˱<åö‘ùÅlªgóÄãõZÌÇ\ÌãôriRÿÓ ãö4ÈD> ÒxúžÍÄÚavßr —üçv#ªž¨zªUÿô8mBÕ!T=1€ª§u”ã œžþ€}¦ N³nBTÓS8=Õ§§pÚŽž8š–])­MÂøšwI #Ó9Â×Si|ÍLdNˆDæû —|ªf,S>×Tý6æHÕr¤ {”#Ũ ˜»8 ÕÄ!&êõ$GªuáÍx=æHµäH1VzêbŽT0GÊÝ:¹í³›#í,olˆ‡{Ê€s¤€Œ˜#õ9G ˜çH3Ì ÿ<" ŠÙÆ`AåHµ,øÐs¤l&zŸ#Õ¸ì˜#Õ#ûá œŽ9RÁi}ÏäöÍnŽT]Âø:æHU0û›9Ò7+~ŽÔÊ(C=ø]}ìô¦)­åLÆ–j-7r¨†Aß4'þl¢f­ ç£gBÑ)]á7tCÚ~™òÆxV¢º<Åþ%)É‰ê Œ+Ú…om·wIÊ›2=nHIÁ'É-u[JðÖØw3l;[Áæ‰ÇÙ - >ôl›‰Þg+4.›­Øa·£ÔR¹¾²ØF}•»}×r3 ›µËEZ¯Á™ºÒTá¥"ŸÞvNoo‘g³ÏûQ4.{ÙrÊÙÔƒÖ»P$sÚïB1ö~9Œÿ÷íj“1Sæ—Àý ¦¨".åÁé@Q4"Åw Ýî˜õi.[jдÕ7[@ÑÝWˇЄ{–’ZhIOÆ£rT¼Øo{•àÅèêC‚#Çwƒˆ-Õ¶]Ï“âbï‰Ô¶p¾µ$›àÅÕÆ£/X–É[°Þj-gUõ±®°ð‘¡ïVÐv~•Íó«Z,™_Ýy5›+^Þ>Ýq©È‹^=Mº¨†›i}ë˜~·Ü)OñÂ~Û+pŽÑÕpŽ‘ã»[–jÓ;5r¨fóq±w쥴.œï­Eç‚s\m<ç`Y&Á9ÞeaîˆhÇëw)TÏy®×}è­€*ßm¨mhÏæ‰ÇÐ^Ë‚{íÙ\ñÚw\ª$´/¨«¨—vW°¢>i¯¨Oå+ê½löÕ|«¨k\6òÔÜŠ:t^üŽ]:—oÖ/§VžitîA&ª˜z½yÌ €ÙfV‹í©šËâªéÏœ«ø±X`‰ÅH91%‰qÅcœ¤iÉ’HIÎÝÐdÊc£÷m¦Z¾ä5š¶·C ë(ÑáfµgB¼M{G›œï>姇OÙÎÏ÷ÀÑÖ­vv¶^Ñ0?}¬KåÒ…_¯s¼ê|å\ ÔÉ×)óÝáÛn„á—=qZÎwþ¼ö8Ù4 Ô"›‰þÔs¹‰tœ8Ѽô†D òT*EÈÝ3ŒfsýÔœk—»UòËÍmtÇÝqÎïþ9㜮èŠeùã¹#î¼ì^»aw¼wÂnÚ#CÙ{ün½ü]µ Êi ”‹S\L¶õ¡SŠI˜ïÞÔA¿” ŸjîÉ“®)Ëç;X^ß”¤!Æ5­'çÂHâÎW›dl6âujíWwI&Czæä艘„çæT_œÕ'éòªÃu^ ÁF)ø|´ì… 4úî@Ü…c ,ò<"Ó±ò^e ò>.Ó³v•ÐLrêNîÏlÎÝb¯'Ëñ Ýk_r'ó8ƒšÍ³Ãî<-6xFl0&Í\s¿Æí1‰cS¨ö¶•™'Û,M‚†õÍ.Á#Úì™:¾ÏÞhˆ&õP«ãNê1œˆQKÉè ÜD!Dš¾ê¡ú–qð}oÀ}Äöò ÚGd/ËŸ`€}Äõ*< Ö[Gõ*@¯Žó:i,'ãÞíV»Nÿñì~}.Â}.u–ç0 ò1ìV—:i¾#°œé6Ïã °¨†drs}0WëÊù Ù“Q˜‡á:[W²ýò[‚2ßm·›C{$©¶Daÿ#Ä0ÒG†îQÑGÊsÈwW©cá*SÂÈ*Õ£å+åR7öÛò¯á}Ia$ùn\±¥Ú¶°\ªÙ)\?<°²ZÏ·´„UP5·¸†õÌÚF+harí‡mõݨºA¬lÎxŒT;/ØB…*Ó[ïžU1œ}¼w6Þ9+dLþo6¨»fûzϬú³«›¯±|)\¾¤n—Ü ås­,d¶ »,`Ò ùb‰;¬—o{sC`Ñ2¼+d}¾>¶÷WǾۭãÕ±’Ñ Å´>/I¾;GG±K+—|]´/Þ`äBkXO—‚¬·˜[ >÷'l)(òÝ0ÛŽZø|ñ2hѰÜÆ,|®x²hY°™ˆ¥4}= X@w` XdË-$Óú°P$ùî][Ú¸äsÀ¢}ñ&K-”†õ$`)ÈÒ°€ÇÕÂ<Œ™úÆT_œÖ¿H¤Ñ¾OIû>•µïX¼Ó“©e¾ÛwëÕ._¼Œ{4,×xÜÖhµRÃåI-ˆ€vÓu™¦ûrùOîêñΔ½…“b §ò¡kͨ¶mâTm§ ¡ëÔå6J,yêöÐuª‚¡ðÐþ9µÀJG± à „êùµÇªÁ,ñëà gkŒëC@[#ÊwÈC,Övη…S5TAjŠY`íðñe%Tëq¤Æõ$À­‹59ó5¹œÓýªÊå4ùn¬]Ôåxœñ2BÕ²àžÖæx|ñ¸:§aÉæêsÈ ö¸BÃÅ*]ïšQ¾{Jga§ükŒ`4¬©k\OÂšŠ°X¹«¾èiå®õ¨v£#YÎxiYp/+x†/5¼Î îiÇëx–l®’Wrû^Ë»N~SP‡ýöp^Ši}w)’|>ØRmg‡¹T¿Ó2ÅZÏÇE„UP­ÛáÖ“ðõ6ýKvæKv›ûU¯ËòÝ*»(Ö1Ùâe,Ú}µ=-Ó1™âq®ëzÍè€Ñëqu.* •¹ž*I¾»DGJ+—|T´/Þ` BkXO@–¾@%áÌáÈ8§G¸ÅËx§ûj{Yx‹|©ºu[mOKnL¦x\oëº^sÅ6*`í{¥íb›-0Q a‰_N[c\ÂØQÞc|±¶“¼-œª BS<Èûj' ‘VBµúFj\OÂÚŠ°X‚3_‚Ë9ݯ*\N“÷ÆÚA!ŽÇ/cS- îi9ŽÇ+r–l®(‡Ì`ër1¬Q¬Íõ.¬©å½§tÖpÊï°ÆFÚºÆõ$¬©‹»ê‹žìjQQjv1:’北ё–÷²x'høR¿ë¼àž–ðx|ñ¸Š§aÉæ yõ ·Ïµ¼ëíýêF¹ûñá„»8Õ}ˆtqz|<øZmŸfÕ»8qÅp 4/†Hk ÖšÕ“ˆÒƒÙÏÁ,Ü#V›o^ÀfÝw{n;€å0ÅËØµëZ{¶râeÄÚu­= V9,ñ4Ní¾Z3!jî«$:'»L”Ï–÷§ÙS—×ò1*†Ž”¢S Áµ_ž¿¸üéï|üòq»]ÛˆBë¬ÉLš}(b©“d¾””2s¿ßA±*þûí1‰tNÓŒ™…AeªÙ¸„@ÙŠg4chG„¡58è¸ÙnÒ=iÖ Æ¢¥ZD–ÛÑ#Y„Œ JWšŒ^†Â ©÷µÇ¬Ð<ˆØbøÅc ¶ ÐEòíòãÿBt›¬“})üAÐN‹?KÑ„_å”h²ß=$é´ç𩙀N°/'7ÛÛ¤¥/ÕPë)Å»ÊÀ>Înn’4 ÝÒç„E3¯ÇÌó¸Ž×JÛÀ—úŒv5[zn•¹[ ã_`ØÚ‘?PJ?ÐOºì)Ir6ä´ð0’åY0‚NY¶‡-Ù­Ÿéãb“|»ÛîöK䤋vo¥à²®WwÉîôa¿ýûv%?½»LÒF1 çUî Pö4P×Dä{ú´=§9}ÚÌœúmàm™8iTMkæ§S‰Œœ\Á‹ÐžžT¼Noo/’ý·íî«´í|}u†~¨ G ¿Q +ÿQ u\˜–¸¢Ëw3\‰­McÜÄŸšUÃ4˱=Ö¸l¾IÆ I€‡×šxäéá5MKæ×½º^ÃLdO¯½€q¿ÛÛÈ…àá9õ—AÑe*°Èc¯©w媎³ÝÒ’ZÕ“ˆfžln¯·gëUÆmÕ^éƒk“f0­ÝÒ ²|·µú¥…¸T3ZžtLk_<ßÜvj—fiX-®®’ñYþ¸˜Aj4Õ¨È|¾Ú$#Äÿð µïZ$Ã`Î@‹—[=2ÌÍ7ÈT–¡Cs4\¥Í¤Q3wêǹ5tœ6Ò¶h~â¨0û*‰#Â2ö4u”Ó˜~1´‘ò—Çú×T4ùî25M,ò;¢Ñµr£á ¦U½Še2º¬Ÿ]Ö®bAHèæÔw;ê*ô`²Æë¸£ëŠU‚ «Ùsù*Ù¿8?—µ”RÝÿ”¡ËžöËrs›=P®f;Ø.'· ÍZ¾~ë )A¹Q¥ô#~òdþ"ùön ß„áGËtdå~¿+Ä›°†àßr–³Å¾]âe„ýÝÃ>SÜÅþæ8mĘ:È©°«*ÅÚ{r°…ÇBÏO³h]öRæŒ"Òœx*QÊÍwÉÄdö pÈ9-&8€<–°}*Äœa l‡`úÖÜ%wÅ6¶Ô+m[[SXN_¾±˜™)-åÃ&]}Þ$·ƒõ6s5Yhy›üVY*ø¦ël[®–›¯ƒÅü þ±2R¹QúÛß´ð¿Â¬óßïþýüø¤„+™È,ñ¯WH 7È9^*ÿ½4Ë ¦ü†RèÂÔUÏïÍñ%¹ù:Ï69ÛZ~…€)‹Ç£Áçí~;¸_^” †|÷·ìyO3êˆÏïàçØ‡õOÑKßžþçÙéüúêôâ&ÚO8´ÆÌoâóå" $zö_ó‡ ¶Ýü+?T‚~‚qêzç|=ˆ†ÛUz¿Üß|!)"ê(¨•BT.Æf•‚¢Q"D*Ð÷Ó§G3¼&W‡Œu¨Á¸Tƒâ›ùé·Uö÷aþ²b9™kLHqƒw¿Îy{zõfþÈô˜zèŸÿ–ÿ@gŽ´/¶ƒ;@¢O›€‘Ÿ¶»Á6S¡õvy›ùÓÿM>è/=<Ð žÃþ5Mv1‹„s£i$@FÌ#u xØ<ô?‘¤qݲ™$¨=1•$&OþF»Kò£–7'$ÚÞn¶—ÇEÿ­¯Ö•ËÚ_¤EÑ X`ô·XG¥,qþ·XâüoÑw³Ä<.úo‰µ®\Ö#-Š–XÖËWV¯ÁX]ûuÕ²–¾nÕ0ïáXóh˜MÞXlµÂ*l°r‰÷£ÄªkÑü+Òon…WD¦ &Þ,`‹.æsáîW¸«¾æ‹X÷µ¦€ °ÈÒùMz,¿¯±üê‡U~¥‚mX*ý£»›ÿM¦›ý-¿E8¦¢j,éG6ŠwƒuLHIFIc<çY‡4^9r”Hão}\®§ØàÅ’SÞÒ³/Ïè/Ïê¯}f*{øŒ´›Ï”ìæÏ?-×ëË›¯£ô|ù1Y^MɈ=œý~³NÒQú"Iov+¨ÅÑÄJgÙ%¦ŸQ®³ºC Ñ ÔòZ¢èô©âø[¡npÆNC’Q>Ǩ×ƀ•›û“`ŽXú»`V(ý:nO¿NäYÓ0/˜ÏÞmMž¤^5/™zÖ%ÁÓjÁ%Át/ w/'è¾à)ÛTäÏ–¿/xª²™SŠ'¸?`^ ˆnj‡Áè*ý‡ “¦ˆI³&Íä™4SaÒL–I³v&Í(›*f6žIšY»Ùx&o6ž©0ñY¨fCiáÙ‰Uk,>b–k&àNí)øcÆþÂ3ËžYˆ™…˜‰Ðož¿y&Z²°ˆñÇØëø#„8£c(1#C‰š§ÐJÄè!F1zˆÑCŒbôà zÐ(@Žñ`”7ñå9@sÚ”h5‹Õ E`Yf˜E`¦˜uÅ~à 3HCdÄ£îϱ…t´µ³xMºÿG;§Q%œíÌi$MŸÐ¤~óDí¸ë8¬ã®¹ÕߤKC²‹_ÏÏ1ÂH¯ˆg~‹§”öqíc³\L¢}´Íßì£arðÁ0at8‰ f:”Ä„ç$žE'Ñ,Óè$lóÄ7'a˜Ü0œD0L0é$¼üYX‚¯Ã'N+Õ}âÔÆ°¤Ú¹J=³’jåmÆc';f=vÚù±ôÀ¨ŽƒŠ§ ÏuºJîâYWѳ®³‚?ëZϺŠsÆúY×RÚúqÖ•²4òc´û9EŽ´)y?P´)‡:>NÂüøÕè¢yáK™±q¥ Å‘q¢F8vi¸Ï¦Å. ÿ‚é8€»Ï]qwïp×òzrJµ`Ek–¦xºp–æ×ÍzµùŠyaSŸ‚ÏÑ`´Ä4s¬gjp±ëG²æçÌ8«™ÛYšb§v’ãEÕ LÉ—àÓ5%%1_ÓÁ5pÑó„î•·elJÜQÍJ•äÒ6É·w[(n )?Z¦°¥#{wa-Ùák¦^ðûó_N_\~5‡óSòyµ$I_ÏÞeóüÛê3”¸Ùbî“Ý_éþöùó4!Üåóçp™]Ý-÷þýÑü tŒ!áN|ƈ·È6G¡ã\ÓÍá&ù&$$$îÉß+ò»'<"U>ûõb‘ýú)öÑ~± =B~äòõÅõË«Å凋l»m ˜~‰,_Ô_’ájoI‚Ÿº[q8jn'Í=_¥{ûªkDë*RÂU»Š»QLa12+}\dzt·Ýí—ëâß Èäéíí|{ó5ÙËÇêðgXn°ø —ÉÁ’O(5ˆ˜¢Ü—¤xžÌiý¶oê-’w™Ì`ñá Ðõ#1x•Üåô(7Œ–Ñ)ù¾Ñ)I‰FG†7ŒN%tý4:±w”i\Rðð:Ðh^µ !eˆ¼*Hè^y[A‚c1c©°5ŽM¤î;æj"-q™×´Ç.Òàu"v‘ú¡Au‘RY mm¤Tࢻ4¼d#iL W8«ÂOÞàÔÄü${¤péëG4|©ZÛM¥ÅfÙë*íO"§¢&fr:¶–šÊѾô¶\N…DðîR¥ŒŽB{)î°àzÐ_šÓäOƒZå=u˜"–„Û-ƒSágŸÁgµV5¾ ´ôªñ(Ô¬†â<¯ºÕ^60ê1Ípµ¸¢ÁOÆx5XG¿©6Öp¼öaD¸k9mÐ/{=§¿$ëû³íÝÝrs¼h’ä„+$n”â¥SE‹PîUÌ>BPÏ=á™nÿ²Ü“òÔS¡ÑJ¿ÉÊpÓ%O´Ò‘;h.wjILð‰™?«åæ©ìöEv½EQïÒùYz\ã…;¼ 2^n»HÐv·¦Úš01¦=þ~w †ûç—]ÖŠßè‹>3RÈþqÚô3î?v4ç3Ҝ׮ý3çiÆÌ¨#ÒÌL¤£ôE’ÞDã~¸U)SêWUAûÒÙU…‚ v+ÓÛäîc²+îØ Ë@WÀÅéê_ÉöÓcÙŽ*eº+íëâÓb·ø'J<‚cûj.k·³)Óu!õTR&íj4•gUóÆ\^Ñ·¤FJKG>™£Fb>“Üðiû†Ïä7|¦¶á³p7\iél‰uÖð˜Uˆ·kOØ7oOÙÏ|ìÆç}J|}úÿ›3⛳±¼‹ìIŒ=ˆ$,E ƒ‚)Lµ1ˆá@ b8à L ÃÀ@‡à®d›X„lÞÒŸèkÒ}EÜqWÄ]wÙÄ]ܰ·þV»íä§Ú|ã%” åúz·Ü¤ë%< úzF/áÙ NKnqÀô¯¹­m}æä~̳}:=qõ” ùuœ¬êKÓzn¥þ¥Y½*«±µFc-VaA6B€"h„È$0´a\hÄì«bØÂ櫆oÛЉ&ÇͲÚíV—VÝh@n‹¡îL†t¿Àxˆ…I! ÓŽ¢PK¦ÛÊ©‰ÂÔ¥(t£IQ˜Rn¯“"1-DbV?êQ@žkéŸ „Ÿþ«Ÿ{\Jüª+ b6ÊÄ8)-~Õœ¥È*©JÖi‚‘jÒO‡u©…º… ÍªÉª9ão˜\mÆŸW_ eß•1‰ŒÀêk5F—×üæ§1éì4f6.>`ÌHÒsó£cœñà‰†Yžjx0}Y|ðLçzo¨ž/| ÄUr§8º­¿7éÕzõ‚lΫ‰ÍyÝ®Ñ µ9OûÒ¹Íyœ‹ôšÛ!|ì`p5i ©Å“ÑvÖ®Åè‡UÆ(7Ëú†6÷Ì87rÓsë¬ímæ™PÜ#îØn\ٌߘAtÛôãÖŒ_2bÖI(Öܪ&x‚LøùjæµF1\w°ß-œôÜ‚›X½Ä&µ*¢l1ËŒÍ$WnÛJ4Êô¸ûà ³³¹÷½4ÎÜ Â@ë§€m¤I«Œ«•°eæÞ‡®m•îÝ• l3 ¤úÅ uŽÊè‚Þ»Ajk±p\è$6{Äã2ñ™'ç$þàÑè¼ èPŽ…lkàÃ=Ý üRke¿öáÿyö¤«äó*Ýï~· ÅdóŠŠ7 bÔ… Ëp*ì"2Nb‰`«½ ’^d7_>&ý•|œºp%§ÂE=”–^MŒàv¨ ñv«®=­Ká,AÙÏwËý— u §%&>;$>›éyÎÓÀâ¥jR„FÅ’T+HIöïu—¡ðÏñQšeK0sK·ñÞaúˆ„¯Ì$ŸÝ™Ülo“©^¥v ä>²ûË»d”BÝ}ü°Ëžt½}±J¿é aÑ tpznýu®šmöå¶y"¹ÍãömžÈosèNÃj.ƒØf¥U#Amsi£ÑîeËÍ]3wëòCq™¥g¸üR&ýDvïè‘”`ÙØÈÀ?…}ä± Fää~ƒ;åññ íóòžæ7'Ä7'R!©±W«â*}÷Ssp•åìÒDЍ(¢¢ˆŠù¿ÍQ‘>86p¤ý¿…Vž8á”Vu»“}kÙð’ÜqXäúߨ—¶ÈElÔrO®9­7Lnõ7éb‰¨‹_ÏÏ1jè­(ŽyF;òÈÌŒž.<²Š¦µó>Z¸ÛîU;»§›ÌMp@/4Þ^ñŠJ™5z%—5ŠÃäøèyîHçªÛ)xÝg¯ò ‰„â"¹„â»Á·Tü²L°Á¶æ.¤á`HD4À 0‡ž`«ëdã™á\™bO[›~‘¬õ÷´½k­†¹hO›Ðíi“Öö4µÚ+d$^{ ¾/ R+°Œ8‡ƒžq«fñRk…óDcÔ°4aK~þ@ù†¥†²*‡ t’Û°4á7,a×#³*”¹%áT(}­Gjwb<™¶.¢ÀC Ú)E?ýPôC^0!`€}´½.!½y‹Þøüyf=wËývgÞðæ¬ ÝòæTDÓÛqêq€¶Wë²ÛŒï²še,mwÉ1ÆÃMò¡ï¤ñÍŸ[ÿÖÌ"““‹ï.ÅwGHÄ.__\¿¼Z\~¸ÈÔò8TCþRÅŽw»ÐÍ$« axYZä mñKû¦¸¦¡9 VE½3~J>¯6ýWDf¸ªƒp¬<£ú06cY%b(„’*V}q\.Ô‡—vÎÖ¬öAjšÃT  ü9)ø3nU…ŠOÞ$eê‚NìÁ_0¤Ó›Ü oñåÚ“uš`‹E‘ÂÓa}ÿ _ˆÂ¸j–ý%2à ",M®…k°pÄ%N%Pá²Ý3J´Ÿ0igÙ'¿ÙàÿY¨-ráåáˆÀ΂xxD „”“‹Éa©ar«¿)<#d„r`¢ÃLlœ"Ãx=g„È^=W“ŽZÏÁG Ÿ;:['ËzÓeÑ\)ë(ú'ñLì‚jÉuØiUA\ÉÓÁ÷N"jì¦BÊÍ6­'¨­nÌfJþ@ù¶º†¬—1tê€ÛX7æ7Ödpú: ³ÛÇÿhÏ&ü©í)ÒŒX½ºÉÎÔtÜ"D#Ðñ–€‚™öä^o ­?^øä>8й£(áMš8‰“&|ž4A£=q$jiúÐÃeæM€«IàÁZÙ8Y"ƒâËFPFe¸È #ÂÅYæ ÃU]¯ƒ'M#J–1ðÔ"Ì{ùÛýrs[¾Ô$ýÑ‚sõ–ÏA/s€†“Çtn&if§çÍæßÖrÎ3¥„†Å!.ÊF;1îÕSè»|ò³ \¥6_€mûGéUf«`tѸp¶fŒ ͘Y’ü]£Fµ<°kœæÞÌ Þxô'u…(»AéfË»'±ddâ:\è$Òáú¡8IÀ¹¾“-úð£eºN$“³Â‹³åçXÇù0í^¾“«í¬îs®^Ž0lb»ÿ¥‡Ø¯×"±mÕyû˜½Õ¥ÿóšöêµ0“¬z .ÌT€Öª þáÒË<Ù›'”È>z½ù´}þüeþà!J½wà#…Ö;#YdÄŒ<‰I 2€Èpßbö­9`µÃŽË—ZÍ’n±–;¶b=xØ}[PÚdÏß Æ:ÒL¶žIz³[A{_[2e0 lb¨F£$N*êv]d#+=Ï!Y>;‹ˆ™6\„ËE\›ç©'#9û›J Ko,'¢?p«‰¨ˆ³›Åä²Ñk©wé­–²P›±’™¥k"ñÛG@B4ŽÝŒ#›‡þ[Fën5‹PUÁ&¾RKÁuê|ff)ŒŸ[{…åׂ4¯d3kF:ŸY›Ç¿ï§`zcw‘Î<ð=«§Û^uJJ…u:€Î<…ª"Jy'—gpÆ~Là•ÀKQJª†Èah—ªY¾N(¦æÂR <ÿªfHgß\*GÁððõã×4ÙYUðB‹ª^´^+E¾ed³Æað¼œÕðëó_N_\~°¤ÉþÛv÷ÕªV¼¾:C¯µ¨èA«¢Á±†àÛר'Ë5ªJõnW s¶^eL·ª/ù+-êJþ U%'Á±¦ר%ˆÙ•$¢+y»ÜdòdgÍ·7_Ñ{mF"ùƒÖDƒëHß¿Fm)x®óˆVõr':s¹9½½U MV]j>1߉¬-׿¨pz:''Ïî_%{™²ŒÚê’Íye‚îjI¨G¨KЬO”»i8Ml‘kn®<7°¥VÃ…Ôtz–>¨½Þ¬cµÈ0¶0·å=)åz~ º)^Ö³Þe‡óÏ”9-ç~VVOà|³î"©ŒÇTõ/`S‚>÷©ßMjö~j]Y8£*¨Û«H‰žOœ3^:?- –÷ífS—ö±Oºm¦sO—›<-Éí&¹‘N`ý0P*íå°ú„ÝÁŠå@ˆôËv­áÔ¨¹ÅÑK-$“Ö)ö3x´nÚlº[¬ó”´ÎSQëLlNn ïwGé/Ût?zx—-7PkMæ¡ÁÆ9„dºEzÍv ‹j†°T=[Xþˆ2‡bÇ¥^ 6ÛñÈAGìÐÂM"÷¤ÙÌú‘A¦‘Kƒ‡vg.Läb>_äV’»·t¸yÚp¸¹fÛ7O;lî”bið™§›ý„—¦œ<Ö\XÒbÃàŠÙÇ=wH}fvaOˆ.ì‰TJRå©rã|ûyµ9Ýg®ï^_Ì¿­>Cµù=ó>Ùý5Û’ÛçÏÓ/Ë]&Š™Øfìôaÿå'0˜âÇìÿ--Þöì"\Ù™ã@~ 'ÆÍ©éÐ-¿Å¢¿ëE)~‹½Ý‹¢ÛØG£ƒ&Åñáîhýô”äˆ_'Ýh]Z.–Š ýµ@ê.Nýœý8¹…ä„1Ô·1”èT«MßÐYHLØ,ï0´÷n»O^¿ Ôœc¤Å3’,{#'=?)ibõKæyÉÞE¨Œó>>Õ¿zvtZ9SÜ–r÷²c/3ghÅ£(§mÅß*çàÝ|Ýl¿m€wºZ~“öñE“[™.»ÞbK ¹ @òå}Qÿ^z¾Ú„9š¦Ëó¤/Þ/i/çÛÆ¢šÿ,ôJ&ç[ü&À6þxÚ¢qÙK#ý ”ÉYö²+„$òm’Ã+?þ5ÿÝáôˆ0Ù–{¥‚‡}ðGˆÝasÑ2möò©>JiŠãnËçûÖÒ:¨´—°5­_&ËûsùháÄ<ŒxÂPÈ€1—ŠÒìÃ0®Tyh–ÝG üñ*T˜;ˆ¹C#î¹'‘‚¶Esã„9/P¨u1@kÒ 4w+…ó¯Ór•ó‡ûûl É­Í4¼X~é¬g¾^¡SþN"hPk]dmå—²}„·¼éœXF¥È&“®ªge"1†z^-2H»hÄji„–У.F1¦Ð­Œ€ ±FH/ѶXŤàßÊ8”i¼Êi¼VÆ*>…¯ PÑÛ#Ô!K¦^%ÿ|HRùÇVÌ«(w¢_ȤN_Ä%JLЍD%Øæ²ÓsLbŒ„p‰KtâF¢°Ð ð£w')ò¿œo—·å=ÛèA²ë<‚yËå÷éàW3ÎÓžÙïámƒÕ2fõwΘ_|Vÿ"ý‘Æí3Ñ<E4„h Æâì³ ØWœé{š_é™Áš‡››$MA³ñþmú9P€C›;á ^zßnlbýËÃh8na÷€ÍÄúÅÑZã ¿.ÀZ ;h¤ÆôðbÐ èÜÒŒíI¦…'™B€'þöÞ½9nÛý>EŸùÃ#)ÚûXýPªìIn)²;±eZIvÝ©]]´DÛ}ÜêÖn¶d{Îï~‰ € € °1S‘¥n>°°~뉅úìàLW‡ÌZpk&°kksƒ³îsƒ–†Œm¶ªÎC&Vx³r"OÅ9#yª_Z±lšæò´Å\ž…žö>£ÆÖvsMè©N5kTjí°€>ÌÏàÏÓÚð°Åò¥.6Np?úÙ½Áý0ñ_¯ }Gêš±äšÂœHÜA±æ¼$«¼=ç6„£Ûxv¦±jnêp¨»]ƒrç =W«òÈn¸º‘GÕòÕ:ɪWY—{5svK½¹Ãû會R/kƒNd¥^ŒAG홊'sB&sªoÐé93ð†6óYqfLº©Sª1n¬3›ºj:¿Ñ¨+õIR”÷ÁŸõyüNöû(U­ t`pYMlpŸrà¼0„¦’‹Åqf'yxeãG9PnÙJš±VRÅã—YIåüâ}Iè¡T’é¡4âø'À¡…TÇ‘q¥ºç­I¶Æ\kÑ!øzB+½d[¼8Œ­mú5Ûñví¾:>ˆ* ú¶÷lŒWjç1Ö»q\]Éz·Z¯ã ¤V1Ü„Ö- YZçmö™ŽÍNY7µA×£2êêÔŒ7‰bvSPcæœ=æoNÞ¯ÒüCí½©¨g`Jëګ΂¬šfÒ©#KÁ„ú¦ûÙŸÊsרûצ„k’3„yn˜£¦éîº0ÑÙÆ¥Œôv‰}ròÕ¿ÙÞRC^ 3œQ_¸j™Â—)LÄÓž§_¦Ðd¨70¯bñ*W*L4*ªÛ^+ …´-x®_{_Á1ºü–~ÓVVmÎÓüƒñóƒ™!yA¢‰Hp®9Ye%\å¬ïÿò¿®_^¼8ÈîGO°™÷?fË¥eã›m>ùÐÑRÈÿù{õêç£ï¾[2ŽòG£¯ù ¹„ÌÿÈ'æyùÍ—åÇù#°CÑr:øzŒ‡ýÏåÓ×±¢6Æ‚ö•ºÛ£äº³¢øéÝ˯Ël—]üa«òÚ^MtÒn‹·Y_(ÂlÉRã %•ÐáVPõÂoÞ—Ë™èyý°å'ÂÂá-»Ï¶"A`õˆ}úú¶OV·Õª-Ù,€Rà\‡hÈ xÇS„å9¨LÿÜï§,>­Czhøcc;ùpó;FÔâÙ58¯?ò«ˆ?/^^5Z];*ó‚&³xµ@/fŘٲF­ž%6ÍN2#—ï^_\¿¼Z¼x=Ï'Ç~ãhRVo™‰~Ë* ®”ô ×ÉŽÅ&Œ“ÚÕ)Z:‹ÑnôÖ)7ÅK‰Â0Y°b ézmÒth,Lêåb?']Å~lX_ šµIuEQN_?J¦#©FÓLÉV!ÛÅ1m«MnK-–ëÛôk)¨ð= t•¬?[ðzµÅ2B’øÃ£§ÜRb_øýý=\žx(@ÚñþŽ.e q2$tÉ󒀓ÒíÃ×á ïG7»Íèv™Ý'»›O"˜!Ž—“Äqßß/éÁ¬\<Ò——¤"°}DŽÏSŠ<¹5Ðî‘,L:Ò_Œžñ)½ù ;z€u}Ȳ‡ÌÏ#fâ ¸x1&aŽ|—³úñ('ùü~N}˜“„_úöì¿ÎÏæ×Wg¿Ù\ãv SWȹ}}Yæ¿ —‘áÜ€ó¯NžáG]þ>õöìê·ð#—wÄàÜó¨·×Ÿçsº{Ø®Ÿ—·zä ÷ÈÿýhDJób3º¤§êÃÃúèÎÚä Ô?æ(ñ7úÉ8 \ÀXL¢PP¶˜§;Éáò &/{¼üþÓÀ$nÓD¼‹xPÁ¼CÁâAò™Ó€PAˆk‹Y{#:FÞá6„ÖˆOe×Ú{ <•$gÈâ’ÄDês1öÛYCN\¤»/›ígx}uŽo¦ €þp(€€ ˜@,,`¼G†r)¹Ç)*A/x  ï“ÃYz>!jkd ­ÿ DÓˆ/\˜@ã÷%zè»WËž.ûíQÀ€—š7¸ð‹©/Ñ&|Ž­­nÕ<‰–ãêNÅúm§ál‰6‰ýa‡±ì;:Ä+œðÚbدt4…úh®[٭ă¶1Ü m.‡+'úVr7¢Â8TµCønQfx¼É1µ6[ ѿ2Õm“±‘)ÜŠZqÁ·(-´)êZRÐ^ø³Õ*à†*1!ËCA„kŠx %u<ËëòÝú§ÍÆ1|ë–Ž®RDZÈKQЃ‹/:°³Ó]­ õ•~¹M¯ÒOIöi Ë½ /ì5_áÍÂ/òêßd»a/ÿ‚ÀÀ×A‡?P²6` ȽåË,÷4ÖéøÇ!ˆGeزÀã@ðL[*·/烑‡s…á|X’ n_¬Pp3ßÜpÕ6èÇt'›3+,ÉuLôdL§MpU8€ÛŽì\Õá QÐ,ÂA7U[7Ai;êA©%2mÖp‚"ÜÖóHÖò¢Ïnk¶.×\‡Nã³/”¦ÖâñJ’5îó ÛÇZ§yjƒ9 C‰C>…a{à‰ÁY~·IVâÍ’m<1o™\µÙkuoÔkl߆73éÛYø?åWÞ‚qÚ³í‡}(DÎÊN3pM°æoAO4|õ¸ã«ÉkgÈ&Æ®¤À¬Çmé:ŒƒœJÖ—éön™eùäM °øÐTÐý)úž‰†€÷Vb!7Ÿ’-Ò…&à\WöïïÄHÚÇG =ù²ŸQ—ÀÞÐtl•_tÊ_t*¸è{þ¢ïí*“ïYeò½²2áÖŽc¿»‡ø\±NWÇ7ùMéñû³ÛÛôöøýÅ|°Öá÷R÷Ð|‚sá:ÈÝȤ žCÔ¨Ûß!Át„6­ÃˆKƒªÄ(õÀ°=xyƒ™^ó°ÓF#‡*q¨ û_ضtÈÁFìá9ÁN89¸)—SãKyp,°ºÃRþЮ™2y‰Ôm*¦W§(:D6"aÆg¨î—ÞP¿ÙŸðR?1ï£Á]·è¹)1%:nú< Ão‹n›Œ{êµõè´Õ¥Ä¢ÓæÂi»J¾øl”ß%ö„l%›,¸)cÖM©Ø±uµiÈKÉÞ,×á: 9þûhA¹®?S0çñJïÛùh;X¹ßAD¹êyH‹ Ü;†^EðÔ‡¿·iDßñÇAL(BC¯€ñ“à?,â:¯Ë•ñ§‚8D<ÀG+ƒ–ãd!ì@Iäf8xy‘su»¼1ÇLö‡N–ØaÀ'K“ÿÊŽ×)’6±ª;f…£oPí`ü5ñoTa–“±á@í<ËCv¾¹»KÖ·ÑG#,Ã$ì­–…а Mþl®{‡|uâí Ûž;Ï ÐpÐ3ÿ­?è¤@²ZÃÑ'\–\V–¹JB„ZR³X ŠIÍ“æ¤æX?©ÙX’¡M^¥6íŽ ¿ê&/J´„I+‡°*L™´Ñø¹"öª?K /6;³ÎÂCÆgÄ Ï¡ z":[@g+ƒg«ƒ×Çf,VšmçëóËÌ– –5”m˜ÌBFɇn`,qŠp¬ÇÿxXî¬í«¡šÞš’ínŸ={Lov›-UÎ\éyfwã µE¦Šö’åÈ}?môãԞƘ²£R}-Õ`Öº€{+ˆÎ8~ã ·Ÿ Ëÿ˜´óí,b¶ø¼ÅʈkÒy¢í,zÀDÓ7} ~÷‹˜‹•%Þi‹ãÆšDÒý c¼X|sÞ M‘+®'ì99º/ݯѾ¦üÃÝñSfz™Ùe&k®Ç)¹üߣt•¥è®Ç«ü8æž³?rõV$øí0¿ì|Õóât?ãAòx8ú_9aì—œýqÈNÖ ×€™)˜©œ%·§€ÑÜ„üçè¯Å#F£¿¾üzŸSŸÞŽpß6ùnù+ÞŸôWjH¯'ãÑ*]çãNù/p`ßNÊ+>äo?S±üáéóÑòïùEù?ß}GO”vÉ1HJΈ£Ý#zö‡twó)úñh™+žCú:ù<çwW&íSãQ;ŸàPùÿçýCöiñ>¹ùÌÚ{å&¬Çé!ó`<óì³Tçè¯Ì]£Šýgõ å‰+…ˆþ ¯Ü'Znõþß~ÖØ¿UŒzhñHŽ˜ù“ã‰Çô@sœZñÆŠŸP÷(&/5Ÿjà ˜WäQwWÜ…·@|Jž­š’ëÒdýOìYÿÖú¯l­µþEeC0ÿƒ)ý£ëÜP/š£åϧÀÚÈåÎ9¡Öp³†ãIJá°íqRg8Ž• Çq†ãD Ô1/=±'ϩϬ٢>&öãDÁ~œØ±'*ö£pîôæOjFNˆɯe-3ÒúŠS¶&™¢^%sqâØ\Ô1ML;`LÇØoh±_À~:ö›Ûüð—À?@ƒÿVŸóد˜->Ç~­Œxïc¿b.úûµ8îûµûâ‰íc¿ª±ßê¤éMœãدùS²Ö¡Åc¿îc¿€ã-vc—wÇØ¯­Ø/ÅÔAÅ~)ºÂðzÙó]Ç$¡…íKì×êÈëƒûµû¥xé‰ýc¿ª±_éÜéÍŸãØoë§lMÆØïob¿eŸ}÷G׆€Ë'šã+÷Ëïóhã߸ påtãÀ7‘ü£Áêlñ9leÄ{ sÑÿh°Åq‹£Á[ê4ãJɬ(>X+³zMð·M'‹yP9 ¸ñ ƒioÒªÛîÖF.·áPm-÷ÅDc¹_7Ëu®Õ P´µ >1stâHG°Ð‰‰ñ6›ý%Ëx)åLq]& Ù~¸rdd¼¦FH$ò1,8ìöÐמkí³‚0• HýGQç‘b1[|Ž[±f¤xëÿ¨b¶øyj˱blV=µVÖþ7°L. Ö<úBݽîà¢/Aþ+@j°Îõ z ƒ–ô¡µ‘Ëõ":®Æð¢/—ÉÖ^/<¡»A×¾t·ýQË ¡3¨¶Ë[Œ÷8‚™¨ú(á—µºüÇjçΊ˜->;+VF<?Þ=À(¨Œf€—|·l }ØÆ@ ‡ü·ì ÞÄ$Ðl‡„”™Ó†HJ\’ÕcõÝ!ÉöàiË$bfpM“¶T'$vЧdŠgÌc»¤~Š+š¸]$%.ñí…ˆÕœ ù2ÑÚ$`Û°:Ý…õˆ§{¦nä—]Lˆû$q#ê¥OR wÀ¢cЗ_‚ýßç^êLI,û™õѪ7bR(F}´éµŽI-z#&…cÐ;·çU ¼ª}×›!§mÃišo—Ûåc몦<¤Ûo1£Zo~U9Ì/ȼГªUâü·¼ãnQà’à|v \}Û^v‡.7¾0”„h}©°ÈWëËòØí¥X¨9Ü$kI¬qmSTÅZª˜.n˜"¥º©O5¬\&ä›n?ð«àÐ*œ¬Ž¼ õ;ø §’ÔVN¥¢UÙ K×2y˜Ëð2!˜(œÈHu’€@ÿÕ¸ Úw¦ÇµŠ|šß­.·3øš|‹ùæ ]%àÝ™B×)ôQˆx»Õév/Wë\ÈÛ8§¡TÂb9§¡Ä%>1 ^Ââ"µÑ Ò _ÂÒ˜áiL¦–¨xermJVô ½½´p5'C(7©Í4C6…c¥E#͈IáØhÎM4U=àØ [‚aÞar?ºK ¹5Œ>“BÒüת}t›TdUE;ùÒs²ƒñËÕ«v×I±Œ §ÿ$«^"âê¸1ƒB\!iq[°Ê[Äí`üW,cÃA\äá½Ù|49jSN- ä ‹’¼‘Û¥%…ƒÅDŠPbPÌu'Í¢`$/–ÙÍf½No Ž HJ2‡ %5ž Åæ€%ã÷,Ý^%_ lp*å0\³Ýaç 0)þÙ*±dË6¶”7«T!€ì¨¶1`¹ÍEh"%Ã1›1E1B¡ƒ M°4ù—}Ä$šxäm0ÂæÀ-F!89Žž_Ÿ_^¥÷«oöŒÌXïRá‚ËØV½Î“îÂ?S—¡Í4îÉx­áÏ&¬a›²þ×·4ðÇ×Ò{ÃN¬Uµ°ø8Ü‚†Nsßû.ml×qØ7l¯å:ýº3÷Y¨»÷Àc¡¨Ž¿Bå¿B¤ë\+Ö2ª¢lhÉðAEZ½\_2€ ã¡Ð²5,ÿäb“Ç\£‹¢ ̈ÅôRaþãrOŽŠŒ=>û*Æ<\wEÆŸ= c¶ë´`4¶ß‚ˆ4÷\˜û÷ÀwaèŽ÷Â忞d†Û“ºT÷XñGyZ¤@®J9€ÐñeXY–7óëÆ¤›`ôe”0{2 %ð:]g¿¥ß‚Fi@“ÿàÜ“#fŽÏ.Lë׳Æg÷¥õˆí:/þ†íºÍêî=p[(j‡ã´PDù¯©Áö¢Õ}Z2|Q“ÖF/W™ è¸)´l ËI¹L¶}ž£“¢ Ë€Á¼“2dtùÉ=9*bæøì¨´ñp1k|vTZØ®£!pØŽ ÑÜQ¡îÞG…¢v8Ž E”ÿZ‘l/ªQÝÔ§%Ã5imôr•ɂޣBËÖ°•ëÍýò&z*z*ü«‚Ø22C üÇäž< w|vUÚy¸¾Š„7>;+í‡l×[A08lwÒØb/ uû8,4¹ÃñXhªüWôhûQ’[BhñðFcÚ¿\}²À µ©…–±z.Wéÿ<¤™ÅTË@aó‰uCÂÇYL–ÿ8Û§"e’÷Þˆ‘›8% xJ„iXxú‡eÄÑüÁø9;qS‹9>ãeëÛÅI(,ÃÃGsßžº{O°rpž=E”ÿÀI ¶ôTw‹iÉðI­^Žª èBëð<ú6ç´^,o>ÇLd=*s'´–…oÇt4+d¸K Ö9Ý PߨkcÀr¸Ebþ1ÀcX};‚uŽ_G¯jø(Ãz˾ /[ÃqM@YŸU×<°â˜ÐËÔ‡¥¼pZ½ÿ¨%¦OYLŸªÇœðìPžÍ`:WÚüÇt÷y)küôp,Œ·sŒÑmFÊ”Š·1³oïÆÂxå¾ Ò UÏf*žÄ ™Ä©¾›ZAצiœNãÔÀMö:‘#ÆŠºÙM6Æu‰£ÜTøsÚ‡³ªí±¶1ª¢Ûªnâ ÊmåˆòßÄé-©ÖÄ(¯ÝV룷Rãdk8n+pÈÑñÀ1§ÖYN 1xhY5D•ÿÜK^MÆ?ýN+#jnMÆŸ³kÆl7¿†!pØ6D¤¹³ÂÜ?pw¥Â¯a8,²ü×Ìp{R”ê†?+#þ(N‹È):Y7VÖ†ãÀ×̲3oUœo•y«ø?ƒÊ½E?È€9~úAVF<Ì œ²GáM®õˆ‡š…“1Æç<œ…1ÛÍÄUÚ=ÈÅEW/7@·B–ÿ†O®³®í€í&ãà ;w~mÑ/º{àN Ç«a¸(Qþ+Bj°Îõa-£ªmô)ÉðA=Z½\[2€ “u£ek8. p·lº$1áV…ôV 7Ö£T¶-z6ZœñÓ³i?Üa&ÙÔÜo2lí†;Ôôš+>çÖÚØnbsN÷ «UuËfpÎ*G”ÿ¶M_Îj#£¼vV­Þ²³ÊËÖpœUà†_lòᘀkL¡5ÃrÉà¡eÑUþCr/‰4süô8­Œx¨é4c|ΨY³Ý¤†ÀaçÕ‘æÎ sÿÀÝ• ¿†á°TÈ @?ÒÃíIQªþ¬Œø£8-RP£HY€Ðɵ±²6¸f–˜˜p«â|«„[ÅÿTÎ-úAÌñÓ²2âa&ß”= oòo­G<ÔœŒ1>gá,ŒÙn"®êÐîA..:¸zù¸:¸²0|zsp˜å¹ƒÛ Öܪ¬ ÇÁ½ÞÜ/o¢oë£o §FäÖ¢9 âáè€u×þ¬„/~º²m;ÖJŒªè _RÖÖG/W¡Úùj‘l ÍÉ=;{NÌ¡5g倧91þƒhon‡;~ûm‡lâpÔ%–Bd´B¡r€&hI•ÿÐÙŸýYÇ%ÏO[C·nyRò4$LÝæ ù<¹?{Ì–¼_™ j[û“‚O8üwo^¼ûéW/€”ç6>óÆQž(×HJˆ)Îýn ùûO4 ºgYÎPb ek\ qþÄCòŒz̵„ºÍ<•Ù7›uÆE* kñØ1*ãmÀQ!§ƒ“ÞVÄî€{Ï¡có€—ÐEúåÝûÿC–Ñ-Ì«B Ÿ+â´ú³LÁü ‘b É!‡`àÜ&²Ã§æ‹tB]œÞlnSÒž ?Kì?~?¸¹Éð•"-jk@ÆÐ€àß* bì/äÏk>vØÒI…T€bAÔ|K«Yå€ÄD술U¤u(Ššõ!Æ!±2ª‹™X] ;°®˜•|9óeFørÊð…ÞÈÖÄS]îœrç´f3˜˜G§b 6ƒ–œú^Ì©S©ïõ‹½*æS‹¾7dÑ÷µ^ßw^§`iÄØÎo.õú¾>:H©’° ðã ˆNÁøq w.|ïcôPx儹rB=˜ûaÓSm7-?÷÷õª˜×ÅÞú4€È¥£Â š;CYÒôDÏ«çUÏKß}¯F¯U{ÁHV¬¹0Áé“î#“vð;€çR <Ð?¾{À÷½V=/üì£emÌâ[÷ÑRÐà®w©U)Bó­Jµzýa-?®ÓÛÑj“sw±\ߦ_Kí_zWÉúóh±?Á—åè‘"üᇿ¯‚½‹Ò¸Âïïj¾¿7Ÿ0œ/ÈÅ#}y mÈxDz ø¾0jô)¸G”púô°||1zƧôæó<_@)˜²âx‡£›Ýft.^$`Ž|÷Cþ¼£œ<æó;ø9õaNþ~éÛ³ÿ:?›__]üV%ž#RCÍá:::̹á5¹èEh•; ?ûïèaŒ>&«]ò¼\Û'ÔÂø€V0¦áv™Ý'»›O,¥à'¦Ž“âBx¤ŽrÀ/Œñ~ÉAÇäÍõX<×ÄPò{ªm`ÀØŒ W¢²/Ëü÷ô22œÜÊHG5F£Ëßç¯Þž]ýv~äÆbp¾$#¨Ïó¹Ý=l×ÏËgí<û„{ö¿ÿ‚þT#ßöb3ºÄyúð°¾fèèÃf;Úä+ +¼®˜ïÕ{%%ð¿V¾|d>ØûQR¥æ|À5S•'C¥­!×úKH6î/ÕqÒwoÉú؃MM×qÂÏÄ´¥·MK“ñ<{Fa;Ô‡bË&&§›íŒËd÷©3[ƒþ\üì?kÁ@™²JÅÁ®5PÈTüeøÖ !10‹Åΰ£ÕÒÄÍ0,ËãßHoë|õv2þÑ^mÃÕj°·‰•p¯‚ñ:íÌ5F-SsìTÍ€-t­+‰ÚA£ÊGÛV3LÖc„N×^.ZˆæŸe¢­tÙîöÙ³,¥µûU+ú­¤ÌØÄ<Î¥aLý ÷¤7ôŽïf#ÏŸƒ X°¸·Ikã5çìb‘söº0c 'Ù6dâšmBáRèݬ툩‘+Îà-Ö,6f[9œàVcñä£çé·rh0bxWí'¯ÚЮÚÐ̨Vî2IÄÛë²ÇÅ:ýr·ÙîŒw]÷…—àæ‰6njÁ¢ä°W=È‹`ÁN vM‚«#³ÍâÚJRlYá×Aà¥úbÁõ{ûŠÿû9¶¯©ãEÒñf‡ò7Á>%Ëíâ÷7o(bÈ- Ž;ºÝé 5Ö,ív:Ñvw<ð¯Qßõßù"ý<¬vÑǼw†æáS¤…jòvBÂ^x÷µœëÑ·§åÍ?Ï¾Š•ñë«0.\³G_×~ýyj8Ñ›÷ÌQ‹Þ|\$‹$zó¾IGXÞ¼È@³çË‹\eëž<õu?Œ*,˜ÒVª"µMe+eB²%µ§ 纰‹†âãAµ2õE²K ‹9Û˜¤ø÷ûd¹-æñ˜ÌÈðÿ ÿ)«ðŸjíJ”"^h ñu¬øjñÊ`Om¶;´-²Kˆ•vyàÒtòx½¸ Cˆ}ø}œ½Úd»ã‡Ëœ€`á›!ÎK§¹„Wz3—,ãx—*ÀXH¤67q𨗒ñ¿µ@#;}ï-Ð ‰°¹€è°l‚‹ù|àS:»=ÝÈ~Û>« ÔÎæÔb¶Øœ`%Û|mçrcâÙÃîÓO Ì„Ѓ"|ÚZñÒ¤yˆŒ @s°öMŽks‚¡í¢J°bÝ]/ŠuÇÖù:h¹ÔÄAÞÔ¨NÏŒF4œCÙ¡²´MPAOºÊ?, À–ÕѬX,¥½ÅÕõÕž‘ËI®[÷Ôr¹ñ»õÏùÝé-¤(”ƒkkÝË>SZ/ñ™* ‚±Nî`ûâ»Í.}},¾SÄõïCé®×ÀLß›ëu1üd/zë5pÎ÷×þðÅίTõÒ«Õ{-ì®ký4\Ó4%~_^o¾¬Î»J¾XÈM§âÛäƒæðöžѰ,Ç!jĵãìÍrm¶ÅÛsƒ¥Ìûø4æ¹ëðt—*º˜H”NxšÜbÉJƒ|­\±8îÄZ ‡6ÉPËXX:ߦÀ]}†ïxQ‹[HÖ C aj¼ÔE Îâ:-xQdUµ+–‘¾Ë_:¿\£À Z#–±Á•Æ$÷o²nü†ytD¥-€áœ×åš5Nñ±)º¼Äi|†Zyå0ÌûðjÙÛÝs_ük£–z smwƘú ¯³‚ÈùÃýýf»Koݾ #’Þª9áëý­áͧïò¯ŽßÃŽ'*=Q÷™sªK8´„–G}ÏkuH…8½%ªí„ˆ(ÚÊ9Õ¸Â×t2Ô*9± o®ß‚xMª/qj:ÝWéÿ<¤™É–”h¸t½ù¤˜¡™-U £Ñbʧh²yøR~ún°tFCÀæŠ O+àŽ¦JkSýöf“Üæ,ì¾N‡:ÎÌ‹EgW_Œti¦X¡êç˛ϋ¼üiÃ)åðÚÑQÁ‚V/%?hüäžޝO{Ì8ü(Ééîw[Âm6¼ž‡÷çÅË«|ÍÃ?æ¯Î^¼ûÓþqàü,œ0j€JsJ໚”´7u'ìÔUP6uøÉÏŸ^–¤ M1Kò´9Kr¢Ÿ%@xA¥lû‘±=b¼¥ Õ«â)Œ´žô'´Âhè  =QoõǨº ÑÂ`bgabîšmþÓséôäŸ&Zg­m3jZ/ß½¾¸~yµxñzžÏ°S¦FApЬè˜gèÎ6«®÷ÄΙ=¼&ËW¡híé¬;Çú½Ž€Éª M× P¶iúj·']níUS^êµ3í=ëœ.M'%4…¸‡X®6¹Ú],×·é×RüàK@”ö*Y-¶à'ø²9$b?ü0zÊ-ö.J¤…ßßÑßÃeˆ‡Ä?áïèRÆ8#CB—nv›Ñí2»Ov7ŸÈµÿæd¡ Ž—‡Äqßß/éÁ\<Ò——¤"}DÆðSŠ<¤5Èî-ɧ‡åSà[Ñ>¥7Ÿa;°œYÞÉyļ/Æä"ÌŽïr>?å´1ŸßÁÏ©sÚðKßžý×ùÙüúêìâ7›«`Ün`긭E^­ nö5œ bkæÛZ _—ÂÄÆR˜K\‰>Ⱦ,óßÐËÈpnÀÑŽ'Ïð£.Ÿ¿z{võÛø‘ƒ>bp>-5a–çùÔî¶ëçåóÆæÏ‹ž71Þ ÷¼ÿý¸…ì«‹Íè0 ¬Åë`AŒ>l¶£MQ >×;+‹Sˆ…êðÄÃá˯Ò,Ýé÷Pã·éö8‰G—Cwçãì/â˜NÆÒÙ¤èËd›¥:ëMÖâÇ^óNó­%Ѹ<|ð6É*q:ï—+$ÂÝrÕ‹[úÛ™¦Žw¾6£±>æD؆ ñ¦|œRß©ns×»:öý’î^m²”~G—ðT#Il¢…)ÊÂÔÅz±”ö@WÆR˜ÈÉÑ!–š·µYO2×*‰Or­›SÉ ‹Ï7ww›õù§dé¬|LovpÎ;¸0±Z¢üúêü"Ý}Ùl?»˜»,Ïhs:P¶üWºØuX´,˜dŽ<Âßï1‹B”[ЦD× L­äë\Éù‡. ••˜%,í­Ê]?5ÊS -W‘I_ ZRJ\j–+&”X©O¦áSçRú>é¹BR…Gã”bi2ÆPå‡/í¯<Nøñò’•–.tîw\cȱi¥uþ÷:¹k¿Ƶ:* q­Šå.×±ÑkŸÙúÀÅŽ3¿¯CŒ£”T)ûÖ%žöÔÈ®Ï|žîˆ¬ƒÅœÃ1vêp¸ ]–œÁ•ß¡z %!îb˜Ú%ß:F¡=¿ Ž5Ôj4%U߃‰RkM7ô§c§éÁ‚fYàÒ˜lœ°RÒVÊö’rÏkÃËî¨ëÓD<†Ÿ°È)}}›3rÒ0ÂñG4…@ û|Ç@›ÃnA$"{‚ ·‡ ÈÁð#šB ˜{¾# ÅQ7 áãßÙííeº½ÓÁ¿›OÉñO÷àù”©K`ã~;!Ð|@€xY(bÜb1wë@ß&8Çõ@V@Mã&½Ð¾E—%Å»¾¼¨rÑêÛbŽ~T\a”§J “ ÛÂkÚ÷É©˜6Ü*/cѱ*Ÿ®èZ½HY%¤!U¦!UŽß½!Eñ®/CêÝúÏO‰aúó‰äsºµŒ½Drþå¤îË©ôK=éÐkaC±çŸa‹ª vó<Î`;ÌÐdRSÑFá ï¼ÎCÛ³8 ­7ÅÍ)7OñDŠÚkÙÅoiaŠÆŒ‘¿ÕO5§xÒ<ÅSý)tî©eW¥wOSl4f¬Ä%¥$HÛ‰ëHŽ…OÄ‹ú Y¨:^9a®œÔ\9e®œ>W4ÆúŸº)8Owo7·¹‹»ge‚„n[G%»¶ÊÈø£afd˜ÉÙçµmfyØõ5‚…ˆ ¿FÐ ~ù˜Ú,›.ûYOF­û¼Kñ²| ß² Ïæ¡!½nm<+1´Â5tüîÞJ l×0[RÖhëè5ÔZ¸li—•€1‘€‰Ax½–muþm*cã9 ±0íÄ'\À”B©—ÁŸ£ jåfA;YWQmõ”V5Æìv±z‰z%ꕨWDF|#xÓŒwP KAúlÔè[IýžÖCùТÕc!ˆûJz/ÿ‹'»Q^S¾OÅ_ÏÆFñ— °g±ø«|ºê¾šÛ[pŽÓvN‡6^Õ‰ïÔàÄÁ‚Êùûkä%6œ§;¢nÕ»„™D1ópg#ðëq–û Áù~˜wŽ_1»XK€¶pÔ;sÔ!ö¢Sô6Ýà[tYÂ{D`ØÂ“ylÓ2@ <€¡çÿz^v"å˜×…'vG-.=Ùmñ(ûW0zÔ”%\aH0ÁéLBÔ; ,±©w$€DV”$×%òXß%ú *@ ê¬9mçGWi s»C‚ªü»jSËò·Vü=ðœfs>%½4ßkÓ)Á@–L´hÉ!œ½Ë /yWRу,iöªEóêª[mgdÉ­›ÖZn"íö@Dšëö ‰@Ld9ºNA±S#áçÍæ©UqŽ™@¨ ÚP Dxj*<ÙX8_¥Éd!œ B£ "Â\ïåøÝï¦x××>àŸ—ë[0‚ zEã"Á­æ‰Ó&f*á µ‡7¸¥MhpázQvÏ«ÌäLôºÆÌò°Åf¥²&$Z»&å4H¿Á¡Ëem4¼¼î¼ßKÙ8hö»Î7Bs§ÐA9‚²9(Gn±œ¸ïJÊXNìG=al¯ˉƒ.'Þ§¢ÚŠa£¤¶4²XPKž­^N«Auîáë»L«>PNQxYUBDôŠÌ:×KÙçµWdyØM^Q¾0èŠP$5zL.¡VI,ë’J¾û@˜M^c¬‹ ṖO˜„ˆ°m6L€u„¯|ɽAÄÉ~Í«ï{•ÞE„-ù2Âb"Â!¬”{^#¬ÝQk!,‘˜ˆ° ÅVp“®-m½·]wû–Èl²õ¶äçw«[ÔÙ>Ÿ¢ º¤(bµV×1Ðk¸¶>p1bëM¶ç»ëxæõ†cëǯ¦ž)ØÔêî£â¶¹[¹‹·ª¿¤»Ÿ>|pwÓ9z~”á>ôº0+²‹á÷·÷ ˜®ÃÑùFÌd‹u3艊•3–÷-¢wŸoÖ;WRQTÎh&ÈZ ¤0pÉ€4ô'ô¼ÉJ~9~×ê3ò¼Å|®œVaÖŽÃM;s†.“mÌÈ“²ITÖиД,æMÍ3à[ò‹&üE }â]ø˜óªŒ?¿ÿy³½ ¯×ÆÜHX»i¹Á X½é°ûF“xoŒ^êjÍ88œ h+V=Å(¸Êë]. ;5ÜÑk»Žo1äï¾€Ñ ¹2ṂЉÿ‰$ôXÜú':0n е6[Ƚï)3#ÄæÊ”킲: …Þ0i.p¹âö‚Án/(TYkÃÁÅïoÞP„+^7§Äæ^l:C4úfB³kåû´ CâbØØŠ! GYÜÁ¾Aq[Æëõ§t»ÜÏHY±*;ŽU о˜1£ö;H¦Â!›2â’ d².:&íæTþè&¾%…â°b\„´¤¨á4Âi7pÚÚ¸a=*UXŒLõí~ÇÈTŒLU—v ‚2^ˆFßLˆ‘©`#S5ÎèTMÈb„ªúÅ(ÕUšõR÷ØAy#OJ˜Ž<r;]ÖX¸è¤1óÙí-†Qgæ·iV‡ý}kô #ÌEmŽŽÌ–ÿJZÀ†‡GReñÇ?o¶9Àg×é×]p‚RÐâNBèýhjàEèê䑞T6uùlôq{þˆÕA'ÒSH <àŽ!!¤ b‹Z /½Þ¡f{ÜIõ¤èÍñð€_Zæ[Ó0”«”^áKsN&¯±õvË4¶}ÍÜZù¶Nª*ߨv£ÚÝKµ«Å=€®õÜã.;qì–wi¾"àçSðÄâƒò™oé›g& kÞÆ£|Å´ú¼©p,3ö¢™m\Ÿ±¸>3ÀõŒöªŽwÙñ]–]'ðØÒëÙâž÷ÑØ@lñØ$º]Fn×TŒt‚tSé°šjƺ©.ÖM &pÊ1‚(Ѻ=åS!æê£Þ´4…fbþL fŒ}K”v½}[Q^MÜ™pgÆqçmÍ:áìÛYoö­þ ±qTÓÒ~“:S±o5ºàp t˜ðc†WÏÜÚÈ]t°Ñ1¾»}¿¹U?éÛª÷Éx·b—OY»¼üvy´Ç£=íñQ´ÇØêh»´Ç;4Ýb¢õh™fÓá5>î¥p$‹•#ÑŠ†T4¤œjWõ$¶:aøÞí˜7f^3ÓK=J R¢6Ú¼-ÄûŠå½›Hw™[h»…Öˆò1åEùžßÄû¿u6ŠDŸ»F+;EãIòN¶ŠÆýã:«b²Ïz¡câÍ`ÜtB® ˜Ø@€ID£U1õQºSƒ^’ÛÌwB® ™ŸÚù©Læ§QæëVÅÌG!èNæ½$·;™ï˜\£u=®ë²¶ÄkÚmàÝŒb”1ÞÍdxÇWSG¼cVÅ©ÐÞyInwx×1¹^ã´O…´—ÛVü&ÞØŸRœ2ûÓU;6ØhzVM· ž:iûT¾ƒ|ê´íS§¢§ÎÚ>u"zêiÛ§Žmö+®Ø:î|•&[·gHwÐ5Ž¢"̆qî* гÝ)î 2ßNÚÄÍÓu›>qç«%`)î9(>0X²taùÛîî%gP‰Ï="-¸%^ÒáYÓ†)·Íl±×v¦Ž-•²ªuz·{¸Ö-剄Åò’T¾8îÜ^A½þS H€§·Ó<²!Ê 'ÕnÞ‘ÀÈ1ÖýM"š´@ºže͘°f††Ð(ë›è¯SW_Ç—J-9†‡ææ|JÒrq¤ÕAc¬L)AC<¥üù@œ‚8>à^%­~ïí¤ rı`±ïm@‹Z{M»ÿõбP£ÏzE¯%ÂGÚÇbÚ‰}â7ínvxúl%DdçäÙŠ¿iõÔÙµ^@ö—tw™nïæ;gñX’òÓØ©f£- 3D[Ž_Õã¬kf¡éwâíK̃±…NqV`†C áÆ%2ÑÂä.·s‰\Û°uÉføU’2t–ýͧdktŠ'¼ÑàôNxDTÇ[:1P˜æ²$4YÁ$¸Ñžp¦k‹7\žÛ)e œÃV;¤ÈÎYâX®‡Ô ˬq¿#\ó*˜Ï® EÔÐ„Ž³ÛÛ%B†L‚»¨®ÿ !eI— Qî” J\¥w%J>„Œ˜„ˆ ,q€dE %æéîmÎçßÖ›/k¨€#6 x£TtRkRÒŽàá}pÐ@ÓÐ/>ÔŸ'ìêùƒ»H`I¥()3‡Ôjò¥¸d—swå°HƒáGiV`IG‚ —72ü[úÍëÞo݈pN5îò¢ç£ÍÝ ‹ºÄÌ󺳛ÕA'¶n<ÑPnå&Å+ß±å„^oî—7{ˆ}î€ÑŽ?âŸ)þIØç;Úv#"Ù|÷e­·imHP‰![¢„‡A £Í±«Á#›ýÁÈÉ.ÕH¶,Þ$êÅ>Á›ðWÁ „™Áb& ¡ß@™áÅ|¾€“ìSP¬†G<¬0+U-DÆ.nY¬¬\kÞÌ^¤’‡ Çg{h2Ñäl4ÑdD³ÉÔlªç¢ï†S£o4ñÙ ãéìa·m1ÀúíQ’3p!ࢀš˜QÔçPG FÑZóÃ|z½þ”n—ê8*,È)ŠÐ`Æ¥.à¡fÝùWiÖÚf𬥚Œ¤07ïɨq'åe©¬„¯:«ØnçµÜ¾ß%7ŸÒ[“ÖkCÐk BUd Qs)²¥#K¶XJ~親|k5TóL-ñ¢UGùÐÜó@ß8hÏt›ÑÄE•U›võÙ¦§ü­B­ª qñû›7µ ô–Ç&=6é©ZvºôT½«mzŠÇ+öé{"Ö¹p~X~ÜCw‰°»DHˆî’"[ºÚYD–’7îÒù6Mÿbñ”€!×OÑdÄ*C69«¢bØðb™%ïWZ˜àYøSfèÞ}Ø„p­¯ÉËuàËæªCcw¿è0ÏúZs¯×7¿n–ëëíR¯bÔ³•G“æú£)p¿ þõµaÎt«‘%$ÌõÈÒÐS½ÿ5ùKº»Hw_6ÛÏÎú4¿¾:ǯ¸È ÝtlÆï s¥–ãW]¥ö;63“&kÅJ1Z°œ!Áé—Ë |9¨q†%Ù,§ûÝ–´Ic“å›ÓáMóWg/ÞýÙ}3ç×™Qµ6ò¡Û:ÑÈœÈØþhÁÉE@BQ×–˜æ°Lì·´Üǰ÷mF1p›QȒФ“àZRüo6*eL/}Ìá2“„; EÔÐ7*ßÁqæä¸;ü¦Ú,Çߟ֔ڎ„³µ«ßóÃ?~A½BóÉ0)Rt®? ÄÆD…–\ Y‹–TDEªÃ›nt©FÈJkT¤@Igêí»¦0 ƒ@Ñ’õöXe¸Dô]eÛ¬c•­§U¶kÙÎQ˜#Übmùt½£0Ï7ë3‡xþeùvhù3È}ºý{nYÝ>{v—Ü#³ê¸0ÀÍ?æÿïÞu.¹¬÷\’à¡MñW-ÿr°N¿Ô¯ Ö F¯¬½á e"³‰œü¶Å"¿í"vY;˜ß¶Øc÷úâúåÕâÝŸù¬>u‘ßÑ;EÃÿÄλ`3:ê'c¸Nå¼ 5‡2²É³’»¢•š«´~N[˜«¾Ç„~Ñõnô¤&ÜAåÈu@Ö™ÝÅ)Ç‚dg2Q6‡ Q(´zBÚ— ùìÕŠ â¹½šÎTÂÃVÒS7fÑ/Úg…¤6ÈD! ˆÆñC}) ÀÞÐu†öù4!­ÿòš%@ëš¾d±xR }>Ip¢PB¬üã!Ý~;ø+ºè¯äÒÍ´|ÛãÕËŸÏ/®sóñ´¿9|þ¿ÿ÷h¹}I²Ñ Qä†"j \Üòéq‘åd¦€WÇ£üí–Ûl÷Ÿ7ùÇÛƒCê“Uºþ¸û>ÊŸL7‚ ½hðÉY~õÇb½9È™p_Ü‘=.ƸAqqSñ%ÆZ,O>°Åùï—ú$Dx= @>ûÝ›ï~úµ¦ˆ <¸ëª˜‚‚ƒ ü„59ì wt¡ T¥TÑ „&ï,˦(é‹q?ù‹«Gsœ)(U@s‰åòô¡Uœ|D¸°A?5\ôÚö±=îÓ§(7!j)N†U'Ø’5Ó™¡rv{{¶Zm¾äæã&Ûí=³ìÀ` ~}›dŸƒd–wQ×Aáq½åN¯†ÌŠ9‰Šx\ÇWé]ÄãYv„ŽÇ,5𸉉^ãq'ƒ×ÂcN¢"7„(@Å2Å0­P…7U7Z ãUÈp¤DˆªœHŒ“Jœ×Pâ¡ì½¹Àpƒ²‚[ã !1œÖÂ\hà¤×ÖBcoVcÅ+šMÐü˜ëâ¤? à Ù’€ú M°V.Š„oÈ×脺ž„ìAA$f(Æõ\¤ÞfßÏ?/ïƒL—`rzÈF6—Dj—ýÙ«‡”²Ewu%üQ¶ÖºýXiÝ&WîG µG¬uÁ™°Pü¤*wŒGŸˆ§=Pÿpti妔-|$¶ðdt@žH!PD¨ª,„I“A@² æÄ©õ¯¬Pzóªº"jˆ¨!öBC@£cTTDm,D“IáIˆl'²âäp²½¼ˆ=Ç~Y¢BŸ~ñ †½‹‚9á÷w5ß߃›O ·8_'ðÜöâòÒÙDèûˆüòâûk@ Ü#ÚYnŠV8-¾îŒøbü6ψoIù‰˜r‚Z~ÓŽ^„Ö+PƒøÙGc"%dÝ¢Kž—«ü„bÔü°–Ñx0 äÔ{–RðSÇùË…Dðûj¢D0«b¼ÇÑ1íåozUý¢‹ßß¼¡¨U ·¤Ø9å6°`l Æ+ÑÙ—eþûzNn¤#Œ£ÑåïóWoÏ®~;?r±:Ÿ˜ïæy>»»‡íúyùÌq»g>åžùï¿ ÿ•È¥¸ØŒîqÀÈúð°¾v!ì²ÉeiµIns{âoÌ£±/[Ø7@’äæJÑ£ƒ–7Õ‘1ø¾BªÛÖÍ蓆~ÐÁÛ•øU£×ùêGâe“4Oo“Ï)È3¯» ƒ «&8Q¡eO¢Bw`XÑÕøÐãDuÕ E_ÛãÅ/)8"ða•f&ÇV›ñ{;?U£3Ìò¥rüîê–J=\Î8B/):=–Zì·…‰x ïpµ¯°" Z¹‘( þŠ‚ý-¹¬@ˆ#åÕñò“Œ1ã¸*<ˆ›îSôP` Û , ‹1ÄòéŠaijÛÛ‹t÷e³ýl³Ê°u ÆÚÒð6mÏ__c‚õ-,“’Ã’Á¸’ÿ…›0^¥á•–—$Å h¦‚¥ ôºœÜúÀ¥µä^÷•¬cƒ‡m%- c¹IWIuéÝÅ;êûM8Lå0}&õª~EKóêÙ x?¦nï·q1Ü`opê–¡%j\#ÛÀC¯•nc—ê]цoV˜â¦­Æ~H¬G¥WVOkÊ„4¹gÔçðJíyé>T¨îÃ3Rªµ¯3‚Ü”Ük¹ôzשf§ïk¨h¯Ú C(b/ɉuì}G`ªcg ÁkúýÏKÄZö>ë¹+5ÜÊÞ±kŽsVB®ÑDC.Ýß§”À•°‘‚ä|,¦ Ê§+¦ ®Ò»ü)&‘+ß|¥nÚ–Ì Ü;bh‰’w\øHT‡?jÑIü"is²n<›Ÿs< !ºÝ*Ál‚ctS”Će-¤–^‡ºí¼)ÐÍe&ÅÕ›´ˆé…¿ýÊQöGÕ#‚œµ>…'Ü?¦7»Í¶¢ñœV¢ƒ­¬&ôWZ]?µåÖ÷í‰f>šÅæš–Óü«]5د’l~ŸÜ¤?o¶9-¶Q s±7XH`˜Ò$$¥?¹ªkê#溻ĈÕSÆvð_›¥­ç«%˜-RÚzP|p(¼f*¹Æq)lyá´z!ÿQKYŸ²²>U‘uµ"xæ¤Ý3­î}ÁVÜø’_}¶ZÅîBo Tðd °FS¦@)}ÚxÈù))'b½Š”5ý”¬ŽU+-«VXë#®Ø.\‘ ÑHˆFB4¢‘вŽEAz«û-eaU_¬fj«¨¥¢–ŠZŠ“#(ö…{+nÁ¬Šõ-}göb}‹žXßë[b}K¬o!‹õ-±¾%Ö·„RãÑ’öXßbüÜÔ·ðQ#K%.|ÆR• _\b·Ð?]½Ö,×££Åc©‹ëR4W¬tA„Åè itPÆ?߃ƒVÇrKƈXå"ãL?E.cKËÆêˆ%.¶K\¤†B4¢qƒQ4Ì«[šU ·Ú¯ßâFçÅÚ‘šŠê)ª§¨žèåoÂ>âooe-ˆS±ª¥ï|^¬jñ#¯«ZbUK¬j‰U-äq±ª%VµÄª–P*;ZÒ«Zl€Ÿ›ª.\d©¨…K¼XªiáŠHì–´ ‡ëV´\lrW6u-áÔµ lu "/Æ ÛÅ e\ #Zhuôá§´dìˆU/õüé³ö£t¬€±RÃX)±¦›:©a‰hLDcb„×C4&¬WÉ4+Koõ¤µ2ŒvŒ3r…YTdQ‘Õ+2s ö£{®§AüŠU5}çcUy¥XU«jbUM¬ª!‹U5±ª&VÕ„RYÒ’öXUcü\VÕp%«µ5\JÇj… WÔÒE z…zµÍÛÍíÃÊn õ9FR©­¡¯™ušý¢ò\u©±†š›òÂYõBþ£–!Çrœ)†Ñã`#úcXå9ˆ¦‚4 AÊøç{ðÑê¸ÅaG½©žhNõ¸yª'úS]—i“±¬’c dªÆÕR5Â@]‘ŒWÍÄœ™ÎÌŒ8SÑ`Mœ™pf¦Å™™gféc¬t%‰cáǨî ü ÷*a!¼rÂ\9¡ ØLr˜¼_+1ÂÂvJ¹ZÂ>¹ý–7Ú®Ñ^öj´WGÑ^ cª£½Úk¼±U6ƒ¬G[ÌÜ ³R3(3ØXýUÎK-§h1E‹)ZL£h1…1Õv-&‹vAØ&A?Ö€!à D5VçÅUÏɇE®ÿ¹± /VäzNnw2ïc²«¼=-@žE¼‹È~“ÛÞÅšc¿hŸ†LûžÕ[sáxK•Ö\­…¥k®”Ùnu5z¸V]u- ciµg¥ÕL+‡VWÇ­Ó/¡6x°=ô½IÂ(w3 gÂ÷±x¥§ŽaÔ[˘Ó[Éu}»®XuíæýºY¾zhÆÂëö…×–m´f£5­Ùh͆9áÑšõ ÛØ`€­PA¶ý>®ûZ“-5ª¢1©hLEc*Ì wU¥mb/„m*„Q¨í¬p¬Õ¯x9ÖjûLn¬Õ\æ½,^޵Úaëuíb¬ÕŽxHñr¬Õƒ\¯ñÎGÚc­¶ ¬wV«ÝMcìj‘†½ŠíN[bÏW¬Û~Îv»$Ÿ·[D‡Vâ¢eúá„M?Tbú¢ôKL@—r`iPM: ``ûÔ˜<`ˆã”ŸÝ›…êA=ð#_ëôf§'tÕ¸mUyá¸z!ÿ'RœÞÈ0eðB-„bHq—¼£3r,_N_ÆFu•ù3NÉ5p¦’ت-”+Jã I¦ƒ]g‰øüÂìq±N¿Üm¶»dE@F áÅ2»‰˜PÅš/áÃMMD-æ¸fÁù¿¤»7››dõâüüõ¥+³™D):¶œÚÂ4œú³›Å3ËßZƒ™Ì¸ŠÍL®uh6¿üzŸ¬oÑ{mîúíìÐs 2Ñ’4_péÛÔÜ&E4®…ˆP0ˆº·zFz]÷ÖÁÐÅuoM¨ÉÈ”Á±ç@©z!R?‡Ÿ à¹ÓÝfv`»|ʤz ÿ‘ߊÕD.î ÀYŒòÇÙUž'¡>B½K¨Ÿˆ¥aL¤aÂfßлŽk…¡"³ÆUËõŒ•þ>© $$Gah͜ƀ1  $—È"–ÝIÅ×)¥uôÄ\…×V0çšñr‡$ü(É@aä+ŒèjñÊPú´­·®Ë[(tµÇãX—\1n`µÇþãÆüðªSƒ-Æ5šè±x¢ Íç5íV§vV±$ —Ú¨X:ú ‹èç+ÝÞ^/ïÒl—ÜÝÇÐp4 ùph˜&#Æ ZÄ êéu¼ ƒ¡›…†™Š¡aORÏZ¡á]~ób‡æËRP˜®t©@¸ ܪ›„‚«¨¾»‹Àn ìJÅ1´­‹V#ô ¶Ñø8Èè‘¢Ú¯›u1èt•¨å(1`TçCDYØÃ9lwQÏ_¯Û]t0t¬Ú(óİ˅+n³ƒE˾®Õ¸ ˆk¾`¢J—«ôǨҪô|9ú­Óó†¨Ô‹ajuQ­GµÕº[µS¾}g»bÊ׌OLù7åkDù‰r …tßz“ìKÆ7ÊïK:“èD†B»o›Ô´,ù–AØ(ù&ðl4©Æ-Ö’ÐÏW¬%9Ͻšô"Ý}Ùl?gZE$Å÷F%$Êáˤó}÷ P8|\,’¡Ã³íöéf§}S*•T|¥nÓïË[-Ùu"mÀL(߀• &ô$¯üpÜ+ŽÑ¨N_²¬ ì™”€Ójº€9å]ypù:šR—¤7›ÛÔƒsÞàL”èyœÁ••îŽß³:&HXpZË ŸaÔ5|ú¾O·޵i¢»ç®@Sì#æ£Gõ¤"êçšc²xêе&ߢ7}ü©k`ÐT"òß#Â@œ¨ EÂV|j Bx‘pÜÇYjf¦E[#Co“¿–‘Ñ“QÑÓfR{!Ñ@ˆB4ü4 ucjQG#j*Ãx8W߉¢Ž«%,&ŠörWÛ„÷´h$Ú5¢‘} <è–%íåo‚Ô¹ZXäâ÷7o(jè-)Ž¥3fÎÙ€†”9›‡±˜Ò†VÌeÿ´ÉŸ•ž­V¨ïµV:»MïèúDó¤„Ù*š§Â]„øe>ê¤,m¶s>»½ýéÛ.Í®ÒDëÀÖŸ‚?’r™òª<&w´Ç|Ñ}ñÍ |n™Ó4¸[âÅ„Q:™Lób>_€I&ÿÖ¸ƒôÅXÌ'ôýôEÝF°^ñ·ê²æ4Æ|NC°Üa†ƒ/q`VŸ dHn—»]ºŽXQÅ ÌšÐá“C 1¤ìê 4È2ô7æéîbyóÙë>``&·û  ððÝaö |I¹çuo/»£N„m½VñPîÜ%E-ß»n唞­ö1å£ ¦ ¡)Jè;Úx#QÙ D|} ŽŽÜ?<„tŒ†pü M±PÂ>ß‘Ðæ°q‰È^ àUš¬.’»t0"šÂ¡œƒ¾#¢å‘7‚b!.{‹?-×·¯6Ù>ˆ„ô€q‘qÑåô-¼ qÙ \|q~¾ÇÐHQ0:RTD€4ÈZ&úŽ‘öß“´èìR^&Yfó*xá³gé«$ûŠôÑþ¬ê=ÓNà5_`êOX– Ø<;µ„Ï&]60Ï10CFgódÞ¶YLJDgStsÏwX¶8j1bKU9á”ÎÜ4MÄ‹=O¿ Iº¿VʄʾU …eL¾Œ©‚¡°ˆib$SM!˜4 ÁT_¤½0¤œä»a„!F£ÆÚPn”@}!9¬q³xQ# –Šüò)sùÔ¾a£ùjS;H¯AˆäÖÞÑ3iLˆLšhÌDc&3£hÌÔ3Z®Cuf]Ii«žØŽ£ï-øñð§{Ï!°«­ç±G”þ@Ž.éNúûî<Ñ›ô{9Ï“°æyŸúlð‘6ø¬‹Å^øÑŠÝ6ò«ß>¬vKƒf¤ºöÖdÒ݃ÍÈù(|ñ>ÄÀM†»†h3r}K!×YÃûùҞ˕­ÆeÏe~s1¿¬t“ÆðG›‹_¤ëoor¸x»Ñê_2Q§¨XÒ)*¢ «s¦#9§×”7b~v{·Ôj:2‡t,ÚpüQ¨UxÒ‘8£ä t1¬ñˆHsX¸9J¢˜ëq§CýM¯/oDDy²ËmúaùÕëvÝsF €æGÀ%í4±ÐÀ´Ð ž‹¾t0zqáÁV|Î/MÊUîvû§]P#ÿ"ýäœJÖ¹§—ê²;-E až”ÄÆ›‹9é;wDÓ§½Øk„"â/×¹;“º‡(Ê2 ` e ‰jŠ M|ô?;#zrb´Øù‡åîm¶ ‰)-1&MaRÊ@ßñÑîÀ‘ˆÊðñìööüúüò*½_}³²]«í‰ÎX¹¥ÎŒµU5Ù´Esc+øû8C< fir"Ðm= ½†Ú†.[½ ŸhNø¸yÂ'ú.ÝùUÏ5ÙÌL¸ÑÐ1ò«EÑô”lZ~ìðiu½+¼rÂ\9±¯íÕߪn¼HWVí‚ §43(œn§éˆºÝH·×³ÐkÝÞÁе¦ŒÅlisOÚ‡ùŒžoÖ;“ÆbÅ~g 𤔴i7Ñ`ØTÚFêßt»j¸ðØXÞâ³óŽßÿ¼ÙÞ¤Áa:KL¿õpô zµ;{(«e’ôܼœ ÍóÝL™œ¨oE}á`+j¹Ã{Ò¢ÁJÏŠ²hÐ"/¦¡E2©éUÑ‘B((Ö!Út­I2@ïÀû«Q¬bsåÊvAY†#PEÐIÚãŒcƒ ŸûÅhÁAìcµwLìåu3/D£o&4»&AQ¾g=VD.†¥V+¢p”ÝŽ+ÔÔ¯€Ò_tã|ù¯4Ê,ÊXö†+c鉞™)Ÿö>bÖÄ 7A3N<‡7B| ©¢u„éÓnchT@¥*FÒúÄHZŒ¤U—v ‚H^ˆFßLˆ‘´#i§ÃR0Mµ²Oc_¢RûÇCºýcj£®bjêqEw͘Q{Vk䛸/¢Ã ¬‰>FÖ”1;‚uk×Á54 ºÆ‘Ãk}Çbx-†×ªK;І‘%/D£o&ÄðZÈá5™ëa)¾& aÙ °qoQ°=ì6ç«4Ù–!º=<•@À…€O&PÓ¯oåÝéJêêHÁZ“xN=œ4DGÊ>ãņ!ENDu ôróÞ$ë¹|ì}óŠ·.%$Ķ;¦½KåôºëŽý‘'š§”Ò{î4o•Î…ëã øˆ}<Û•&?`Ë‹&#Z\¬éÈÒb–•7Öõò.Íi¸»ÿy³½K´Ž…HGxŽ›W%ÑÊ2µ²é»±Õ b›‹‚8^”†ß9ž&úìþ>]ï£ÁÄq `›‰£$šMzÜéÈrâ×—ÆÓå6ÝwÙÇ,‚ðcR¢ôk²§kñ'KÌù?{Ø}z·^}ûc™¼ÝÜ>¬´âÔ€ F€ -tùÓ]šŠ[eÞ€€§mÖ~稺Sþ€ôÀc&€„,i,s0„(‰Å‘+…G ¸ìE\ä×Ír}½]êpßûNªn€²àBÊeˆHYÐ7K°¨ËmRÄ” ÍûèmòŒ*Â@ÉŠ€Q€A@ŸCŽ0 XeÞ@Àüór}‘Üí£‹DHØE"$DÉÔE’sÐwÉòÈ]¤B\öÂEÊ‘ú"Ý}Ùl?GëˆáFØ¡"ÚHFLrg&ËÍK)µ#¢B…#a#MIDcF¹Cféyƒ›ëmòáÃòD”7ZU»… ž%ãOJ sN9BŠÊêó*~IwàßóÕ2g‡–1¡eá<ÛÝ>{ö˜Þì6Û|¡¡—ƒ¥6:*¶g‘»°à„łД‰°€¥Â@p ÀÒ *ÿÈSnå&:ùLŽž0¯=ÄÒÀñ_¶±.w£/7p<À›†%Ù,»ûÝ–ì cúåƒY,Ð`®x0ùÇ;41OÅ»íšEJKšÎV+ÇÂ4ÿ²üC8æ¹OóyNÊ:› E«d@°’U’П`IE‡â¯šääúDº$ØÝ©èm²kŸPWUÙï^_\¿¼Z¼ûó™‚u m¤°<;Ô`EÖ D!#ô'be® IUAFˤ n'ÏRÙN®ýñà¨v¸e‰=<ÖC †È`eƒ¡ÂwaYº”\,o>›œäà¼VßX²LÂ'˜1¸p?7A6_^¤0+Š ŵTù_½/eŒÍ‚}]p«N*éWÁ¥Âh!’.À"ÂC7J2xºÖAû“Ø¥;ön¯¬Šx¬AÀm˃kؾOmËyÇF¯rÞ3³Ø ?Z±+9ŒÀF/Qý’£ˆ©‰¾¢oútÉò–ÇÈÎ`F;"Ztæ:6‡î=b:¢Ù·«ȸ*¢H›$oòXò!y×Í®‰Ÿ®îI¾¾…2Ѭڂ3ñ"!-чTçLŸ$ZxÃòi˜¬÷X"FĈŽ#ë¤Ùõá³ÕýÅ«4YõQ½Ýý®!BY°!ÀÃCo;°Ü\n?å ñj“iíeɃ!ô+„ßý˜‚Ñ¡»2/Îχ.‰ÁÊEƒï¢A³;té¸L2g›°]‹ -Xyƒ÷] ƒ‡ ¯’ì8“ð°gÏRò^ÎMfÐBAˆèQ8¸Ù;¬—‚ëµ’V‰Š” þ9®dž¬k=ú‚– @@ê2:t•“í)4ݶƒÊRšh‡E§%½ÁJ MDϽ øil(E¥˜/“Ã>Pù@®‰À¹mÕâÀôt‹èTô…ÇðLô¾4 ÏöÐêõr}³¹Íß>Taa© VVX2|Žé¡KJ‹cäÛˆ L‰wïÄ‹ŽˆQD ˆ·/#`ÞjÜwžßµÒ×€ŠhàÌ^ÄÂàˆõä‚>>=hÁÐ<<½?É V4À¿—ÉîÓP­*B_°2AðÝ’*´ õ"]{³Inßn¥$(²ÂŠ?•Íá0•Áëììön¹Ò²Ç$…¹äñàý\a.u ¬s÷Õ‚®~z¡ G„Ÿ"Às:LQx›¿féø8 r@Ó¦Ðø) Ã\þg»OïÖ«o,“Ür{X9«r!â„ ~JC•ÛaŠDî˃ jÙå6ý°ü:ÔÀMc˜rÁá{€ˆaxÐA"PzœJÖ¹°§ƒ-"çé VRxB|—– ãC—˜Ëü?oÓÿyH×7ß\‰ s*sšÆ`E…¡¢?9¡ç®®Æœáy­”ð§ÐªH wr«k‰™¯Ò¿rÒé ZR AH âõ$¤Íæ ŠðXòåÅôPòÞĦÂù!IÏ?–»·™ózÚî嬘àñ{Ø'„p¶gÄiAùõùåUz¿ZºsÜß:/'/i V(ú†·Š•ä¿ííS"/GŒ‡wÌ_½x÷§›v:>¤ÛóÍÃz¨¦Ea°RBÑà½AEó{H¶ˆÓ!ÚæË9K":–È`å…%Ã{‘á¸>$©ùÇCºý6x±á¨ Vn8:¼žïƒ‘œ³‡Ýæ|•&ÛV¶Â“¦Ìñ¶t¥Âñ0‹W J(á¤lPô.%žKÍó0ÅãuöSΚ/ÒUºKµÃ‰¥,L‘`iðS8>‡)xï¿6ëöI'”…)æ? Þ†œùéÛ.Í®ÒÄþ³çåÀ‹AAb˜BP ß»˜3™F(y­ì`ƒÇ‘õ<ír¹˜?·ËÝ.u¶=¶'™ÁT,6˜‚`$‡p|¨Âóëf¹¾Þ:Ì´»ŒîÄ…)0Åð=–šXnÉåÁ„pß&_Uƒ B[˜2AFï·H<ŒD€bŸ—ëaž]F( S$(<ôÉ Þ†ì“çt¼IÖòe3¼ÕO( võ<\ýoC^ý¹6»Hw_6ÛÏC5ˆyaŠE€÷fQÁéÁXF9QTæq¨B“¬”ÐDx/) Ç#-`׆€…ÓÓiÓ›Ýf›ÏÎë«s<0G.özÔšU¡±(.6BA—³å¿ÒÅn´J×`õ<ÁËù?~̨ÊœŒŽŽ²Gpbü:ý’ÿyôÏüŽÿ&_ƒC¾ð“–?<}>Zþ=ÿ:ÿç»ïèsÖ™ôšµ+ìÉ!Î?—Å«ò?fùßùÝÙã"ÌÝf»KVåPÁàœìñ]y,Ú£ò•ÙB½8_ ‡Å³È¡õg9ùwßpÚ}ò¸¸K>§9}Ç`(ŵ·°ràŸÿ >,ØF¡N>Ô«?ë|79Gà‰Åíù Ç˜”â®âK -ôê·‰/%õ¹ü‘¬–·øOgÈn!¼H_öîÍ‹w?ýÚ[ÑŒ”–ƒŒÅáyZAàýn;bú™<%ó@Óy–åhS8 "Å1.°(b1—õˆÓs¤”+`¦éÒ'4•B(Qlþþ‡ô gV`ÎÃ\/§ë› Ä1 xéæDpŠ„.¢Fñì·†¸×QÚm±`?^69” ÃK¤íy3*¨?F:rPcàcozªcŸÐ¸2¦pEËnÉ?«£eйWÜ´:fÑh\F{î¡ ’ÁXp8Ö G…;SF™ÇšÈ|ÒŒÌc}dðoì'w3n,æR fÄóX›´t,Dá±½ÍÉŒ9ˆ0åÏ‹—W*•…ð:fàu¬€ÒšÏ2‡ê-¨¦§Æ®Ë ÇU¯ ë÷ Ûó1·Ð‹yrBx2–K\[*3ç©¥'À¶—c…”)ŒÐ«Œ˱`jYoüÑÆÇä”àº: [M­ Ÿ ¸eë×ËõmúµÄ;ø*pÀüU²þ) ¤|™-éËKÓÁú#²ÐŠï p¯AHp;—!©|+zÀ§ôæ3h¹›‚uP‰Ô@)\<Ž>nv›Ñ ¸xQŒ³ã»òçå´1ŸßÁÏ©sÚðKßžý×ùÙüúêìâ7K”Ÿˆ)gãP>Ó^„Ö,P­øÙGcìf²vÑ%ÏË•~B1ë~XÏh<˜†ÛevŸìn>±”‚Ÿ˜:ÎbŠR¡¶*ÆÝJG¡†OF¬û££Ã*ë#¹6„`lCÆ…+ÑÙ—eþûzN®ÞÓ›Ñèò÷ù«·gW¿€¹†D Χ¥ÑsxžOðîa»~^>uÜö©O¹§þû/è?@)²Ñ/6£;@ XGÖ7À²‚ ˆM.B«Mr›+Ô¿qÿ2Ù %„ˆÑÙÈ£ªªíÿ+ô{Nª†•t›ÕHx•$;Y´Š¡uùîõÅõ˫ŋ×óÜæràÖT)SðlèÙÒñoF0ñrªSÊŽ%§-MÝœÍyn?¦ÂЫƺ­óíad:ÿlÒ‰¯Ÿž{@ê’ôfs›NZIË„•–‰zÞò ñùßÃϬÄmÏE.š§¬añ;$ À$Oƒ]Ü(,Pˆ-¶ùrŠPþKjð¡­› ¿xzѵ&ßb2ÅŽQ`èˆ3ˆ1#Â@¢(wGr€ë‘˜ÈC Çàq‚8ˆTèh;:å¤ Òy¼ØjD¸^=DuBÔ   „Úh1d[aX Új‡§Â ]ÆÐ­ï¡ÛI”æµÑq×{Ùè˜þò7A0[ͱ¹øýÍŠZzKŠc,»“X¶ÜÇiÍ–Çã¬Ä³+oŒhÓw”{.“ݧ>"ÛÝïÉ•’k?êíÚCcéÑsÕ 6aÕ;lžÝêKèó¥(þº—š€éjžnù=Š!f…Äd…/#%-ý„2ˆ—KñTÇ¡µ¿f/“m–æÓöaù±uj=¦áˆ«øé¼ IMÛ„ý„µþÕ ù|Q~ae(ÉjÊ癦õò§»aiÊ äT] ©9CñÅ{ôÇq†"@ï¿ÿ¸Í ‚ %•"Òã¨#Í-< œ²t¬åT%€GdR'lGî©VwNÄMXæUǽ4¼Áœ=|*‡àS]<–:tµ5jŒ³‚I%HŒ'•$— ¨Sva'877­ÉÍUЭ977m1­SÕ ÝTž¡›VŒYÔkp„a‚ª4¦›ÖZ²V›‚s?t2}–¬ó¤_ k¡GëÀ‚â7¯8iPüQßG}õ}Ô÷Zú^K½õ¡Ùº,_¡¨tÊé*|É@R¹…2íc1íűÌ^Óî {1¡ym”Â¶Ž >Òî üNÝObêÞ÷Ô½(^a//ÊXOãS/ÑJæ_oh»V?>Ó*H'i|BhøÉIB‰ÿ©û‚ç2‡íÌpû=i¢]Aô\üÕÊ)<«UÆx'!ÚF?ªkÜ`?iúÓ&—Üôlµ:_-óVºŸ'.|¹â)ê7õ_áo¿¯3Ð0àl·KrÝ|ÛÇJvÙ铦5ü…ÍÒã‡Ú ‡çÊ•7 îbŠ] Ï»õjɤ;PÑA”Ep5a‰ ž…é½|¬Óþv­2|@ÆÈ–r¢ØíR†Q$å ? Zü8ÂBÉ÷ÂQ»Ï÷6r«šóÅ‚ •óÅ÷H·e²k1ñj+&Û‹ev1E Sh^ VhÚ"²´f˜;pa¥OøòKº¦W/‘TÔ7w«ÙǸզ(ðÊðM|LˆÖ=i‘Ý´ ²^-¦ ?jêv[öî!J öwñ§Ù:ÞGèVpìpÛ÷6Bµ“n]Nq„ÃèIãfÂŽÁ=rT¿íKP–#7|ªä‡0©Ä˜ø¹9ДcB :öȺÒv¬”“Å+iñCšäó« «jr†¶^>œÅ çšx”ùÇØ«|êJæ~^®o[ 󓾿_–aÿŸ95÷i>Ò¹Õ:ÎÔa}J1!)ðÔ9ëéÉaÝŽ?i8A¬¢ilsŒ¬|’¡‰¨Jv­¼6Jü‚b)‰ð÷82z‰ÌÛÅáÊcËÆtLf ý9¸;†'‘­(æ&á»ÞøjgµÙßKyTËšóÚ${æ¼6>^OÖšOAúy»h£s£S7ÀÒ ŠÈ¤¥Ce{Fýød4õù€ÑhwìM#³AšH•žuh?l†éöKº{»¹}X¥YÛ.c­ÒBx ŽCpø­ƒÁaZz³ËH^¨˜Il+ãj„Õs¨ø‘}¦QYÑ1n¹E'<Ñé,±ÊPC´zÐRå ñÇIÜä.ˆ âÚð¦Àþm‡Xáövà ìë›áËwhí…¿|€ñªÖ Ž%1"ºj|"©§¯™¶­,¯5)·2,/ä;çúÓìøŠkgo–ë”ÔªßÏ?/‡P·ŽIŒ-U~65H”ñ3€ˆ–ݱK#ZÍ}iáPÝŸ`½•£Œ•†ˆµ›$ ¹M TCÄ©˜;©wôz Ã̸Ãw?®çÎT‰;MÝ1J‹£¡ððRÇ­‘Õc™:n¦ÉSu]SÖZ1o°ÜÂZql‰ôÛTYj`D£bŠhTD£ÂŠQa¨6½Õ˜Ö•e;=9Ž• ª-ª´¨Ò¢JkWùQÚ>âuŸ•,JOŒQúmš€ë?øJWÿV€öy2añLÄ0¬ó’c6ƒŽ§ÁíÙ3ʰKäU€»Üù*c'ç«Øx"-š.0Êäàœ}öbÀÕ<àÊ­×þ"®Üî£c,‹i/–EOVƒ?SΈ@4¢ »ÁQ¹ŠëC»uz £ÓfÖuš]}åOpÓÕOT?QýˆÔÀ:ÆÖŽöc"Tùóë(VrrÄ¥ä(¿àü&Þÿ-Q0ÖFÇgVÎ7TNK’4×ÑÑaίÉõpG' ñh…µ1Ùgá#ñ’ó^‹ …×´Û…‰ P˜DPh±6¦û¥;&×kè„v00µÓx|‹µ1óP.œÙ>ï |¤}2í6qF1Êg[¬Óý²‹:&×kô‘vWØ í6 ð”b”1žºêÂç—íµÿàwãž<±ñä©èÉSOæû•À'ÏlÑœöqó´Oô§½9“'c\%“Ô´+³jÔ:˜Ú&;:®mš‰ù3%ü™ñ§¢ýšø33æÏL‹?3%þÌÓÖXaKÒÖÂQ5øAïUZDx儹rB=þ°™J1y¿Aú…1®í—™µ0®}2œû.†o´‡£ màhG8ÚÀÑîª¾ßØÆ€y×£e×Ö¨³^)3êl}ïÚaÑþŠöW´¿¢ýí/ûË¢}¶iÑUalP8(Ò•‰"ˆEºÞ‘;‹\ÿk’c1¢ÂÚˆ5Éý“ÛäûX‚íªþpOK°gõš×F,ÁîŸÜîP/V]ûEû4dÚ÷²âœ ÷[­8çêC¬Vœs…Ý]Tœ£WhUœÿ’îÎ?%ëÌ4m¢•á’ÙîöÙ³Çôf·Ù‚ ]> -A3roC’ã„MrTò$¡æ8‚ÎjJô’(ºhñ Kì”ÍìáèÉÁ`‡8.Ż,Òy‘~¹ÜÀ1˜ü(É`æNBš ”çCY,ÐP®p(ù‡8Á :{ñîOq´9d©^ü9‡B0ˆ¶iJ˜eh/‚xnt%μ# ¡g/’»°³‰„ž>åŽÐ£[2·þÒKpA(go €¡þ?pHÏJŸ~whÊxIÖ®6[wTäm$¹…2µ Íð`Y:¬E¸bý'5 RôQ¾[Ô‘­¼ÛΛQIT•FE{0$í©þ\®n†½š!pJ…E _¨°°=zq…E Ä*øÛÐ³Š°%[þ+]ìF«t üCïü>?(–ÀüÑÑQöÔê:ý’ÿyôÏüŽÿ&_¯í?iùÃÓç£åßó¯ó¾ûŽž >_! Xzrˆ‡ðÏeñø|”Yþw~_ö¸Èp·Ùî’ÕÁ!}Á"KwÙãºòX¤f¾ Êa%ºq–{÷-Áäqq—|NrjŽÁ Šk‘ªüçƒ &QZ.äÕ‹uþò›ƒƒœ]‡#ðÄâö|¸cLDqWñ%ÖhôÔè¦V<Ðg°³[¸üZïïF+KBazè«Ëò±X‰ZÜb®(1ך¼‡þSÈj“ÓO"­óçèÁ¥p,6-ëxT™Í–*OÊ£ŠÊ@k_ȱ¤Ã)ä˸½`JµÈÒ«³×í×_ui£³d}$VÃÙ´ÜáSsÓcB]œÞlnSošª3Çï_¯s û°üÑÊ­hÌ«#›¦¼Ý±‹ ùB¬ñLæƒFàZ›®}ÀA,èZRo1›G¾~ 1Q9"âˆ©Š”­;§›+À؅ׂ—Ž+^m)MœbŸ)÷¿ø5–½+¬ /«Aƒ-~-®f`\üþæ E­½%ű´óÊ >°f¯.ˆ÷—­WîàhÕí¼HW6Êxæ æÌP 09ÑûVågƒ÷-åg޷ݱ7¥Ñ‡“HU<éEÅÃüu³\Ã,cÛÝþ]jŒ9Ü'I[bÙ)éA6`àr6 è·7þ&ðW| zm@ÿlŒ”À›F—\ú„Ê+šðhu¾{}qýòjñîÏ‹Ð5ÊÙmtôaÑP|BO,²¤#ä @AX¼ºkPî=‰N€d¿HWaA¶ÓjÍAA5¡'Bµ%¨–34¨¶_ ÈÎk?í¦kXÃ7œf±O­õ4‡—Lj=1™jŠÉ¤YL¦úb25ææ4h11=ÖÀÊ…Eµ†ì>~,ünêcøW~ù”¹|jßJÓ|µ®Qwv‹MâÖÇ 75Xðh(Ž{AP4©T9Ú¼[ `“ÊöèÕ„I±WÀÈ)ß×t ØÖOgÒwÇÉyN3oÝsr6ÔŒÂÌn&fÆ*™Y;%CûðÇïçó7QëD­µÎðùÖDG^Û‘¯áf޼íÑ‹ùBRbRàÉKƬF2*ú¯Y2fÆs9S=SmÆËCy¦!ÆÐV­‹k€ïf>³š†¾#VŒæqÿF³Fr¯9¬&û7š¾Ñô¦o4}£éM_'9¬6¶Þ̼€sXwÆ]oF\K;­Õö;-ZhÑB‹Z´Ð:´ÐÚ¨jou²‡ÝÓ…½ñ¸{©Î ùØ¢ÿ+£³÷ƒ½÷ô”¦xƽÂÚˆgÜ;=ã^ÓøˆÞ·;“ŠC„iD„æµ1Ù/Dè˜ÜPÁËYŸ„5ë6pB!‚1Nd8‹Ø¼6¦>ŠBwØ1¹¡ —³Þö=ë͵OAM´ 蟖t˜CÿÔÕy¬ÕMöÎc­&œÏžØyöXôì©gwpŽlñ Ýsd/Ò¯;;;ÑÈn„±nŽŽlóÉ·ñ¨6ùÖC3†a(÷þìö1Yß„½3¡«ŸT\1ãÊÚà§aÆb6¡ê§aòk ¬â³TÒjر¼–´uZIŠ.pÔJ¬Û°Õuø£9™òV¼”{0VÊxãU» ±¦U÷Ek"Ä´ƒuyêK–ì7‰cèrh<‰¡tA̼UÖFLB+¬¾SQÍ6WÌ>µË>uì‹m&{^¸Øi´îÑ2¯Ñõj϶Ûܰh×7/<{‘!{&#C‘žÕØÝ‘QJ]/+Ó1›ržîò¿k=Üå©Q7rdTAO¬ÊVejóyQ5L  0»ĵÙÔIQ¥XíË1Qóª·n­XAaSKfË ùh<=‹»cZa0—¿ÇL Š=ˆ™Åü:!üËl“:^éEæ•V'.Od¢ÎJ‹¹UÖ9UÖ3›$Ø¥yÀ½÷°.ro‹„"Àa×ëìM>Žþ\.w§·Ð”†ïeÑÔøáa©dFÍ€;ñé$<½}ÈvéíϹyx•³¬—Ãæýœq- >|‘Óå‡p•ó¬pИhvìÅ1ÈP2vv{[¥+Æ1„lÁŸ/ƒ–G!i1¶¡ÊÝæç*Ü ÈÑ%%õѱðíKØãEºŠˆ,<_h¨ˆ,$-"²%DVänˆÜ%%õˆ,¾}AäóUšl=ñL;s?eD†ï€Ê(ëa‰HIù­#?]¥³ó9]§7»—ëäý*½ fDÇim–+xÇCТ!¢+îxhÏ1›Ø0·u®"jAÇ/¡#ŒÜ‡ˆâðõ¥ˆ*?µ͹ጞ•››Ïm·$¶ªàÄcpœÁoŠHZzßìSÌ$½Û‡0ÚbY&~dŸ{}XÁég«\œ^§³zgJ|šõÐpe*nžócƒÔžnž‹kCamÄ-d¶¶ñ¸Õýc¼•ÒÅæ1üÝc¯Ûnli·k¬¬×Ìî•!ØNÕ2êT[•Q뾓GªxðäÚŽzñâ/–Äpr,IàÅîå¼u(RhñD†ÐdªIœ‹x^Ï;-Ûæi- ½ý‡¹¨ß´T!gÇë %mn(iNw÷ÄÁñÆ)*upµ ª>þ]¥0DK[&­ <‘nFBâÍmEbógPX˜7è—­(œ©©pþ°íÍTÀ&’«ô&uf¦Å3¡¹C­mжvlZ¿Îò?ξ$ÿ?{_Ûܶޤûýþ ÊÚo•-Ê9§rfæ–óæÛñZÎÉÖNM¹‹NT±%¯(çeæî¿€…šG–(t£ûé4ºŽû¨¹"3|U©HñCSd.ØaÞ‡|’ í_M[=W¥N£¨âRרí¬ÝâóÉ^ÅV)e>y˜¨:fÜö¾µD„ ]7BµqÀÌ Ù–F2ö:EšÖðu‚¦'(7²Þ…•gV)fúW«Rš·fª‹kÜöf²Ý¯äêÄ„ hBÖ?’,sµÂÒ)÷[¯©ÏJTòžÕ‡ZSŸH }rE‡6Áö,î¸ì­¶µ5}k®Ë‚:¼)Wüúj‘ߎU|IÚF!Á$Aƒ 1ÅÝa帬,¬õjTrÌо3 |…™áî°r|ùœœ¾·¤œ7Lq×2µL9[,ÞÒ©‰]RdÙÙ¦ˆØ@[£KO¹}PyP¤QÒ}P,åwÂè¢Bá³öe¼“ó,Ðæ¾Šo FäF¨vVÔ‡8î¶®Oðø{RÖgnÝâìV¥ñr=Æ+Pf¾Ò5*Kn,up 3N©ã¹6..aö¤ÿOn~ïÿ Ô¨²ay|ccd£tx…=öçÏ÷ †xMîö]¸es—m™ ‘ñ‹¶ðùJ—lçó«ôûïOwwÄøHÓ¡™ÓJ¬†LÅK‰lâ«#|Jèð)QêÝ^ñQoVëb'÷óëìÇ&èHŠ$-ÆSÚŒò=ª2½zõØJ-Ù(šàIw†3QÏp&}D"ñ?ÏidÄ}øk ÄÓûÜäg¢\`ÂÍ;&TÞ1‘Ía*>P5øæØìÓ™6G§pÍo4¼ÑðFÃÛexU°×—*¾ó"L6ÇŽà)¬LñÍÔø™}ý”¤é0O˜ ~¦4úNåÑ—Ù tÚ²zxH—óñB ™± À|wò5€z;4 ¾ÒL°Ò$V¹‘íèût²¤=ÈæÄ…a¶@2"¶9ÑÒ÷©¢¾'Ýú>U×÷iOÁ˜Ž@ßµh@¾„ 4fÍ,¿hŸï¸%ü yªâÏÉ×éˆß>¥Þ>• ¯­}µ¿S?Wõ;û—®òç2.dt£óÇèšø¼æì+Þü‹ì,ÀÏÖ0¼%ñ=Kâ©û¾Q¼|¢Ýd¨oã[ ¸I0­œ–Ôç#ˆû£=ö|@{®év°{ÈfL$ѱˆÝbÓÄÇ6"£PŒØFÄU0ÜF„Q¶,ªG6’m¶–‰×É5°B® HLà@q ‡lL}T{&ÑKríi¾rMhþÔ„æO]5ã6ê0×NŒ›«ä<>1öx¶gYùø©±ÇOÌ·D#¿E©1ÿn—³ca»-:‹=n%pöD§Êñ2X¼ æÃe05âxYýÞU€"`ðYMb_D`Èþ¼R§íäk†éA`c}ª§m|gÖxaÖÔ8Jø¥Ñ#iôH£G=R“·cå£õ›.‹râA OÝåøvÐâc Ò$Ö ™8vÖ EXƒ4<¹ö\·´äj5¿[6¼¬:²§ù>V˜9ó¼Üë$¬½ö¿Â,ž„lxYr+ÌÆL®= ‹uF êD ·ÍÕÔ‰NÊ̕Չ†Õ˜«¬•®/®c¾H£¾ŽÛx-ö^1ÝculÕr>ôjÃTî€R¹#š¯GTVÙ²£ÊØzÕxëÕxr鮇kìÝÒíD úѰÓÛEÁØÁú!{¼ðˆ½^üÈ®úXg{½Ä^/ƒ+†—…ÕYø_xKŽ$dÃÇ“øØë%žÄÇ^/ñ$>žÄ{Mî¶M I™>Ÿä:MR Faš>©[:®¦¿MéÌúx>?_mæq2heHÍL ©™:²‘ mä¥É\³Ç#Å:8åû,1ãËOãôÏN®pölƒ‚öCgNã Ï6Û'|J˜áh€£ŽXaЧ+C­¥ñ0&2ÕˆJpIÄt×è²~JÒŒ{˜'øÒð’…áüdõð.çã ‹X:cÁŽ!ïfl0Å:Ɖàê¡çÎg‰Ö¹‘ÿ0RŒ«JÈhöd ]U§™ hé|@.ÛL‹KãD¤=.)_MP›ÍsáÜv¹¿ÝzKů6äêÇæª¨cOÓU^]Ê™Œndt#£ÝÈèF*¹‘†<‹®‚q@Õ¬ŸÜgéºæŒ®5W2Îj¦õ6­ ë$6­ m¥e Ú’2 cH±R±ÜUÑ’n±7qn+õOgŽšF芪žëøç‡Ú €ï„ªm¬ñaûT€Ä~JIb£ëíúN´ëÑ®÷m& ìãë"@QÛøq%,¶0M|l0 ňíüP…Ø>`pUˆíìïÛ%âØ> â€H6¼¼OÛøLîöµà_O3×7€Ÿ³4×0€5Þ\§þ1¬ñÔ×hô³î¨Øî=šÎ#dŸïÏP“¹GpÒëcÝ£'ujBÄ‘³F…aˆB`ðàYM⥄`ÐK5¼§wjä+†¹xcc}ª§o·Öx¹Ã–T@Êx¨Ñ7¾iôM£o}S㳘b]¤ÍºH–ÇŠuâ O•Ýëøvãcm’³ò[Z›q@B6bmÒðäÚ;ˆÝÒR¬iÔünÙð²ÉžæûXyæÌðr¯“°öÚÿʳ{²áe)V¬<3¹ö€.ÚœÓcµÖNxffz>ÕŠ;aA›¥¹<šuwÇóùÅj³¸ÍâTžÊK0Óª…dëøæòÔ sHIž<ú= WŒ0M@§óHð5€³H;4tög¡ 5Îèi·åqJ”YŽ9ähu¦õÈ ±2ìZ×c4â‰{úÞ8jBòXgö ÒjŽt@¥ŠèŸ/m ~yç:¤–ëŠA†—M×MÓ€ÌJœÞÓÅÚ`®Y Cæ²ã¿Å>Íð1»Ç)>*ft-£k]ËèZF×RÓµ4æQXtü˜éCòf|S}–6hËÚ iÃJMö¡8¬¢-Vfûp|Ö8ÝÇ`ÉÈxº.yqD5BUý4È?ÿÔ |çTMb%‰/"ऒ$ÞiwR’§ý´Zûhç£vÞÜÔ ·ƒæÏýi¦â䟡ïÔùØ]#Nþ‰“W /ÛMÖ]Ãÿv±ÑŒ„løØ!Nþ‰ýâäŸØ!ö_ðšÜíkH ºôftö7‡itú÷JŠÑù?Ü£Z€È/Ò˜4ä‘rœÔR29Î9@1Yë&=©›T„ ަµêÄ8(^Ôñá¢Nœ Ì\ ¥[R=)çµF5ú«Ñ_þjôW-N Š5•jßÚßwˆ“‚ü8°‰“‚?§Ž“‚⤠Áq Ö2 Onœ'®tË7Í÷±R-N h¯ý¯T‹°'!^–nÅJµ1“'y^˜×ÒÔÎô¬ Ëåy-M£MÏ rS¤×ü.¥:½²Í>eëŸcmcD7’.FE41"ù«’ô7ßÃèm¶¹X°Ø³ ü§Õêž’)ŠvùÁoé=9 #»]ͳŽÕ[ñ¼§û ñfk- «à¹ú§ãûûÕ÷WÙ]Z|{ÐêÈRÓ xleJ7ª GÐéýM)í§ä@løl‚Tbúˆ«ØCe°xÈÈšÌ@d^xc‹[Ä–’Ì¿î¤TMœ#ï<ÛÝå°a –LÁMþ’Ð7ëÕCåUr{¸K­ ¿÷¯»HÇ jáŸþ´Ch—$0@'ínÀ} ­6Ðè›`h"´ôƒ–Úä\“¬Ywçã‡1MßÏL²û?HȆåCÄú7NÂIÎߺøpvFP+AoMqs|cWy—qk„á+¢,F°R¬[ñXDÇÇÒ`µE¡,‰;i hñ&Œ#¦EÔİÖÐ%†µQ6D²ÃZï´"¸°–uŒF¶li#¸Eß¡ߞΠï"F·;2^fÉ«ƶ%]1²•Šl¼>®…Â9ƨ–„¨-Šik´‰øÒ_úhÔ8¢Ù’–Ëú¯ÄX6ʆH6b,ëVËÒ“ÑH–mıå7¨F±WYz‘>dCz‡Ð¨Û÷ 1­£p 11~x‡aÅy >¡{—ð÷rÞ­òÍöDT˜âQh&ÆÍQ‰«ªmGhõzy»šß¾=z„)…abÂÓ£jÆ¡Gÿù´Øœçƒª‘+‘: ýA´ø¡>ƒù¾ÿ6#/]¨+Ëxf<ÏÈ “yÐÊ4ӹɫó3€.Ãfמ¶NoÆ*´-S›gLqß–Ã'U³<‚jUÏFÕbi8jvùPŠÕi‹Ð”8\Þr,%*Ä‚GRªˆ£ EM.¾C¡m‚ö=¿ˆRœáã¨Þg„R=ž†¦†×ß ¨•Jm¦ö=ߦRGßácªÞáwÄT=ž†©†×߉©•Jm¦ö­u¦Reácª^!DÄT=ž†©†×߉©•Jm¦ö¬{¤’…1á#ªViLT-–†§f—ß §X¶Mßf›7÷«Õü*Ý rd¾zútŸ9+#¬hE!aE¥„p/÷ºJ ë=h-*D’!SSˆÞ:Ä•’˜ßŸÖÃ\ ©.!ç_ r«E%ÑãQ£’?ôˆÞU9}‚»ÑªPø±7³Ù ”ÝbDlˆ²ÝÞ áCªÑn}T£áŽM§Ÿ6cûw5‡BVÅ™¶E³ÙUI@»_ON;¯XßÒ ×]§2¦M„ƒ\‹žªC, ½P¢—%f N.˜GøµÝÞ"x6àаá6‘£ip=ßX¡…[MîC ª@Éô V ïê?V‹å«ì>ý¹Eþ}Eó(ÜûŠš ½ûz/ÆéÜ÷Ö¯Ñ[mZ÷ŸjŽ…¬˜3mÅÜv“ÝÂ6‡»–JŸ v±°ëõS¾9¾¿?)Ä?®M¯M ¡8ƒšòâ×BÇŠ6ðÄÇ–¼ÝÜ2Ùš—€ Zþ€AZçZsì¹õ¾·Þ %\Eº­øÖÔrb+[?Ú•ÆV¶Q6D²[Ùz§aµ²:2æZÚ C,ã­mÙoRmqË1n]¹R\%mGæÛ±ù‘¼;Ú™²íôë´m)!2™ZX¹ÏÏ–Ä\þí4fR8L!“(Å?ƒV8‚¬˜?Ñf”ÍÔ 8³&5:Œ3a‚=ª·É4 ઀Ü19âE“#Q6D²“#ÞiE˜ÉÒ_1Ÿ!c%k)‘âK´²!•©{"d>Û[]Ÿmøô‡À» &óñûÏM–_eé|вÏÒç,8QžŠèðU§"ÅÅiîh»Õ;!]õ Šÿ«VüYKÙ0jöq½Øl²åÖi¢{$ʆ¨ Xßð~Œ[åŽçóÞÆCG¯ºëú1>%úIN¡Úë Õ”¤ÇŸ¿P¡[Áz†B‡ÿ+x}·Â¾Ù;ÏŸçßÊ.³ïÅ?Ÿÿ½øÄ?ðŸ:ì¢'-þR8Ï‹?.þó§?‘(…ÄêG™/ܳ=´„¿/þQcWñÕÅ¿çLð 7y¶É¿íÂwîó¤´_ L@à b~¦À¤ßnÒ¯ÙnAÍ>XDõ^ÀüýàÅŠID”V,òê›eñå·»»»övÀ«Ë "ªOUD‘©’ñ–LW^€äÓæËï˜R`ƒ_$ ¦~Éà {,1f? IÑåûÓ‹ë×W7¯Ngï?^8–* ,©wIIêO18RÇç‡Í „íKzxUà¾ÃÙêóbyº¼[鈩jÊÿä¿/Nf«[hh§åc«W4…¿õD˜L N ¦Íç±/©é×”Ö¯i‡•æî:øgëeúíç—iž¦f¾ÿ˜ePÿœ˜o.îuÓúÙ€$;}=°¹|þ¹€ÚÆ'Š?éÞøD}ãy‡’œåâÙx­å#CÓ<šò1ÁÀ8¥€Y£n\lÀz×~Nõ÷sÊ2¤²™\Xœòa±úBÅi³q@mG&Ü—“}ð¥*%kò§Üw&Ô;%ÿÈÚW«9^Ç·@ZJ~kù]À3Я¤«ßÈVæ"»ç¬X—Çèü ƒõsjÜ»9¤ïBsésiBê€×ígàju¸]~K+{v¿”õ¶ãoöØÐ‚Å2³b¤¯œÍ„úŒ6²Q!Lè†òœTI\ÔÀ°«ìî)Ïô1,ì1Ñ<6 °í*KóÕ2Xð"Š1Zo¬kå¦÷!šùÕó#4 u¤2zFtÅá·Ù§y\'еË_¢x´šÎ#»…H‚ˆÔ(umóòøEqì·­C*æ[(†îâž5¹8%º Zƒi ^k0!!iMÅü1h Heç:“—™'‡é ^_ h ÜÀ½vMAL7XSWÉØòí³wǯÞt¦,WÙÃj“^ebìÕñ¨ ^Y0!ëK«–Tüv}%Ñ´†œÂp2Ý„]âÂ#(l]¨épŸÀÁ‘<ÁK•ÝŒŒϾ99¹_4ƒ…Râ _&„¿0ôMÖÖ‚ž•¨ ´}ƒ•áçî#üW¡Ò[iУ¨ C—„¶`aQÑü™q¦:;yèi’ÓκùéMµ­ö¶¥“ežVžØYw**9Á1‰Ï{ ª›„Püz Q™…Á°ª^ªÀ}ÿñâõ•L”e£~b˜ª ?× ·ºpƒwíºÞn“$3¾nC¤+êÖ°çp·Ôm:üœO¥ÝõºDáYˆBË'˼à: Ó¸´ #ª^k$C`©K6oV•(ˆíhªãDŒ1X!7¤ôS4 £ÞÖÊɳɧz9 «NûÔÌa}¾jŽà ¬qé qaÏ ¸a¶~nHh#©ÙF’]’gª§i&ËðóMt9Ý|üõtD†‡„TqÖ\=c~@CÜtÆ|—ƒdtŠˆN™Íe¢z¿:Δ4ÙªÞ·å“Ñsè2bÿž ,"<(G…’Zè}šÅÆ\ެ·¥{õsâÌõ™cb\.,@¨kÐ+ë]|8;#¨• ·¦8Ž?°3þ@àçôœz ˆÏÌ ; Þ=ã€~ÿyš³è Þ•DxíΕ\Þ¥;¿,îÙz¬QS´NÔdx«§ÃÖ‹wi~’>‚Ó뻟.Õ¢ôŸ¬ëI]¸*AR1¬F€]ÛêÅíVµ(w_F'PfέBOŽX#jò‚V‰š Ïu‚àwÈJq{»zZnƬ$…a«I‰ïÚAq=`yýc“-‹˜ý?Vê-AèI`ÐêAâ¹vP<X9.Ò‡,ÿ1Jµ€¤­ÏUñ9`%øð®¤a”Z€h Z  žëæt¨ŠpZDãSHW¸ ×ï³ð#‡*ø…îβu±ù׋§Íœš¼pÕ€"Ãgm ù°RüÁG©%eA«BIçZ¹°¼¾ý²:Ïr >£T‚¾ • Ãs• 9°bÌ a³bô­ž+ÉñPã .æ‚r&ân¬@òËïêºòê*ffHÙÍ ²mÀÏ“»êYQ*yÕó ûª'I”‰x›¡]Buüºði‹$ºÂnÚ¥–£E¼|Ù”!îeÐC'êνùyHÝüDµ÷­˜ ÿàMNVér®jN{_¹÷®IÁ týþl±Ì‚´À)¾w bä®OH+kDwÒíbjÅ©°WVeA·R1¼éuY|]„/>CÆa9ÆÙã-”™Zu/8#ÅH÷ÿžò“ë“KçhæEÿ£š~^ÛCįš˜Øþ¨ε±ÑóîGÆ—ž¶6?"´gzý¾z*¸?w|‡Öš”ps¾5 náK?ÁC97^È´Ù¤·_2åpÄÿÉš¶p…´¦ÁçC ‚ÓáH\Þ§??¥·_o7‹o#<«c) Y)hJüV †ë¡*È,ÛôÓç½íD|,pÇFȓթA’[(„~,2Ù¹±nÒÏ ›/‰ŸË§ÍéÕÉv&} í¡g«!1ÓÓ#Ó#b¡çY£ËnÏð UÙ†ìNA*üí*ýî=.ªFÚ@Y±dpYÑA³h¶0Òè4½x>€²áe§µFI£ª¥ø2 LÖ70‡þ6ŽlÃ…_WÎ+R›­ò_u''œ ; f Ôði0nEñžˆ£kÔ“Ý©© –wĸ®R3ºìTX¦Vi8S§Öå­Ê|«k_UZõQÓÁœ8Oa‡q:\ÌÙèIû!Ÿö Øü&> ^),i ‘Žy°Sýüù^Á ¯ÉÝ®É"ÍHÀÌl‘f6Æèt‘êñÒóEŠOÀTíôÐuúé~€€§r)ÐÛ­>M0ðÙšC { !¾‡=¥X9 zD|iDPâýyL-Zð ý†;¤"’aÒ—]ú›%‚üÀ›Ùì(·LüC¡Ápq¥êÙ£±dÚI¨ :Ó>Tâå'Ó.QÞeÚ®¼3Ó^!æVdÚ!µ1g4|xPÎy…~“3FÁ«DÌù¡AeŒ˜DбŒU˜ÎÁÇ«gŒÀ¨Ÿ[å+0# r Fê@rbÀc"àñ2”°Çèú%ƒ¤N[¯æO÷Æ”|=±‚¬ÅC°›Ð°›HÃ.ä\ø°Ò!·䊸è?Ø]9fÕ¶;QÜîI÷v'êÛhmwìvk­!½Øª"´äÛÓ}îˉ3Ë}gB½31oå¿UÝt›¶ÆzSÓH x › Ùðpc&Ó‹ß"K.â[ÆÜèâeìykˆMº¦I?ÍOÒÇ×Kp¼ä¾+µŸW×I–àÖ®écVš$EÞJ›ë”52[ÝÎNÏmµ…Åóm5{#HÜгx¡½©¯ÓÏ©i¤®Y‚ºx!P¤®I‰Hm©ÛØé=R_|_¤&ô,"µD»Ì‚_³§ÇÇ"Ê0Õ¸…fbºqÍ„xsÙ1ažà"OFñ­ÆóýOeQO°N‘ód}F+´sÒsH·±z>¦WÚ‹v³»¥êµTMø¨ÞRµ%ýÕÁ 6…$l§ È´SÅÄíT l$‘쥌ŒÛ#e£Ògw?gÙºÊWÙc¶ó&‹,W5P3£ÃÈ6ÊuSg!_ÊK…h{„”y~ ˜»K œb‘zÖÕ®¯EZ%#]”¬ñ@0ÁL¬a»ìת׻I«2\žÜgéÚZz7¾GDX¸#!D¹…9,íBþªHµÙñ WY:/ |ÏZ1ð˜zdÏ_¥›4H1ÇtÄ(²‡¥3ÑóÒðÂù±#ưJe¶¡}V`ôùj3Â!h˜²pM;¦ÀyÄÂkiX±Ó]®Û¬ð.»ã„·»#6æòÞ,î ©R;0%Ñ#èሙè¹G`xáíA¥4Ûà08©ÜÏÈ»˜Ÿ‚¼uÊ1}Å¿ábx¼}cc“ŒØ<%6Oñ¤›È¿D4Ææ)á7Oixfz§4=£­SðÓ¥;§?m¾Ô¶+`? ®…)ƪø7œUìÌ2»Ý¨—P{'Œ%áJcEÂ@Gu‡“ÇëÅC¶zR®õNáÊ""`IÄÜN_-òÛÑ@#IL¸IR1ŒXR|ÜfL¼Êîžòhƒ¢p¥´AÊ ¶œàè õ6E 9?Oüþtw7‚¸‡%(\ie)FXüNVgÙæbqûu;‚ñè$8HF$Ä#à~W‹ø<ôüØìºÛ€±ªlÃùoAëñ÷ô§*&âšU,Ä—0ÉÛ0åª!îà â!&~*ù(.‚µ»ÅÅjÓÜuß½;Dwï&|¦Àªß½k;>cXÐÞº nݱW?°0©b„¤ú+köÛlãú â|áÎ󪦿Պ£Žè ×?G Ñ£®úD[&Ù,*-lÑåªü^`’Ê—ÒüHQa]qÅ'} žY]¾}öîøÕû.ŠBaÏ6ßWë¯Úe¡§W'èU<°K½Ø´‘ óïiŸ;¤Ü¨‚5®­ð›¦ì›¦½,ð”Vâ©|T9ð#ú×þ§:·ÿé*C¿©ç5^F%™S‹q7ƒL^ImcPý'uMeÄ%ù9æòf m„<2ÙC Bi^$ˆÓ^4Р›S=^Ley1óbÚôì0H¥¸uø1Uvó”>CvN}Li;7]sع§ÓdE;íT´SŽzÝ4°Y–U¹Ol‚±yðuy@ÁÃÕˆ¥KÍc©?|HÜÕKŠƒ“‡¿èÐàdJ—½¦ßÿ @IÔ‹A/y¯–é¯ã\†’sü/>œÔJÐ[SïBá§Tˆ0ˆÐ.É–#‚eú=F¿)OB£Ü&„‚hcaââ^('?bæf(' ÎypbàÁ†/ÖÏ—¾vú–‰å“K½ê=ÈÛYÕ™% 29ôV#9d¥öƒJ!¶U€`–,aOŽKA ¢àoN»Üæ›ùË—ß²ÛÍjMmCíAT­=ˆ†aµG¼—{;ÏÚ” ï€9e*–rs—r]Iøã Ú˜GúThôlu«]ZÕ×ïv¨GèƒÖ#DÃðVî]« Âü6k‚À#‡²?´¾8í¼õžØÓ”-PŒØþmøœÞ–žþD¹è‹m9°˜÷âxfò^WÜhzª~¾JzêMüéƒò`Ž^nº¿¹¶Ý}ž /h1lDÐT\y;e_z¼ïÜ3¦5=~¯“îôËì{å]QŠÀTøš¨ðÐï'éÜ5VȧR«fB1H*$4¢³JM œ*µVß¿XVµ‘0°àù—ï~ÿñâõ•»^d*$ŸÔÄÿšÉ0”˜± ôÞ\¾?½¸~}uóêtVl“m`h’S¸CŠÚ?ĨBÝåà°)î¶È`Š;]LJ4o"Ã2Àä€1*Û`ÝÙa)q-ǘ€ÐûÉtóÑ׎2–VžÆ1ckù‡Ã²áMb ›q§p§Ò~Ø(ÞyÑ€sAØù5PÑ4ßüuéTlÿjE@‡nËhª l ‚j© ì XªÔÖ&¦Ûsü(Ù§.¯H 'œX‰¼á¯$Ö2=æŠUש{ÆSнLƒÕ¢ø}¹*âª,¿]/Jù TG*Â\ë¯/ØÎöÉM[: æ°¡G±t¹Æt€Fª/Z I´ 4'Ýf¢hò H0m,à[¤izéEíK+Lr²Ï 8Õ{$p#Å„ŠÙ¨SñJfˆ7d$P§É蜑aÌ€ü¤+Ò€³Fˆ,“¸A~ ‚i§Gþ`y`Õ.ùVDÕ‡>ù˜'—O Âã*ý¾µçÐAGy覀W¤Ä“Ž~'-Œôý¨ÃôÒÛÏ:jåÙŠÃH.÷ÚËöAæXð2‚¥ ° )Âäbä¡Fžg9À}$û6`ÓY¯CX"Ò"\*ÀåZ¦Ï!UÙˆ¸¼o¿Ã¡2”`Ùæ`ÉÿÖ -i’Xž#üë\t*lËXé² 'cŒÌw¨#£$èéâYìϨ|©)¯¯¨õ$^ÐvªÂ ¿‰÷ÿ~^ÔŠ.Á°Üž°Ñ†K: Áîîóç{7¼&wKî# |ôž—Ù37é‡w_C¤ßÿŸOìØíËÓ”<K²¦$&flL„+V†‘¶1¹x™Ü T¢­Hà\ey¶9ù’.óq`cjÂ>ºÆT wh]ñqÀãêB 7[ü˜€ì9øõ<ÿ¨TƒÕG[ÞÏ–óyè»7¸êvë]êÊV˜m5N]ü3ÜÊEpS6Ö%ï6Ó±§›¹Á˜4Ž‚“Æ1il"iL9†RÆTI^P=¡¬ˆ Y*+"ÌÂ!.(—§ùuúùõ2ýt¯Ó±Ày®µ–ï ª™•#¹‚²sÅ :IŒ‚¬k´Ý–<];G}Ï×YX=?o·®Ú`µc"ÙÂb)u“Nð•¬(Ç–¨À¦k,H¿nk@zp–m †Íž û`µKî¤à’ºI/ŸZˆhB¼¹lµôr]t;w¬«¡}ÿSƒŠðQñ¦¸w0Ówt·±|>¼WJŒöSn˜)èÙ’ðÕ>P½gKkû‘vv°}<Àú¹[¤û"gç¯ÖGVóXxÈQÑ1tÄ!¿É{;ÏZ•¯Þ‘Ö©O¿+VwsS¬îºTÖZ)n¨ÕÝ ±œNB”ÓÀÌ #ÿgE˜'ÈT3k:¢ù×b’ËßYcPIŸÛzkFRHÀácˆX#hŒ‰!†ƸŒ.¤0F.°cP¼ä8¨¨ÎúÜÅ %•Ç % CÇ õ9mG(9Þª#záŸ;>‹À:¿J2†Àº¢#(ei›Rp&yžæŽ'Åcz{cWLÆÐzÒ¦«-hÆŠ1z#r;Ø…­C«„´é(ù=«¡WQ˜rTe£á*‡bÑèÀ~à÷”ã"Û|_­]âyè‹ø•« ¢bpM!÷°ýàóÝÜÉñåpÊÍÞ¿zÿщæ¼Kó‹ô!˸UÕd¸¦®TÔ…¬*CkJGî·f¶»´¯ymøð®$b¬ê€È \þ+fwÈqü=ýy±Ú,î~ŽU)j ׋šÿUƒ`zÐÚq{»zZnF® $‘¡ëIKjB±>dMyýc“-çÙü?Ši¬ŠBÒ¸ž¤ø¯&ãCÖ’Y¶.„âzñ QÓ†ŽÔ®!5!þëÁô`µãm¶ùgë¡îxäYUç2Ù[‘²¶t ­,ÍÍì:#©·ÀðbèΆã»ÇO›/:í.°0˜¸ÕÓ0´ªtVû"V‡lRŠ«Ø§l~’>:¶*³Ž×IjCÖ†”¡e&}ÞNm€9s‚àÖŒD`zhuæìÁÔ ´=SÑ(jb+´¾m“[™é{C4ËO¥'W©Z±O²ŒsŠúpêšìããœà㜒Í…]‚Œ¡}›siߦb¼9¿æœòk\WG5ÕGc¡ÈÏ!_O¬ø?ÅYçHãrˆfrVC÷ó¿e?÷óWÙ] ¶?ê«–¾ŽÍUje¨ïŽ’ùÅóÝ$µMO7}Ò½é‰ú¦·õ*oåÛ©<¨M×Z<2 BßXÊ Ú¯s_æ5d¯g 7ÈäÝ^î;ê‰yg[þ[{ú“ò'.‚~×Ħ‹=„ Ñ3ˆž|¥‡‘ð×øP‰#Á”µ p ^?.Ž#ÁãHðþ#Á=H¢tF²]zà%¹“°È5¡ö‰ µO*µÇï„/äßÅï»ðËðr O3ÛAsgçòÃìÝùñÕßvÁÂÛ„ .¶EîŒì·b—7Oëåoõ£'F=á=:1òèCæÑÿûàÿ;a˜}±Úy\Âz÷´¼‘ÍÎÝj½³*é~•Î —õßx߀ºFV^7@'QMÈ›ûÕj~¹^m²[¦,d¾zútŸÁö7ò•"†:$ÒeÛK_Š irvï®8CR«#P½BiBL8@ÝBq”Î몖‡@i«> ‰éNG@"¸]C¹TŒ‡.û† * ñJ^¾lðµŒIÛÂM«—Ù÷›“³E¾É–Õ弊ÿò/…ò¯zˆOÑ¿_Ïçkऀð‡ñ^¾| ‹#ð;^ w0 ’Ñ7½ƒE<êxÊ>~Ê<¾xÏûž£æ{^°ïyÑ +Ôë ^Ðñ¢!¨½ß}º,غŸÿ^¤w«¼øíÃÕéå:»[üØÿ4›íg`ÛŠŸåæÈ 9 î™@BÑÜ ´ÐÉ#¨˜`ÏcvpÑÓ¦UúL³ƒažfÚX5ÿ³² êµÏÎNÐM[€nªtS彛ʎ̞²ðVÌÆDT†`°kB.LŽZ¸p¤Î…#e.1\¨\.+ŽXVÔžLÉ#’/øq„øñ¢… [ÞÍÊüxÁê×+ã2çËGWrêE÷&œž½b‘õ§K¯šÒ/*cÙ§àÇøñBä’kt:ËÚGnãÇ‹×W2%}6ë™ÃT 0?d"ø ~ÐAHAU5@†‘j^£A6KŒ™r]FÌ.ߟ^\¿¾ºyu:+$ÎÁ¹?K•Ä™½K*Çýõ§˜óþZЛÚ+n¨r¯ªàiø¸–OËY!š8Óòê¤*…&AE85*R„"Ú¼aÊ~M}Åp:´ÌPÍfpã9:®•¡ö°hAgØzA2¼vT[ئ"$ë[Åà i jrY•Ô¸S&ÝäFO.]MPG.åÊ-ë½JrÙv3©TfÖUF]9KךƒÓήµÇÕÕ>­Á+&dx%b®÷µhPÅ| …¡Næp•¥÷CÅÑ'ä—;Õò‹ƒ×!’ôˆÞÔkDm„Á4ù\·—fÉ©Î?·Á&UįP%h“´UªÙ?³T§û«ÿÐÁQò úÂà•ˆ8ì^‹¸{Ú•M¨÷"Ô|¬¯"‰kª”Æ£R&ÕyñfoVò9/Wf%“BÕ¸™®Æ™Ñ5ÞœøÖk‡câeyÔ¨Þ‘?ºn o;ºÆ$ãvN´,¦ü‡Â+IàÐ@øËX¯à/a›Yø‹{mg® #–†{Lu•åÃfD,Ézƒ®°Å¾AŽ{ À"ßä¬ v,À——Úà2w úvï1¡:,(Dz-¾ *T„öYShËUB‘ì^›~¬ÁM+–~”P”òm-…¨V­gF±q•P·ižTV‰a•–‰G˜“ÄÙ´ÁjßU‡Þ5õ¡?éS¹2°Ë¬¼m <Á>‚,º?Ö¼q–íÕ¼@–°éŒ¤]T£Åæ’-üF¤Ê‹YåE-úæÄl¡o8 ÃT~#K¹ž^Ðr@Dʽ¯U)?‘S¸¾8Aé°„¯?ðéêé0^—I%±W$n3&l.Œw›1iÏ$0Ð%¸»¾Ì]²Aþòƒ¤U| ºÁ}›mÀ=óâÉÛilOò² jtÚÇæÖ,Ÿ½­i‹¶Ö¨­mclvÖ8£²±mÜqg_V&–@* óª‘OÉ«¦³é“ðL-`e)},-2aŽáÕžŒ sä¾V`ÑvV<„¦sQü¾\‰ùízQê`ð&´"q8 êóI½,¯X›R¬_îXÖàĨùÞ¶Ùæœ§ 7ì®á'ãMTåì¤JÚ+2L6êW| ô™áéòvõPZGÛ”õ"ÌÏakÜW,aµXÂ1il/,Ì;ÁN‹&,ß7•µzV©Ç•SÚ66š´pN=›_»[F”Ëô!ƒQ%n§8M4Üb-¥Î*âÜA7ΪãœèµÉ kêÎÙ]?RT^Ô4ÑŽšÜ™iæ°æ_"hjx¼ iBºH‰‚‹ä.²”æQÃPÊ36̶bÆDË‘š*LÒ 0Su€õ¼’á/Ûý*4€ÑZ?²ÚÂ!\3 K58–ŒëiîW¹¾+65˜’h.J¡ÐƒëRÙ¡”W8¥>3•ð í~µJiJ‡ É“‡* ‹Ux¾˜‘ɪ"!¬pEËAáí¦ÒÜ&Îç}*ei®ï¦Zçg‹efJä23<¶LÌ!tö*ݤVôÅÍ(31}~èÇXÇ”íë™}"ø‡due:R=é¡fBõy —Ë·_²ùyúã÷§»;¦bv ‰ Ñö\“¡–¢ÐÈ%´æ¿ûk Ø{{w}} rÚ”Üã i¯_òPÆYbÌÈ3~ÚÐ6^‡„ ×»¤"¹õ§|r¡ñªJCXú‚"zû%]Wò.üWý×|ñÏì¦g1ù=ŸžîÔïïW·ä‹è;5 Ô̦7Ø ½îyñÛþ}Öÿð¼Ö'6 AŽ{m¡½ä“B" /ç³bÇ+—ˆÈþÎŇ³3ÀµR8„ŒQK” Üc ưþd)ÌTo š1.c  <$¶äÆ‘x—á ›‡«—Ë„#J©Ì7ép—Z·Kr{/m)¥jõ¸1ÎàôæëE,ýä¿ÿclŠFk“P3Bpƒ¨§M7‡µ±ykh(Rº-݇v÷!ÄBöÏw!¹$Å™x3(Ø›AÕþ¾Y­o³³ÕçÅÒµg¹‹‡Â°=¾šŽA²Œ¼;ðkÝ]r7í@¾_j‹ß!áæ2GÂûqÒs¾{j§ÚÍ÷‘Sù!ÏÖûùešçûŸ~OóÅm°ÚŠèŠŽeoÇRÈIï½J³+ç»”jÛíïíÀn¦ùz/ÐÒÊSî@Ÿ‡qKpÂä@nO‚ Šú0eûô()p>²ªÓuY8WÙÿ»¹)?x`#š5~â¾ùh“arÁ¯àÆz^ ë¦N#“V†ኺÀ½¸…—Þƒ¯éµ÷A˜BKfkµù»`©ÿ·\ÒKøv ÷°K–¦P‚½Ö ïyÅQ‰¨-„ðb3Õðû’îô5¦‡AÄ'ª–S7`YÎh,£±ŒÆr§ËXj¶XíA¸å‚@º §«º‚ûUÁË›Åržý¨Á²2õWéòëÎÍü¬— qñ/8Ia ý)€¹hùû#øð!éÝ|#ß^‹<4ß :To¸S˜Ÿ¡+˜Ý«ŸT~3|È—ìö묚¬t<~ãiäÍ·½Ï«Íjç¼ù¦¢±äO)ž÷¼ zý¡|x± ÿ9úÒóãÿ:9ž]__ü­I½žÓÐëÒóç{;¼&~S`—ѳÿ FÁ4Wø–ßjá>$$ã=ˆ0\¢a¾ÈÓÍíšRðQÇèo¥IT„.ɘl—"xIî$,rMèýÄ„ÞO*½Çï„/äßÅï»ðËðr w"ÛAH±³sùaöîüøêo»àGáU@Û"\ýVlòæi½ü­~òÄÄ“˜'ÿïÿÿÃØæbµóòt÷´„×çïVëU÷«t^¸ÿÆùt^Yù??D·'o/Wzg\>ÞžÀô„]KW‘1à퉊“CÞž˜T¿Ë I_»PWåŸ5…a‹lM‡ŠÌRª î6¾f/ÅãÂ+ž‡[ZÂ=¤¢Ï©ÚêîîFjfB±"e™rÞ¤“I,#à^C¨¥É“O:²•¸<¢àH)qI Áþ:ê;Ë–Ÿ7_¨“¿ý'à>å§óýþvž:ÊÝÛ;^oçR"Ûó–n¦9ȱˆMÿ•*-×Ãjÿ(ç9ÈñÎûªMó«—¯Ü$ï~µv³•1l!'i!ä :)›Bvª)È‘¢‚L»äH]AŽ´9y´‚h­92 '#ÈlwUðòÿväέ”³qê!.œå¾ýˆzûÑo’®Ýïïë?k¤÷öŸ}ö“{ºÂº—®ô\áèÿFÿ7ú¿Ñÿþ¯]ÿ×€#ä·ÇcÇéëL¬z'½¡Ëê%‹èNDw"ºÑÐs'úIoíã “VÛ¬bbÄ*š·~= \¯êw±‹6-Ú46MÜ£˜$6i#N,æö¡†Õr1wý§ÀSNñÁ‚Z zkŠc]7~J¬ëö¦ÐÙcˆ%Þ~@€áo¦º$#ÙZ°L¹o0ôF+‰µç&p0!€AEì’ŒéÖâ eÊ}ÃÁ¡7Ú ôrϧaí¹ ØŸÖêÃþÔá G&‡nôŽ#sjÍyvbæÙÜ»™S3϶s;~…ÂýÌãù\ÿú›jûwíÞÕo‚êõWœC}€`÷¼òô0ØSŠ¦Ø H†—­Ç%-¼ô¾éµ§ÛѺ½…mÞ×-˜^;¿jŸäÕà©Ô¦\妸FßôW;Pœe²È,„Ö}–jhN 3=†<š°h«{Ûê.†zo°­À·ÚÂíÚ¢>ã«Í›ÕÓÒù@`WC("ÃnB‘â(Ûê˜*‡Û!ä*›/ÖÙmóK\UHb¦T³L΂ÕLJô0z{bVzï[^:ß« e¥L±+°¤sRî3£Êìò®K]äëSg/Œ÷»ôUüqjËôºj^m ª™ç4WÚÏϳ|8XkASêG½ô!ê`õ- cáµóŽm£´¾yÇvÜ·ÆZ˜é}Ö ü,¬ÚæO7?éÞü©úæw_Uoá{[=¸Í×"e…‹ƒµjIÂó_ö÷Ê=÷SêSY×ÍÚW+zzé:ÏŠéCN¹y„;FzYùfþòåCúøgüŽý?ð[ÿÚÀ /­éHÕŽç#WmÝH¬y±›Ãÿî?äßЯ¬7¥}‡ŠÐwÐ }‡êÐ×îuÕäK¸\ÞážñÕ#Ño‚Þ„ïDb'zB•Ž*ssS¨Ì5ÞtøÊ·"]­ë77›ýV[ÍgìÊ"´²‹u[µþYÓå._rBbÉ6÷½/!К±C;¢p{ÈÕb_¾$!†kü÷UN;¸Vá² ‡²Y[Ågi˜0Œy½û19i *ÜØ•«ˆù¨rºgúìám¶ÑÍry(šˆš°%1œ`b.,—¯Ò wõfñÁ¶ ‡IT‘Blƒ#zv7"WZJ>Iß òô›\8ʈné„Ëc¼Ër¡PøøÇZ‹®ÖœÝç±H¤YÏw›º…D³V,溓: |#,¥ ¶¥°ÌÊd*¯L˜hUÛ>Kõè5£z´ê¨ªÇ ·!è-pÐåÀÜ G:[0Äš#Žùû ×7±ð»…‡Ý ¬^ïbáÒÔÕ.Öq2|= =^ájTñ‰«ìaµÉN/]Gný;LeðÑ&D%±3 L<Œä·Ccm+Ö¹Êþç)Ë7'«Õ×E— 4tK÷h‚å* ü[ö3l-#HJÕ0E£)ìf¬÷…‚–Hè*ìÀZRÿ4ª-Àpµ„³l97ê~] wÕ¾æemB¿)^Ó‹Ã{c3½G}ã‹çã½Ú¦P°ØÆ7ï‹/ž_¨(¨U#µïõqK%j[|ùüÕêöjµ ãN˜½‹çˆ Èàlæ1%ÑÌ0óbf`æ /žoæ‰ÛåX…¶ãfyAðÙêóçl~ºÔÎÒ(¥GÊj ±˜ ;?…Œ˜?.C•[݈Žo@µ²ˆE°|¹kOÈC#ˆ!`¥/U‘ Ý/ë–6_Æ}Ê( þ„ áùéRÉçÐO–Nó>Æ0„&+5…a+EMÇðz“bí xnÓ•·½BlöâyÅqüf‹µ§D¬Ž¼ÕŠ¢íèH=ï ñæ²8#i>Aº²Fõ€ne¼䤽O@ºöó7‹ûBtƒUfLY¼F'ÏЮkt†z_aixé)·¾²R{麰 ª Kø*¨^Öz7BÌ ör°(,…%ZÂ@d1Û¼o€lxéiGëãît«èf -ȃÞ#¿]³²µ¯îå¢ÚtÑ»bý½-ÝëªBo+zYZ¢—½¬èeIzY¦Œ®çÖÕ¸Íìe 'A\¿tÛŠ‡5jÑœEsÍ™Œ93áþ¢÷pW>1Ë´=eG:Þ”„Þ½úI½šƒV4˜lú/• `ˆêùó½‚^“ëAK\D£¾•"$Qº$ÃJ—\Á2¹õoÒåâ‹ggµôÖÇvÈø)L#tIF²]`™\!ÀËNÂÚhˆ— x‰³ðtªÉ`xú4‡óàÄÀƒmô–/Ÿ¯Ø\>ýh›¯0_Gu~…‰Š9?yžvöÛò4„´ŸáÕ~%æÆgYÅã¬êíÊ©QÆ<­íɉÇÒEm\´qV&I´ƒº¿x>èæZ<ãò!¯ϸüH÷Ä3®xÆϸâWý8ßG~6¢1ƒIßF"Ô|z…B†ö]šoIzÖÕ,ÌÑñ$f1E1b•ghkÄ*f¨÷áªá¥‡œ³ÂN2¶«A<ºùØfC•?ÎÄ2f0Œ4¬ªEÓÍÁr,Z´eÑ–E[&cËŒá·Ð=\Ò3+f\}H4ÅŒ«é–˜qטq×úq^g\Q—©tk#«i8׊Ÿ¯V [~$ï“iu>ÿ2ßÌ_¾|H«ûý?ª“{õÞ¯}¯µçhXfÐÙÔŠ˜¡BÐ0†f¶°ÉäÈÌ:fÀÖ‹@lùò5\‘JÞMÍÅhç‚%Oc\¥ÓÀWM](»&f´¾ŽÕBl‹œ¿[:ÿŒ(ѱüö=ψðl—ð¹¹Aïd¼Fè2ðc:KÎQÅ™ëUTÚëÕ(Uöz®Â[²ÅêJe0ÎV«ÇBü6ÙMÕµˆPYz>R¹Kí fSawP&Í]Àí¶½§Æz)…·vHè}96T:.Â#¯ö ¢C¹Æs;æxìUOL©׉¶u÷éÍâ>»\åEHV¼Z–&~ºÊ ÀɳýÇ«Õ÷Æq]ÅL@€Vx˜û7³ÙM¹ÂHâÍ„=ä|¸úLX8‰(î&J–¸Ãaù”žÓâWN‰Yd&ÏNOc3Ë𣳠7eiï9A ’´(ˆÚúHeO·„C“V/ê¡ÉJ§Y„E¤HãåØtû8&ޏä¹Ä µ.…#¢¶Çø&†>\ ­À4~uÔd¿<`j;Mêq A¬Aá$B1¹ â"Ùš]ÍfÍ Â¹Aµo@ˆÞUÿÏAHQ3î4ågðó%Wƒ¿£:õÎF:â‰Ciéç ¹R´oÄëVÓ¡×Í] †]åèFWÛz ïo·1£¥ äÐVAˆ+Jú)µ¾±o—¾Rßü2õv‘ÈÁügVTCâÀÝÓ8¸ß@`†ÞÕ¿5C'ÓckB ìѤ‹I¸­…‰‰Ä +&Oáµ x8ÙÂ$ŒÎ8¤ß$ŒÎc#ÓDßÒ9»´Y¶y—æ¯ÒMÊ;Üé—ŠÀ'=ÕÔ>}™°§/ìu*'¥k|vÁ¶Ov²Nnùôù’·¨ö]Ú¢ìù„Ï>ø@õìy[¥š, ÙSa}"N¢c²pÑ!’ªu^’•tt%‡0òéžp’2`¡Â2Tp4BE —:ñy 1ÑàC¢½…$Üàû0´à{;¢MYo¨çøEɨÎÌ$Àö/ÓAAÉ™9¯p$W¦8™CЧöï‹ x1Æœ"Až/ØR—X‘Û^5ã!7DT0UvÚañˆ HLÓFy[›ïXÌ^¾Ê¢rx1F$È DÉ «&ÝÐ[€=Žþ¸‚Â2¼­ONé‹êî—·³Ô‘oN ¯—þ9u²9´k ÚðØ€K0â3þ~ü·ú½äسí*CÕÙ¡¥  vŒvôè¼5}bb ƒŠíkTmŒ£ê½íu(b]õêÃgrˆ÷ªUñce”¿÷¯»ÏTD;޹‘è¸,$rk ßr¼íñ)¦_Ûº‚RR i$ÙÝ“Ž§KIS ¨Q”7¦´š¼©¾öLi¹ÓÕ2±%«ª£O{AOVOKOúcä‹f7ègÉ…ñªgIž/i«Z1)eƒ[ЪlH@dt ½uhíâwÞw¯Y- ކ‰+oÆ«o*­úéZkGZMÃèê-æ¦/.ùÿ-èôC7‰½(Ź1RmDÔù§Ä¾“ú‡wÜ V_7¢üˆýV0¢ý8yZGÕ£™1R̓Ä£xh/ƪwF•nð†šk è²Õ:À,×è´×#Õ ¹ÎAÄI›å P„WPëàë$¯7ê•·bÌ·^‘m¾oæJœT·ü–£c…„ZBƒc£ ¶8ã©sØî¤oNGèã¨N¥Ž7ëNõnÖ‰yÒÕ:ÃT¤Á5ÄWäŠá®ø´3ª–¦ìª)ZÒŠ½Ñ7[7ek 6!r~Ý\Ãlš‰)X³Íe4—Ñ\Ú6—ªvÁ_“àÅÅvÌ=¸b“¥tèN\ÿÏâ Õ%Má]ub˜cúÀÅ-öÒ´¸_Ak<ùM­Ùë+c侘ËSíóäPßmg½›«,_ÝËÎ Y^§÷:ú:â ¾ wç¿>XÅ¥iÎk˽ÝN†ú~eשÜm]FÃâ]Yà>].ø}¿C©?¡I Û¸GÒzÊê‚ÛyÛ¥Ó Æ57ÝRN²à¾Zþ7¬]ˆOW«•^q½Â^ã^ây­Ûo¥Ð?°A¬)vDjô ¬;"I÷ D"g­|ØV7¯<A¸S×Ú!P3|ÙÖ^€[Q¼~]Öm—·Á"WMZ {z‡=mÌô>ä1¾x~¸D/¿VfXmáG@MlâgÊ ò{÷mqOhТ‹v,Ú1;¦ŽÜþ‚öp)»ši±»ž˱¥ž%†±¥ÞÀŠûèÅ>zú”{xyÇf=^Äe¨}/¥i¶kñ å·38ù<ˆÀ²T.Q%â Ríùî:¤DäÄx²w<)ä¤÷Á¤Ù•wE’@Q«Ó*¬MÁd©ð2‘$JHFÎÀÉÞæKhl| ø–ÜxÁú#ðš^>'C^ƒ+ç/´¥êH#­°Š(¬ã‹oû5ÚŽ°ïä>K×€^çóL,5Ü® »ívM‡{ÄÚ@ðREîM·à¾,Ôpƒ&S aâɉg\Ãß"å®Z6†4ºð®’BŒgUÛp¨NjádŸ]®JaZùRšß”)¾GŒBªP²ò#³wǯÞ :°4ŒÓU Š Öì!õtÃ.}°ïqèEƒýþÓiéP„Šù ˆù&2‡ab¾Ñ…ËŸuaå¿™Ín€nûvìÅå {èE"˜Üá…y‚C0¢‰<«Ø,¶ž‡ùdH=+LY^Ùã[v»Y­0uß ~!ÀA¤DkgÂÚZ²gvå]1N›“Ø®QʧŽëå}¸˜ko6P }^e÷'OkÀÅ€6ÙÍHzq7è »%wƒ÷PŒ•®ÉYŽ¢9kÐ]@À°ò[=Xƒº¡+æ òÃó9îÅœMP;KŸn=èH—Œ)ì(þç`ÚåZ¥ð?Ç OøŸ^(SCƒ*N‡[ÐÜwÖ¹ÂàÀÈ¡º`Zƒ×LˆŠ¢ÀøºTñíγÝÝÆ·íÕT1ßBÅàóÖ’AÓZ“gZΛ(·D¾n¾6ÑñZ*!eéX¥àÌ/}Í~î+‹#CÕ¿‚”˜_ê_ârÑûÜ’¹UóóJjÛœ(nó¤{›õmn=gá2Œ=d c›µV0Ùfì Î}¸/óN‚ LØã¾3¡Þ™˜OÊ«Œ•.xpsòß'×éçwér~ŸÑ]Ë>fŸf«Û¯•¥6âÉR_gÛ¡m¸ûˆ¨Ò²¨T8‚ÔÞ&ß„5mR!aRñæµuÉ?´Õ%ßôŠÅ>@%£b§›‘¸½bqŒ–Ch FªÔÓ÷‘/ùñâõ•»¸B›z3|©Üq–_þpi3§òvîòýéÅõë«›W§³b¸Ï\ú$4ˆÙ9=b>ÊhSm]ÝŸ PK»ÿ-^è'Ët*a’¯O¯éXI¥Ñv­ÑiñÇ)÷õW5ŸÇ¾Äh®j/¤#Z•:‚^ÁîÂø÷ºØ#TXXvpÞÏß?m Œ|bÔÜIL, tH½&£_¹É¤uÁú¼=i~5BÊJ·‡™ºggá©pJi#2Ñʃø K3Ô×XÙ.ü°Ymó§Š›ŸtoþT}ó§}6úæk€¼‘fÉÕاØÔGN7ly×~õÙÏ#©ÓGú²‘ÇØ=xú¨Õ2Íï°×Ô–ã¿<-牂_KXåóXÜwN©wN•b»ß/v‰‹,Ï Ñ¤"˜8œà°-$¿-Z¯Év=5ÂÝüt¾ŸŸ^²~½š ;T´aÝ6ìP݆‰x5µ¿¦Ëκ‘h÷rW¼=³ëd™§§vvÖÍ?·#r³$âÀÄ, \{%:ü1˜½­— ºåÚ‰CÊN¶¼S½€Üƪ$–ŒÜÑ* Gm³¿ùdÒ ™H&7i°L²ˆ“»¥zƒ?çS¹^(;!¯®*øXZÍ ²“\)K†šÔjTïµÈ®°~¯ùD_ÁúPk÷æ_n‘¾\ŽC_.Ô—Ë‘èˇœSFãBcÀ;Öð•£Ð@ˆ':·q¯K_JÖ zÀóÜ^¬ wà¬àÑñífñ-By6‹‡ìf£rÌÝKojbG¡=59~èP‡êÜ—S ]™€"Bølø—gDâ›Ö-øw&„ñŸà޹y ;ÍÏVŸ?góÓA¢uÕ}åªé _³jZüP+xæÔ¦\÷Ý(ÙP–ãùÃbôšR95) GG ßCVsp}P—Íšb°Ä…¯!,EÃä€qµBƒ¿t!˜3ë²£x tUá›å2`3±¿b´&Ó`•îcÐÊ1Ó‰þ Žî\~˜n½þV†GSa(ˆ*Õ«ðLå*'‚ÐKžá3_…ô‡$iÑÉ}–®Ï‹ºÄ䣲¬ êÂ7­ ’†µ­Mk\ß,îïMˆ³øºŽûjÍŽ²ü©¯½­,Yסn·(qË·.ö/ö„·\0ö5tIT&Ä?›–ýx>/Ù¬€Î›-/þ©x$¢ƒ˜9¨«2ÚÅ !“4 ôaJ¯¦•c¨§%µŸÊM#­ÔJc)R™$zk¸³Héš=ÝÞÿŠ@ÍjÄžqA5"*‚µ9°²4 ¸6»|yÀÆê![ê ÝÓ§Ë~ªé=®Ò‰†{é_±ë=Ы&ÐöH/†Ÿ»¨çÆõbsŸí?½¹O?çc¿›)ïnžÑu§[q7OÄ2O-“uóMR ³É:Yâh4‰ÐõýE¢J÷M-«×1ð%ÆnÿÀÚ·ê{‡~]Ê×u4/åsœ€hýÃ2 ÑúGëßûf¾Ë6F£æåÍ|¾)›È˜²N“eÒ*iôpf­R4Gaa”AsÔ£Â#C£‰”ü¾ ôþz.óûtƒHH‡øËt±n4ÔenS,"«xuó¨…Iâ ¿¾ó)››îØËÎMiœê8æ09÷í2]§yLÒE\T­v⨮ýÂ'uw–‡0þ¸*~²L€¸Š‹´Íºé„/,‰xrùÇ«¯±îWÿÝ€ ¬m²¡–×[sý*gõ aé†d0aP\12‘ÍÝG&m7NVvJ'[› lí´%[Û0LÝÙZNßN.±o;³µÓîlíÔT¶¶E}ñÜ!jWQ·U°Êp¼Mæ‡!ç“ù¡ï‹N-û¢Ž|Ny)72úÑŒþcô£ÿH ÃXýÇ|£Ý"㑆3¥ð *—¨rïWÅ.~ÿ<ûQûåW]"t•.¿îܬÁOðÇÚ£€Ä_þ²Ãޤ?Eø-Ü¿?´üý|ø°²ô…xß|#ß^ÛPä8i8XNŸ?ß+þ]¹;ð« ª}Én¿Î6`4}ñÕ[(›~ómoçój³Ú¹o¾©xð§¿Ï{^D½þP¾N¼Xü}éùñÏ®¯Ž/þF¹:h£€‡žýgø0ÊëÁßò[½½‡5àqè}舆ù"L7·_hJÁODS¤Y‰k£(|½™Ø…¾ä†E® ÉŸ˜ü‰HòYs%ÿëMbWòaøü †—¿‰ØÀ LÀg$â’ƒ13bÂe„’oî7L`Fb3’ˆò¢0Ý.ki™Üú7éÊuÚÎÎÂ%H¯‰wÎê?5¡þS‘úO£ú7DáÈCK9ˆËà##|r,óÇp&Ó Lç!QÚÀyT'~'|!ÿ¾(~ß…_†—s›æÙÊKìì\~˜½;?¾úÛ.ø±÷bu±1…¯¿[½yZ/«Ÿ:éûÔCÞS“¾Oòž:íûÔÞSú>5až 6üì5éÞôD}Ó9•¥r|c‹5ƒÚt­Å#3 ˆT*´<â¾Ì«5Ápß™PïLÌÇ:òߪj᯲ÿyZãOªs u0©ŽGªù ©k+L‘£fŠ5§Ö‰ãÎÔ:ú«ðÔ:zDÜ^Ï®CìÛ/ÊP{šÚðµæ­N¶Õ–¾pÛóÕ³¿Ua<m_o@¯4œ ÅqbnÞ’ µÐuF#fKi:ôòÜ‚¢¸×t—vEA×¼œÚHí(´’⇺ ­”°0hÌݪS«“™™hFͪ’ئÿ¼x‰Óøí+u(høtH¨QÙ¹¢ËQßì¬í]õ»O××g¬†U ×)g;@@ù:Ÿ­Þ¤í~EM·’u6dw4á¸nÌ.Öw]kF§æÅUW¸¦êBs¨FÇ„þ€úe¡ç˜…ô`[7PoïÜ>0WÏîÁMW/9׿õ-J>°X”¼-@m%7!×P]rÓ 2[˜[=¿³6—YΛÅr‘#µÑ‹¢aj%nSá‰çõ©3œ~ÉN‹àY3xÅà0µÒT9ž§Æ'O2¨"ö_oºZùÑÞ…=p¼Ã!À²LkÍ–ª1tUÄU<„〶K}Óð;d•<ãÜéB¥—wjÜX’ˆõĽá ÔÚ¹!¯:T.Ãêö«µqų%]ŠïÚÍ?\^È·ø1ö®ˆµáµD4·èTfÎ@)}uŠˆ“ Å…>^€„J *ÖR¦ 2Ûo£VB„)sVïò †LN§ªR5^å‡<2[xQ7oVëÛìlõ™SIeU8ÔPÑä–Xg‘%M…ke ¥p„Q³5È‚(ÀÔ÷KM±W½!PÒ–ÖS^Ü(¿Rc²‹ªVª saYü2ÍóýO¿§ùâ6P-ET¹VQ5—ÜïË­lôùbù…§£¿TÐÊ3Ÿ/˜_xʽLÀ›qR"´pÝ 6éf;Ù¬\n¢ r¸“L(7Û¥K­ãIÌ{-6nLHºCÖ¾ZÑÏÅ[ Š>Ë7æ¼­€€4¸€Ÿ«Ó`]‚šèðôuxZ™é¿Ûc~ù|秆}R—Fß 0ù² ps=<Þ§›ŒWúi't=9_ÍŸîaáö´|(~A3 $brˆTã#üûöl,[¼QfpiÁ’—/_# º‚Ž…ý—Ú@„ÿ` ð‚=\Ífÿ²7P«@Ñ­B?«ÐÁLß­‚åó­ÂZupú.ûC™d™! ™ËdaÑȨp”ëfs8Ó”¿¥ ÞÒ)…w6»áN-ö-? ½«lü[™N.ƒ¦|áÏ  &{rLZ#Ó†G)KÆÀ¤ÊÄÅð‚¡°ØNÄ«Ìòü°Cû~˜cË’ë¤Ñ•HÚuŠ.St™¢Ë]¦-v™Ì{ž:Æý}ÀÁ}4Æ+iÍÙ8à© -q#Ë¿)•ÿ9ø°%Ë䜩R™ ¿·ÚƒkšI}˜±ä7Äñ¤[ƒ>Òžði¯òR^Ó¾·’;r8ýn&wÔ¹Ìÿ¹ÊÕÇf¥kþfqOC=E¬·°J†m¾Œê ±¦0¦Ä ¤ÄÚØDRÌ8a§ÅÚØáqbÌвÇ|šØÆ"ŸÎ O œ(6¼²x¦èàL±Ý‘ŠTt ¢¨è@Yò8ª7М¦Èu²ŠÌ@ »#ëœ k‘ÜÎFê¦õH@ÐJ˜9À7§ÕyþwšsÑ÷V3†WŽSØó3­šHC”I•æÕÖ #Ë*mkd_4ÇÙ*>P=“Snz9cËxµM` Phv —ó,o ÔlÑ$Å“'--Ü â Åôúùç,T¶½Ö©­è„ò6Û VðnÖξ/>—ò±XÎc¶þóN¾™¿|™I×Ùü¦Ø ªM}ŒuÐÞ¶fFÈímk*h¯‡`¨È¹¡»™ï‚¾èí’@»:P7Û?ñŒp„8ó)ëÏ]“SÀHJˆç¨‘6ì¢}छ.`\ñß‚%æ<œêˆ+ÿR@t\Mú>Ìó ¼Oˆ•»*Xò•ÎhÍÀ¿æ1rŸÞ­òÍþÓe±ø€5R½§~ÞS'}÷œŒ¯ï5U v’5Q =e0‚¯ðéê½UÛrmŒac̸Víü©±ô²å*§è‚Üi# Ê;ÚrÃ@ò ˜Ê··ÍŒ ªÖ0òëb ª­ŒRÏH÷pC!»9ø—‹VC\oGñˆ–0^B®ÙÅ§í£„êÊ1RXÔæYH+z95ˆÜ¥ãoÅ—~5‰vúÕôN*–9I#R,nð·p‹µ)j\`¨.îÎÀ!è·ìv³á'”0z:;ë`ë1VZ0ÜPëžåÕ ÏNÝeEg¯væ}|.(k JGÂižÏ¹×H ={‡Èð"}‡YêúpÒ|B u8?Y­¾.4´ÀùÁ¡†êè{sP>ìoÙÏp•ˆ"(¦Ãzûü )fƒ~jŒ¤´‚IŸ-ZÅØÎ'gÙrn±í^áU­tT¨yÚQ3²F÷ý¼Tª@A¾¦(Â{?xoã¤ïÀn|í|HWÛrÿë7ÛØæ{§ñµ§5œÔ”<H•åµwïgä 3OÉUx³X.ò/`ü-ªà s¼àC Ò䫤5,×nP° þ¡eŸ©#¿r&°Ó  ºÜŽš2©ÅCë©E «»P*ÿ¢>ÝáHÄ.õ]Â#Wï‹Ðædvõ¦¼7âÔbEcà¹ÅŠ’‹5SÏ.þ&Ýd=4ÁyzQ5îÔÌ-6Xü´ÖE1üì~J0Ô÷(Ô ]ùE*2iªšFšq HÄu‚±ðnNþûâ„jžQ¼E½ ù€†Êƒv¨ÄKÙåà!®,—±ŠãÑ;ù;¨Q X<Õ¹¿ÿxñúª£*°u›dø7«ÁzH`e!¹F¼D£!±z3~`Í}|ËàÕé ^4°mÏZ$ X¹#*Æ«üc¸šå[–bA7¯Ê€ø)PúX Š ŠY¾+©Ãæ‘äÜ3 þlµz UðÀÚC”8°n×¢Vòj û¸.võr1¯ûÊÈ¡‰Žè¾ò„øgy££šÕrðÉòÆœ‹â_ /I„+!®öEàbØÂöˆAËUµ’Uôž°aV±rîí {{¶>%ÈDY”\¹ §$¡BÇ'RŒ>ÆIUûµÝ$RýÓ|ŠWª/yš™îäݤUL›7«õÉ—ÅýülÅ$hCt–°e¥a`qo°4H‰?-ï³ß߯¾gsyqÛ9DƒÄeÿó4ÿ˜ªP¤Hê‰Æõ&ž¶àõ‡~ì ÁF_l-]î˜a—”&|ã‰Ö­xàЊÉ%› TYfe¿X@ÿv#3‡!ŸO/Cf)ŸuñYŠ™>£´=z`5OÛ"b·{ÑËÅæÕBå¸(Œ['f/™œBø]hù78îUºI‹?ç˜W±è˜Ð[Ì;Ÿ!Ûðªù8­¶ÍþÞ#ig˜¯7H,¬:åÞÁ©¤ û^1Ðcv—=À¾_þ¾ZmF“Á…䄘·…+8[‹ØdŽöõÇÜ&[Þ->g‰ÛÖ^ËÛ, )±É¤—Y>U§±«õi.8Âì^ýÿ¦iÿKDààC“·txxu E(âàp“äÖ¿qH—‹ù.>œÔJÐ[SGgÛÝ\õœ›Ýš¶434›÷ݳ««!…ÿ?çqéêþSÅ‹ÐCHšš@ª]ô9|´²v¹Bª”¸õUkS¬šê¾ƒª žÓ4…xVK,èë5#ƒ<µ½L×¹²tSX?…=¡EÕEuJãÄ–à$å ìç¥<¦b5ÑAQwPZÙç³wb~áB×$á‹ÿ‹Bç^àwµw~U;”m)leƒ¨¶®­Õ+› s¸k ËE¸ÍQXfzTó0™2‹$ N“½í#mÜÓT3ÈWÙ—4ÿâ<èï3ÎÏA€ä ²®!ZU’ ‡ž«Ú?)¤52¶¯›%"‹3ÌÀ>£ëME£úD“úXK©†ãÐ]+Õð÷ôöëÓ#$è}±§>ÍK<»ÙÓÝÝâG`hÇÒ uxìæ¡ÏÑ„¥ÕóC ˆ ’Np¸˜2HŠòm¶ù#[ƒ‘ ]-€ÕKþÔúÿ2Ë·o,~×ïl1Zf –z7þÅT^§Ÿy·ð}<†ÿ{Bþ»Ð"rLKY Lš"ü&Õn„nª:!ñ»ŸN—·÷Oó mâþ§w×çgìžW¤IŸÅ úëC¾‚T¯¿Ù)HL·uV]Š«®Û¶3Áq'BX€2¡Ñ„°fBí´`àþ5‹V¼W ;a¡ ™#Öð¨ÛÝ‹µk‰6x0DÉñÄ¿0¶Û§€ï ÒŸpP˜|`®(Óƒ T†8v¤Ú§õoZ•ˆ±±w%¢‡µøKEbC*ŒQ~å&ô!1¡‰õÊ\ÆK0PËøÏœ'&}žh²®>X®šL\=<.î³÷¥#›C¯Â¿Š·6 GKð±ð<¯Ž:Æ;‹ß Q!øU‹—<20Ôu²>a㶬Yp\wrŸ¥ëß ä­nƒES¢ˆÓ¸:Ãg$ ÿTÎB Êâñ|Ž×àñ!¯‹ÖÁ5#ˆ–îI4AD<éÕhÜÆ>ŸyÍ/\X2Ê«!u'^eé¨-|ˆxË0"\¼%ˆˆx«SxØÂ>ŸñÖü•ð–Ôˆ·Ý±Öõú)ßdóËõêÇ" ;à¢I 6ê¢É$ôb89\üE,äçvû 3Âõ B¢o ‹µ³ÐgÿÀÎâUc2J—¢ŸÐ—E&b³qà0CHÄa­-\¶³xÕX-â°Âͳâ=s@½Ù'òl]¾kZ>þ“xÎÉýˆxÇQùü‚fd(Dw©ùõWM›ÏrßxÔ|#û’Z´zDÛ#™[tx#‘õ8Ïrð×ýOÇó‡Åòýòþçþãìëâpþ¹˜…©ÈŒ¶Eãf˜y>[ÓËæÛïg&´°Áð°„) S JDéD€©*LÕÙ0e¥š.Lù?0`Z³äˆÏ’)fÉÅ­ÝLi{SŽÔ™rÄ2[W.[ŽølÁŸAŒ9b|µñi¤~LÁ#•ÜŸbÓ‘ú‡ñ~&õmïÊÀl UïÊGÏIÝ!šÒQLz:DÑ ŠNPt‚v¢ ¡¤nëm›y;^Û¸OÌ÷aÇ>šoÚm“£%Ž–8Zâh‰³cÑâ דµ3‰Ç‡¥ºÃñMF´ÑND;¡€v qØ3Ë8Òl,GÆ‘†}Z'Ä‘†>ÎøóMâHCï´ßn#¡iÔþ¡°ÜGÈ7í÷»m’Mí·L¹–„'| Gg^﹇ £Ü;Џ×"ÓíÂ=ËäzŒ{–)÷÷|¤|ʧ¼ª7óšv˜?%¥ùSëM›9{}›ÎZ6KÔ8ö|¨É„ճ庂^)?7Y~•¥sùƒ:XþHëiÒÇ'œÇhÌ7°Ó| 3ž«<v BRàêL…7ÐïðÍlvöÿ·ãìÄ݃vF±M•|Àtj Ù¹¨<Õc‰ò‡éáxE`¬ñ&[Fˆ` ñ%l”@DD  !¯†Â ,^À…†/ѧ« ‡W WÑ5šÞÐnA`ê®êï¡ÛÜ®=~_ݚ͉.é-o" Aƒ‹Ìíd®žµÞU6ØgGϦ†§*¤y Q[Ô,ãÀ ƒ™=RÍõ×éÝÝâ$kú¦¿|I~ö2]¬U-oKäÞÆ¿þnjÎvýF¶0½x£©‹f³ï‹ÏeM×Ç‚ïÙúÏ…s2ùò!}¬Z“ï—¯<DóbŸ'#åÿàFã>#Ð!)Ï|àÆõªðC †$Wî9Yð(5¼‡› ×5º”ÐRþ༴q4I¼“BC¾n7[Ü"©pÚ¸àšÃǾ˜L°˜$VÅD­X¿ü€¦˜°ûb‰9} õS¥«‚6ÅÄØ¥ÂN&7®ª‹ [MäXLô)H…·%ÛÅdÚðyÓj´ eÏá-–Ò+ò®O–ì¹È¾_®ÊU€jêÝeö³†óô‘öl¡?Í}ã3ÂÇÝkŠjá]ã³w áâ =ï÷§ׯ¯nÞ¼(Œƒ–µÊé=gû"Û|_­¿júÜ‚«5’N¶™8Ò³·Ž°Æ%RþΡëAÀ!^¦Y¨þ0‡²xeHË1–â¤Ï÷‡¬ÒÀ¿L4*—WŠy!x¾– 1à7<@ îí––q+}`n ?m¾”m’¤½#s‘I×Ç Ô)¤ <õwP]\£s2±(L*º9,G ‚Nø×É}šç¹˜ ׇ^>®–¥Bc±,ÑöŲ“!æk’Û„Ÿ±Ï;;äÒ™œæùɨ¨Èî‹ëe#wãùnS4Z¡ÎÉ1e«ôåçJÿTk žÞÌÀlàåÝâsYi+•ÙòéÙ*âóZ€^ò¢xˆæDÅÐZ6Ð4 Y:¶Ì—*¡.®°Á—n¹B!fp‹…‰SÅ•d“ "̾.–©Ê˜í´l!èFY™ðT“/ê~Q+û|θ˜_8?ÍB€V¥(£ïÚˆ-°ù)¿,¶añcë‘ =\T$ˆˆÈ¨‡Œ­,ôÍ/¾!IÅÙ”5%±†B¯†¢…¾WP˜^zÚY?QëÍ6TOä‚4Íêvuï3D–ΨÂ=im̬˜P³fNˆ¸Y­>"§.r¶°Ðì4½x>zÖ7ZšîÑ`Z+”4œ–¤—ÍéJµçÊÓˆ«­­ç‚ã“GÞ,T2VãqWéyK.„º˜Žˆ¹ÚÞªƒþC®áµKù«Xq¶Áa…×Ö@kÓ,æø8ü9ÏGs}šlr—ï£Ï‹œß[Íkå}Zi .Þ*„«í´ß6óo¹1^+üm«Â†Á­q  ™0êSk”b¶Aöyº,Df]Í•r¢'³ÕíWôÍ;Ï+†ãOXÑôuêZ½{ ·joç!ý˜¥"ɧ›M•/¥ù œÂ[ÅBNÞ#¾ 2¸üÔìÝñ«÷Ý«ÃaT‡1¨ƒñ) M¥àÎXµŠÀÍ$d³Rºi5i·I_EÏö-ÿXKv51ø0N Æ+䌭–ïÛHÑC‚KÚ#EEc¤£P´ ÅÄW¡˜˜Љõ9³ØÀ YŽcan~kýp¹®àýeEžÂqn/ï}›3Ï~]¨ž \ýŽ~µMŒ“ØiЃAÄ{Qo Öϳ‡év뙪?XxR¯Ø̸C/rß+¶¶&wð.Ë$xð{&yôúD™|G˜ßh  ¨·‚²×âá––âµ½xîP1NžÖ—éæË(uѨ: Õ{­ ˜Ã+Á»ÕC6Z-ÀĪxù^ëAÅãÀ¡øÏhõѨ Õ{­˜Ã+8Òt¨Ÿ;¿­]k”P.•úæ÷QÌ|3ùò[v»Y­ IÀ_ÄÁ•ªVª¥Õú‡Rж-lSÙšñæî k¹¹k¹¾©ÖRüaãþVòõâ!›mÒuKntiS|áÍÆr\EP¢ÂË÷*ÅF²UNv »ƒ¶œŽ­à“á_žA­)ðïû(X{zqýúêæýÇ‹b#Ü´"ȻѪ»¥ýy’ÀU…¥a(}!·m¯¥#ÉîÖ,ÛäU&aÁtFu˜¸ Æ«QMÈéña* Aß*B²zD BwÛñÔ­®0CÕÃT—®õ>i Ãð)Þ´ÌpT¥13 ´YdGÚ |„ø€âÉø˜·º]Ž(Ãý{ù²åsåÛñ÷…ª»ÏË¥jUïîY® Ÿf²VµUF®4Au|Õî\vÏ,öì‹fúX޲NÖYºÉN zÓåmÖ¤æA“þúTB„l¼©ÁzÞz Ð{CòR9s†½…ú)Ió#ìK>zeT½†è5D¯Ë~—ý –ý„’ý:Xkþ†’:ñ èq¥?áK?ülû™×0Œ©q;©k @J⬻\ @ú—ˆ@õëy¡}{«µÏþ>#¨õšrÿ']EípÒ•oÚï%¹“°ÈÝ¢i^œHÝÀ0/Î)¹Y^õÃåFy}xœ¥zÍùq±êý5sb’uÚ°%¬|IG̨g ÚùçsÎÀÂÊ»N©fß”©›¿ èùQñ«ò“žé8@Ýša×çÔtDÌUÇÜ6îùŒ¸Æ×­„·„îD´mEÛãyYˤQ•S«M¸çj¢êœ’gÅkSUˆ®ß8áwógqåR ™žoÉnWólÚ~`§ þSü§à¶"y6·Ÿ—zx•mö?•=mŸ3ˆ&WV€„vš‡˜œ†éÖEv!;ðØrz3‘8½™Ô é>Ñ¢2jP…÷Ýh ù!ªyÖäH¹ôÅ œ2\«† üØÁ Ôñ ,AƒÀàc¼,K“ާîÌ<ó£Û–3?4 ¶JŒ¦ÁÐ@°½52m¶7šÜhr£ÉÝ“+ml†°3*&FÕºÄÚ“qמh~n1FOÊe(«ý¦ÝÿB”i„‚¡°\™á1øH¹+(°L{ý§6G.³pñá쌠V‚ÞšâXšc¯4‡M¨Ëa Ìå 'ËUä¼Í6àÍçé£Ã1šéc ìWQž«9šˆÞ@;¡ÕÕ ¨uÿÚ†hb®›»­PŽÐ,–rM4–õ MûãAýžÝ)¯?U¼—Y­70ÿÑž/|]èô¸`Z§|Ì÷}Kï'ìé'»(¾¥¯q¼GL[UUr“>r[`Êñé² |EßÏ?Ó}’(WÉÇJ6/†l'ª½¬ˆ[Ëa‰Z"}D‡Cl>’Ö îÙÉ„=;a4© ‘æà…BÞã1âE #^¨3â…#^(¥=^t¤=^,ùE%/K~iaÉ/ê,ùE‡%¿ˆâ!Ê[æòç–?O»dÖ/u|ô+ßÁú;X¿ª—o6üÅ.$üU‡W¿j”pþj»„ÓÈrQàÓ]Æù«Z˜+Jñq_ž‚Ìßøñüø¥¬ýÕq¤,Ÿ£ã¾sJ½sÊ>]9"wµÈßAEë$–±‘Uu‚26" è5õþWv²%ª„O5~Š™‘  þþ%Úçq¶ëKn*¹BÞù*×”wFº[Iø‹p ײd¿„\°¾]eÛº3¥ÛÃO£åÛøér%ܯ²{õÔm«ú ˜zÕAJ¬údË@U¤Ô êc–mÎW›¹Ç=Í¢÷hÍrð·ÀÑà -ðšÇÐ+PÈ:Ÿš]tÊíˆ!ë‡tO@Þ âJ l¯ºúmø!šƒ?DC?­BÚðÀÏì¢ÛÁëÇèÁïä>K×jð×ç–°ù{¿!^û­ï İ|×\S‘eƒlߪF}¤î £Ý\DUß*…Ư ×ÛÔvßœ”ZLõëÿº~}ñj7ÜGû÷¿æ‹f»õÁ ÈÈíÑ€b±ò¢ô[ÛùÓŸ” ûãùȉº0ûc—Ìýξ/>ϾØ.x÷ÇþÎ.’­½¿/þA¾•Ö« ÒªÄ[Pß̦š×ºÂ¬Í²u!v×_Ö«ÍFgVKZ_ê°hô\Zš6äÜ^„7 AЇ>®þL®7·Üyiw²bç.Xêÿ-—ô²®€WAôÙ,p-[]Êç•O)ðØj‡Mì}2¢¬êuJ‡²Í¦—¥?xÚŠ88_h.¬4H‰°bV$ØìVgMÉÁIFƒ(µ¬‡±pT»XÍ œ»„Â˺¾ÀÆnQ½Èó4Rõ#vkÍÕþ4¾C®¨.²Í÷Õúëõê?Ÿ²'•xýôê}–¨"_t\ d%â§¹ƒ¦P óÎÔx[T ‘ÛÞ/]ìixÕ¤´«T‘Ÿcꈑ=_Bôb —Y EŠˆÑ»ûëý‚Ã=W9w†ì@Óï !€l+ØH•¯cG–á¢ÀQ³ÿ+XÃ5‰5.Û¿¾^¦Ÿî3D¡C52¯MJBÔŒ&®L9|èäôÕ"‹prH Q:9d¸O'’ÏËô)…t6 Q6D¸–Ì&’Ë«ÂÓx…`6) Q2›T¸M’Í7«õmözy»š/–ŸCKŠˆ%’"Àµ0ÒÜH?,ïÆ ‰ !Ê"C‚kid98<žæ@-Џ•HÕ² mP¢6ˆªrÖ5p+F›ŒvWá`t ѧGu-p~U ¡Ý¢,Ѝ «bNX:D‘âVðúÇp£©ƒ>ßk²±ô”{»©L.TÒZ%}õ©Oü üÄïí€PϯOeéW2€¼^<(5ëh|–8«çü-ø#{.¿Ð±=ä]XèÍ¥ÇÛƒûÆJžßKrªv-P9Êç|\p¢ÏMæ¹=Õ¯³ûw‹ÏŠãWdÞ¤$ĸ§IÅpç=‡:Ž|zx„Ë d¾Dˆ%~Á[ɬèØEäô•Iø—bY‘ !Žh?4B ¼“Œh‚%¼|I°q—ùèf:—ÒâÙ…cZ_rgèrËä§´{–žY5mJr3t69X ÏŽRžÝ ¹b{r/±»åµ)<Ïé2Íór€«jjiÅ`ÉÀô ;0=TL9JI.¡~D¤æ×ŒôŠ7w%„áS­ ‰s§¤æNµòÐÓ‘Sæ×ŒÌ…ĸáö6Ìîæ ·ò€Â$œ=Ô2\ÏâÌÆ6i¯ørl¡ø¹¨C0KÄÕ¬a¸}d}?^¼¾ê9ÌM6Rɦî<—æ\b»_­çsÚñ¹œùX&ݧ„vŸ’îSôœÂ0ÑsŠžSôœÌzNæ†Qú ø z^¤Ÿ—`Ú0eðÕÊ?šú0.šzǦ¾‡ðM¸8'2àÜ Á&1U툧©M·Mõp" ˆ0„ŠÀ°%½µôº Xë&;jEQðdzà˜§¢zØ_‹Ñˆ$jDC’¨ØàÛœ`+䚀Ä$"˜FhˆÂ4€6øCïzwÉFPmú¦5úÐ7µÙ[”—ãê×P”w¤ÁybÒç‰l_Òò‰Ó>OdÛ¨jv:%ÜÙÞ¦èDÜÄ*9S•ŽWÙÿJÇi2ÌÜe ÒD—ïO/®__ݼ:½ÿxá ’œ¦H&!‡vG¥„†)!oæ£^f@ñ6Û”ùa‡éj:M¡YaurÉ&@^65.9$”Ì!S³ªèo"ÆU•¬þÿì½ýwÛ8’(úûüÚÜsúÙïllÙéÝô̾“vÜiOÇc¹Ýïî=÷è0“h[–<¢ä$;Óÿû#¾H|T R$ÍÙŒP…PU(Š5¼šŸ›ª5ó@ÎpzÝàžÐ.üêKÆ¡±Ó›‚ `·›Bµ}Û¾ Ü¶î ó å²CŒ›â†÷ Êìµî #ìö6IÐ ÝAYÝqÝqž^ “7ÉÃêî6 äïvˆœMðêgüµ®ý6¦jÊ¥ Ûlð‹Óâ Þ’z$O¼õm¬;o“ΖõãÃùòv±ÅDÔ}Y­gÜMÙ˜v±£  A»7²¹¸@éÑè32#&0FfFZ”*_}¶ð¿º’9JšÊâæphG4Ir ‚¢¼ê-ÞMÔï# P ù¿l[ ÑjVkõºØuèZ±4D«µïk¨ÅSñCèÁ-Ì7 õî‹?ÿ˜ÔoHýÏ«¸– ó£)‡‰2½$R?_b ãîÌ«Œzé/z¡ACœ„/ôµã÷R#¨³¨•O2N_ŶŸ¦"]f«íæ<¹¾þß²¨î¤CÍKt¨{‰M»Q½÷A—]κû÷oZü~§:ÞÄÜäЊ·êã8Ä}Yš=ŠòÅ mȨ;h‚^utÍ3uE=s[Q_7"b7•& È+ÿýö<ý£C»þÑÕ}Nÿhl‡3Víto«kW»šñÂq? àíäŸæ‹ êuÝZy{É/Ëô¯xöv¾ì­}/¹;V} TØòbKòÕQÂvëon¥OC§]D-ò÷ñ¹99+Haèí·ÄkyÚ¡ÇcùÊrXD>Ó š] ‰·7ÍF{2yvîhv‰™ñ¹-ãMZŠ® :•gqtg.GV®/JQÚö¥Éè ¸@Y‡­X¦Œ×Å*fÌ{ÉŠ†-Z¸¹Ú0W-ªËÄ8šÒh|ééµl'åÚ-kVÇ)K·MG™qö5¾¬n+š$×È d¶éÉ bs#µ 61¢Ï&g%C:%l7êeO>êLâKŒØÝ9|MAƒ:KÄ·Ó_•õF>Ç„éCqPùûh‡¼UO¿÷XÌɶ~î±&Ê£‚¯=¦Kd_|9Jl¤Ÿw$[Ýå NàºûYÇlŽÞÌ‹2"˜ IïÐmRT"r»&KFϤí|2ÿ´Œ•·d$Í [(,›Ìž]~6•]À]¥d»Ed³/Aº˜ùÒØ§Å! 2|]÷vëNÓ™ñä(­™½;;G :šß¶;MAíËûÕ}¼<*«|tÛ_”ÉN‘Ï ÇeÎ ÎßηEÙ·Ÿ<ü>Z§ÏW…Wq4ûéÕÁü×uÚOúGrºº»‹–ÕŸ-íJ9²Ñ5¿ÏÖ.ß.–äi×õ©¸/€nT­òßsòè ˆªx–¨Hj„};™Š ícÉké[)ê´‰iûM›ñõ£_I)æ…þÙ‘¢iÓ3k68mޤrynŸ¶q©“¿ô5:§“ÿ¸øäìò¾GWÌ<ý£t­;ø%œën§s?WcÔ68`ŸÈ]èGóB» ðÇÊþØÕP¦W?Ûìv±JâÒ¶Y¤~­†îbåçq]nƒf¬ÃèæW‰×du1.s«ër>3L¯ÎZ\ldƒC‹9á\ÙºweÃgÃØÂ?#†7)ÁÀ6Ù0FÙ0–ÙpìÁ†æ¾:[Ì]Ybl0¾<›±AŒBhG.n¨r¤ºÑ„vg•C@ûÇùÚöÇíGU %no9x#—·—íî6#‡]Ýæ-`›£ÄÍ-ï²ñëtu^Ô ïâ„°Éäu¹¬µê}Ÿ‹ÚòK¡ÄçëÄÄþ´ZßE›ƒä:þj|ÀÎIc+sËùh?P†ÐÖò4µ˜_ÀX×Εz¶€°Q H1n`d‹¹Ÿ·ËvF¶ôb¹¢‹î”1Q¾§¯-þ¹=¿ûæF?~LlÅM4 VŽœÔŠ³ú¦!J|ŒOÕƒnèµn(-6v/Fƪ{Ùésš˜…¸™ßÅéäg×z{YAînz‡Ýñ¾CÍJ综ðX*ð&•A~Ž&E%²•z°Iî’ä:ú”ôôåš§8è‚…ðÝÚ`ƶu’Ú±Åט’òàÒµØUâ6ÓÎÝ(¿-O |Q˜© í²P¾T™3Ì9VT«P4vÛËÏ9_ÚY£»ßYVˆf{éRkhIûSÌU¹9›¹¶çÓyìa{H‡Ol{ÚŠÛgw‰:éöËÄFì7÷'ºî7Gð^Ô%-Îãº-Î Ë 6ãXµ áía3¶bẄÁVlÅÁV g+Öo\ôÓˆØýPÒt8©b:”7 Úr™Øî1UßV-0¨úAÕ‡¾ÝôÐf½Ó[«¬’Úêy-Yôvq;šÀ×£ƒÊi«4ª%¶Ÿ4êˆØi:»KŸ„yîÓ-øÎ‰6¸¾}ï&‹i÷‡MZøy. ãC/ÎúNˆÒ§O÷Óß¡–¸­Kab)ŒË·Âˈã:FÕ}pXÛ>¨e¸!öÁqˆ}pÜæ}Ð6‘xò¸V~-à ±òOB¬ülåëï燕ÿÛôùãZù5·”~?õ{~c×걇ØõÏCìúçØ®×£¨†]ÿÛôûǵëkn«w}Ç>ÇžGl¶{ð!DÞ÷§J‹¼ïëü¨)ø®»Ú÷LÁ·c@—ãJ]>‡º<®Ô%ø!דJ]ž@]>¯Ôå1Ôå÷•º‡ùÒ¬ÜsáGfEºEÅ5ÎÖp~剔6ù%D{Óaf÷f!²aª·;K†é~×”ÍÏ›½¬Q›2aнq½â¾7ÿµyzº˜Ç@6LåYüfÍ#õ¥„¥½T€Š¢™Å;ȵ{jK¿8f“¹,Íãyüv­£;#¤¹üþi$Á’1* c ˆôÜ6kßÄ–|6ÜÒCF0 ßDÅ/hêKtYÙ–ô2“U_º=Š ’ýÒAz$°ÇÓ¨úRaÖB7Âl<2c˜÷t°±ôP¹¤ÜÓ––ˆ[Ÿ?9F.ïÑ ŽLË «Xo¢î;)§â>rE¥Ø*ÌP±Åkhÿøä­òRä¯ãM9³«jÜÿ›«%µ8çl¯t8Ó Á}ùÓfýŽè^jo”=­ÖÝ©®Es éFo×ð9â¦ð/÷³h_ÏïºìæFØÕÓ¨šËGÑ´sGä=•ø¬ù¦¼ÎÏXQð½ÙteæÒWüXZ’ñsYY:1{+$%¡~“•å$ÌÆHÉ€„ÊHºi„,å'’sÄ5z¯OR â­Cbr&ïSwÛØ¡åŒ.@Ô¤T»=t‡#=tëɾô¯y‹}¡%ë*! ë<Ó ÞÞ"ì]e+¯}2,e“aH^ó ²”úÖ 2·»Ãà’ d.<î›e¨Fe™qw 3²Aà›ÀvH³×ñF|g¼Ñ»»Œwõf<ÆÙå[½|;»ïyƒ²#éè;ë¹àz ÷ÞO­^ñÀ‰¯ËûÂCì Áò;Druwwƒx»¸kÙ¶-ÁÙÜt$Hø QÎÙÙ1µ‘y4»»%<}™»U”ß=ÐÍÇC‰3s#º¢ëR¯½}Wë ,vŠŽˆóçó…ùó*<Ê?s‘±=¥ù?klË”ò«TÙ2ïv¡P„Ó¤Ã;ÇÏYRËÎyç®QÃÝö-*H]*e8hþ+ã5ô}ö,Á(_ãâë¬Jyº¿å¯¶Æ·«YìðÝÖeS‰‰ST{[2‹§«íÒ¸<Îæ·ž7Ñb*8L¦„~ôö“åßK9oÖ·×6áMÐÔÃé`Š÷ˆvØùDñ~<´¯û‡«|dÍJq?S¼ÕïýŠØØâµa_öK榶C% +â„q4q×ܵ¦ O7WÊ{\j/{îåqñ^>ößËÇå–Áqw÷r)Ò¹•Pt¸–ô#ü–÷¶ãÆð±û¸YóÎýÁ/~¬€»ÐkC]É õ?Íûš¡ ››ísÑX”ƒ-9Ø’ƒ-9ؒΖ gZ´Ú†nøëû³¯Ñíf¸—o^égŒïÉý¼6ªá6À—?m¾¨øGo_ÈÓ–ßß×C¿ã=¾.C‡ûü0÷ù°Q0ÜëûÜë[ôû ÙÍ>höâ{GñÞû5†ê(˜×9ɉ$‰W?Ë4‡ej; î±µÚrÇfp°Â‰ tÒ Š8QUÄI‰Ð¯D>ûl’©äG0XÏ\¿î1Xí:„¥vúöì8oó©†}ǰ¼ yw,Ë»,ƒG‘¼3½*„  ŒÐ/ÚÕ|®°Ô;¥žž2ö8·šN`þ þœ”Hži¨°"àÎIùÜ™'; õ'š[O©3OŠC`‘kÈÁq ¥¦É@Ž‘/ò´õŽÄÝÅácŸ×‹¿¼á?nƒáß&û¾AÀVÓ}0Ù“}0Ù“½SS=˜ìMšìµYw=±âvhÀ•·ÝŽë¶Ý°ËÚ,ƒ›[ƒ­5ØZƒ­5ØZšêfr[xØÝ·vc0”·NBÙ µ}µ14Úþ ð…_M ´UÜïâ{¬Ò5°WäÚEN[¦1˜4Èê3a¦¤ œ`ù™”±¶0©­-•m6‚©l+Žý{bØîÁ· ±3¶‡Máº.jÉïülŒ€P/OŸî§Ìhõp[˜ÎZÛú{Îahëbü˜uC̓/'Žj“µ 7„ ‡ãA”\ÇmÜõ©ÂV·¾]_ËpCìúã»þÛõÇî·¯‹“6nƒúv}+‡[ß®¯y¸¥Vö\Ùy¤J«ÇBâHŒ*-ñN0‰§‡oO[ÏÛ(ê“x­n}¯æá¶ZâµqìÇàØ¥/œ¶zð!Äýs‰S¥Åýó:¿Ô†}l¢Ú×Ú°Ûy ×qÕ^õïÀÑ^«öz õzRµ×1Ôë󪽅ùžÖyá×ðÐ䦵?³¯7Å~a$çºã©õß‘¥Ðƒ€Ï!ª;‡l¨Cäg© ¤Ý™ð€ñŸ~>äÛßÍ„ï:ß>ü~¨Séö݃rw““¿úrS©DâþÚ_’?Ú×Hv3u0Pu0Pu0PÃÚ+Ý7LÚÿF)Ÿ›bá‡X'}ß7 ß¶;À6†þ ¡ÿ!.†ÐÐÿA¬‹!ô÷í/à‘¾tâ ÖE+ƒýëÛõm|ØÑ˜æoå\»5×íØ1ˆ¼‚uÑÊ—ÃÃŽ>·>!÷XÞ±Ôæ|ˆ:L¤pQ&ØÏè8T¼¶4Œ.ïß3’NÿBXíátüÊQûšX_ââvôQ11ˆ^Ý=ú|ë÷Q¡éD·ÃGD©/÷ÑáR²…—’º­,¼©Ï mfÃ`0 Ã`0”M°è¦5Úªv•hQãÚpq÷~×6F] ‡„‹CÔEÇ£.Ú†0¬‹6ÞË ‡{ù!áâp/ߥ›Ûöîúá¢:ÐEµîž {[m:?C^Y뽇½·6/‰k¸¼Î8ß`¿Ž7Ü'ëëHÎ|Üç{äëHV:xˆGh|»šÅGZ{ͱœ9“Ÿfn)]‹9gs oÏg_;é=Îâî8¶}öÓÏ}œM-ý7Ñb*–Ât2™’™¶{‡ÉZÅúöboRŠYºgU^ÑŒSŒQ#Á)2lÅ£©ìÿÜ“F–»Zóu¾?únoO›‘}V§Íåz¹\Ñ©"ÎLZ%S²gSJøU [ŠtËÖ(m1ùùå«÷¿ÂÞWúO±cõêf+ö™¦ãSd³§´*¾…’DØéébN¦X»y'_ž•ÊcÅ=ØEÒ.ïolë˜@Ç^߃ð¸v+—ÇŠOY.-_î’ËhÝuó ñ|Tm|EµKbº‰ËÂ=é&C‹·¶.XÇð";‹l¬ @¾j­+Ì`«Ç‚2Јÿàr ¸Éû=§“ŽÈºJ·áhæ2ØB*ó]1Î'´ø;ëò„æ M›úÊ:Ê=#Ò;Ëå¬6¥úSŠæ¦ÔŸèû6|®QÑÃ[ žÌÚ9ØÓ–•Èí¤“æÜI´p¹°7Ò嬣vÒáN줘Ca,rqɘ¥38ƒ38ƒSÙÀ©® w§ó|Ô] M7¤èÙýíXÍÑSù_ÀÕ‘«Ž¸øåí[i¼#ÎÇܵÈ1äÕ¾óíž÷öŽ ¯Ø ÖEÍc­–5½Õò c‡?èSÃGmKø`Aºó"Lð€~uôâwî|á>IE“¯SÆëmVϯUïˆáu€½#dÈÔ5ÒIw¡~¾âSåk³okŠÏr>'¸óäìî~ó­ÉíðaµZÔ¿âùÀº»èùv»îÉ\í£«_ðغèt», Øèâ?]ÄѺɥ_ËJ§£èî:§ä7û|VH^E›è2Ú|> SqpŸ6yÿá¿+ËŠ®‰£ÔAذï#dX SÄÁ<9<9Rx’o¡bÎø¹_Ö`¦ÕBÎJåMòçæÜŽsI8TÄ :žë¼—-Íq^Ý\ÚWJkì9Õãâ©>öŸjàñh!Ëôw˜]™êRts®Mu¦í¤Ó¤õ}Ì]Î'—ó‰¿Ëù¤Äôèl€lÐí|¢»as†úŸÅ@¹1“²àÄ0M{`?%\¶¨§ú “ÿÃÅÇ¤É ùç9fÆ–ÈE’“uÀÍ¡_/ήœó’¸gæ!Èc½wG_z½D8yês6’Ò%·µdÛ\^™…®,“ GZbZû žÇYp¬a´òjläP ŽÅÁÒ”'ÎÇÞ”Û¡[z<÷Y‹mÏ5×Iz¿üqµÚìbU×djŒ±û«™c×+Y¹™å¬í\x©ÄÕ_ãWñß·óíÛÕ§ù²ß{Am÷w…>¢VíƒÝ=Ù)/gwh§ÐÑöj§Ðµu§0vwy§¤^:žwñr{=ßhý†6J‰´>•Î òx»¿U´íz§äç…ÍÖ-RCº’:Žé€.×1ÙúqRúršö2YÝæW`Á>î~ª¢"ó|_ó˜…ðr†$—)<¹\êôvÕ†¸³íZ|Ť8êÄ$Ô~¹äÅ+ã¢Il.[j)=À4\j©ºHÇ/È2aÒÏÛ1/޶ô¦¬þ1À·f¨D±¥?>v=ä×}=;,e 4m œ^Çw÷‹h—ÏWÆF3•M ²•ûž©Ê‘9B,‰ƒë”¡Ý7'[ÂÑ–èª!1XÎËÀÅŠè¼ Ñýà—†=SO äawfˆ›’éÐÝäb¯‡ðËÇ.™ hBvÓ¬mƒ¹èËÝXõÇËeÕƒcªŒ±ñ:ÞL¶ˆbKvq•{CdÇßp$¨@Û‹]1˜]ßæªóI¾W™ßïf žlfÓéC|»Y­¯Ùäs´ŽgÓ´Á5³Òéfºqü€e7ÁÔþ9J>ïbÕ|š«û›HÌn6Q~¢Î¹ 씺³Cª,Y%›~.Ül`½X¹Ùhv¾ts¾îzíž_¾š'©¸LõC<ëÙÖFׇU¬ i×KYçp ÖóióiÏVòi‹–ñi ×pzD/íÌN{QœÙ{yIÝi:´=qʨcÏn¯b¯¬<žKq>2'õ=çAo¶N:²û£eŽqÎ7“LË]Pb ¶Q<³j€þÛüدïƒ}Hþ¥e8uÍdäÀÈQŠUe«%°ȳfDçW_åÞ ¼Bð¬^ Š)±<Y…LµË›«øÓ<Ù¬#Bbia#]ø;Åb Ô¤òPú„SòÇßÁp° Ê4Ô󤥀E©Ó*X|'ªø4Ò̈Oyú™ìL.£$9H.æ$8á|F¾å˜\ÅÑ¢ó1 Æx[,L•ÈñQÉÆ©Y†å»wçÑaiÇ€V¦;†'øHLðØ‚ý¾˜âƒZÈ$ìêÝ6Áznð]M°í\9O°ôÏ T— ’ZÈ$,gZ ¢RCÒ¡©ÚKa©'ð‹ >ñŸ`¿ p´AÕ 6²Á9LðIK&؃vn.O0¥ÎêdP¬# $ÅÓOõ<”;T>'ü˜Ï¥¡O½v¨f\ã†õ»8!`7¢³Q æsI6µØpCu“¹XçÛéi<¾§Ÿ£eZp7O’t2JËWr\—|½ì'T¯øavà “åó¿ý­™neâ¬Ïµßß7⦩î¢QV”â^|ö¹ôú^ú¾’Oü{Uë|ï£u´Åâïï©C‡þC –ñâ`›¶‰>¼œÍâÙÁ‡‹)ï¼zÒ†ßb%%óŒÎ˼å…Ü2¤>$¶O™ ’Ÿ  Ê®ƨf%…L2œ “Zà, M?î0Q&¹¼»„Ü´³¤I†Ã*ϸJÂQŽ;J˜¡ ¹I <ùò„¨š…Œ°†“æ{²Kw<(fƒ[ê|ÕÒPRæg&„Ä4û§êN8£ž[e|0§˜QÏ+3ê¹ë‡µŸëüÉ?¬ý\fË÷>lyÎÙò½…-†áTÌ–ï+³å{W¶|³E *?ýèfÝž¢‰÷#öNMÜòùü» äŸï³“ý:°ªÊ‰éý}+NIâðsÒ‘Ã8©ø~Ö«Æëçt&-§“¾HÒQ‡ „1-?l„ ¹— 1­=TT£6ÀAÂnüíêð²E?0 ŸqNÈ ¾Ãà#Ú±„‘WÕ´kêJñU¼ ¹žrt.)GÇ9sex4˜s(kZnÐ…¡º—&šÖuUéí­Y‡0¦ÃŽiË›v7«ùm<Øvý°íØd>㎠t°îJ1i0ïp޴ܾ Dv/ <Œ7­µð*Ü[ãL=6ך=6ò^Ń™×3OLç#0ôÄPS¯$›cÏÆ–›{Áï¥Á‡s§µ&_’{kôἩ˵÷Ð{Ã<©ÏêËì;Ù°‘Ž òÄìö’5Œxrt¬›|€©˜m-ås6]}D׋jVª’tS÷íô``–áQÛ¬Ëb3$¼u‰°Æ°Ð m†ŒÊªôⶤb€ŒeäX5@ìMÆÜ9¶ ~Ö$oRn"uË }Yr¬[ùƒ1A²Û$³ÍéƒGÇÅ<’ ·P™M¾a9AZôq£°´sGûQwÞ!¼xœ/‡fÔó^ˆ™]Ð9„<è¹ü°U˜wBà×¥N”¯Kè­½0eøŸx®¢/;8ôt(I¦äâ6Ï-ÖCM³Nn1‘ði$!u =Ž$?~ˆ'’l!6î´ö€dÏ£ˆŸõ}ìi}‹­ïcë»ðÔ‚³˺Ø*<0ù\ÿj6x/]8ç:qò L>|øÊMìÌœÀ­lÐÀÆìîrÖ6h+6ðñ8$h-ûâuà/e£¹)ýLaž•òí|Ùuo{:˜[ºŠ!·›d” ƒZœ†²*½¸=^%%Ù3=J=9I©Ù&§«»»hYúãRx*œãbTð±Û’TÙ S+°ªÅÒ5åõÈYu{õHâ¦ìZÜJ‚5„7¶Š͹Ñ+šk7òÓÏ1‘-GÇÄa±câÈß1á+â-¯Zåš>.Pç„´»@oƒ×WèÀ“û‘rr?rõ¸÷UJÀ^¬RòUbF¯>?‘j®!¥+ÆÓ®× ô;ÈV¾³•h=½>½kÆŠ¾‰U2¦A¨†ª0G»"RRïb¬’õxÄéß¶óòSSâÉ +g%›Ù‹ñífµ–‚Œ°²R[«³VŽrQ¤5BQ*Šï ˆ~8.-ñU‰oD{Û$>™-&îÙg‘¹Ì?x ”u=XŒ ®+®Þâ§¾á½0lb-ðñ!wï‚am~j|ì©ÆŠÕøØ_FÁÁŒÄ>/Ü*t®S(.íá­œrxéŒT…}÷ >òNåütÊäü5‹rL 7Ï”IVæX™b®ÃŽøï£x‘ĬÕÃUÚ‚ ´yy“j¯².É_û)Ø ‡ú!ƒaí {ÑÃþè_ÒÝl¦—7/oöÕ™ãJãš03&“•ò"çö1a´9'=Ézžœ}½OÏFiºŽ¾‘V"Dñ‰DÕùøh´ˆ—)éÑÃ4ýƒÒöÇÑañ1%`ÌÆü/Ï~Íÿœ¥ÿóÇ?Êãùj_®ÓôDi5‚öÒŸL ç¹Ë·’ü_¿ßÑkkø;[i¿ƒ6:µ€7ìGp4Ûø`1â”P8ï˜7Ð(+FùXjãx—çÙ«¿½OØ6Øû]±÷ Ãe{?]ô^Øûd$ƒ½ïËŸ–ÛûAˆì}Œ‘°÷’>Øûì}2'ƒ½ß={ßœ7¿¹kÞÞ/¿Ò`{ŸÚ@ƒ½_ÒÞÓ˜½§D úJ¼œÙE/Äßd†?ž’x¦=ïÅ•ï›áP‚?-?!z8`ŒìÄ9 éð9`݉\®0Z›Çµ"¹‘_W¿=Û‘çë0 ;ñt= éQÁ³õ7¾†}Ð7ëž–wð7ëµá÷?#üu5_¦ -}LÈ ÿGóð’sŒYèÜ︷ÔC¼X‘‡7ÄQfm¡.oÈ ¯N1n‚+êÜë]¥Ø==zQI†ØÍ&ã ë6ñJ¬ççü«ÒÕÈ V$]¥[ÏþÈ×®×]x9`þ´ÜË„hO/ǺIû`δ6a_Er¹”vMÖ§ªBø D%¹L\>Y³üUÝe´ýbÀ+ïìUàÚ–[ÖO?V‰ "3`êǾ\Ñ ŠÒ—?-W”Aˆî¥¢„9ÓZEY‘\OEéçîHV[˜…ÈhôÌf›[FTÉá–’Ñ´îÔ¥õ$$õ7ÂΗ©éÐL`Gƒ¡]¼UœŒÃrð5‘P·­Ø ëÊŸC-·¯‘íiaù©çŽ\`¬ìDÈEPâ#,è¢ØÅÏ¥§Çín£÷î—¯Áosýu=Ñ;?n?¦+`²I¢à7µ§§‹9Y&Aô~¸ù´Ä0¹Ÿßú0ÎuÜ(0GØa—À.Üjí}pPâý¯†}Ý1tw5íqá‘éï`"´šÀä[6\kh.'óªö[úLïc}~¶œ ê{Gê›ñ¾¿Ê›oPÝUxÕÅ]™ôÞ«mŒCPÚˆ¯[esAú(öå"úF?LÕˆÊòF•{=ž ¨ó«ÄG˜Óghý^|nÌç ý«q«ú?ñ½·puÂB~+Àó1¥Ë÷®Â?§tá‘Ђç•ÉÐç–Ú—¯ŽË{™•c/°P‹š>o˯¤ùw¹ž?„2ÿrC¯¶P‹ÞùlLþsû­?¦›9ÄΘnº½† W~™öO±no*ü5,ùNÕíåM8Ý^C0¬Ÿ°P†˜pÉÇM8M·{9réÚgWÝoWŸÊ¿Ïôú4Päõ äPÕ’†ž±z9ò‘QõØq( g7ªP²~%Îú¯ä²ë÷Õ<¹]-—ñmé—W­^Äùðú³’ó1µc9K<Þõšþ%‰×WÑ—áSï…óŒë­' > ®{vómw”I-þª{šñN•﹋=Ô£¼#dHä‹uWñýâ[h:x©Š$rÆz.—¯SÚâM_^b+#uVµ\\‡¡¼ŒÐî„Wª€E-vH…£¼_”*C{ì†Tô.Tt¯µó ˜Ëq©:yPÇ~Üé€&n±î»þ}yK¦uÐÀMk`Æ÷Þê`6¼A —åSËõp²{­‰1þ´\ »>mÌ%fÏõñ»¤üKØA—TÆ)Ó{«‰Ó± j¸“Z®ƒ«ÒÜk 2§åÚ·*Íõ©^"{®w/V)iåŸ4 ª·¤êe|ï­öeÃpY>µ\ »×jãOË5q²ëSÆ\bö\WúvÔ Kjãü#SIö7ñ·(â.}ijwjØñÓMíR•‰îµ vüˆS»pe¢ëS¿TDö\ùVúšÕ |K*ßü V¹òíÏI¸K_°Úvü$T»pe¢{­€?Õ.\™èú0“=WÀ׫ûùí ›ÖÀ”íº fsÑ}LÇ1hà’lj¹ ®Nu¯u0ž–+áêT×§…™¨ì¹þÛvüÜû„ „i\‡öçôJ5èÎr\j¹ê¬LtÍé&déVêYbª8®â¿oãd­¥(œyê9¥2VÜ k«q«å27ñõÉ^e«õHWOŒSÿw²{ç\ÒRâ°Og÷Ã:î\.œ]|@Û'— Ý^-Ó!hÆÅ3øé쮸”º™÷¦Í9oE¾’dºR¾›Aó–úlBží¦OŠWŒlлexÔZµ€äžj]œ3-VºAˆ®Gçf¢±Ç*—xÇjP¹Ù,‡U‚»ê‡*5ݳpH1ÂAs—áQk5w’k×ÜÅ߭甎*°ðË¢ ~v²"ɸÎV¾'ÚÅMœiùç%+ÕöQIÝ{ Ÿ’¬˜wpð„”ò„ÈYûæ éVÊÁ]yCœ3÷µÅª Bt="L5ˆìú¼"ýO5HÌŽZTðà©×3bhðúFM^…K­ÕäAˆî­‡ÄY!¶ÉGR™è{I0Þ´ÜO€ìú<%¦aö|%UrBŽ’RŽ’,#tß¼$J½+‰[bå¶XUÕ)î±s¤ki CÐ\Ÿ[¤çi ‰^Õ‘z"ª¦î¡7dÐØåXÔZ]âÞ:AÜt_›< Õ(î±ûdLË}Ui®Ïñ¡™^ÁëQñ‹ƒã£”ãCþGß|ÝúÇ®ÜÎß´h‹=„è;A:øŽ@d×ç éÿG8ˆÕQ‹ "õ:D ÞCŸÈ É«p©µš<ѽuŽ8+Ä6ùG*Ýc Æ›–{I]Ÿ£Ä4Ìúî+©–+~°Ñš¶Ñ¤$óªyÖ‡DóJ2¿ »Ì5Q{[L²ªôöÒsMÌÞC¬*½=µÁ¶´ØüªNq=–—ñ5€¾]“x.ëÓèþåCÚsôaüÓñÎV•d?Ñq¼ûêýÅíž«ÕÂÇÖ©’³Úd“ÈZÝwÜÒ1‡¶³GŒ*[G÷›5]nâ÷>ŸwÕBz™¤Ì‚܆G™é”ö¸/ú°ÛH¡¬$æbY¢oWËd£Š>Á`N> ÉvmáÒ"ж‡¸°&»\ÐÀFÜÓðì'¹¦¢ÃEfSÀ¡M¦‚/¤‹øËûÿ-Ó,^Ä›˜ŽðGyîÞWQÅFXÎSVQ+¤Ü§½¦ v,Ç·«Y\zPctÆÇ\|˜looã$é‹F`ÔAxu€q¶[º è(`Eíu>»)ùLz£SKÏ×DbÀ;†uèµgx“ªs«ŸRÉ0+ØxGòÒBÒ …È¥¬ ›ýäaºŒ¿Ü­Ö›ˆ«oE\³•To×ó»xýr»Y‘›—Vn™ÃøÑ|ŽGáSfýø2°®¸r‹½€5¸ríŒ2¤y¡7°)—n ºq×®âôúòŽº«zôÙ³»ñlÏ~?TýøYÚÅdåÜ|zßÝ/¢MÜÀÍtGgJªÜÖùz­ªÜЙsÅå»àüwšµpóø»Ž‹sð]Ñ|všV. 3dj¶’v¯BÓ«…LpišÁïÌ*jœÎ¬GÅgÖ±ÿ™µð\ãÂV,”¹UÇÖÚÂÕ”éÂô¼<¢·éëCÆ7s¹žØýmbðà—‹¹ ‚^/jk@ ³#9xRw¹p ê½Æçcåp>ö:í—éÕß}9›]Ä›/«õo¥mÐó«SÞÅðÆÎË žóž‡€± ÝÊä0Ômó1_WÌÆ|)7m9ÚxeX\ÒŽkÑtÜ^”…LGßßÙøÔâ÷wȎи±*ïï$Úã÷w¯¨²¯QO÷Ú;¯pOÑ´ׯÊÀ[‘]-ײa©/«h‹%²ºÛz䵟ÄËÙõêt1O9:ðç”u;œ“h¡œó Áœlf/^<Ä·›ÕZz,ÑÀE‚8•¿÷ãÚƸ¨ñ@b£"ãi]1,®+r^"¹i!oå–!å Øñ”x\°+b ³ç‚½#Øcò$•fß=¨7©p˜N™p¸foîÒÂÍÁ3%´^YJ`=—ocþû(^$1kõp•¶ (m^Þ¤’íHZò×~ vá~È`X{Bã^ô°?ú—t`7›éåÍË›ý F–4ׄÏ1™Î”ùDŒÉ ³ö§Ñ“¬³ÑèÉÙ×û”ñl‘ÖÑ7Òø -÷D"î||4ZÄËtÑÃ4ýƒ’øÇÑañ1¥cLÊü/Ï~Íÿœ¥ÿóÇ?ÊlB>çTÊ’§›Ö÷Çxsû9íý`4OeÙ¾ ‡ÏxÚúÀ˜föšRëÂ:³ä?T‹üé~›|ž~ˆnSuzþ$ða¼¯tÌ×€Ú—ël=QZ,›îO&¬óæOä¿øjþŽŽ[[ÑÿØõºû]’¹É&kSLè{%¶Þç¼·yVö=¿ý­òù9ïc°ÑÊÛh{h£I£ëŠ&‘ÜøAÜÆ-0ih‹l´ Ä[ß²Øl´ª6šÄÎÁF랆NŸß6o£U^w°&kÓŽÛhoØho,6Z#5Þa¼A §Ž[Loºg1½ÙÅdå–at¼i—Å”xÜbzc±˜rÉùF—œÞ2±¶’ͨª$”úè$”ÆÖ'I( «+’P"¹iIhå–!LäíÐI”x\*B•„òvj™$¼ŒÖ•ïV¥>z' ¥±õIJÃêŠ$”Hnü3Ì6nÂDÞ-„A‰Ç%¡"PI(o§–IBrŽÿqû1åêå"ú6Ä\—– û$6ÁvE€îHx:ò¬ÍAÙ5 ¤•‚áØ£X@ò±÷AJW3i!öIJƒ¤tžµYJ×0„š¤4¼{$¥Iâõðp±œxVy×'¹¬ŽlÈ•˜ÕfI’öšD°¶Ëz&{O¯O/¯âûEe™tôh¥°ÎžÉb}|]‘ÈҢ܅T.f›ùÉiµD>‡.©)RVZ»±‡2{×Åu%õ ¤}…tçås—DsO¥òË[2½Uå²ÒËã“ÌÊðû&›•ÁuE:+DïB>pÍpêj‰Œ>\Nk¤¬¤VwbÏdõuüµr,›ÔÇã“ÓÒàû&¥¥¡uEFK$ïBB[9fˆ6yß´D:.™‰QV.Ë;¯gRùb•W•ËJ/O2+Ãï›lV×鬽 ù\À5ó}¼²ƒZ"£ƒ—Óš)+©ÕØ3YÝ‹wq»”Ó=}8§ ­+2z‡ç 9ÖötÁ€KfÛ#:g¹ìòÆ®£R¹oôv)•{úˆOZW¤òòr¬íù‚—ʶ}ÎRÙå½_G¥òõê¾ú'äNŸ\–Gß7Á,­+’Y¦y'.g+ÏL—­¼yZ"œÁâvV$Gi¿³¼{& ëþl@ïÅ3–ì¿ÒyÈôï+›;í?øp¹lËøï,–ÄàýÊó”Ê6zü$exŽâ-˜»ÿ¥SÏPúü…¼Iž TL«ÑÓ'(ÚÐÁì”N£ÓOP‚ F±¬ï¼Ie’ÏiÊSÒõT*kC¤²S*ºNKåà¨ÓXÖv^¤2Q8ÃÃÀöroƒëŠtÞéÃ@®µÿa`-ƒÀåt€‡æN쑬&jhÕ¬èÞÊjcpƒ¬v´¥;/«kD­²Ú܉=’ÕD ¸+ÚÔ=}Ä­ ­+2z‡¸ 9ÖöGÜÁ€KæÊ¸õ×#©LTÎ •+ZÏ=•ÊÚЩìd7wZ*@RYßy=’ÊDá ©5ØË½M­a ®+Òy§©5¸ÖþÔµ —ÓRk˜;±G²š¨¡AV°¢{+«Á ²Úі®eµÊjs'öHVϺ+Ié¾>éžsû‰æŽ?åîÐ3î¾>ážÄËÙõêt1O™^U?JQ 0°O^WóŽd²ÇÚü]ÁàÀår%‘ í¼ÞIæó«ÓA,—Ë9÷ú'“ó± ¹"»Ú/CQ_«(–v[§åð,^Ä›XÞåee¯³ˆ$gp/¾Æ#o¦ÙŽÂuÈùìÜš]&^Ç›K~ h|}’C`½Žp ]_¸ùHv±xsuFÏðb-KìÖ3¿÷ªÏ";Ba'H·¤­1žà‹v÷kŸÓ{Ð%¼Koõé:Ž6ñà«{„¾:mꉳNõà­³xë y5¸ëŠy4øë ýu…ö+¯MæÿO•Ûw¯eOŸËx>l?ï̋խ\ÈqºÜœûm«±º­Œ;<|[ &³Çç³ô¯ƒE¼ìô¶CÚ™³CºÂ>M×FÊ©—ËÙ$ûìžš,–ƒÑÅ/oßîÑeRÿkóBöè÷Öta³ë§ò¬`üL›m‡”+d–[k¾ÚpYíÄýÆšÑïvWÍǪÜRgñ¥bîÉüÞÏ.¬|„0á‘:Âû|öëûÿ*î]þÏÿ‘iñ’Û%:-#êßΗæ#vGQ/H•Ê"e qŠG ŸDã“Ç eJ×…1Än„±‰[x€$·Â‹Ãä™'¾a†I6Z#Pñ|·k²`¥[ ¼Ú‡®ë¬rÕ¸Í>Rn³¹øs§n}•¸Ÿ#U¸ŸÃähk•|N™SÍh†$¬Ö ù4IãAXÞpΙÍEõÏ«ds°½Léï´ÀÎÇ5ˆì@"ÛÆÒíàäÃb»(²•‰†–l¼AC\éH<ƒ\Ùè•„ Â„Ÿ|³.d¬û°ƒEÙx‚ß1¢Í]ý×§îJ5‹ |ä¡f:#:k¦¨íÁfÆD5G›¹G¥ 2û9zˆÏ/žËû XøV«…OrÎgêZf_낈=`Qó¹!ìKpð ÐÜ”VP[iÉ) ž=ÐÊeWÞN&owÎÚ”Î2°®0–¸wU?섹œç ]`25°Þ¿{ùÿ¾¿¸(`3מõpY!ÄÂ甈}ÖÂè0)F+³9%ø&^'äcâѯֻd´FJ«MèN1{¾l ³ )îÌæÐ]bvŸg«í‡ÔTk€Õ.3"öX 9Í.læ púìëf°[Kà7%gº hḠۅå¶Fž“§3 ËtJ៰]8Ñ|~¼Ïɲ¬õÌŸGÔdÐ0ïý5¬C×3áçâPqHžuäÈïtñXvý¯¤ LôÍÜ´ÙÀ´ÏŠ´‡þZäÕ#ÆÁЧlp’ùZÔ±ö- :fgöÞ¸ ÿïPñÿ:lq÷nJ ƒ#YpeLÙ¯ìtRÆÒeq¨ßƒé£(gK@âÿL•¯™ÙÁý:¾ÕI6ÉáÏn„-/¿ŸŸ7©$Õ GÿP÷èg†˜4 (ñIK’ØØ _þ8§71²šØEN >Oo)“ÿÐïiH‰±]Jxˆ…]› ³a·c»½x±ïz‡ûÞ²ºåÕýq±Š6Èêû¢?:k@6îŽm J´ÛŽ`ãÔß þLqbîa×ÊÏx–4lôÇ­ù ›íCU…µ~QÏ]µUl·sIcbÛXЙØ~ôËù{y9ëÉlÅBÖ“Åöc;çÚlçb/L³i¬z3Íæ£_þÿ./ÿÅ*¹´ìéïÞ,w:šŽ­qB³ÛÚ¦£Ö4ÿP¤ë‹[­èÍ*—…zW¼2-žb}Øù…­r{N_ãJkŸþîÂ’wr3ÑÑtl™šÝV7ݰ¨é¢>%»¾ºÕŠÞ,sY²wqÉ+Óâ)Ù‡Moåú={Ä*Öxöê´õ‹ÞÉœ)x)×ΕŽ?Š3V¸ônXÙcP¼KÜ|aݵîñB´ëÞáU(.⇠íåz™>L‘Ö?ýÝ…UÿÁeÕÓÑtl¡šÝ–7Tô¨5›i‘™2žžÜ§óå,þ*­W‚å:åùU´üm4]“Ie¾DÙ’üË_FÏ´ ¶’öX'×ÓÆI!Ëž÷ðgªÄë ’ÈùÈ`HwŽÞí>­6«ÑlžÜG›ÛÏöwi£(ƒ; 78­þ~.KDÆôAχšÿ•Åyûnc’"nÿ©Š‹69ýßþ6I÷ML–±ôûÔÿe“óÀ9xKšM8gÇS>?®Ö£ÕC¼NíÑY<ý?y¿<Ö- KÙª†{qô¯ã MÁ/r2Aª%ŒÌ#ßÂ|D‚wç‘Õ/¤Ñ[ïõŠà¼&¾aŒ 8ÆQÌ‘Çw"Dó3¢<â1ʾé"‰Å:Ö¡–þ&¶‘åQT›XèAµ2†  šÍÖûó‹ë³«é«óÉû_/XâÊxš\ÞfRÍæ¾1Íôe4_;fMN6³/îSølËd[§¡\Ê„ZK2e;…4XÚ0ñrŠf:%h®…(Êþw³ƒtÌÒ,ƒù˜¥'RÑ.O®…R åèZØl+df.ïl-HÎLÇãœ9O{„Ôÿ—’ô"wк}ôÙáƒs&dkä§Y äœ8Ϭ%K®ç_,Ü=Ï‘ÏZ?ÿWžçáÄ^>µ^ ùç£ô*ÈDõ]¬•›‘š¸^¶É|ì±°ò³Ô3+*?ïKYnî3]·éæ%­LRÄçjþ…YmÅäVÉh_ç PËÔ¾ÑãXU‘cï ¦¤ú!…Rp#|xêæé–oáå=ÓÌø‘œT›«¤ÇZ}êz¿µ±õ¾€kÃ=fÛ"=j ô¨:ÜÃn ·…/û껬T\GAn+“<Èm¥âøy±A:v¹Ù |œ¯“ÍTûDªÓ9£ÈÐÊNò—µä´ÿ^Nã´(K@_ô ® .ƒQÔ«|@Võ-hÒf®PÔÑU´ò}<Ï^ö½‡G^*á|8Gû~ÎÚ¤ ¿WÍ®¿mVå\(h$2zÂÊ®×(^â•" Ìsz%z®Žöåφ9x´=ûr9a©ýT§q]³ëÇàFÛ»¶IØOí•°¹%—©£ïÒù”7` 7ÛO¸Ú“Ä©,š æNñ6Ì9Åìö»?Û1_[÷cÏ,Ã[nò'ÝÕæaˆ{iôpžVÎŽž™=ùÀÚ*g‹ì¡ù:iøäñcùENÛ¶ZM€ô¹þÍĦ|wq®fkÛZ»"¼ÁBëú$åÎC|»Y­ XÕH(Å Ûóÿ‰;ü嬷^χ³¼&4-pk8/.•S óµUhí2¤@Þ’J¼gÓ»É?È÷Æ%Ä·¶µÒöu$X^G.»ÐŠ‘=0^Ò=·hŽL¿Ì®T€4r®ÈxPžŠà6…©x(äÐïsذ¯ÅÂ%ÝOQ1àPR pXë¸L(iÙš¯ßB8pH &]5áhR”Öcãœë:?ZµOÛT$ß–h÷ôá°kç ¢ÄâDÂd¾Eã¾Çô/qÅ<ª ­ÄMGû/ýë¡ì.æÓýÅý>ŠIÌÈz¸J3%Fñƒ¿¼I— ‰îÚ#í§`7ê‡ †µ'DîEïäf3½¼yy³ÿy‚Å$FoI™.‚\æq—ñýO£'žœ}½Ož*­ˆ´XGßpT|"Ñ8I©ºyÈ ÎÇG£E¼LG=LÓ?(é”Cam]?­>üwJB“öÈ‚žÿåÙ£ùŸÓþÒÿùãeNŽF›†ícL"¿¢‡ƒÑ\ …WHJöÁ([ ߥˆ•-L%?V¥Œìæ?Ýo“ÏÓÑío{OS$ ]|¥¨­\çô‰Fíd’ƒLt~í ÿÅ—þwt ÚòÿGK©PÝ”Â-%Ýêx Љƒüð2 û/dÖÞ”ôô5@ÛˆªïþíéˆÈƒût›3qõÿŽžþ›á!MŸŽ~PÚº‡†ê/m!b¶_Ç*u¦bƤe´™?Ä£$þû–œz .¹Y•WrÛò/’mi v1êä~)¤"rµ¤j<µ6ß²¡ŒnÓ¢1QëÑò;›ƒÃX(±ÁGwÇhó9±ðÏxS£cµ\|ƒñxبù¸-¬£ÏtcTæU £4CçkœzðsDù‰5xLÀl¿‘é:“šçðÞEôÒª—^ÝPþ5§s-õ6òp—o#[›å5ð‡½jz!¦^BV¦ÆT¦:3«g²T¯Õ‚½5»qziÆÓ „ŠnYÏ£{ܸÊSm ýrFƒaOƒÏÕÙ•srpºö×éŠÍr™nÂëZÓ2…Ý®² Û/ã&}º/j‰„²ÆÓêF§K\­v‰ß@l-c?=?ZÍF?]³F£TZ•FY9è´¾ë4`šƒLusJ-üB…µ‘_Õ´“NVuF…¤‹£€ ê®ÛE™BÒ]­y2"ñ"Ü{×ëÛ&ÞbIt|)â:›¾G\ûÕÞ‘ˆ§XlŽ€½Vó[Æ@"Äwjè¹Æ9;גּ1ÎA£”sæ²—æ_{ºÿÈ»¹ý:mcwW ëC˜8h!™s·Z°2*È¥¹¯H_ÝwÑü±b©ù4ž²¬ÏVR:¼n éÍú[Æ‚ì|CøÊú›N”ˤCò·`ïä6ÿ“|g)ý/™a) ‘Ñ|Kn„ØZ_m7ÓÕGr£÷)}7XNnì¸ Ü#Mþõ?¿|Ž6{û ø¥ÆOîæoVNTLÞØà¿“\Þ9™Å»oö軡èK¶P¡Ì ‰..‘ŽÊH²Týɶ&}ïåò¢UHõ>¡ËxÍlÓyO¥ž{zŽ–I½lýH!+…ß%O`®²þüŸ,¢f(ÈYÝ‚Ã^*é/³ŠG6©_˜µã»Rzì‚HûG»”ƒsp=¡³‹÷kü¯5½ÐÙ0.ãlp‘þygcµ£q%‡ÄX•ùc§8ŠLæ÷Ö#ážünú~Rß)U\y©Ï7°þŽÄúrÈ{¥hµ½x2ë×ë©q\ª–tÇŒs ”ŽOdïñð|¼{{Àî:òÑÙΊ›gá’žÂuËTGæ5þF¼i‘ro: ›cf’6ªÒ§hû5þ0Ù~¸L—P²³Lm×9 %RFÝùülÒXZ‘¦M›Mó ¸P{¶äs´N'-mŠ®óŽ_o›ÛÎ+[ÅS"ùš¼cs°y.„ö/‚09ÖÌ©wOµ–#U/*{£]'[«¸&KäVÓ¥x÷S¬íR–—ˆ1@·UC¹Ö¬ìïéñ ´ë¤kŒÅu`‘.nù×J¨~~È-KýùÕ >§Ý z£ ÑÎS—Tk¶Öö· V¼ÎéÖv|(ðUÓiÖlKµ«/$ô)ð‰>Gç&ÄC ´ó–?•À•sKKØg<Ь7–~­¾¥ë‡ÍSñ–oµçYkýY}H¸6$\®UY.ášE°6”rÍ&U‡¤k}Iºæj¦æÿÙqÚ5ûÔƒ§Câµ€2~H¼Ö# c‰×,îà!õZKR¯A2°Aa±A>ÏùØ +¸piÙ¤Þ‹³³É¤X“´iG|0lIw´Ë½ÛP6£Í¦®é£kÖ`éà›í»o¶`ÊM{# mj^¼þéÚT)Ý×ìl2ÛíIÚº¯ÙjNÃf°rPiAUšw¶«A§k¦[:­T޶v*µ:–¯{º6«6ëhv6™»ö$m•tWkÞŽ˜®é‰õ‚·‘——ÆH=ßh“Yö™ˆÖMÛ®É\²æ]«n»¹‡4w,¯šÎÃÚÒ«µkS•ȳÖÈžê\„³W»âÜà`BÅ8c¹Õʇ*7—]Má¶%ÉÚÎÌ—É—ù'º~¥ñ.'ðfÎ×õåWk™˜öN´Öˆ”vH£&uÐ¥|ièÒF3¦¡- r¦Yt;f)YÓž5v’²¥L«$ˆv‘Í¢GjN‰¦±´¶Ìhí’Wþ)Ò‘WmN…SȾFò Y6Š‘ Mí=Jyf‹Á¥p­†¡-ãYHyìpÌïyF3ë5&6k—ÐöÏp6í"öí:YIHDf…Ì“UqˆÔ—Ѭ±±DÖÔfÅþâäfºÚ†²˜¹yMw3ã¡Y›<6µ$+“F¼ ¯‹rnô.k®:Îâ-Ã׆Çîà-´ èΖ{0±—ýÞÏÞNÈ äe’²Wp©À¶L{ÌB/ì·Iåا–‚rÀ°ÐžhÜ‹-Z@`)C©²¹pH —wˆßD='ú¨x¢Çþ ˜ÉEÓ ËŽLt)²¹´×&Z“˜ÔVÝÓúc·xp±0S4b^wž\Ä_ˆÓˆoé\Áý€CŽHþ2¯XËÖÕIsŸ®ãhç–…¬¼e%|ˆ(gYiçÊ^VÙz†¼cSi£Vßf(°ý;Îãíž>Œ!úÓ½q¬;°Žwywz¬ÚǶ‡>Ý{ÉEt$×óÍ">x¸ŒÖÑ]r°ýi}J°ˆe7y{è)oŸËÛCy Ù%:ŠM“¶ˆÜš(çÛ»’zm¯UÌ´¶šR5Qn·¦÷Gê{„q_‡'Êã!{Ó½F8rzpTÃk„1a·11Ã7âþFü¸ŽgcðBÁd™pô ÂX¼AзÃ?Z¶hå™Q$Ý×8çgó»›cËÝaäßÝ—R Ǿ)|õ[3…¯XvïnÚdà!?òø˜µÊ±ˆ8ü³u-Ûf”T]sÈx:TÎ@‡Hð\•ÿc=­Õ‹Úíȶˆ£åö~²‰ÔHì¸VxЪóê@¡v/y·š-ÓGoÒ`;t¬O5|¤P,æ}5îû0Ðv¶lÍ?üÛÓÑ¿òÿŒˆœ¾¿¸9»šœ¿¿½¼x5:ûÛ/ç7/ßž]œž®~y{6íýxöúüb?oöôßþð&SùG*+O¯£‹øzšÕâ‡dPs»ëëÝÕO Å¿\ü29{uùòê‘àwqÊÄoÙRgT„¹¦¿T~hŸSJÅ#ŽüøºOÓ¤ÔO&“·©i¸Œiò:ŒÓI^P™Z¹3A”ŠÓB'Šþ€!¬)ùŒ?ש]·H5?%â](*Þ©ddXl”üty=¿‹×ŒôÏêÌ Ý"8 —ñzQ3 ?n?~äDÐ}6#i¯iùÛù2µËh·é¾âÝæÛŠá/âTªG·\4œ²¿«óŠõ#3+/A×p>c§ë{šô’-Ý¢¹RÖmXüöRë·NjœÖñduû[¼y-S3lmêÓ$­O + Ú-¹’ͲLF1½ŒyÿuAVçïH%ÆFÅùU#„dhl´œ.æ© V!d¹QŒüi’(þÛFÕU-ÞΓM¼Û¯®‰“1Ù(:ûßÖË(BÀb±åíê.µtK¬¶¥mà³Q÷óõõeÝ JYM¡(â‘hŠ&•¢Œ#/R5uK)m9Jg‹–ª›»èðí†Ñ9ißàW~S‚e#ØÍ-vMúHµàmÚRÖíתºÏÖD‚Õ®S²Å*Qt¼ƒ†OÛ]GŸ~Ž–³Efå‹“•0ù> ®¶Hdg%Ù¶’÷X ‹¤^r¼í’úÈ©l4IZ)¥Þ©,g©ÔK“‹½Â[ÔAÎHUq¾SÍ[¯‚ÝTçR¯f=5BYª1ºYR/é x'ä…ëÊhý)Uì(€š”»»CAkÕ×§—S'!µÑö×Õ¼yÎIHm´½[ÍâÆi“Úh»X¥¿›§NAk£ïÍ<53›¦NBj'ÑzÓ8mRû©ìkó´IH­´­îç·Í'aµR'7æÎöP„é$étzh†:h(ª¤𣱬–hŽÂ²º¢9 ]5†.‘ëÚnRÐ`ÍñÌY]lïâµ&õjcœ‚ËK»6ǹ²:¶9 5íß¶óf´…„ÈKó7DZÒú¿A­õ¬ÍÎn‚E²3`©ƒux2Bœ¢ëaŽÛ‘YvKfþ¹ê¤(®¾nÈ:Iqp;¦šütuw-g<.aµŽ¯×Ñ2YDÔ”›‡ˆSz•NŸœ‚ž]Ä›/«õo»¢3§ €ŸÛEœì™½Â_’,¥qònmúµÕHt¼¬z¹Ý|þ1Jâ]‘)ðÛh$÷Y;"/E]@Y.wB]‘\<ý-wEÁí¬è…R®N’¬ÞÝôûÇi*oØ}©,ª¬ž®§ŸÒðíivE±u¾ü¸šNÏxàâ·ûx* )–±~„¡ƒ%÷Ò_Í\(Êä@‹s7sj_¼¨Ý7Ã0ëÄe·ªˆ4bËQÈ¥ê”%\nW‘RW+¬^bZ‰%Ïúb¶p".o‚ÜHÇ»¡ØùJÇ4:DA w²»`¨×E­añÔI±©C@ì±;îÖ]Tó8¼Â†Õð…,—˜è˜Ü¨à*qmz=vG±‹wD19 ×ÑÎ4œ6»áb玱´ƒíåƤø\vn88f’¨I!)xàhóêjTlZa Yu(ç¤DvYºaã NJ+É—ù§)y<§GˆÑ”üNO]wâX5MpÀiŒ¦Ûýeô'n OFOhqÌzñ‚ 3õµð?%Ïâ‹äï»ÙOÛåmÚúýʈ§ûäÇï? A¿XgÔꥄ0ý\G÷$åè‹F;7Ä‘(ÃÎ âìÀ„á̡Љ·‡ÿMÁo_¼x Ìio£§ÿÌ*0‚ò]é!O%rÒŸtèâQ$އA:¡‘.©Œ"T‚¬j7ÔÄó“áL0dÔ„aaPnݳóh†€þd(øIC" =ÐГºŠŠIèØYÞŠ’·pC»Z~œÊQÒŸ «AQ H4gK’@]ÅEË$„ ÆŽU´qEMŽ”ÛÆÛ˜=ð”Pk¼AŒ«ôý•9v³’y9Q†€½¸‘GÂfä¤?zú<CÇ œºØæ+‹þ¢X9†AÀ¹£HUXÝ©ˆXYŽŽÃX‘fmQ/¢oñLâ½D^Å 1Zàô=¸‘5Ï×wú7C<Ç¥<ƒqêúLäFÉd%M^!“áQr?@Ž‘p„ÂK€âˠЉéÿM‘e¯Õ\9¬ªù"W”äCBJQ Ê©û×ñæål¶&Né ‹TF‘É0NµêìL,ðŠŠ4?1#%h't’£^ Ì‹(JÙ• UZ¸¢UÉ „Ö!æ°>¨âŽ,ÞÈèbÜ‘áÝPšîØ ·Qň¸5PNdÉ1ž‚©Œ¢Ä"¨mœPËátµTFQ+!wjµê·ÑòÓ6…ŸÜ®îsäJ)E¯ÂaèíÜH΢ ;/`ˆ3W†3‡vB§3Zfrƒ=™+Òdز"†P µÁpÊ-\Ñ*²™ÿ­29‡uE ÍËʸ±JWÔÛ…‚u»Èn-ª.ƒô@£.¤2 ¡ýp¡¶ñ@hh eR€.qEEµ3<äEBK1 ʹ{}™\hîÂAÀ]ø 85È;C.—2ôj08F€ÖÎ5¤;£A)fDhÁßzK'2ÞSë8Z@§  ŽµÁ¨‚ûp"MŽÖ$Ie”%¢!Amã†:×È0gE ±Ðá•[8£Õ ¯¼(C[`z)-œÑªÇ¬$Cj?ŠÈðN(ÿ¶%ÑIQT¬¼´ûC¨Ï;Ÿ+KF ºGÆ£¶qB­Üp Ür!E®Þƒ!صVNè'§Ÿ£µæy•Ê(rí¶qDmÚìÍXŸ8Xéó|bp|¢°{RÈë‰7£ß­–óÍjýÓ«gVÄæ(V¹…Z5#f†Z)fèµÜ™ zKG2RÉBÎ缄#õ8ÞÞ e¼~'˜þdÈX ŠI@º¡Éo53TYC'Ý{b(åÎhÅEŒ——eˆ³Ë< æ¼3jIÓHZ¦@ÃøiõöRŦRºå´âö)»rÌpÓŸ )OÑTVáˆûγ³ä6’ÎÊZ¹„ëÅ [i2ÿ~‰§£ÍjÄ9|iÔ,[°@GQ<‹02iÎ…üÆ+G%•r”Ê[0µÚΑh,ÃÎ â, †3‡öB÷vµºOEò&þº10Ku r›"zÔ>¼Hcf|bÅË’l9y[/R¤Ü_:5y•Bœ-¬€&¥G²¾š‹5/ã„|-^¨J7ÔŠÍžÛëv[ÝËNWWf˜¤B†Py‚‰áU[¹¡N¥úiÔåZâô)5yµº‹æË«øãÏ«ÅLæ8 ¢¦÷à@§Ù£/ÙŠ»O+× ´ºÿ̶N¤Ð‡ ?ùA‘²ç&åÖýf¾ÈýÅÐr‡sBA¢+Ó+¯¾¼ˆ"“ 0ŒJ O´ï¢{sZª!'pÅøY;gäË&þ;Ck»lÊaQñ&ÊØøÇ|BaÙµpBKž¾ |éß}‡``0®]+Ìã¿ +órXWT€>TJZ-¨·s"…ëe¸³è½'¢¦´±™ÈLLûwÞ½¼%±×’ý,T2DÙAœ‘À/r‘ñrý)“VJ!Ť@•Æ•ö`„L(…—U×U~zä?EÿWÐéÑ£çü~ƒýýBwÝòwrrß¼H ¥±(ýg=Wë“hÅËx}—3%+¡½çõ¥Q(Iوߴ{QWµóóM¼Ž6«µŽD”ËÈ2زHßi‡þwÒ©ÿzìgRD‚õA5εš52ú/æ•G™…Kg(åê'R}¯ækâ%•PðŽBÔ—E1Ñæj"ÍÕ¤ª‹Fë:ïØº¼@jy¨A­YE”Õ–‚èAÚ¡r™‚¥ÊN•;Ñw+T§#®¼kñ' ‚ ‚c{O4ðu)¦G¢ç·“,‘fE+¦$i¥Y#õC?Р$å:Nö1÷’H?¬V ˆüM:§ee;¼ýe”“¿I‡´¬l‡³ùGþE<Ū4:diŒ«­äe¿hÿ¬¼l·MåL„7…ï‰|S_êƒæÅéoW÷™´r&Ìð‚&qfláÿïÄ’l>É_<òX~f‡y’=#/ÀÄj8>ÈõO¿)=kkiô*azAu}·_5ýÖÈ*¡ýSí·Lˆ î‰x±%Ú}GèSKJÓ8›&ùqý"øxyY©õi>Ëu3ýA:e¥eûœ/§‘tÃÌ>¡ŸBe5å{Þä½RJo“iÂì‹§ÿœC/«Ü{MåÞÉOF3«©Ðóóc¥gò“÷LkÊöü[üMÑ™â7é;«+Ûùb•ÝäoÒ)-+Ûá]tÏ‚¥"Ò½ QËjçÌf¿h߬¼l·ÆM­rA[ý^–¬a²3¦ùk/©ˆâ *cIR_ò×êå >[é"^æ“’4¬¶tÿŒûYïì'í›×<ý'‘âGY4i}†#ý›Éú¨J‡ÐWMsPm¦`€Ï–ÂÇ#àzcBÑ~Ü.Yjªk§…mÂL•«Ÿ4*‹Á3²èŸÙã{ã-9‡úž¼ª÷ƒR¸˜'›kŻׯBdd“Ú”Ù²• q܇$õ«fÒU0 \Fžú3ùM,e'+xñ¢º ˆÄn[If­4=('Å÷á, „¦ü+pðŽ¢v¸Ÿƒ B»’µlÀ"”ë×ÁAËO46:B;,¥ªh‹¤ÿÇÅîÙ Ñ<ÎÂ-ùŸ/^h4A›4„7ä}4__O·Ëdþi™Ú[ĪcÿEÛŒ—éÍÂ4ÒÓŸG¢ÙˆZ›äŸ³ˆ°‘°îÈP:d€Ù§š…à(d ÐÂ2ìì›Í™ä!C3o,¢)ø=÷CÔ$–¹yM ㎹*³ƒ¸0³G²Sõ~šn;¼:Ùö ^nïF¢A:~å¾Xo o 4X\SªõÀ`B.DŠ,é‘¥HÈÊÄq„  J>¯Ö MR¥JKZq@+ôy®Š¼¶ …šoÊꇪ„ˆ x»……Àd„0Ñîlc¥õü*Ä“JG5ÐîØò ÆQµ»£ùg -VifþNÎXg@«S‹lÖ(ôŸGÖ'6ò.•ºî«^&SÚ’˜Ljä3lNµ*£5-NÉc)œªò•¡g}V§á®è °{M2J«6.ÖHoCBëQN$Ô*ž º„¡`7n Ca5úøG-ì¢z à+W ¡·¬U¹”ö‘ʳû Ùø"MN ““Õ§ÌÉrá…$L{_`£Ï…ÉÔ_6ÔAmxéB° m§Y û IvUl#W†‚É”¨C“Çâ‹ÈP8y<ô˜hªk[(²±ÙÔQFmF\vœÁ53nÀ2vŽu×ðÒ¬~º²z€2ž£°ê|æÈÖ+‹x-@M+Œ ‹û1I*ró¹ËÁÊMŸxÓŒ*C˜d毦-D  r$Ò‡þ8}YµIOl^Ù3aœ”¼Þ¤E¼@G dÿµ!™ôÏÌσJçsFÐ*8»d“Îüíd0–ÑC1Jލ5IaïB‘áqˆrkb\xŒºCýø¬ûˆ* mÛÃ-¶gBNj8Mmä0&źȼ=þZ3>nòßèû6¦ôly¬‹€á‘[üÔ¢Êæ¢æã»ñ^›ôð•Ï~êxyÙÅCš?D ¹ßô§è˜Ô”íy+ÇSmE<Õ¶R<Õv¾Ü>—»e¿Yϼ®Jçr|ÒV PÚVP’]¶©Œ"‘½¶•1×ªŽŠ–*È\YtRúuŽ*/!häôìeQH"ä1 1ý'­ÅºFú~*ÿžoæÑâÿü_‚á£Ñw¯Ówä÷Zn~£’{ôr˜Œ×z©”âݨJIF=ÁÀ¥„£†ÞJÁ¥ô¦ ¨R~›fŽm&=Þèe4«4XÈRM›UzÖgbn—=4+Xòc½œ‡öÅó…1Rö_½J¤éÕËóÃPƒ4`NL£ÂH«CHi\õ*)ͪ^¥$@5*ù1J/Gúʃ›€ˆmRM jkN”“®Jôb†•!h•t‰F¥’ÅP¯² ê R¶?£* ‡jà5‘e¶Ó+è1Ô,œcÈå¤nz”tͬBãí.Ë.fÔ(I¿ÌZžšË¨ Ç\£4KvÕð÷TP•Éeå –QÉ;`i–a «Îbkuš“È,”²•ü‚•Kéu0î@ƪó³ ñ% Zr²£ß”$z% 'ÕK³)w€^#dèuòÛ| îÊØ:ìU šN2àˆÂJ‡ ,¼lw8¨ãÄA8EšA Õø." ÁÂAð˜(K S ‡Ð&,œ¬†ƒm A¸çò½Ma#9üà XÜž@ÀFP„(‹P°ƒñè+P±¨ïÕ­€Ù·*¿{¶ƒYx1kW¦6 ÿ}é{%èׇzõVضX°" ð!Òmñ-`É{ °ÎdÉUQ‘­Uæ÷zµVu_þmD¤MvOpëè¯gnþÑè77?¿\xöûÁ?žå?´» “&ýFÀDoÜTÀÄe&ˆDòøÔßì3ÏÙÝG®Ó¨T—"›¯ uâ¤Rïé‰ëœ8#Ë÷-]¹À¼•®d*`IUÜ=¹Ö©Ð/iË¢¨Ü7Y…‹®<j|Ãý3/HÕ¾©aoAÀî*aQ¯È0\ÚEZŒæˆ”»°sLZ}~¿„‚‹@!¼á#­€Éð†A†‚‚Ô›—`(¬¸I?üɃ¼#ÝÏ 0Ùí# ‘Ý ¢Â%<’~x(—ûò/ïn„‹Û¶ÎÄÅçHý틺ëGâ/ïæÊÝVѾ°ì *´Å_ÞT¿˜8ïÆÒ½êHý]Ü•·¤I dá",û“£^¯Ð½³¶mOqï>’~v™_xŽ”ŸfCßaÓ8pÜ,l¡¼è–"ðþyD,z°‚̈©¨€s+>–Q¾×ìŠ ì;¿€ª‚ c!©}ûç«ì>[öå{Ÿ/`«•†¬”ïWŠn»—£_ÊcjDQ¬3½#ý`›_mëOX® @Òd}Vzð\É`*.»Ì´³õïbøå3ÖjMqÝ)ý@ZzÉ0øàÁÙìB_œRˆL޳*E ɱÈ![å±(Ñ] 5þ«&nbÁHLûË·¯ÔȘ‘QÄ£ÂMÓ0V6F‘KŠß@+pi¯¬,­À¥½N7Ò \ÚËqq#­À©½<72ŠœúPcìFf™K/oô‘¼ñ‰¨7Ò \Ú˱v#­À¥½R5Ò œÚË!V#½Äi-U–=ù)Ü´ò¡¦ Ô`1§•zKÃáÓ1é¤P‘‘ú›O!¯Ã¤Á¶’E(ÛbÃÏ‚q«bI,’ ½ vMã‚«õk[AÔ·"=a<ªÈ-I±0*M2—ÆJƒ¡€êòX% ï5Yä—Ç’íР] ‡ÅÒý‘epà§XÉS½d{gÑëUzž[gZQÎ¥±È~E âxôÅ#ÅßÃ)>¿ û kââr×"øGfS[Fg%èµ²~‚ïÙCEþŽ¡…90§pññ¼¢wÏiTè;{Ïa½øÔ]Ò3xÉJ å§cs¹­WCÈc—{Pb¿•sŒÑIBîÖ¬Ôߎä.Xù—cãÜ(ÿòà€ Á$Yç‰{ÇøÝ]aSÜåYØTÕ@z‰ß¼{EM-FÖj¬û2Bƒw^–g˽’hBL±"kÑbE]®öE6sÙšåµÊ|Zøa²¼”,Ó:ªaõ¼9BCÎ`V°‡@Duö'§JjU–œìY¢…®üéb…}¡¿r´âËßj”ÇHŸM"╎\Š;ÙÅ-m773ÐY g³K/Å.g—^ŠÏ.½¸¹]z*vÿºôRìv饨•ëÔ‹ƒCìÇ{¥ó€gx‘‹WÆv’ù ÙŠJ~¸\+S`Å(ÞAWÇ–[J/zQ¹¡>üE| =–ÂW»¸“WuyF¡&Ý»ä=$5ô RZzDÚð€” \žc>Ó0¾Rü©}Rýe~Ð+ý¡yl$´DÁ¢Ë÷Kò ÀÓŒå{Îß/ÝK¹ BàxÝ !/Ç«aÂBcÌ`Ó2½³8(ž™¡<ŽTƒÓÈÏ*½¢|ÁœO™³‚v—½-æfsÂxìí\Üölž${K¥°Ýí]ãgw{»¢Ã{Á$x:µÞJ¬ÛëG³hJï––DÁ3v”ï;ñÝzIÙ}giˆmºb\À޳4J¬ëÝe3Z:·íDK3ÜojidÛš–fø¾´4*Ú”¶IòÜ‘Iùí(%ü–³œ¨ôfQ²€X”ÜBåñÈiˆ@unB^Ë/ »šŠÞ-w}:¤4÷vür>üjx-ž‰0^[Öm+–µ?Ž’­€6×ÏT£Øé‹(¥nß#¨F¡úé”í !pfC(@š4!Vv76>…P@Þ0 ]E[JûÔCœèW! ˆÀ¿&€*öá ;üã±Áß±À1#ß½H…ñ‰ 7bÌ/kÔ@“ü¥?²”Ïw¤LþÒ‡EÊ·AS"¾áNIöá‘j”ß(A)0¿f söáÜùGRBaçßSqÀ-¾¼³£¯ û¨K *äï¿Ó |-&Ù‡eŠÑçß  „;ÿ\M1réÓ6¡°©mó{90ËŸÖ)Æ®|ˆ'ĉï†]@J˜ÁÀû‚%¶NíÉ´uDJy|²¨qµZþ¾Gr£Öå+KuÑ­~©½ÚÒéè ²?Íuo÷’·@nMË ”}±  ÿ–U¥ž"02O|«tß[,üa[-üA|€ îšœ«RïXDÁ¶rHì 1ÈŸ «Ž…:¿¬xØ·ÇJcÊ?Sa‘>bVdABº}*ÿžoæbåÿa”atûšÔà^OK¢Õ‰OƨÅâ_FéGöer©PNU¢Õ¯ªhEì¹TH¿Ã£UdßÍ6 YbZ£Fû&“^|IEY¯ô"ö‰ l’}®T©1¾Á¡Ìu²”Ï®+åüUZ,²#h¥ó…Î~ù›jMö†N-–>ƒ`TÀàüqœVn>}Sä´4jœÚE­Q3Ùkuâå¢Z w$e¦6*VÉÉoŒš­Ás9k2T“h¥4Q±YcTSèhujþ^µʵ«BÈÙp´åƒæZ8ÿy"µœe~ÕËæ^åIªZ%'EÕk°57ÁúÊ3}jjjN½rÅjjå,¦V˜§º3+ÄáĬ1øªžŽ´:¹æÙ¾àZå;êR=3Bõ29 ‘V'B1àb9Õ !RóÀµÒsrà+F°•L-Zº;,)PP@@–Ðl#ZÍ¢–IÉ=° ò²Æ¬3E´”ûB­ y+Œ õ¿ZÇßÝ©…‰Ñ‡üþX­Pž «UÊ+_£êJßüa­Q&^ê@QþüT-ÏFÁÒséóÙyí;p3O"Õúü!£^.ž*å X–½Óƒ‹áïà‹ÇD…Óƒ¡•ôñ–RK^)%ôÑ”R¢¿rR+Ùû$¥¬± cÅt´õE†i¼Ÿ0ê­ïThö2A)û$¾U‰×Z¡ÅbðõBñ5ë¼0 zWJiÀºR"G™«,>\)CÔ£‹ WˆØi£–…<«ÅÃÍH Úju4ZÝcmÒ¹Û¤(±6‰Òf/âTØ‚ÓÔI-éd嶌ڋR™6Q¦M®R ÂkÓª–ƒ-´ UËÁêT*Å0¼<‰r)­LŸ\ ó„†gÍ`¿^aÌS'Út±B…qhP'K*… õ©’‹!x}¢äb^›&©„V&)/„`Õ)Ê Až@°ÈühìÖʵ١>h†ä ©\¬Î”QƒµRg̬ÂÚ©3gVaíd>ëèȰ6 Þ&e4Ü&­ÀÚ|ŽâO‚ÛñJsŽÁIê´¹ç€å=aÞo„q¯ æ¬X^×Y¡¶ÛÕr¸…¶ãµ ¸¶ëµ ¸ºóÕr¤…¼û•b^‘J1Â+–æt5R+îæÓ¹«k3.*•ù…&E¸VQ%ÄÞ7ÉaåP‹äKto“RZ^}J)}}EZˆ¨Õ:†Û°r¨ÅÇôн1ÐbþCtû› NJ!h²~1yÚF–UíV÷(BQ…µCÐñ¨•º×Õb>ÝnóM|g¶ààºÁÚ$x›t¹ÃmxB[²˜ß«GÔ Ô!­K«” ¤•¨Ñ%þ dÙݘ–Ý hÙÝÀ¶BV®ÉùÄFÈ*4ƒØY…*ßåRZ–íR!«ÈõÐÚÈGÁÂ]g·V.µ0.,^Ç©(ÁE€¶>“I¼øxÝÅÊì`ný}rëOå(Y|:°²2õJ“Ãhs¤ a"H?©ÀÚLÒÜ.¤ Öb­/Ûu´€Û²:´eºÞEÔÒ^‚@{YÝt’`}\Ä_®b~Ów"C`½¼Š½È–õƒ®ûº±­›m¨âSªŒpS°Ö2F-̲gçÖi1¨N©åªRhÖ˫¬^ÅÉjñ ­ £…D$© GT›Ã²㲑dÑGÅ=«Cƒ z¬Ù€¤¾&ñæ§Ùéb•Äï—$Â9k¯W裠¡r*Ù´ SUJå£DôŸ_æ3$‚°oWËO <«0Û\¦&Àæl½^­õFy ÒŠÇ)‚íxÒòr½J­1°!«BÚ±§`;V…´#Q\ÛlǪ@^N¢Å&žý%Ÿ/Ós#ÀSíii³þÞ½:!]ê­”J¬íäç—G'Ïñæy=H-2NttçËû-4Uür¡iédzº“U€vÙ ¨“)“cï¦÷YÌ´zä¶A9õöÉ©7à¼Íj &˜x§?ÆŸæKÒï\<@%Ðöl9ÃZæUÎlÚ¼Æli¯Ô­Ó­ð&þvCBSHô¹Ñ^«‡{È0@ͳJ íOó”<꺡±=F{ÀÚ‡ºr‘z¤bàí³Z¤õ/ç©‹¶Îj±Ö,diŸ×#=¼¢QþxR=ÆAt •Z µêUJhªý hZ @ÿºžoLhZŠÊ/Dté’Az=§Š©À5êä±HÅÓéô6Z,¦Ó|LP­A«xg§Q*Š!:&FB£($ž¼Ÿ¢»ùBšR m{™®T¤%©BÚ‘cæÃs°«‚Û½ÆÛ½.h'þ~/‘æDa/] í-m-3”Vþtÿ};_Ç˲z³­‡×ptÑIÏ©ÕÕ(UëjÔÉôJÅÓóå\ZVz Ö*=ã߯òI¨ÄÚ¦bo.ŸnÍ:…·Sh€j±OL=¬;™¼=Ÿ}ÍàÕb ž ’ÖHvT&û•>o7³Õ—¥­•«´‰W]3r¡{ýÓ«é]½ÏàD39»V@ÒßÄùD‡¡%ÔéÛ+&ý-ALI0‰Lµ(`Raµ˜oächVbØŠký@EJ =³ŽQ, L_o%é"J ¨É†<;¾ž~»](ö£Y ·…šÒ a^dÀ]F[ECgeä/K–—ÐW±z&ÈÊ HêØÙÄëùÆH¯Za<”« v¬æmüQ§O©3ZΓÔ.žÏ´6¼ÂCnM ¤Ôœ-z‚@“^⯛+c¹åæ|l—]}Ð'„öG–@3@²rÈ1™UŠ ÍJ§¯£Íç8ý#ùiµž¤ne›Â†ô—‚\Ž6×ëù§Oñ:ž½é@H_Ô#”‚}ˆJ¤mª Àfi9Òâ*¾[É7'FÒîÕÏ?näêVôM3ÅÝÓR ú—åü+܂ԭXt(Ð(¯@Ú€ð,ËÓ¡Á²B65×Að´ÜhAÒéЇ©*ßÞkÍÔJ¨-»7AÚJ•¯MRó ±#¯ßNtL¼Ø€×¼5y™yG3 A;èíê6ZÈ7ÍZÔ†hÆM 55F«ó„3"Ö “jL¥ö(ÚP­éœÈ{]-†pAð >íèW¸ÿ_±þ!ø‰Ǩ‰¡O£ÅÂ<”uÀÊJØ¡Þ,¯0ÚÐó °$³r£?ãm¤`‘bZo.²¼ â4!|µÕ¥R^ai£ÞÞ•Ð\Áø^ãø^Ûð½¶ã£*Æ(W™ó¶M>Ï©>m¼¢‘ž—Ñ‚p[óâZ`l=QWÔ•ÍTz8å6ü¼Ž“Ï« JLˆªÂž@p6ái„æoBOh¾çÕÓ­^ƒI ÕÄÒ*íñçU²q‰ÒjbiE¨§šqLTÁ k©VB8ü¶‰@ÉU0N¬¥Z‰â$kÚ4ª´Z f¸½Qáùð 1¯@Ú@ö‰Tƒ[ꥆY‡Ú-pì j7¡' ô¦1…ºx%e´YdC‘:À€¢ÅüEz.\¤Ì—ŸÎßk”:p¯–,+%‡;aŽ\ž«•ãh·Ö«M:“Åyr–l¢‹yòÙ´&µjÌÂ?_ƽ­\…µ“ÏÀj9¸î¢59¦ Y­×¹­£´†#c7óRp'§åT®YTaí`‘.j0ŽSˆŸ^Í“[¤‘\e´ƒ&Ì^"¢ñU´‰€“)áÕø&¥Ø€g¾@¤•Z qÀÒX«…ö-ÒRªÆw›î¤Ì2Ç©T›k9¡à§“<“îOëÕ¼ñšÖ+1@%r’%ôêZÔwN¹<Ó.ò èÖ hÔ)7y±8H.#°ôaB€¥s!–>´ø-³ÒÒÖ¤p½¥‡óD1Õ¡ZKk(¦ Àz™Íæ¤x6AW`éÃ>›ˆdÔ@ðÙN‰Zµu6aÏ£a™ÍIÁl"1n„! ”hÂ@©ƒäÜ®60‹Ü%RQ á3š5 —²•)^Å›ÔF•dVÂm_ÛÚ¾.l«­+½ mì ¨mì ¨m¯¯H£miª#°moî& m í°])ØŒAr@®´Í&ÇdÛŒa2L@g ” r­mÆ&E3Ê? mm1«ìZIßФˆ\I°)X«Ð-WhYJ J¼-ÁZój¼=0AX¨Ðm\°o¯ @µx럣ĈFÑk-¸W+”}¤oùê[j“ÌoYœ­ÞYÉ—¶`5Þž>IK~üùÑ‹a]züì… .ýjBÏåÒ›aÃ÷”¸–¸R–vk2ºغ‹ÏÖëåʲ‡i½]ÐåiÊ`+ÞãıGβßâ›63ô *ì« Ëè¾D÷ üšÀäÒ—m`*”u&kF¦¸'ãÚÐ fÙ¯ˆëŒ¸÷ÐeŸAØzI%zA/BÓôÿuaÑõz¥©íÑæH½Ôƒ^é] Œn±pPÕVá…€•¢ƒkå2¯yêJ‚ë¡ø±ýzu¯ç¿)6%õÄn/ãxŠÅ”1÷$¹‡Ù†P–^¯·©Y1Óà¡ZÁ‘þ)ôËÅâ4åÜ¥Œº ÂFËå›sœŒ´ÒFØöµ½í$Ïýâ•^3œ¨„ìxÔŠ·Ûð6 ±ßUëÔTæf½½‡—r°ÚÞþ*ZÎlúB Š:á X?à9 à I»—ËÕ2wôœ®¶K¤+ëÙb7Y Ò!:¢'Bä(hj5Ë(ôAþG»Õk€VØÍ(X·Ç-àcz¾£^ú 9£IV£ÏUöi`uº²b`ÆÌ&FŽ…|óXE@J€¾@¹P-ùM“¥ÿ«5ô£ bý¤ÁÓ2ò•œk"/ O?›iùãâ72- šËWYR!ûviöš–ª /°?©¡Uy™yö5]‰Ê XbsÈl•Rú¥Ø¢Cðï`øwü) oä«¿œ¿2¡ÓBö5û†Uo.åRúÝ0+4`ß)/ó²"N}q“™pŸïV3”û3ÖW)2àR£hyãÅf¿ß–·z¿i‘÷þ^–œY‘§û²"N ÞQŠAxEš©Å¼vYž—™s FIæedld1j€ùvöõ­)(²r@àì/K–ò ˜EVí!’×ÐR (Hæ¸YVµ3Õ+4`Žfš±¡+'‰õ4”Z…É©å<=ÞÅ—‘œ´Ë¨‚Æ4“jtm.\º\“ÊdÒŸÌåþ‹ä – uØ”²… HJ ¨¿ý:_Ìn£õÌ„Ïë ZTñ–épºÎËtHê“HÏý›ÍZ—*ô6©™'·zØ–^cÒßþF¦ër”_•fÛ(=¢++Z)ÖáßE¿™Ð¼àÀ鯯ŒÁ§eúºÒ“¨Ê…r¯¼ˆ©#E«€Úœý}Igµr¨E*Z—ZŒPÅ?»Æë –Kˉµ%y'¯2A”¬ Áˆµ›ØÚ‘NÓµcK+0\`› Þ†ðk~‹0r~‹rl3ÁÛÐÀFúQ½´ö"`}üu5·S"`}k[û°>ˆŒ²ö! }¬6ó[;% ÚÏö.^Ïoí)0XOoŠFõ¦xT—$Í”­ ëãoÛ¹½ ]ýñׂµŸ }¬î ø*CÖµÞV+—ñ*[‘IR£Eð>&E}L€>xšeHr˜UÀˆá¦`­L¹"@èàÒÙÉé«ñö{û‰Ñž –sf0j¸)X+S- <ê༗³e•X[ƒ_@%ÖÖàP©s ’äzÀ%¨P'S*‰s27Ò'$:¬åÄÒr¢·¤ôŒ^ŒjÔ)ò&W6ü@~ZÕ'2@Ÿélšu2­’R#Ô¼_ÌT#®·ôp±öÀë±&=L (k ý­W<ƒšu ½² 7w*X·7v+XmŒ´4Ì*hÄ`S°V¡Z±7Øñl&éP¸Þ ¶l€:ˆr¸1\-ÓþF]ƒäg¬-tëgRÜÏÄ¥(%òѬ¶Ðak?)jo¬_ Ò‚o‹¬\È"Õ+€¹‡šu2¥’Y q¬ÆÚ\«-øUN•Üx[„ËÍ®W\†šu2¥’áq¬ÆÚ\«-øUN•Üx[„ËЩF¯¸ 5ê”s@~´1G TbmQ•ÆÙ8wéйhöÿ·÷íÏmÙšûküW`25¹²£8¶3É­R&Ù+K͵,iHÚžÔî "! 1ð¤dͬÿ÷íÓÝúñô"Ã[W5KýWŸ>Ý}ú`–¥ÆÚKÖ„þ6lE0Ë?óšø}74¨çæek©K}JNêÙŒNàD‰ú-'Ò#k'5Ñ#+¥ûyÀ+ `^ÿ²ÞþW¡e‘Z¥VŸ§ùИsÌ *ÎSûÛ[õ¹Á•3€<]N£º7v|§ ÷\r§Ü´MÉëc'ôGë³éQäuBâè_›ð9Ê"z³­õº[»q –³Y>_ÎQ)@÷îd‚5€xT» N$X$©ë¾bÞû:ƒ0<0"1ÎHø˜~JOâslm 2¼»óóâM2ÙS5CÀÈxDÙ5Æpæ±ù•ab}v/§î!<Äadr­;à[wÀµî€o]n„Ã8#oÝA¸uM­;hnÝA uÁÖð­;µî ¡u­»cE!3Ýt§Ü‘®KÕÅ&á4K‹ 2¼bôbY5Æp«æù–ÙØ‹D€ó¼Hp0ž“똄‘CÓä&Ïs®Ï|gd(có0&ósG ß÷…Ó)ŒrÌá_Îq!Ìç]±qÀõ>›æñÄcQÅ€þ8;DôªÒ¿Îsß$U è?&§úeÅa~žf§K–±;¹ Ë@ͤÉé»$[ÓÅ4ñD88+Á›Clˆå£«‘E€¹Â¡ÏIú<¡:&r¾…s‚ì<¯üâO¼Hj¢½AÿÀy.´™HVÐôæF|ò²† ÕBq{°¼½Ø¹Ñt¾Ï쀧Ÿ\bž<ï³iš}Âl8é}ט¯B×ëD¬ë%èNjΎêóUà¢2l5Äœ(ÛoôÜ W…°mÀ0š Ó g qí P¦!4ˆ[‚ã¬!¦-8FíA÷¡¸ƒÆü^žO´ÇWCL«pŒ8߈âiÂñZ(Ër•GÚ)'úÚ_~™ àÄW Ëk‚€—^ Èòš Ò›,Ž>ø ©Í€ºËP¿‰ @-K™¶äª÷&@Þa¨e×ôºpˆ ÐËR@-ï¼z]Ž}IíÊÝH*1TóÏ3€àz¶ âöön…嘃»yèØ_ü«YC˜Ï»+i”cºuÙºnUú0æ‡6⻜uþÂ5:ï.së±ËÞzìò·»¡[]öÖc7pë±ë*À‡¸U¬Y…ÖG c NB¼w:cJ§,»‹Er9CLòˆåk2áNr ï1ªÛƒ‹ …ŒÀž'¢ y5žúýÁB7}Ä]ãú©p« …-áw„](GýB7> ´ð€uõ7$£¢€RÔÀ`¿f€oµY" QÓ¸$ܼÿ6¹#Bà^ïüò"tƒ¼àû‚í‹Àp_Çû‚ð‹Ðˆ_èí»Îó6„øðö²s°Wu-áe/ëÚ(æn¸® HX9ì…]o’† QsiS±ÒB×v ÜÅ] ļ WwI9Þ•@ÒFN³,\àÕÅ=&ÇÔðoð< æÀyk$ÀÅ2q¶á˼&ä 0b>‰9Œ˜UÐÅ)âµ€|RóµÁ¹£bîðå^ŸK ^ïõXO¼ ÜËÕ8Þ[·@^38±6 ̇.”å _ÅTMÒðµQDÓ$‰½æÉµ•×N—ï6]µÅTMÒx¯5ß¶µ©‚^ku;¶צ ±Þò6¶¯;ÔÚÝ0.ªÝ¸ýãÀ!~þ*/¢Á’˜=$ òÜÑ´cTÒ°Ö<‚2ìi¾AgR†¤„9[˜Ñh¾¾e£MÜ v4Ü#+ÉÀU*âù¹ /‡O­B÷rm¼ÁކÛT%7Ëó÷sM´Á†ÆŸ»¢kbaÎ 3ö’®6ð6…Dðn™EÅlï"^—Gó·uM´¡29upôkùÚŒzíF<îÒ®‰…9æÅÆ»¸kbaΆپÑþâ®6q7x¢Å˜Ë_ÞµÑ&î´°„¹Äk@<_Ãèßx‡¸4“ÑÏÞä-Áý÷ˆK#ùÙ't“ׯüÐböá/óÚhwƒGZXÂŽÿ±¿iÜoóƒ—q=,ƒ¿Žk£ÜNaàB®GÀìT.Ѻx³„€C[Ýê­ ÁMW làm4$t§WQ5]þÆT Òðõo@‚äн#õ»/ Æ'sœ5ÆŸ¨q¼&ЏûIˆÛD™SÀwøÙÄxNº·â.qFBðÚ§`¤è÷Ú±2 <ÐæèvŽò^ØOý ³&ÆŽLø¼7p¦r8ÖÐ-˜z‡€¹ã`¡‹0.Ž%®Â80“‰/Ãøm¤„²úv÷a ÷¡ 1ŒøÛ\‰ÁT ÖVMÍ·bˆJýÆ\‹ñB2Ø‹1€Ë Zá»1owÚÜŽ)F³eq1²ß9ìAˆož\æW 7b›¨Ám~Y¦b2 Úêã5aUbÚC«O×VÔe¥óÙÁºÌ£¤×׿Åâ]\8ßâ1ÄEÇm¹LI ŸÑ=^úû¡XðxЀ<Þ†ÐwJËòÞÄJú¬bDOÞñɩԣsÝ'p¨u)hçK@­KQ[PùÀü²p<¢&B<®7qìÒ¥Hð—ñû¿Ëù¿ ýßeü¯µâ(/Ëù8q]æö_ëÓ»U ,B³ÐÔM»}½.ó(Å*"ÏÎÒs‡¸,öèZÕe>åÍxêQR™GIK:;ɱŠ=z‘oÄã ÀQÏ~ÂðÔ€Çsœ}¼ÈrYæQ¼O¸YÅ=•ª/x;5à×zBé©Ë KA\j]êQ«‰4q9ð1Žó ŸÓc‚®D==!z†ËX|`Ĭbä7¤¡,æè19ò3 Ö¥~}eÓ†@VÇŽ¾oU9ϱ—/3w°AÉ<ï ÌÛË.’yà÷ ðÈÅKpaÔzÐ[U9ŽAÈc ÀOVT¨]¼¹Ö<oÖ4KQí5ÈÊ(Ô S0³·´<Â㜄_¯8,TЍ­v…ˆÖÙ­´ŠYúãë 4›±œûñÂRMñÕ[hz0QÄM;ž2 ë ¾@ÄõÍfy¯/›:¿b´Y˜Ç)7 Ÿ h¸¤D<.ÑÁ³x,7?’k¬Òøýß}÷”YЍE b ÷]Uv9ÏáÞZA(âvOEìr†ƒSö=ƒ£û‹¼ »pgYz¼ò.¯ÿL§ANüT)„QÄæãxº¿·×;ñc®ÆŽÎ@ÖâáA+àèïeàÑPpýÓ¾Èì" âÝP–Ûs? l–B|‚Û”Ýù`ß46σÝ`^ÝmÈ«»y5 €=KÄÝÁœnçfc7[uaŽ0јXApÜ ÏT€IÁ9}—Ïé©ÏéÜÏ$l޲l~Îßr©D‡òsǵ åç>ŠÚ†ä¼MfÞ"-o•“÷Š@rmƒÜ¨²Èn ‹ä6eø™ÀvLp/†KVùL•ISÙµËæ¨Ý@ŽÚe×AÝÀ:ˆOkC9m8¡mÊfîJÈäëõ÷tyyjám‚³$î©ZMhŸ­Õåà„ 0ùc±³;é" Wí {jfI9¢Ÿ ä#l”Qà ?<1Ä8#Á?  ÃËï׈ØÈ¡ó÷ïY’ œcúhnV“€ ãy)Ƈ&( ŸÉø¸#ë¹€#,±Ö˜åc¬Gõo ãPñv„¢¥†~ùõ€€g$x¯Žõ1ž“õá èCtÖ a®Ÿ»'ƒ>Æsº'~å¹Ý<¡¶¾°žü`¨/Œç ØÀˆ€fÚdækŒÍYN1œ”kðW(ïgšÓS>º4ð—L XI´›Soà¼Çyõ%Èûœç-Áp|ªµï<“†% ZIêl)ˆ¯K(“¨a†Ÿn(øk8Š‚ 7eBáDˆ w…†²¹Ï‹€‹"MËù<ÉYD|<‰¿rL‚Àl®Õ E­zÅa\„„˜¼g†óe!ÒçÉ|6Oó? å[Ý'æ"À§ä#±¥THÉf‚bYÞÖ q0Zt.ªî›ã$ òmÖN&" ʤ¯\$æö®¦^¡HìÓ}ÍòšøÕÒ¯a¶?Š?v¯c<áUhÐz–½†¹(v_2ác!»ÃK*›$<2:_|c8[-i¶£Ç}N€§á|JwhkØ·6 Ÿ­÷Ì7yPhlêÇ×îž"KÂÇa)&#ãýl/’°‡&(©ó9/Úˆ³ Cžz—/¼GyÞW r,Š`¹D¡º©Û•Mµ3©øú5Êrh‚ulæ“…ê ÷ÐDÌ10”‡çïTÂyÌ>á ÏëŸvcœ—àŸüaœ—àŸÏb<´êuΡ ÈÓx8µ¾ÉéLQlÛ¡[6l;憧Ml;æÜÖ¦¶Ý ±íн@óm0Ís1›,Ø®d¼^Îù(®)øš„-4[2h´dÐÂýÈ•X”0ÙIÀ[–1h%C.]hË?™3+—¨aå”å5Øuò¶4Ià ÖpºÀI(BCÜÞ©(CÀÏËa#¸›ò€$dJàÖ¼A…Ÿb`v™G\›(œÒm‘×±ñ ,05–eòæ*½ÆÎ~Y„!ÿîxœÌÜ r÷“³e‘pÜ ¹õQfÍå¸éÞ—ðës—(Çí.Û|Œã¤Ç½‰ùŒ B!w/»¢gk| {­‘ˆÐ>‰®ËAD&2­¬K¡føUäx¯`ä()*‚BLì3ä/ÖWŒŸ|ëFôÂzŸa:O&e ¹Ï‰5’¹°?úà„}Ñǧ·n°ËyûÝd>†9eB™ž¥Ö³ëÜoâb/ž‘óÎn̈͘¶waD‡“é̾Rä(Sùä)ä#ÿ„ÄE—w;Ý.ø0€¼ižéä–³µ¦À-G#黸³÷š L€£æ…`?²F`Ê Ëq>Ü4´«å44LALÎÊðuø¼+~Ädºîù²a¾ƒåÔÙSõ1wµãê2 ÁzÇ%wÊÝ *ƒ‹ .|¶iCˆ=ÏôЀVÔ‰X$‡þã|Ð܃Ÿ7d8ã_¦ËrHŠÊC¬\Ãx>މçøûÒ=ypA\×]Çt0ÄiYÍ,…6Æ¢eÅä ÔcÝò³UâÃ)Ba¬á¤ ¿ý8¦ ž®z"Y´Ò¡³uêÃ>Iì:ÈðÒKæ¹óÒh†€‘ž}C(n/ÿò>Æsb³k,Pkl­D\|=+”áö·kàeù8ka$vƒ‘èMÏ>†8Á¦ˆ1|Þ¶ˆ1œh+ Â?ÞLâ()x;‰!`d -3­Fi—Š{åêx¬T£³Ü;¶×7 ÖL_üÒDH½36ôؑڱnyzz2ÏLvãR¸¹ÞaZˆfußøX–‚lÏcpÓβL˜1ÖÖÙåƒÛùÀÚÇ 'ŠHBÞƒ|>vyõú£F®“ø<ñ¾#‡q(á„K8H§Èņ},ßœC½9I¶x#šÏŒFòö²Ì ¹ÅTÊòVc3=*,Fg²`xÛEnz rT™Îô‡I:·®˜{¯Y‚'Ö™C€eГèâ?±¹C(Ï-&tŽU@\dLÖÇe¿AÝE8.ÿ– BynÙÑöòüSÊ(·H¸Þ1a%Ô ¥ûù¸Ÿç(BjãÍy2é¡QÈ@ùv2_¤à"«WTÖ ÛÆl]»áºz;è.Â×±@ÑÖè6&ú…{GŽ!àd„GŸnóè£j¦Ê|ï9:„™öe&ýðÛÿâëk‰BnúNÃZBAkÙ¨`GÄýO—Iˆ]¸Ùë0¹œMÅH6ŒÏßÄÙdê®|ds!<‰Y©?˜ûƒ!ªVÒDA i¢ •´ÞY a½³–õÓª¦‚ŽkC÷Û9 ´žËÎà¨>r?$ á?=ìQŒãYb¯ ƒd­ä óÒ†yÀ;‡y>“cãgÿª" áÚ‰áPÍ ˜&S1¨Ø ¢0] ‰öág€¨…¬~~ÝË&ÉçFy%a“L±Øl'Ó l’¹Ÿ´”i¶¨;-xÄä”Zkù6ÄM²[5yËöî¶iïn»öîÞ¦ÎÝÛÕ¹Û6–ºícI‘:ïl l'³h#Ž£®ÛÅ¿‚´¹y] ‰{ËyЬ]mÛT¶…$fDTQšš¹ñÂÈ^ùî?Áap(¡+Ï‘5ˆ‡Êè'E>½JÓE2§@†Meô²ļ,æìSw‚:JANõØŽ½1@È«ÇEÀ¨ŽË^Aº䢯$1l%ùôûzVÅ5 0× ôÝ#†·!¯¼†H(ŠÁdjœf wŠPž›ãƒê7HµK„çñ…úi…á¾Q çh Òä³-S€I#\¯b=4ÒYã v5ÀéÂ<üøLS+@.z¿ÙrŽÒÜ §¿Q’Gä ù'ƒÆœ.™(ä.d}‘xëñ+·· 0bVˆš6ZZ(3®å“ÓARÞùW]lL>dZ[—ª'–j3]$ÀuÂrð\öNŸñœô^,÷©Ž‚‘‚v8!Ìò;ït÷1†S½N£¡ .#Ë{ã¦1œê]*êa êí”áQ1ÒDW6 s‰YbÐuŽÈó–ãqR` jõµå©u¢á”3}Íaò!×RUêo øÏ9LS–U‚ /}ÇÞÞM ëûDq()ÞÙÇxN¾ÞÝp½Án0BùøqÖ‡p4 €ÞΘò ]SGwÓ ˆ¢ºäîz]ÈhB× |޲³ûâôÙóÀ#v#~™ û „Y~zˆ,Û‹*†z,Í&C¡øK#ˆ‹n;8S<À8N÷…qœŸÒÌ^áݽŠÓ)Ñ»†ºýaÃ^æð—£@RÐѯ1-ìÿ˜†©ÉÞ  opÀZT(âþ ßpá‘€LÚËŸqÖŒre'CÖ5¦Z.q—Ç^=•%.½%9IMÁö@6 ò´ÅéBŒn{étrhŽ˜u¹™Ob{Ë'‹¹ §;Kû©ëþ²Ô¥>Î^[Gúu™K©v¡Ô÷ ì¡°õŽ’k÷ã >9Y6Ì?óà.O?¹ˆ‹ Äd".×ëxüi9SØq6vBÌE]nÚ¿ÂóírÀá.:u ÜË/g"¶õž» ²Þ ü2ñ¸U±K/å¥f'mÌ듉UÚü–»Ä<-Ôo >™çŸ­—±3ÀVƒàƳ×Í<¯z17ÏãÉ8vk[#Ÿú¯°rŽË{i= ±:V¯(¤…â^}z‹ò±Âïxõó:A€Æó“÷·YêR«{‹b8 YNw²1ÀéçK€xàÇÛx«›Éög¼ ¸w³<릗éÂã50d³z çbž/î¬íÁ€_?•R/œ O†Oä¼I' Ÿm ÕÿîG#…&zçí‚D> /³ ÌG¾ÉÇùrV £3™/üTËÆØ>!gt¶¶œí˜~Õ ö«.Er&V•sK—#÷ã4v9àÀ}—Yç”Ûw»á¾«öéý,­.oò˲”àÿ@]δ6L(÷(ÜOz:n!È¢ËÇIr)rùx²1œo“–ÓÀçþ¹EÅr;8õ~—³ ¼–J.¹µ”B€6&§38Kóy–þòá"ŸµB\.zTôùÂ] ØÏE7;ãuƒ3^74ÒwÃ#}·y¶ƒ$¨ÿs³]78Ûug;DF;fÆê†f¬nhÆê†g,ê_i!_v”ˆûáì× Î~åF©š©Ø›K·6š'bžìeÅ"öV´6´{Úü™b1Ïo°xtyiÿÔϵËRDâ±.w9Ê7ÿû<&Âïyq[^`m– X =Í™'N9ª·ÿ´«‹›0“€šc@ë ëÝ[F!°É§Õ…pEïSWÅ0Gp©»¬¡5‰£Ñ!ÀïÁ@¹Íÿ¾L–¾~æg1€>îíþÉ—Âh" ÁǽXQ£(/øûzË" Áƒý]ùjV€{}‹N¼ü—ù{7²dg<§ú»É$Z˜ÛƒýñàórÆØlBÞ¾|2}A©“ÓÏ! ßòbÚB|Ü“°¼œ¡ÙºÜ=Õp>ze”³ ‡Ø.6mQ%þi·]Ž9ì÷FØå ‡õô›]8œwa˜¥X¾»!ì"P‡UÒãsï]Ø>ÆprÞ膼Ñå¼Ñå½Ñå¼Ñå½Ñå¼Ñõ¼Qv3wŽfß„âÛÅŽ5¢D­ZœÐ6ʇ¾œ‰˜jˆå“ŸÃ 0W8@ÛgN§÷!ÌÇ11ö¶–Qh{Eçr¶¸ñÈu9àk-^–"[”•ΓeäkŽy»˜WÆ×I2Ÿ:ë{§ÜÔV—ªMàùÔºda†ß½háA ßÇä´¼€éܦ 5Ër®{ˆxÊwI¶t®oò4¬gÑÉÜ¿ôÇÓ„$5Š Ë(ïKÕ„àrU;zÞsúŠjÁy­ÄÙzJWЭ¦šÎK)zXDEÀÊèqßt Q…¤I±$-äX«ž¦¤”p?0N”p˜ÏÒq@€Äƒãx 7[^3¸d|iˆÎæÈ¤.ˆÌŽOþêFvM´!(£&ÚÁ÷-à¹5Ôì[5AЂ Œš€•êá~¡cèýðå•.Ýó›eÒé”ë*_7:åÛ].òÀdѰ’:—§Éd’LWþ>!+³>OgdÕÕmP†ÅX4Ïg“aî~d%ic}AãÁu‹{ÎÀðùóR´j:˱‰‚9|XAÌèÌ©)‚ù}XÊÛR(ÔÃR Š`ö–bP´ÌuÃò mËŒ·ÁRDÛ”a†EÚDíòÍf‰.i£Üv"ÛHS“i³<‹.œ%Ÿ"È¡j‘©6˳èóÖfymúJ™¦6KkÓgªT±…ó ²Æ ·Y\›‘®e4·Žä2mîÁm"¹LN›Gš6ÒêDµÙºvý¢N[›-l'‘t7÷4‡*h_³4‡ªEÜl]»~[§¼Í¶“Ø¢§µêefú(›ó­6"k2pö]Ó{çß5dðí€Ã,D§¢öÅ<»Ø­£,õ—"9µ«e"˜‹;HuQƶ™bê”WÕ}§ù‚.óWÙr·^ª”­˜35s”ú£—94sQ†›?ÀŒ ïS¢>¶}5DÅHó¿{À¯¿÷ê€|Ë{/`0ŒN§Ý]Àày_%½“«Ÿ*Ú²À¡1ïê¿ úh¤ù®=£Ì ”–¿ÛýÇÞñÑQEk•ÔõK ÞÅ¿G¥N9æH3ÌAåCºÎçÅ<IJÜéû΅غȠSeoUäâ÷sGUêÛr§s×*³­¡’ÑY:/ÖÛ=„å:g¹Î!W‘ˆñ`•ÕχÔÕô™å»ØñÚÏgªJ¡yª.òèë”QæQŽ­»OF™G9[w.ê"ŸÎx+NUâQ™î¬JüúzTòõäi׃ҫõ{Öìï(˜€i…Qì8ßE8.§)<ˆãsƃ8>»™\„å2Í8« €õ!ǃÛ5À̱_…ÉîdòÊäìb“^Í[àå‰bq‰&È–³Á¼ˆd•õ‹í_ž|ùùÉ÷Ï¢ïòçIô,¢/øDi–.ÒxšþS^·Ù‘åiÍæùé4¹ŒÄ¯‹|y~ÞD‹‹$š«r—b þŽQ–G“›,¾LÇÄ{™\æóâ¢låy´;-òí¨H³q×éùh!”ŽÒì,ŠÅ|9^,çI!~ÍçI4ËÓl!æ(¡DIrºÁã‘ÇÙ$€:ÂNãñ'·Èy¶£ë$Ê’DˆÍ/“hšçŸ–³hœO’HÔÐvÑså"á¹IK÷HttNOý‰N§Ò[†Y’,ž+=Â5¥˜ù2£ y&TN§"ß#ꤕ C~!ë&:K01äUüƒ½®|É•4Q?¨-3™6F‹øSRŠÓVÌã›"Éi”ŸU®¾”œÛÒ»“ܨ„rǶ´AL×BŒª[ÍôœœZ$):ºN’fœÏé[qÑD¤ŸR°ð‰d˜ Ý”ÒÃm¹ .’9Õ·¬réçI ¤ÈÓqQ¤ç™t½µP:R„Aœ•ž¨,~}L¢ß—Å‚*;ÖÍeÌë6Ê-òÕÆ}½2Z¨Þ3I¯ÒÉ’DË9 ô¢IÇPz&„PõE,Â1ÍOÅÀ0¹D±%[PRW݆œC²ZWJh+‚O4šô_í†WÍLò«N¥I e$0<Ò="‚T¡¯:Ó¶hØ1=„©‚ƒ¼ Z[YtÏS:a4ªªŒ,žGƒ\z¨|ºL§Õ9œæÚ&Y¢uÏDÈI‚Ê¢$¿ù8•ÑPõ>ª’ .+ªÓ…´k2©:¢” ì½½Š òß”ÌYúøS5D ºIN©+ËþºÔ*Z½Vë¹¾'~ÝÿËž­ºN~v¶môŸÒ¼ï~•¢Å<#c»Hê0©”c÷¦² «P›'R„Kt–Ó\ôòiÔ;s5P-ʾª{áîÑ~]Ãk%[¹PÊ?$D g¹RUˆÉqaIÙRKÏåèùt;¾é ©¥¨y2›Æãĵ­t¬ÕÀU©ŒbÃüR˜¡_ú&z%ëýúxøF (dÏ”­mÕË­Š$=š”V–=•låh&+SŰ俼zZYIô³yr•æËÒ/bì!‹ä°,ÆqšÕÓ…ªÂOE¸dÔe¶)œö#¯mÛj޽–”î*•;!Zõ„ª÷E[e÷¶›ä©Ñ&Óiíq3¶6q‹ž}ÿäÉŸÓ³IrFãÙtYÐÿŸ$Ÿ…YôõÞ×Ñ¿^<ù‰¬qüÝ%¥1‚ëω˜¬ÎÊ4ÍŸ…œ4SYDÿýѰ÷®3Úï¼~ß­èžPt•§“'0ãØ"(z6–Ä4¡<vÏ ‚‘h¾ŸŸDf üüLÿq!Zj;zFߣ!:áP9ÑïâT z¨Àè÷²Òùx9çª}ª©U¬(WD" ¶éO%ÄH"<Qñ–™·dÂm¿üòBÙ*UÕõr“%!òòžjžøÅŸ¨~ö8¬™å+ò²QP~c”)"âÀKúëK”LEtþË^H râp~£ç‘BÄÙMÕEÆr•2ѽ®Põ4šFˆ’M^½åkËh埵Wÿd0î”k ™$ÓÔE¼v¦Ôô+‡DÑúb ¾¤-Ø‹\¶`Ù%³ V]pISÀÔmË…O=¯ u®HŠ*mh,Ge’|ºT1—.JY 1ˆþÏÒ ç_ ¯¨FS§R§Ü&‰~± «piÒñr^ÕºCõÔ*r’L™þMŽ|2W»¤ÁRNÔÏKsÔ¼"’žìgý÷—Ò²þóݯk þ]_¤B©´ðO¿˜ñðTQ”NËIùuZÈéã’k^sÃîÌH-P/Òn¨0-ñŠAg¨£ü# ñ—Ëé"M­ÆTKZ•Љ¬4mœ/§•1[Fµä“Ipé¿8#âYBß²2%«h Iç&YhavdÇ÷óR^Oc”ȤG‰¹Žiq ëÄÒ0[V²œ­Ÿ?%WÉüFµtq!«pš”B©¿ˆá®¬N5ì©AAŒ O0P>;Ù*]Äák.ò¼žœEÔÔãÏ‘˜¾E%϶¾†óÃŽœ ¢¿Lþm`›¢©\„”žo"9$l¥rüŠÒèoíÏѷߦe/q€Ïd ‡>7€zÂF¿ê¨T°±ŠRû_&Ñ_ YËt›,þwúE0‹lÖ¬yݧÔ7W}>“=¬ Y;Û­0±E²;J=²h/ÉZ¼‹³ói2¡Í ¿/EXéqÓfží*V2džÊ—JhhQ|MïâŠêAZÄ_24Z‹–8£OÛëöPA¿#—û¾óªã&5µM¬œÍ›¥üÜT¹–Õ£Ù<¯œ¨+5Ôö‹Þ™¯ ˆ€ýfkÖ¹R‘ÌÕ:¡#–¹ÿ/lêSIÔ³Œ™R!²Ÿgÿ¶¨–4¯P¥Çýio ̆õl'úºîH´U•ÑqT[Ú.šÂ=±´ó>]YÔ_d¥Ðü´] ™õ\¡À2DÿËÒ¦B,cOÕÒ%lyó<ó)EùÔîý¬Õe¬êåã/Q5G8aT8=Gª|ìYN]eo'ý¸sP®»Œ¬Å€”¹UY®:u›ÆU—ò¸òV«6.eÿI ÷½ãƒÒAqß±ÏØhÛ'ëð4Ül¾ºü»_i BÔ¨ÎÌÑÉgMï×Û”æÈ)I¨ìÛoÍñTÄX°Tû˜åBLÕ¨Ð;} ½+¦Üš±Ê¬G Ñ“´•ejÌÈvk“Ñ=?ø a'Ú£šÊè–?¢AäÔ«4Ž–ü¿;y›“žµ™L%=#ÁYªA§4݉@¬úq çün†H©En ó…¹k»£3êߟ–m}÷6Ó]æË“'å½:E¢Ý-:œÅçñBo‚¹9mµS=ù“gr!K®4z»R,–Ô‘=¡b/…!“ίâ©DÏŠ+=R¨ž'‹Qqµ…Y·£aÿ}'úыϯÄ»F»ûûïÞ{:ü«Ábµç0½úø”œ,æ[ÅÕ¶ÞÌúr[˜y·_”ë{;.®èNz%¥ô><^XûÊÁr¿ytŸ§c¢cœ‚Ê…lT,<ôôç¶… ÚOã‚\ÁUÅÚ7…ÅÚª)Ûb|¸ÍÖ Í@݉†;À­‘ô«/dzE¯½SáåO?;"w¡™:É—§´2õOZ û½£®-y¦%Kau R@þ¬…ü“cáN‡ XVª`àï™txÃŒÎ×½£Ýþo¾Êxü)™ŸþÞ ˜k¡IÈ 1|ÆËébÇGTŸ\õ;»ûÇG‡¿òLØTe‚OðJeÃßN:£Ù¨XLF£«d¼ÈçÃÑ^¯¿§ŸÈègr-F7Övv>Ôp¡2ü[ §g[ X21†ÜA¦¾w dêëÆ­E^ƳZ+W>FrÙ%±+èVBì:—/—‡¾¬?ÒZð„žÖo¬ô„jàíƒ ˜ýáÞØÎã¬˜Ê ÀžH¸]a.~k¡!í„ÆÙù2>OãœÒTGœ…ÞÚºýü2Néa7ùt"ÖX‡´*ùYŒdò‡OÒN´úÎb< É4í„ïåóÄ`z—~N}鈨ø÷‹tZxòd©ðý³ÿ úï—ÅüûBLuÉ÷4ÆÿÃóÏ_¾ú^äÓåi˜£Mñ¼¸>ßþéÇí¿ˆ‰²š þãÙ÷õ±J>ê¤C§ ÊÖ™üú•X0t>é´Qç£ÁÅr1ɯi›¡)‘3t¡fh•ÌóË­+ô„ÛéŽövG´æ½ÜRËY•hËõǯ[µòCûÓrÃ3“ZJŠIé4Që?Ž ûI±P¯öYƒµò;:°)ˆ+]^ WHËñˆo葯[iÙ[éËÚï´Ân#Œ‘³æÞ9Iü‡ÝÃÞþhp¼÷vEAõÝËG  =(§^Iá¹ÛÀÖíszzpw2™ú»£Ý£ßVÕ—+Å;;Z󦄶ëzGáš|Gª+ˆKM~—H»q‡>L&ˆaj`-±9–©°ûà]ž¥"Ï>Ø÷kUA-E 'Ð+L=5´æ.^Ð''Žß_¿?Ú_Uˆ’ÒRë¦umé²ÃÞ`Ø9êôWë²RëFº¬w´† ÓJ7Òadé¨s|°Z•Z7ØeýwËRë»l·»Û;Z‡×¤âÍu½¿¢ß9x?è¬x`sµo® é¾À¾HÖà¿RõF:oÐ9¯j%¬½¦tn¬»¨½Wi†âuÜ:æ‡ZïæºmÕ™ˆVº‘Vë,¡p#5¾úaÅqE*7ÖY«÷Õ¦ºjõaµ™Q%†Ž—+¬îz±~W­ÁW›ë¬WRåF:«³2:Êåë6Wè¯RëÆºL ºW+ޱJíF;mÅ“c¥vc&†–«ý•ÚÍvÚh]nmºãÖ0²iÅë8õªçÕlé°½Áp4îöW¼‰X©ÝX§í­x{G+ÝX‡½îíxsû”­ðØZ÷Î)ßÙÑÚ7-Ø-îŽÇù2[Ù;±jíîAya]$å›í¿ëøf]Þª7Úw{ñ,>M§éb]¬ Øl?÷NÖåA¡z£}×™Ïóùšœ'uo´÷zÙÕ OÜ÷)åí¿ÿ•§ëš{IõFûîm:þ´&ß‘êöÝ»|²®^Kª7ÚwGë‹»£M»£\Tq]‘§”o¶ÿ–—É<¯ËJûF{ðd…ŸÐrÜwr÷hýA|GŸB\“ï„êÍö]¾>ßå/ÓuõYR½Ñ¾&Ÿ×å;R½Ù¾Ëgk›k¥îöÞÇx:ÍgÅšü§µoª{Ùxºœ$»ÓéÊýW«ÞTçu>ËœÈò•ûÏÒ¾á.Æç«ïÀ†îG:ZÖª¼óa]Þö[³sáJN”…¶¨NÃ8ÚòÓýNœµFû…œ0k'Œ6ØF¨±vÂhW„f`-…ÉMVœ‰¶¨ͬD n'òm Âoo[aZ•r ¬0J—9aÖ²ƒ‰ü‘í^5ÖRåS¬4lÀËi‚¿m`-mK/Á“5²´€ƒ,B—¯ûÎK>¡ÏÍŽºÓü4ž*ï¬lRQºwvLå7)k¾/’ùšÜW«ÞTç%‹ë|þiMþ³´?VV£”¡ñ¨ýçž1}H9Î&HކÖ? /Ò[:‡½£÷+{?—R+¡õn`O ·½Ù=\Ù{0J—‘Î v×»ãý•½ÑÆtéÝ`·í÷WÞ9K½ê¶÷G‡Ç«{Kcé4¥õñ¦¥%¸É­'â[dÛ#£h¿L„ëÃ5Ïf{q6úßç\œä¶jwI(žtîìH¥›ÖQ¤»ÞÄÓ³ãÙªý¥´n¤ÃVï¬ uÔîäòWòîè+©t#Ýu|M/ \uh‘Òt×»ÑÉ<½ŠïqeöŽ.«o¨ÛÉxžÜý ûÎ^Sz7Ôi´“>m~÷ËÝÙo•ê uº[~œMïþhÊ}WëÞPçåz/ýîg‡wv^­{Cw<»ßµ“;{N+ÞP·¦—÷¸$vg§Iµê²·É7¡tCݵú%éÜPg­e?C«ÝP—½ŽW¾î”J7Ô]Ïãd¶†_é}¤½RRâ_Õ…kÞ£¤ãßÑ›ÝÁ›ÑÑñÑÊöôI+íèkµ›¨µÓÞíÿ¸Ÿ ­›ë²Á›ÝW?þ´¯)Å›ë¸ýÎÁîûÕðžÓših$EÞÐH…­ß¬ï` —k¨å=Íåââu\€+šhy;S?âWÐmD1bÖínéܰ¡IÚ~˜Ç“{<¯po)›ê«U~¾ÀVúH£6)Á/³©ö#ó•èj%J ³iæäª´•€b1fq:ЉE²UÿzƉò“8mWG)÷*/r!9¤ÄWóáJdœOF³©2¶u‘š.÷DßœŠèÝ$•þcÐï ß÷¶^ ¢/OžüÿþYÍMgËLž+ÏdzÙ#èxñâÅOýk$þ}ùï?¾0ÿ¥ŸõÓ?D/øñ¯¯^þøò§—?E/^þôêÅ‹ÿ½x[¼Ÿ¥èæÂ”"¿LNóÉ Gׄ«ÊDÕ¿òóý³'ѳh/ŸÝÌÓó‹E´µ÷4Îÿëw¯D+D2….’$Z\$ÑÑñ°·×‰Îİåóh’,âtZ<HÆa:N²"™D"óHæ’cwÅ?ÙŽ>$s:²ˆ^=mÁ×’Cóè&_F—ñM”å‹hYÖ´PúyéZÌCÑ8¿œMÓ8'Ñuº¸z´²$úMËÈO…uY †™øëÌ$Œâ…6š~.‹ÙÎ÷ß___?¥ÁÏóùù÷SEZ|(*}4è|'ŒÖLï³iRÑ<ùÏe*Âèô&Šg¨q|*LÆ×‘ðN|>O¶ÈÉèëyºSH‘Ÿ-®ÅèIb&i!†çÓåÂòYi¢¨¹I ¼gÑ×»ƒ¨7ø:z½;è ¶IÈÇÞðÍñûaôq·ßß=ö:ƒè¸‰Ö~oØ;>D»G¿Eo{GûÛQ"<&ô$ŸE!j ÌLÉ›ÉDºn º4™þ.fÉ8=KÇ¢jÙùR åÑy.VA™¨Q$ÆËTDÂÀ ‰™Ò#Q±Püz‘¢ïŸ<ùþÙÃýÎa)âßs:§gO£x¹È/)‰§ÓRdñ8Ÿ$‚âùl‰(ªG?ÑPRØ~žýÛ‚îýg¢ªéB„S¶$Ï£Ûý°‡û^Ëâˤ!šˆTñ«…>rþÛx‹¶þúä+.ËñB$dÃüd1'¢¯t ]Ž šâEÞ’Ùg¤ ¾‰$þT2}¥©Å4]q}ÿ>‹ò¹6Ÿo=Ý|x&òJÍ! RËé‚h¿¢|Qü)øer±—g"^¤”òO•"<{úâØ®3¿/“ùÍ–Öþ|,Ò ¡èévôâ©{ÉÌdÔ+ŽßnÍéO¥ý«y²XÎ3Ó²·,ΖөÈVt5¾üüäÉWÕ«o:â—~¢œ¦·j¦E˜é°ËûëÖàêýÊ|ÉÌ/"ùóD¤éY †»ýᨷ°u Âì©.ø9úÇÉûÁ›b«›,(=>ý]Tóçˆ GƒaëÏ’ºC‰ù»ãý-™x -ÇcÑŸ*`Kgµù\~ÑnJ‹_âƒj$=vE‹ƒ­N¿?ø@‹ö;¯ßw·ä"ºÈóOb }…FÓèëè[a¤ ‰’ãçHªýYäôÉ”F&)³÷aK¦rR¢6¨"ùWÍrÒ9Úòä4ϧ‘±2ßÙ9Î^çùbK:Y¢ªíþ%Zç+ÃmŠŒüZ9A6 ÑŠðÚsÅý¼mÂ¥™/eËÐÿ@ù‚L9k_íÅa~žfFº Íæú*ØpùF‘Û®^ArõŠÛ^ŽI–í¢+Ùï’l9Lbá(M/)±õK³ñžÛö2îoí÷ãLˆ=™'䙤XTÇšßDÕ±£;ØÒŠèH çÍño‰–u¤QâDŒ¥šgÛÑ7ú× §Q¤VÒ¢ûØ5¨ì6d<@€J5wðÒvTݰú&Š_Z¹íþ>«¸JíÄ&õ·ó(ïÎmU‡pê‡xšN„mµ¾½Aÿ`ï"zÈH ¨y¬¨ ÕìA"ÔÜžxf{u$‹Rƒ‘MŒdr±õ+ÓÇ\™•ýÍÔòëÖ×–Ò¯Ÿ6Uˆ2+·ËÉn}ªV/©0ר=ÈO&?ååÅ‚×T!U†„°®^o?-ÆêNl2 Š€VOV£ê½°Þ½vJ÷F/1eµÓTU>Â=›éßÔ¼é áFIKšÝ+ÉÛQ%»Å¨gÛWszÁ^%Û·hCGžÉL“sWYÍvë㊖FXµmÝœýäœúrżeŽËE±mŒÓêõ•õß½‰|ä¯. ÛçÕ@~›0 p‡ê¢°Kä(­i‡]TYÒ.^,èzëê–µ4D6ÒWR†Ð½Ò‰µ‘4"5ÙÐ_5T*·ÑC)nC³¿žçñ„“Fƒë÷Ý®ù*Av ”²Ú¬›*Sj®6>ÖÄÈÍí{2½Úà¤ÚBzUîIP+=‹fÇ3Fé7‘îÄùMDÿÍ’év´ÌŠô<ËXùº†%½~l;’ÙÌéîd’LÊ?Žò=¹¯ãŽ)ÖР-Ú.MÂà7$­$DÛIà¥\û/·¤uAº¥ µJ*kùaÈõ`å4í§ÊAÚ%¥7jÑÁÉîxvFir¹þÈnnçCª$ç·¶ŽÚOòÇt•ÿ‡p–ªè}Ý%_ÔóˆþRòÿÓU½€]=²ÏJ ¯UÕ½¯ßhÜãœæzÈœ<Üuòîüü–3ŠÔÜÞ™!U“E=ÅÓãÒ÷ž=”sj8³…®ô-çŒ~|}+§;Ž&Þú¿ð}\꺟›Ä‰”{ŽöÖò{ ¶¾˪h­B¤‘Ò½ºÛ%…‚ß®‚Ñ"$Åš¸M H”íó¿¦ZñbYè/Ìõ×%·s%Ìv†YØàÛ¤š³s4ñýòãú“;ÞqéwعM½÷ 6«®ÁÁU}Ï3Ï\͸æ)–V+–=¤ËZ¨£¯ÞÊ4b¸ƒaROK³è;x[`ºfÌ,uëojøúõ›èŠ~#¢übu‹IÚ­öoÙJvv¤êQºP‡¾Q*¢Yé}~š¨c+Qö§ª0Éh/+úöÛTžzƒî³”T}a])}£—þUýuMÃ^%¦6^=J®M ­WÛ¦>j“DéøÃxUúF{µª+¯¾õ¼ê䛕_‰2™´œá¹ø–÷²3“K?×:o3Ã7ögY鲞vÅê™ÝëêMÓ}#UnÙZιݬ¦e4×¶a^«l)Yrw–„£ž*îUî>« ¦5¥9Vó5cÄs8>ß9ªIà½*v‹Ø•Æß?XÕ+èÛŒ§¤å–;ÎRvëÁT*h³‘¬LÖ½VqÝ5¬›ÜCÒÕÓ*"Cœ/œnM¡"¯R‹?å¿·ó/œ‘Ú$¦ô¶pªŠªƒñø>ìd“Çò ½ÿ•ÕX±÷N¦ñ -Ä‚þ3ωn¿žô•ÝË£·^–¢Ê^ÞŽîµfýë=š>ªã5ÃzÞ—ÿþEµxÏþpÛÓ ©Ô¸sgGa†ÎCLá‰^?ïRý³:k’FŦ´öÓ-½Æö¾›>ZÆÝ" 4`m›?d-¢ûÉlzcøaÏÏ«Ýé˜Ôo»Hih•gqž« ¯ì½ÝYªâÂ'Öðœ5Ô³Úºúñ¼ü(Þßè]%ûÁý«MÞ¿+ÎǽBðƒû–ŒÝÇêýÕGñ-Úô}÷–[Ââa¹a¯žåÝØHKnnï\kï¤Z6{û$»¥_¥¡µ}еչ‡bÁ>RÖŸr¿#èÏ;¬µmÃûô–ñ* 6üz«p úöQâU~.ì`õÕ¸[»W±5û·¦ká]e®á^Í}oçJ9àÚêa×Ãwt¨û̃ç×¶N, «™ïéû;J =@‡¶NÆîÒw¥!|K²qã§^$Y›Ó÷s¿6’Û ­wo*‹íƒ½{8ð>]6;ÔòçýW }÷Uöþ!¼GxÏ9¹o4j%-¼yç3nŸÑpõ'ièóûn2–‹ÊŽYg=ù°Q«mþÃÄ-ôáÃGnkŸ>xìZÿ#E¯\°?pèškõ‡[²ö´¾ë>bÛ¹òÁõöó)VË=Wgûãa#VÛü‡ ZèÇÛÖ>}ðеþG‰^½Voçô;¬Úíû}¼ÝzM¯ªäºù‹z°n¹½²@½óu/ží^Åé”ÞñäßÅgÍo$ðå8«t!¤…K€9ŠõÖO¿£3ÑJz_Ò¡š–>To¡ùWQ%Ö²zH¡”âÔUX›¤m¨[Ÿ²Ê—Gî.¹Ú„½Ç=Ĥ†­}ôù;þý@N‚BÂIØÚGw’¾!ý@Þ±¥=„[ûVâêd¿ò •Üß3®\gqQ븃<›Wæ©GpÒ#ùg¥®Q‡–•s¬?ïáKŽí ºƒ‹l‹Wâ¤aò¹ž‚?îá CŠ»Éö¹ÅÍ^3,]‰kÔQLE›ÞÃ=–'6¡;¸È¶x%Nj—qÞúÊñ=2RÎ9\zúh®i—ÝÞúæð=²_Î5\*üx£žÕÃŽñ×}ÆCŒ3ðÈ]FÓÚ•ø§qänwTo¹ÒöæêÊ\óiác¥„«OËûœèGäCùƵôñGß¿|ȸ±E>XØ8–®$j!SöÄ>\¦ì[¼’øy'ybÎI¾Å+‰¤^N8"j9áZº’øy`×8"Ê5®¥+‰šGXiybn¥å[¼’øy'ybÎI¾Åî¤_T<Ê‚bµ‹ óîCåšûyˆ|ˆmfdéŠÜÓëï=¨ojyçÃÆ{{eÝŸ†ýïŸÿþùïŸÿâ?ÿƒo&~>Aznc-1.7.5/modules/modperl/include/0000755000175000017500000000000013542151610017275 5ustar somebodysomebodyznc-1.7.5/modules/modperl/include/perlfragments.swg0000644000175000017500000000065113542151610022672 0ustar somebodysomebody// Make perl strings to be UTF-8, they are already UTF-8 in ZNC core %fragment("SWIG_FromCharPtrAndSize","header") { SWIGINTERNINLINE SV * SWIG_FromCharPtrAndSize(const char* carray, size_t size) { SV *obj = sv_newmortal(); if (carray) { sv_setpvn(obj, carray, size); } else { sv_setsv(obj, &PL_sv_undef); } SvUTF8_on(obj); return obj; } } znc-1.7.5/modules/modperl/Makefile.gen0000644000175000017500000000151113542151610020060 0ustar somebodysomebodyall: VPATH := $(srcdir) ifneq "$(V)" "" VERBOSE=1 endif ifeq "$(VERBOSE)" "" Q=@ E=@echo C=-s else Q= E=@\# C= endif .SECONDARY: all: modperl/modperl_biglib.cpp modperl/ZNC.pm modperl/perlfunctions.cpp modperl/swigperlrun.h modperl/swigperlrun.h: @mkdir -p modperl $(Q)$(SWIG) -perl5 -c++ -shadow -external-runtime $@ modperl/modperl_biglib.cpp: modperl/modperl.i modperl/module.h modperl/CString.i $(E) Generating ZNC API for Perl... @mkdir -p modperl .depend $(Q)$(SWIG) -perl5 -c++ -shadow -outdir modperl -I$(srcdir) -I$(srcdir)/../include -I../include -I$(srcdir)/modperl/include -MD -MF .depend/modperl.swig.dep -w362,315,401,402 -o $@ $< modperl/ZNC.pm: modperl/modperl_biglib.cpp modperl/perlfunctions.cpp: modperl/codegen.pl modperl/functions.in @mkdir -p modperl $(Q)$(PERL) $^ $@ -include .depend/modperl.swig.dep znc-1.7.5/modules/modperl/modperl.i0000644000175000017500000001613313542151610017472 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ %module ZNC %{ #ifdef Copy # undef Copy #endif #ifdef Pause # undef Pause #endif #ifdef seed # undef seed #endif #include #include "znc/Utils.h" #include "znc/Threads.h" #include "znc/Config.h" #include "znc/Socket.h" #include "znc/Modules.h" #include "znc/Nick.h" #include "znc/Chan.h" #include "znc/User.h" #include "znc/IRCNetwork.h" #include "znc/Client.h" #include "znc/IRCSock.h" #include "znc/Listener.h" #include "znc/HTTPSock.h" #include "znc/Template.h" #include "znc/WebModules.h" #include "znc/znc.h" #include "znc/Server.h" #include "znc/ZNCString.h" #include "znc/FileUtils.h" #include "znc/ZNCDebug.h" #include "znc/ExecSock.h" #include "znc/Buffer.h" #include "modperl/module.h" #define stat struct stat %} %apply long { off_t }; %apply long { uint16_t }; %apply long { uint32_t }; %apply long { uint64_t }; %begin %{ #include "znc/zncconfig.h" %} %include %include %include %include namespace std { template class set { public: set(); set(const set&); }; } %include "modperl/CString.i" %typemap(out) VCString { EXTEND(sp, $1.size()); for (int i = 0; i < $1.size(); ++i) { SV* x = newSV(0); SwigSvFromString(x, $1[i]); $result = sv_2mortal(x); argvi++; } } %typemap(out) const VCString& { EXTEND(sp, $1->size()); for (int i = 0; i < $1->size(); ++i) { SV* x = newSV(0); SwigSvFromString(x, (*$1)[i]); $result = sv_2mortal(x); argvi++; } } %template(VIRCNetworks) std::vector; %template(VChannels) std::vector; %template(VCString) std::vector; typedef std::vector VCString; /*%template(MNicks) std::map;*/ /*%template(SModInfo) std::set; %template(SCString) std::set; typedef std::set SCString;*/ %template(PerlMCString) std::map; class MCString : public std::map {}; /*%template(PerlModulesVector) std::vector;*/ %template(VListeners) std::vector; %template(BufLines) std::deque; %template(VVString) std::vector; #define REGISTER_ZNC_MESSAGE(M) \ %template(As_ ## M) CMessage::As; %typemap(out) std::map { HV* myhv = newHV(); for (std::map::const_iterator i = $1.begin(); i != $1.end(); ++i) { SV* val = SWIG_NewInstanceObj(const_cast(&i->second), SWIG_TypeQuery("CNick*"), SWIG_SHADOW); SvREFCNT_inc(val);// it was created mortal hv_store(myhv, i->first.c_str(), i->first.length(), val, 0); } $result = newRV_noinc((SV*)myhv); sv_2mortal($result); argvi++; } #define u_short unsigned short #define u_int unsigned int #include "znc/zncconfig.h" #include "znc/ZNCString.h" %include "znc/defines.h" %include "znc/Translation.h" %include "znc/Utils.h" %include "znc/Threads.h" %include "znc/Config.h" %include "znc/Csocket.h" %template(ZNCSocketManager) TSocketManager; %include "znc/Socket.h" %include "znc/FileUtils.h" %include "znc/Message.h" %include "znc/Modules.h" %include "znc/Nick.h" %include "znc/Chan.h" %include "znc/User.h" %include "znc/IRCNetwork.h" %include "znc/Client.h" %include "znc/IRCSock.h" %include "znc/Listener.h" %include "znc/HTTPSock.h" %include "znc/Template.h" %include "znc/WebModules.h" %include "znc/znc.h" %include "znc/Server.h" %include "znc/ZNCDebug.h" %include "znc/ExecSock.h" %include "znc/Buffer.h" %include "modperl/module.h" %inline %{ class String : public CString { public: String() {} String(const CString& s) : CString(s) {} String(double d, int prec=2): CString(d, prec) {} String(float f, int prec=2) : CString(f, prec) {} String(int i) : CString(i) {} String(unsigned int i) : CString(i) {} String(long int i) : CString(i) {} String(unsigned long int i) : CString(i) {} String(char c) : CString(c) {} String(unsigned char c) : CString(c) {} String(short int i) : CString(i) {} String(unsigned short int i): CString(i) {} String(bool b) : CString(b) {} CString GetPerlStr() { return *this; } }; %} %extend CModule { VCString GetNVKeys() { VCString result; for (auto i = $self->BeginNV(); i != $self->EndNV(); ++i) { result.push_back(i->first); } return result; } bool ExistsNV(const CString& sName) { return $self->EndNV() != $self->FindNV(sName); } } %extend CModules { void push_back(CModule* p) { $self->push_back(p); } bool removeModule(CModule* p) { for (CModules::iterator i = $self->begin(); $self->end() != i; ++i) { if (*i == p) { $self->erase(i); return true; } } return false; } } %extend CUser { std::vector GetNetworks_() { return $self->GetNetworks(); } } %extend CIRCNetwork { std::vector GetChans_() { return $self->GetChans(); } } %extend CChan { std::map GetNicks_() { return $self->GetNicks(); } } /* Web */ %template(StrPair) std::pair; %template(VPair) std::vector >; typedef std::vector > VPair; %template(VWebSubPages) std::vector; %inline %{ void _VPair_Add2Str(VPair* self, const CString& a, const CString& b) { self->push_back(std::make_pair(a, b)); } %} %extend CTemplate { void set(const CString& key, const CString& value) { (*$self)[key] = value; } } %inline %{ TWebSubPage _CreateWebSubPage(const CString& sName, const CString& sTitle, const VPair& vParams, unsigned int uFlags) { return std::make_shared(sName, sTitle, vParams, uFlags); } %} %perlcode %{ package ZNC; sub CreateWebSubPage { my ($name, %arg) = @_; my $params = $arg{params}//{}; my $vpair = ZNC::VPair->new; while (my ($key, $val) = each %$params) { ZNC::_VPair_Add2Str($vpair, $key, $val); } my $flags = 0; $flags |= $ZNC::CWebSubPage::F_ADMIN if $arg{admin}//0; return _CreateWebSubPage($name, $arg{title}//'', $vpair, $flags); } %} %inline %{ void _CleanupStash(const CString& sModname) { hv_clear(gv_stashpv(sModname.c_str(), 0)); } %} %perlcode %{ package ZNC; *CONTINUE = *ZNC::CModule::CONTINUE; *HALT = *ZNC::CModule::HALT; *HALTMODS = *ZNC::CModule::HALTMODS; *HALTCORE = *ZNC::CModule::HALTCORE; *UNLOAD = *ZNC::CModule::UNLOAD; package ZNC::CIRCNetwork; *GetChans = *GetChans_; package ZNC::CUser; *GetNetworks = *GetNetworks_; package ZNC::CChan; sub _GetNicks_ { my $result = GetNicks_(@_); return %$result; } *GetNicks = *_GetNicks_; %} /* vim: set filetype=cpp: */ znc-1.7.5/modules/autocycle.cpp0000644000175000017500000001503713542151610016712 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::vector; class CAutoCycleMod : public CModule { public: MODCONSTRUCTOR(CAutoCycleMod) { AddHelpCommand(); AddCommand( "Add", t_d("[!]<#chan>"), t_d("Add an entry, use !#chan to negate and * for wildcards"), [=](const CString& sLine) { OnAddCommand(sLine); }); AddCommand("Del", t_d("[!]<#chan>"), t_d("Remove an entry, needs to be an exact match"), [=](const CString& sLine) { OnDelCommand(sLine); }); AddCommand("List", "", t_d("List all entries"), [=](const CString& sLine) { OnListCommand(sLine); }); m_recentlyCycled.SetTTL(15 * 1000); } ~CAutoCycleMod() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { VCString vsChans; sArgs.Split(" ", vsChans, false); for (const CString& sChan : vsChans) { if (!Add(sChan)) { PutModule(t_f("Unable to add {1}")(sChan)); } } // Load our saved settings, ignore errors MCString::iterator it; for (it = BeginNV(); it != EndNV(); ++it) { Add(it->first); } // Default is auto cycle for all channels if (m_vsChans.empty()) Add("*"); return true; } void OnAddCommand(const CString& sLine) { CString sChan = sLine.Token(1); if (AlreadyAdded(sChan)) { PutModule(t_f("{1} is already added")(sChan)); } else if (Add(sChan)) { PutModule(t_f("Added {1} to list")(sChan)); } else { PutModule(t_s("Usage: Add [!]<#chan>")); } } void OnDelCommand(const CString& sLine) { CString sChan = sLine.Token(1); if (Del(sChan)) PutModule(t_f("Removed {1} from list")(sChan)); else PutModule(t_s("Usage: Del [!]<#chan>")); } void OnListCommand(const CString& sLine) { CTable Table; Table.AddColumn(t_s("Channel")); for (const CString& sChan : m_vsChans) { Table.AddRow(); Table.SetCell(t_s("Channel"), sChan); } for (const CString& sChan : m_vsNegChans) { Table.AddRow(); Table.SetCell(t_s("Channel"), "!" + sChan); } if (Table.size()) { PutModule(Table); } else { PutModule(t_s("You have no entries.")); } } void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) override { AutoCycle(Channel); } void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) override { for (CChan* pChan : vChans) AutoCycle(*pChan); } void OnKick(const CNick& Nick, const CString& sOpNick, CChan& Channel, const CString& sMessage) override { AutoCycle(Channel); } protected: void AutoCycle(CChan& Channel) { if (!IsAutoCycle(Channel.GetName())) return; // Did we recently annoy opers via cycling of an empty channel? if (m_recentlyCycled.HasItem(Channel.GetName())) return; // Is there only one person left in the channel? if (Channel.GetNickCount() != 1) return; // Is that person us and we don't have op? const CNick& pNick = Channel.GetNicks().begin()->second; if (!pNick.HasPerm(CChan::Op) && pNick.NickEquals(GetNetwork()->GetCurNick())) { Channel.Cycle(); m_recentlyCycled.AddItem(Channel.GetName()); } } bool AlreadyAdded(const CString& sInput) { CString sChan = sInput; if (sChan.TrimPrefix("!")) { for (const CString& s : m_vsNegChans) { if (s.Equals(sChan)) return true; } } else { for (const CString& s : m_vsChans) { if (s.Equals(sChan)) return true; } } return false; } bool Add(const CString& sChan) { if (sChan.empty() || sChan == "!") { return false; } if (sChan.Left(1) == "!") { m_vsNegChans.push_back(sChan.substr(1)); } else { m_vsChans.push_back(sChan); } // Also save it for next module load SetNV(sChan, ""); return true; } bool Del(const CString& sChan) { vector::iterator it, end; if (sChan.empty() || sChan == "!") return false; if (sChan.Left(1) == "!") { CString sTmp = sChan.substr(1); it = m_vsNegChans.begin(); end = m_vsNegChans.end(); for (; it != end; ++it) if (*it == sTmp) break; if (it == end) return false; m_vsNegChans.erase(it); } else { it = m_vsChans.begin(); end = m_vsChans.end(); for (; it != end; ++it) if (*it == sChan) break; if (it == end) return false; m_vsChans.erase(it); } DelNV(sChan); return true; } bool IsAutoCycle(const CString& sChan) { for (const CString& s : m_vsNegChans) { if (sChan.WildCmp(s, CString::CaseInsensitive)) { return false; } } for (const CString& s : m_vsChans) { if (sChan.WildCmp(s, CString::CaseInsensitive)) { return true; } } return false; } private: vector m_vsChans; vector m_vsNegChans; TCacheMap m_recentlyCycled; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("autocycle"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s( "List of channel masks and channel masks with ! before them.")); } NETWORKMODULEDEFS( CAutoCycleMod, t_s("Rejoins channels to gain Op if you're the only user left")) znc-1.7.5/modules/pyeval.py0000644000175000017500000000456513542151610016074 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import sys import re from code import InteractiveInterpreter import znc class pyeval(znc.Module, InteractiveInterpreter): module_types = [znc.CModInfo.UserModule, znc.CModInfo.NetworkModule] wiki_page = 'pyeval' def write(self, data): for line in data.split('\n'): if len(line): self.PutModule(line) def resetbuffer(self): """Reset the input buffer.""" self.buffer = [] def push(self, line): self.buffer.append(line) source = "\n".join(self.buffer) more = self.runsource(source, self.filename) if not more: self.resetbuffer() return more def OnLoad(self, args, message): if not self.GetUser().IsAdmin(): message.s = self.t_s( 'You must have admin privileges to load this module.') return False self.filename = "" self.resetbuffer() self.locals['znc'] = znc self.locals['module'] = self self.locals['user'] = self.GetUser() self.indent = re.compile(r'^>+') return True def OnModCommand(self, line): self.locals['client'] = self.GetClient() self.locals['network'] = self.GetNetwork() # Hijack sys.stdout.write stdout_write = sys.stdout.write sys.stdout.write = self.write m = self.indent.match(line) if m: self.push((' ' * len(m.group())) + line[len(m.group()):]) elif line == ' ' or line == '<': self.push('') else: self.push(line) # Revert sys.stdout.write sys.stdout.write = stdout_write del self.locals['client'] del self.locals['network'] pyeval.description = pyeval.t_s('Evaluates python code') znc-1.7.5/modules/awaynick.cpp0000644000175000017500000000212213542151610016517 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include class CAwayNickMod : public CModule { public: MODCONSTRUCTOR(CAwayNickMod) {} bool OnLoad(const CString&, CString& sMessage) override { sMessage = "retired module - see https://wiki.znc.in/awaynick"; return false; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("awaynick"); } NETWORKMODULEDEFS(CAwayNickMod, "retired module - see https://wiki.znc.in/awaynick") znc-1.7.5/modules/cert.cpp0000644000175000017500000000633513542151610015660 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define REQUIRESSL #include #include #include #include class CCertMod : public CModule { public: void Delete(const CString& line) { if (CFile::Delete(PemFile())) { PutModule(t_s("Pem file deleted")); } else { PutModule(t_s( "The pem file doesn't exist or there was a error deleting the " "pem file.")); } } void Info(const CString& line) { if (HasPemFile()) { PutModule(t_f("You have a certificate in {1}")(PemFile())); } else { PutModule(t_s( "You do not have a certificate. Please use the web interface " "to add a certificate")); if (GetUser()->IsAdmin()) { PutModule(t_f("Alternatively you can either place one at {1}")( PemFile())); } } } MODCONSTRUCTOR(CCertMod) { AddHelpCommand(); AddCommand("delete", "", t_d("Delete the current certificate"), [=](const CString& sLine) { Delete(sLine); }); AddCommand("info", "", t_d("Show the current certificate"), [=](const CString& sLine) { Info(sLine); }); } ~CCertMod() override {} CString PemFile() const { return GetSavePath() + "/user.pem"; } bool HasPemFile() const { return (CFile::Exists(PemFile())); } EModRet OnIRCConnecting(CIRCSock* pIRCSock) override { if (HasPemFile()) { pIRCSock->SetPemLocation(PemFile()); } return CONTINUE; } CString GetWebMenuTitle() override { return t_s("Certificate"); } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "index") { Tmpl["Cert"] = CString(HasPemFile()); return true; } else if (sPageName == "update") { CFile fPemFile(PemFile()); if (fPemFile.Open(O_WRONLY | O_TRUNC | O_CREAT)) { fPemFile.Write(WebSock.GetParam("cert", true, "")); fPemFile.Close(); } WebSock.Redirect(GetWebPath()); return true; } else if (sPageName == "delete") { CFile::Delete(PemFile()); WebSock.Redirect(GetWebPath()); return true; } return false; } }; template <> void TModInfo(CModInfo& Info) { Info.AddType(CModInfo::UserModule); Info.SetWikiPage("cert"); } NETWORKMODULEDEFS(CCertMod, t_s("Use a ssl certificate to connect to a server")) znc-1.7.5/modules/po/0000755000175000017500000000000013542151610014626 5ustar somebodysomebodyznc-1.7.5/modules/po/modules_online.nl_NL.po0000644000175000017500000000101713542151610021202 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/modules_online.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "Maakt ZNC's *modulen \"online\"." znc-1.7.5/modules/po/perform.fr_FR.po0000644000175000017500000000376013542151610017643 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/perform.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "" #: perform.cpp:24 msgid "Usage: add " msgstr "" #: perform.cpp:29 msgid "Added!" msgstr "" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "" #: perform.cpp:41 msgid "Command Erased." msgstr "" #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "" #: perform.cpp:73 msgid "perform commands sent" msgstr "" #: perform.cpp:86 msgid "Commands Swapped." msgstr "" #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "" #: perform.cpp:100 msgid "List the perform commands" msgstr "" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "" #: perform.cpp:105 msgid " " msgstr "" #: perform.cpp:106 msgid "Swap two perform commands" msgstr "" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "" znc-1.7.5/modules/po/ctcpflood.ru_RU.po0000644000175000017500000000330213542151610020174 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/ctcpflood.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "" #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "" #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "" znc-1.7.5/modules/po/fail2ban.pot0000644000175000017500000000362413542151610017035 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "" #: fail2ban.cpp:28 msgid "[count]" msgstr "" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "" #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "" #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "" #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "" #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "" #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "" #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "" znc-1.7.5/modules/po/fail2ban.nl_NL.po0000644000175000017500000000606213542151610017651 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/fail2ban.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "[minuten]" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "" "Het aantal minuten dat IP-adressen geblokkeerd worden na een mislukte " "inlogpoging." #: fail2ban.cpp:28 msgid "[count]" msgstr "[aantal]" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "Het aantal toegestane mislukte inlogpogingen." #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "Verban de ingevoerde hosts." #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "Verbanning van ingevoerde hosts weghalen." #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "Lijst van verbannen hosts." #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" "Ongeldig argument, dit moet het aantal minuten zijn dat de IP-adressen " "geblokkeerd worden na een mislukte inlogpoging, gevolgd door het nummer van " "toegestane mislukte inlogpogingen" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "Toegang geweigerd" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "Gebruik: Timeout [minuten]" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "Time-out: {1} minuten" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "Gebruik: Attempts [aantal]" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "Pogingen: {1}" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "Gebruik: Ban " #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "Verbannen: {1}" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "Gebruik: Unban " #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "Verbanning verwijderd: {1}" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "Genegeerd: {1}" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "Host" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "Pogingen" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "Geen verbanningen" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" "Je mag de tijd in minuten invoeren voor de IP verbannen en het nummer van " "mislukte inlogpoging voordat actie ondernomen wordt." #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "" "Blokkeer IP-addressen voor een bepaalde tijd na een mislukte inlogpoging." znc-1.7.5/modules/po/autoattach.pt_BR.po0000644000175000017500000000376313542151610020341 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/autoattach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "" #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "" #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "" #: autoattach.cpp:138 msgid "You have no entries." msgstr "" #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "[!]<#canal> " #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "Adicione uma entrada, use !#canal para negar e * para wildcard" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "Remove uma entrada, precisa ser exatamente correspondente" #: autoattach.cpp:152 msgid "List all entries" msgstr "Lista todas as entradas" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "Não foi possível adicionar [{1}]" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "Lista de máscaras de canais e máscaras de canais com ! antes delas." #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "Reanexa você a canais quando há atividade." znc-1.7.5/modules/po/nickserv.it_IT.po0000644000175000017500000000433713542151610020030 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/nickserv.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: nickserv.cpp:31 msgid "Password set" msgstr "Password impostata correttamente" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "Fatto" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "Nuovo nome per NickServ impostato correttamente" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "" "Nessun comando simile da modificare. Digita ViewCommands per vederne la " "lista." #: nickserv.cpp:63 msgid "Ok" msgstr "Ok" #: nickserv.cpp:68 msgid "password" msgstr "password" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "Imposta la tua password per nickserv" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "Rimuove dallo ZNC la password utilizzata per identificarti a NickServ" #: nickserv.cpp:72 msgid "nickname" msgstr "nickname" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" "Imposta il nome di NickServ (utile su networks come EpiKnet, dove NickServ è " "chiamato Themis)" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "Riporta il nome di NickServ ai valori di default (NickServ)" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "Mostra i modelli (patterns) per linea, che vengono inviati a nikserv" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "comando nuovo-modello" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "Imposta un modello (pattern) per i comandi" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "" "Per favore inserisci la password che usi per identificarti attraverso " "NickServ." #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "" "Autorizza il tuo nick attraverso NickServ (anziché dal modulo SASL " "(preferito))" znc-1.7.5/modules/po/adminlog.pot0000644000175000017500000000201313542151610017140 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "" #: adminlog.cpp:31 msgid " [path]" msgstr "" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "" #: adminlog.cpp:142 msgid "Access denied" msgstr "" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "" #: adminlog.cpp:170 msgid "Unknown target" msgstr "" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "" znc-1.7.5/modules/po/bouncedcc.ru_RU.po0000644000175000017500000000524413542151610020153 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/bouncedcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "" #: bouncedcc.cpp:129 msgid "Connected" msgstr "" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "" #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "" #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "" #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" znc-1.7.5/modules/po/nickserv.ru_RU.po0000644000175000017500000000323213542151610020045 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/nickserv.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: nickserv.cpp:31 msgid "Password set" msgstr "" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "" #: nickserv.cpp:63 msgid "Ok" msgstr "" #: nickserv.cpp:68 msgid "password" msgstr "" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "" #: nickserv.cpp:72 msgid "nickname" msgstr "" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "" #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "" znc-1.7.5/modules/po/notes.pot0000644000175000017500000000371413542151610016507 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "" #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "" #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "" #: notes.cpp:75 msgid "List notes" msgstr "" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr "" #: notes.cpp:77 msgid "Add a note" msgstr "" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "" #: notes.cpp:81 msgid "Modify a note" msgstr "" #: notes.cpp:94 msgid "Notes" msgstr "" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "" #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "" #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "" znc-1.7.5/modules/po/send_raw.es_ES.po0000644000175000017500000000554613542151610017777 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/send_raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "Envía una línea raw al IRC" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "Usuario:" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "Para cambiar de usuario, pulsa sobre el selector de red" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "Usuario/Red:" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "Enviar a:" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "Cliente" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "Servidor" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "Línea:" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "Enviar" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "Enviado [{1}] a {2}/{3}" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "Red {1} no encontrada para el usuario {2}" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "Usuario {1} no encontrado" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "Enviado [{1}] al servidor IRC de {2}/{3}" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "Debes tener permisos de administrador para cargar este módulo" #: send_raw.cpp:82 msgid "Send Raw" msgstr "Enviar Raw" #: send_raw.cpp:92 msgid "User not found" msgstr "Usuario no encontrado" #: send_raw.cpp:99 msgid "Network not found" msgstr "Red no encontrada" #: send_raw.cpp:116 msgid "Line sent" msgstr "Línea enviada" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "[usuario] [red] [datos a enviar]" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "La información será enviada al cliente IRC del usuario" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "" "La información será enviada al servidor IRC donde está el usuario conectado" #: send_raw.cpp:147 msgid "[data to send]" msgstr "[datos a enviar]" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "La información será enviada a tu cliente actual" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "Permite enviar lineas Raw a/como otro usuario" znc-1.7.5/modules/po/pyeval.pt_BR.po0000644000175000017500000000106613542151610017476 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/pyeval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "" #: pyeval.py:82 msgid "Evaluates python code" msgstr "" znc-1.7.5/modules/po/savebuff.it_IT.po0000644000175000017500000000366313542151610020006 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/savebuff.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "Imposta la password" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "Riproduce il buffer" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "Salva tutti i buffers" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" "La password non è impostata, generalmente significa che la decrittografia " "non è riuscita. È possibile impostare setpass sul passaggio appropriato e le " "cose dovrebbero iniziare a funzionare, oppure setpass su un nuovo passaggio " "e salvare per instanziare" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "Password impostata a [{1}]" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "Ripetizione {1}" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "Impossibile decodificare il file critografato {1}" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" "Questo modulo utente accetta fino a un argomento. --ask-pass o la password " "stessa (che può contenere spazi) o nulla" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "Memorizza i buffer dei canali e delle query su disco, crittografati" znc-1.7.5/modules/po/controlpanel.ru_RU.po0000644000175000017500000003637313542151610020735 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/controlpanel.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "" #: controlpanel.cpp:77 msgid "String" msgstr "" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "" #: controlpanel.cpp:79 msgid "Integer" msgstr "" #: controlpanel.cpp:80 msgid "Number" msgstr "" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "" #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "" #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "" #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "" #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "" #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "" #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "" #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "" #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "" #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "" #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "" #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "" #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "" #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "" #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "" #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "" #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "" #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "" #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "" #: controlpanel.cpp:1143 msgid "No networks" msgstr "" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "" #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "" #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "" #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "" #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "" #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "" #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "" #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "" #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "" #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "" #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "" #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "" #: controlpanel.cpp:1559 msgid " [username]" msgstr "" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "" #: controlpanel.cpp:1562 msgid " " msgstr "" #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr "" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "" #: controlpanel.cpp:1568 msgid " " msgstr "" #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "" #: controlpanel.cpp:1571 msgid " [username] " msgstr "" #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1575 msgid " " msgstr "" #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr "" #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "" #: controlpanel.cpp:1586 msgid " " msgstr "" #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "" #: controlpanel.cpp:1591 msgid " " msgstr "" #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr "" #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr "" #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "" #: controlpanel.cpp:1606 msgid " [args]" msgstr "" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "" #: controlpanel.cpp:1609 msgid " " msgstr "" #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "" #: controlpanel.cpp:1616 msgid " [args]" msgstr "" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "" #: controlpanel.cpp:1620 msgid " " msgstr "" #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "" #: controlpanel.cpp:1629 msgid " [reply]" msgstr "" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "" #: controlpanel.cpp:1632 msgid " " msgstr "" #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "" #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "" #: controlpanel.cpp:1643 msgid "[username]" msgstr "" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" znc-1.7.5/modules/po/alias.pt_BR.po0000644000175000017500000000444213542151610017270 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/alias.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "" #: alias.cpp:203 msgid "Alias already exists." msgstr "" #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "" #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "" #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "" #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "" #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr "" #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "" #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "" #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "" #: alias.cpp:343 msgid " " msgstr "" #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "" #: alias.cpp:346 msgid " " msgstr "" #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "" #: alias.cpp:349 msgid " " msgstr "" #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "" #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "" #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "" #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "" #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "" #: alias.cpp:374 msgid "Clearing all of them!" msgstr "" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "" znc-1.7.5/modules/po/send_raw.bg_BG.po0000644000175000017500000000430513542151610017731 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/send_raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "" #: send_raw.cpp:82 msgid "Send Raw" msgstr "" #: send_raw.cpp:92 msgid "User not found" msgstr "" #: send_raw.cpp:99 msgid "Network not found" msgstr "" #: send_raw.cpp:116 msgid "Line sent" msgstr "" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "" #: send_raw.cpp:147 msgid "[data to send]" msgstr "" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "" znc-1.7.5/modules/po/cyrusauth.fr_FR.po0000644000175000017500000000331413542151610020213 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/cyrusauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" #: cyrusauth.cpp:56 msgid "Access denied" msgstr "" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "" #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" znc-1.7.5/modules/po/lastseen.it_IT.po0000644000175000017500000000325013542151610020013 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/lastseen.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "Utente" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "Ultima visualizzazione" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "Info" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "Azione" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "Modifica" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "Elimina" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "Ultimo ora di accesso:" #: lastseen.cpp:53 msgid "Access denied" msgstr "Accesso negato" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "Utente" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "Ultima visualizzazione" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "mai" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "" "Mostra l'elenco degli utenti e quando hanno effettuato l'ultimo accesso " "(logged in)" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "" "Raccoglie dati riguardo l'ultimo accesso effettuato da un utente (logged in)." znc-1.7.5/modules/po/modules_online.pot0000644000175000017500000000026713542151610020373 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "" znc-1.7.5/modules/po/missingmotd.ru_RU.po0000644000175000017500000000131613542151610020557 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/missingmotd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "ОтправлÑет 422 клиенту при логине" znc-1.7.5/modules/po/stickychan.es_ES.po0000644000175000017500000000470313542151610020327 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/stickychan.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "Nombre" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "Fijo" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "Guardar" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "El canal está fijado" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "<#canal> [clave]" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "Fija un canal" #: stickychan.cpp:30 msgid "<#channel>" msgstr "<#canal>" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "Desfija un canal" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "Muestra los canales fijos" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "Uso: Stick <#canal> [clave]" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "Fijado {1}" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "Uso: Unstick <#canal>" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "Desfijado {1}" #: stickychan.cpp:101 msgid " -- End of List" msgstr " -- Fin de la lista" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "No se ha podido entrar a {1} (¿Falta el prefijo #?)" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "Canales fijados" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "Los cambios han sido guardados" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "Se ha fijado el canal" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "El canal ya no está fijado" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "No se puede entrar al canal {1}, es un nombre no válido. Desfijado." #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "Lista de canales, separados por comas." #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" "Fijación de canales sin configuración, te mantienen dentro todo lo posible" znc-1.7.5/modules/po/stripcontrols.nl_NL.po0000644000175000017500000000112213542151610021110 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/stripcontrols.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "Haalt control codes uit de berichten (Kleuren, dikgedrukt, ..)." znc-1.7.5/modules/po/lastseen.pot0000644000175000017500000000212313542151610017166 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "" #: lastseen.cpp:53 msgid "Access denied" msgstr "" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "" znc-1.7.5/modules/po/shell.nl_NL.po0000644000175000017500000000153313542151610017300 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/shell.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "Mislukt om uit te voeren: {1}" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "Je moet een beheerder zijn om de shell module te gebruiken" #: shell.cpp:169 msgid "Gives shell access" msgstr "Geeft toegang tot de shell" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "Geeft toegang tot de shell. Alleen ZNC beheerder kunnen het gebruiken." znc-1.7.5/modules/po/missingmotd.pt_BR.po0000644000175000017500000000077113542151610020535 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/missingmotd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "" znc-1.7.5/modules/po/adminlog.nl_NL.po0000644000175000017500000000362113542151610017763 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/adminlog.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "Laat de bestemming voor het logboek zien" #: adminlog.cpp:31 msgid " [path]" msgstr " [pad]" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "Stel de bestemming voor het logboek in" #: adminlog.cpp:142 msgid "Access denied" msgstr "Toegang geweigerd" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "Logboek zal vanaf nu geschreven worden naar bestand" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "Logboek zal vanaf nu alleen geschreven worden naar syslog" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "Logboek zal vanaf nu geschreven worden naar bestand en syslog" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "Gebruik: Bestemming [pad]" #: adminlog.cpp:170 msgid "Unknown target" msgstr "Onbekende bestemming" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "Logboek is ingesteld voor schrijven naar bestand" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "Logboek is ingesteld voor schrijven naar syslog" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "Logboek is ingesteld voor schrijven naar bestand en syslog" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "Logboek zal geschreven worden naar {1}" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "Schrijf ZNC gebeurtenissen naar bestand en/of syslog." znc-1.7.5/modules/po/stickychan.ru_RU.po0000644000175000017500000000412313542151610020361 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/stickychan.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "" #: stickychan.cpp:30 msgid "<#channel>" msgstr "" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "" #: stickychan.cpp:101 msgid " -- End of List" msgstr "" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "" #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "" #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" znc-1.7.5/modules/po/adminlog.bg_BG.po0000644000175000017500000000265713542151610017731 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/adminlog.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "" #: adminlog.cpp:31 msgid " [path]" msgstr "<Файл| СиÑтемни Логове |Двете> [директориÑ]" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "" #: adminlog.cpp:142 msgid "Access denied" msgstr "ДоÑтъпът е отказан" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "" #: adminlog.cpp:170 msgid "Unknown target" msgstr "" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "" znc-1.7.5/modules/po/autoop.pot0000644000175000017500000000562213542151610016666 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: autoop.cpp:154 msgid "List all users" msgstr "" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr "" #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr "" #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr "" #: autoop.cpp:170 msgid "Adds a user" msgstr "" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "" #: autoop.cpp:300 msgid "There are no users defined" msgstr "" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "" #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "" #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "" #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "" #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "" #: autoop.cpp:478 msgid "User {1} removed" msgstr "" #: autoop.cpp:484 msgid "That user already exists" msgstr "" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "" #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "" #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "" #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "" #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "" #: autoop.cpp:644 msgid "Auto op the good people" msgstr "" znc-1.7.5/modules/po/controlpanel.es_ES.po0000644000175000017500000005312013542151610020664 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/controlpanel.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "Tipo" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "Variables" #: controlpanel.cpp:77 msgid "String" msgstr "Cadena" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "Booleano (verdadero/falso)" #: controlpanel.cpp:79 msgid "Integer" msgstr "Entero" #: controlpanel.cpp:80 msgid "Number" msgstr "Número" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "" "Las siguientes variables están disponibles cuando se usan los comandos Get/" "Set:" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" "Las siguientes variables están disponibles cuando se usan los comandos " "SetNetwork/GetNetwork:" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" "Las siguientes variables están disponibles cuando se usan los comandos " "SetChan/GetChan:" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" "Puedes usar $user como nombre de usuario y $network como el nombre de la red " "para modificar tu propio usuario y red." #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "Error: el usuario [{1}] no existe" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "" "Error: tienes que tener permisos administrativos para modificar otros " "usuarios" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "Error: no puedes usar $network para modificar otros usuarios" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "Error: el usuario {1} no tiene una red llamada [{2}]." #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "Uso: Get [usuario]" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "Error: variable desconocida" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "Uso: Set [usuario] " #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "Este bind host ya está definido" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "¡Acceso denegado!" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "Ajuste fallido, el límite para el tamaño de búfer es {1}" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "Se ha cambiado la contraseña" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "¡El tiempo de espera no puede ser inferior a 30 segundos!" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "Eso sería una mala idea" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "Idiomas soportados: {1}" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "Uso: GetNetwork [usuario] [red]" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" "Error: debes especificar una red para obtener los ajustes de otro usuario." #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "No estás adjunto a una red." #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "Error: nombre de red inválido." #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "Uso: SetNetwork " #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "Uso: AddChan " #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "Error: el usuario {1} ya tiene un canal llamado {2}." #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "El canal {1} para el usuario {2} se ha añadido a la red {3}." #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" "No se ha podido añadir el canal {1} para el usuario {2} a la red {3}, " "¿existe realmente?" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "Uso: DelChan " #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" "Error: el usuario {1} no tiene ningún canal que coincida con [{2}] en la red " "{3}" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "Borrado canal {1} de la red {2} del usuario {3}" msgstr[1] "Borrados canales {1} de la red {2} del usuario {3}" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "Uso: GetChan " #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "Error: no hay ningún canal que coincida con [{1}]." #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "Uso: SetChan " #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "Usuario" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "Nombre real" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "Admin" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "Apodo" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "Apodo alternativo" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "Ident" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "BindHost" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "No" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "Sí" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "" "Error: tienes que tener permisos administrativos para añadir nuevos usuarios" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "Uso: AddUser " #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "Error: el usuario {1} ya existe" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "Error: usuario no añadido: {1}" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "¡Usuario {1} añadido!" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "" "Error: tienes que tener permisos administrativos para eliminar usuarios" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "Uso: DelUser " #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "Error: no puedes borrarte a ti mismo" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "Error: error interno" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "Usuario {1} eliminado" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "Uso: CloneUser " #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "Error: clonación fallida: {1}" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "Uso: AddNetwork [usuario] red" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "Limite de redes alcanzado. Píde a un administrador que te incremente el " "límite, o elimina redes innecesarias usando /znc DelNetwork " #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "Error: el usuario {1} ya tiene una red llamada {2}" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "Red {1} añadida al usuario {2}." #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "Error: la red [{1}] no se ha podido añadir al usuario {2}: {3}" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "Uso: DelNetwork [usuario] red" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "La red activa actual puede ser eliminada vía {1}status" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "Red {1} eliminada al usuario {2}." #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "Error: la red {1} no se ha podido eliminar al usuario {2}." #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "Red" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "EnIRC" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "Servidor IRC" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "Usuario IRC" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "Canales" #: controlpanel.cpp:1143 msgid "No networks" msgstr "No hay redes" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "Uso: AddServer [[+]puerto] [contraseña]" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "Añadido servidor IRC {1} a la red {2} al usuario {3}." #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" "Error: no se ha podido añadir el servidor IRC {1} a la red {2} del usuario " "{3}." #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "Uso: DelServer [[+]puerto] [contraseña]" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "Eliminado servidor IRC {1} de la red {2} al usuario {3}." #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" "Error: no se ha podido eliminar el servidor IRC {1} de la red {2} al usuario " "{3}." #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "Uso: Reconnect " #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "Red {1} del usuario {2} puesta en cola para reconectar." #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "Uso: Disconnect " #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "Cerrada la conexión IRC de la red {1} al usuario {2}." #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "Solicitud" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "Respuesta" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "No hay respuestas CTCP configuradas para el usuario {1}" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "Respuestas CTCP del usuario {1}:" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "Uso: AddCTCP [usuario] [solicitud] [respuesta]" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" "Esto hará que ZNC responda a los CTCP en vez de reenviarselos a los clientes." #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "Una respuesta vacía hará que la solicitud CTCP sea bloqueada." #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "Las solicitudes CTCP {1} del usuario {2} serán bloqueadas." #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "Las solicitudes CTCP {1} del usuario {2} se responderán con: {3}" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "Uso: DelCTCP [usuario] [solicitud]" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "Las solicitudes CTCP {1} del usuario {2} serán enviadas a los clientes" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" "Las solicitudes CTCP {1} del usuario {2} serán enviadas a los clientes (no " "se ha cambiado nada)" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "La carga de módulos ha sido deshabilitada." #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "Error: no se ha podido cargar el módulo {1}: {2}" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "Cargado módulo {1}" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "Error: no se ha podido recargar el módulo {1}: {2}" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "Recargado módulo {1}" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "Error: no se ha podido cargar el módulo {1} porque ya está cargado" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "Uso: LoadModule [args]" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "Uso: LoadNetModule [args]" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "Por favor, ejecuta /znc unloadmod {1}" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "Error: no se ha podido descargar el módulo {1}: {2}" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "Descargado módulo {1}" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "Uso: UnloadModule " #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "Uso: UnloadNetModule " #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "Nombre" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "Parámetros" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "El usuario {1} no tiene módulos cargados." #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "Módulos cargados para el usuario {1}:" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "La red {1} del usuario {2} no tiene módulos cargados." #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "Módulos cargados para la red {1} del usuario {2}:" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "[comando] [variable]" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "Muestra la ayuda de los comandos y variables" #: controlpanel.cpp:1559 msgid " [username]" msgstr " [usuario]" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "" "Muestra los valores de las variables del usuario actual o el proporcionado" #: controlpanel.cpp:1562 msgid " " msgstr " " #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "Ajusta los valores de variables para el usuario proporcionado" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr " [usuario] [red]" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "Muestra los valores de las variables de la red proporcionada" #: controlpanel.cpp:1568 msgid " " msgstr " " #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "Ajusta los valores de variables para la red proporcionada" #: controlpanel.cpp:1571 msgid " [username] " msgstr " " #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "Muestra los valores de las variables del canal proporcionado" #: controlpanel.cpp:1575 msgid " " msgstr " " #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "Ajusta los valores de variables para el canal proporcionado" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr " " #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "Añadir un nuevo canal" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "Eliminar canal" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "Mostrar usuarios" #: controlpanel.cpp:1586 msgid " " msgstr " " #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "Añadir un usuario nuevo" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "Eliminar usuario" #: controlpanel.cpp:1591 msgid " " msgstr " " #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "Duplica un usuario" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr " " #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "Añade un nuevo servidor de IRC para el usuario actual o proporcionado" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "Borra un servidor de IRC para el usuario actual o proporcionado" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr " " #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "Reconecta la conexión de un usario al IRC" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "Desconecta un usuario de su servidor de IRC" #: controlpanel.cpp:1606 msgid " [args]" msgstr " [args]" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "Carga un módulo a un usuario" #: controlpanel.cpp:1609 msgid " " msgstr " " #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "Quita un módulo de un usuario" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "Obtiene la lista de módulos de un usuario" #: controlpanel.cpp:1616 msgid " [args]" msgstr " [args]" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "Carga un módulo para una red" #: controlpanel.cpp:1620 msgid " " msgstr " " #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "Elimina el módulo de una red" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "Obtiene la lista de módulos de una red" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "Muestra las respuestas CTCP configuradas" #: controlpanel.cpp:1629 msgid " [reply]" msgstr " [respuesta]" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "Configura una nueva respuesta CTCP" #: controlpanel.cpp:1632 msgid " " msgstr " " #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "Elimina una respuesta CTCP" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "[usuario] " #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "Añade una red a un usuario" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "Borra la red de un usuario" #: controlpanel.cpp:1643 msgid "[username]" msgstr "[usuario]" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "Muestra las redes de un usuario" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" "Configuración dinámica a través de IRC. Permite la edición solo sobre ti si " "no eres un admin de ZNC." znc-1.7.5/modules/po/disconkick.es_ES.po0000644000175000017500000000135213542151610020305 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/disconkick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "Has sido desconectado del servidor de IRC" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" "Expulsa al cliente de todos los canales cuando se pierde la conexión al IRC" znc-1.7.5/modules/po/savebuff.pot0000644000175000017500000000202013542151610017145 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "" znc-1.7.5/modules/po/controlpanel.bg_BG.po0000644000175000017500000003607013542151610020633 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/controlpanel.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "" #: controlpanel.cpp:77 msgid "String" msgstr "" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "" #: controlpanel.cpp:79 msgid "Integer" msgstr "" #: controlpanel.cpp:80 msgid "Number" msgstr "" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "" #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "" #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "" #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "" #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "" #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "" #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "" #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "" #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "" #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "" msgstr[1] "" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "" #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "" #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "" #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "" #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "" #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "" #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "" #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "" #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "" #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "" #: controlpanel.cpp:1143 msgid "No networks" msgstr "" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "" #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "" #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "" #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "" #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "" #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "" #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "" #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "" #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "" #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "" #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "" #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "" #: controlpanel.cpp:1559 msgid " [username]" msgstr "" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "" #: controlpanel.cpp:1562 msgid " " msgstr "" #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr "" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "" #: controlpanel.cpp:1568 msgid " " msgstr "" #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "" #: controlpanel.cpp:1571 msgid " [username] " msgstr "" #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1575 msgid " " msgstr "" #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr "" #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "" #: controlpanel.cpp:1586 msgid " " msgstr "" #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "" #: controlpanel.cpp:1591 msgid " " msgstr "" #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr "" #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr "" #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "" #: controlpanel.cpp:1606 msgid " [args]" msgstr "" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "" #: controlpanel.cpp:1609 msgid " " msgstr "" #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "" #: controlpanel.cpp:1616 msgid " [args]" msgstr "" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "" #: controlpanel.cpp:1620 msgid " " msgstr "" #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "" #: controlpanel.cpp:1629 msgid " [reply]" msgstr "" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "" #: controlpanel.cpp:1632 msgid " " msgstr "" #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "" #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "" #: controlpanel.cpp:1643 msgid "[username]" msgstr "" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" znc-1.7.5/modules/po/shell.ru_RU.po0000644000175000017500000000223213542151610017327 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/shell.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "Ðе удалоÑÑŒ выполнить: {1}" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "Ð’Ñ‹ должны быть админиÑтратором Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ shell" #: shell.cpp:169 msgid "Gives shell access" msgstr "Даёт доÑтуп к оболочке" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "" "Даёт доÑтуп к оболочке. Только админиÑтраторы ZNC могут иÑпользовать Ñто." znc-1.7.5/modules/po/log.id_ID.po0000644000175000017500000000477113542151610016727 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/log.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "" #: log.cpp:62 msgid "Clear all logging rules" msgstr "" #: log.cpp:64 msgid "List all logging rules" msgstr "" #: log.cpp:67 msgid " true|false" msgstr "" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "" #: log.cpp:143 msgid "Usage: SetRules " msgstr "" #: log.cpp:144 msgid "Wildcards are allowed" msgstr "" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "" #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "" #: log.cpp:196 msgid "Will log joins" msgstr "" #: log.cpp:196 msgid "Will not log joins" msgstr "" #: log.cpp:197 msgid "Will log quits" msgstr "" #: log.cpp:197 msgid "Will not log quits" msgstr "" #: log.cpp:199 msgid "Will log nick changes" msgstr "" #: log.cpp:199 msgid "Will not log nick changes" msgstr "" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "" #: log.cpp:211 msgid "Logging joins" msgstr "" #: log.cpp:211 msgid "Not logging joins" msgstr "" #: log.cpp:212 msgid "Logging quits" msgstr "" #: log.cpp:212 msgid "Not logging quits" msgstr "" #: log.cpp:213 msgid "Logging nick changes" msgstr "" #: log.cpp:214 msgid "Not logging nick changes" msgstr "" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "" #: log.cpp:563 msgid "Writes IRC logs." msgstr "" znc-1.7.5/modules/po/chansaver.id_ID.po0000644000175000017500000000075213542151610020113 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/chansaver.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "" znc-1.7.5/modules/po/sample.nl_NL.po0000644000175000017500000000615313542151610017455 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/sample.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "Voorbeeld taak geannuleerd" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "Voorbeeld taak vernietigd" #: sample.cpp:50 msgid "Sample job done" msgstr "Voorbeeld taak gereed" #: sample.cpp:65 msgid "TEST!!!!" msgstr "KOEKJES!!!!" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "Ik wordt geladen met de volgende argumenten: {1}" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "Ik wordt gestopt!" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "Je bent verbonden BoyOh." #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "Je bent losgekoppeld BoyOh." #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "{1} {2} stelt modus in {3} {4}{5} {6}" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "{1} {2} geeft beheerdersrechten aan {3} op {4}" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "{1} {2} neemt beheerdersrechten van {3} op {4}" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "{1} {2} geeft stem aan {3} op {4}" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "{1} {2} neemt stem van {3} op {4}" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "* {1} stelt modus in: {2} {3} op {4}" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "{1} geschopt {2} van {3} met het bericht {4}" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "* {1} ({2}@{3}) verlaat ({4}) van kanaal: {6}" msgstr[1] "* {1} ({2}@{3}) verlaat ({4}) van {5} kanalen: {6}" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "Proberen toe te treden tot {1}" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "* {1} ({2}@{3}) treed toe in {4}" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "* {1} ({2}@{3}) verlaat {4}" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "{1} nodigt ons uit in {2}, negeer uitnodigingen naar {2}" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "{1} nodigt ons uit in {2}" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "{1} staat nu bekend als {2}" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "{1} veranderd onderwerp in {2} naar {3}" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "Hey, ik ben je vriendelijke voorbeeldmodule." #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "Beschrijving van module argumenten komen hier." #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "Om gebruikt te worden als voorbeeld voor het schrijven van modulen" znc-1.7.5/modules/po/fail2ban.es_ES.po0000644000175000017500000000600313542151610017640 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/fail2ban.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "[minutos]" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "El número de minutos que una IP queda bloqueada tras un login fallido." #: fail2ban.cpp:28 msgid "[count]" msgstr "[recuento]" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "Número de intentos fallidos permitidos." #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "Bloquea los hosts especificados." #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "Desbloquea los hosts especificados." #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "Muestra los hosts bloqueados." #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" "Argumento no válido, debe ser el número de minutos que una IP quedará " "bloqueada después de un intento de login fallido y puede ser seguido del " "número de intentos de login fallidos que se permiten" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "Acceso denegado" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "Uso: Timeout [minutos]" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "Tiempo de espera: {1} min" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "Uso: Attempts [veces]" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "Intentos: {1}" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "Uso: Ban " #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "Bloqueado: {1}" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "Uso: Unban " #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "Desbloqueado: {1}" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "Ignorado: {1}" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "Host" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "Intentos" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "No hay bloqueos" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" "Quizás quieras poner el tiempo en minutos para el bloqueo de una IP y el " "número de intentos fallidos antes de tomar una acción." #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "Bloquea IPs tras un intento de login fallido." znc-1.7.5/modules/po/crypt.bg_BG.po0000644000175000017500000000505013542151610017266 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/crypt.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "" #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "" #: crypt.cpp:204 msgid "List all keys" msgstr "" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "" #: crypt.cpp:213 msgid "[Prefix]" msgstr "" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "" #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "" #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "" #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "" #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "" #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "" #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "" #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "" #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "" #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "" #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "" znc-1.7.5/modules/po/controlpanel.fr_FR.po0000644000175000017500000003606413542151610020674 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/controlpanel.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "" #: controlpanel.cpp:77 msgid "String" msgstr "" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "" #: controlpanel.cpp:79 msgid "Integer" msgstr "" #: controlpanel.cpp:80 msgid "Number" msgstr "" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "" #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "" #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "" #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "" #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "" #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "" #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "" #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "" #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "" #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "" msgstr[1] "" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "" #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "" #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "" #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "" #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "" #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "" #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "" #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "" #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "" #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "" #: controlpanel.cpp:1143 msgid "No networks" msgstr "" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "" #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "" #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "" #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "" #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "" #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "" #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "" #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "" #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "" #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "" #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "" #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "" #: controlpanel.cpp:1559 msgid " [username]" msgstr "" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "" #: controlpanel.cpp:1562 msgid " " msgstr "" #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr "" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "" #: controlpanel.cpp:1568 msgid " " msgstr "" #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "" #: controlpanel.cpp:1571 msgid " [username] " msgstr "" #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1575 msgid " " msgstr "" #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr "" #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "" #: controlpanel.cpp:1586 msgid " " msgstr "" #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "" #: controlpanel.cpp:1591 msgid " " msgstr "" #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr "" #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr "" #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "" #: controlpanel.cpp:1606 msgid " [args]" msgstr "" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "" #: controlpanel.cpp:1609 msgid " " msgstr "" #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "" #: controlpanel.cpp:1616 msgid " [args]" msgstr "" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "" #: controlpanel.cpp:1620 msgid " " msgstr "" #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "" #: controlpanel.cpp:1629 msgid " [reply]" msgstr "" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "" #: controlpanel.cpp:1632 msgid " " msgstr "" #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "" #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "" #: controlpanel.cpp:1643 msgid "[username]" msgstr "" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" znc-1.7.5/modules/po/clientnotify.nl_NL.po0000644000175000017500000000455713542151610020711 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/clientnotify.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "Stelt de notificatiemethode in" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "Schakelt notificaties voor ongeziene IP-adressen in of uit" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "Schakelt notificaties voor clients die loskoppelen aan of uit" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "Laat de huidige instellingen zien" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" msgstr[1] "" "Een andere client heeft zich als jouw gebruiker geïdentificeerd. Gebruik het " "'ListClients' commando om alle {1} clients te zien." #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "Gebruik: Method " #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "Opgeslagen." #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "Gebruik: NewOnly " #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "Gebruik: OnDisconnect " #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" "Huidige instellingen: Method: {1}, alleen voor ongeziene IP-addressen: {2}, " "notificatie wanneer clients loskoppelen: {3}" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" "Laat je weten wanneer een andere IRC client in of uitlogd op jouw account. " "Configureerbaar." znc-1.7.5/modules/po/log.es_ES.po0000644000175000017500000000717213542151610016753 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/log.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "Establece reglas de log, utiliza !#canal o !privado para negar y * " #: log.cpp:62 msgid "Clear all logging rules" msgstr "Borrar todas las reglas de logueo" #: log.cpp:64 msgid "List all logging rules" msgstr "Mostrar todas las reglas de logueo" #: log.cpp:67 msgid " true|false" msgstr " true|false" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "Establece una de las siguientes opciones: joins, quits, nickchanges" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "Muestra ajustes puestos con el comando Set" #: log.cpp:143 msgid "Usage: SetRules " msgstr "Uso: SetRules " #: log.cpp:144 msgid "Wildcards are allowed" msgstr "Se permiten comodines" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "No hay reglas de logueo. Se registra todo." #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "Borrada regla: {2}" msgstr[1] "Borradas {1} reglas: {2}" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "Regla" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "Registro habilitado" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "Uso: Set true|false, donde es: joins, quits, nickchanges" #: log.cpp:196 msgid "Will log joins" msgstr "Registrar entradas" #: log.cpp:196 msgid "Will not log joins" msgstr "No registrar entradas" #: log.cpp:197 msgid "Will log quits" msgstr "Registrar desconexiones (quits)" #: log.cpp:197 msgid "Will not log quits" msgstr "No registrar desconexiones (quits)" #: log.cpp:199 msgid "Will log nick changes" msgstr "Registrar cambios de nick" #: log.cpp:199 msgid "Will not log nick changes" msgstr "No registrar cambios de nick" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "Variable desconocida. Variables conocidas: joins, quits, nickchanges" #: log.cpp:211 msgid "Logging joins" msgstr "Registrando entradas" #: log.cpp:211 msgid "Not logging joins" msgstr "Sin registrar entradas" #: log.cpp:212 msgid "Logging quits" msgstr "Registrando desconexiones (quits)" #: log.cpp:212 msgid "Not logging quits" msgstr "Sin registrar desconexiones (quits)" #: log.cpp:213 msgid "Logging nick changes" msgstr "Registrando cambios de nick" #: log.cpp:214 msgid "Not logging nick changes" msgstr "Sin registrar cambios de nick" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" "Argumentos inválidos [{1}]. Solo se permite una ruta de logueo. Comprueba " "que no tiene espacios." #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "Ruta de log no válida [{1}]" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "Registrando a [{1}]. Usando marca de tiempo '{2}'" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "[-sanitize] ruta opcional donde almacenar registros." #: log.cpp:563 msgid "Writes IRC logs." msgstr "Guarda registros de IRC." znc-1.7.5/modules/po/modpython.fr_FR.po0000644000175000017500000000074213542151610020207 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/modpython.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/flooddetach.de_DE.po0000644000175000017500000000461213542151610020404 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/flooddetach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "Zeige die aktuellen Limits" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "[]" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "Zeige oder Setze die Anzahl an Sekunden im Zeitinterval" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "Flut in {1} ist vorbei, verbinde..." #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "Kanal {1} wurde mit Nachrichten geflutet, sie wurden getrennt" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "Eine Zeile" msgstr[1] "{1} Zeilen" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "jede Sekunde" msgstr[1] "alle {1} Sekunden" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "Aktuelles Limit ist {1} {2}" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "Sekunden-Grenze ist {1}" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "Sekunden-Grenze auf {1} gesetzt" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "Zeilen-Grenze ist {1}" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "Zeilen-Grenze auf {1} gesetzt" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "Modul-Nachrichten sind deaktiviert" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "Modul-Nachrichten sind aktiviert" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" "Dieses Benutzer-Modul erhält bis zu zwei Argumente. Argumente sind Anzahl an " "Nachrichten und Sekunden." #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "Trenne Kanäle bei Nachrichten-Flut" znc-1.7.5/modules/po/controlpanel.id_ID.po0000644000175000017500000003604513542151610020645 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/controlpanel.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "" #: controlpanel.cpp:77 msgid "String" msgstr "" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "" #: controlpanel.cpp:79 msgid "Integer" msgstr "" #: controlpanel.cpp:80 msgid "Number" msgstr "" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "" #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "" #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "" #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "" #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "" #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "" #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "" #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "" #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "" #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "" #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "" #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "" #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "" #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "" #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "" #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "" #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "" #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "" #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "" #: controlpanel.cpp:1143 msgid "No networks" msgstr "" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "" #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "" #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "" #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "" #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "" #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "" #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "" #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "" #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "" #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "" #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "" #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "" #: controlpanel.cpp:1559 msgid " [username]" msgstr "" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "" #: controlpanel.cpp:1562 msgid " " msgstr "" #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr "" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "" #: controlpanel.cpp:1568 msgid " " msgstr "" #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "" #: controlpanel.cpp:1571 msgid " [username] " msgstr "" #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1575 msgid " " msgstr "" #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr "" #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "" #: controlpanel.cpp:1586 msgid " " msgstr "" #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "" #: controlpanel.cpp:1591 msgid " " msgstr "" #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr "" #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr "" #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "" #: controlpanel.cpp:1606 msgid " [args]" msgstr "" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "" #: controlpanel.cpp:1609 msgid " " msgstr "" #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "" #: controlpanel.cpp:1616 msgid " [args]" msgstr "" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "" #: controlpanel.cpp:1620 msgid " " msgstr "" #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "" #: controlpanel.cpp:1629 msgid " [reply]" msgstr "" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "" #: controlpanel.cpp:1632 msgid " " msgstr "" #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "" #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "" #: controlpanel.cpp:1643 msgid "[username]" msgstr "" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" znc-1.7.5/modules/po/pyeval.es_ES.po0000644000175000017500000000117413542151610017466 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/pyeval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "Debes tener permisos de administrador para cargar este módulo." #: pyeval.py:82 msgid "Evaluates python code" msgstr "Evalua código python" znc-1.7.5/modules/po/admindebug.pt_BR.po0000644000175000017500000000224213542151610020272 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/admindebug.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "" #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "" #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" #: admindebug.cpp:66 msgid "Already enabled." msgstr "" #: admindebug.cpp:68 msgid "Already disabled." msgstr "" #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "" #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "" #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "" #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "" znc-1.7.5/modules/po/perleval.fr_FR.po0000644000175000017500000000122013542151610017770 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/perleval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "" znc-1.7.5/modules/po/missingmotd.id_ID.po0000644000175000017500000000074413542151610020477 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/missingmotd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "" znc-1.7.5/modules/po/missingmotd.es_ES.po0000644000175000017500000000103313542151610020515 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/missingmotd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "Envía un raw 422 a los clientes cuando conectan" znc-1.7.5/modules/po/modperl.pot0000644000175000017500000000025313542151610017014 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/stickychan.pt_BR.po0000644000175000017500000000367113542151610020342 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/stickychan.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "" #: stickychan.cpp:30 msgid "<#channel>" msgstr "" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "" #: stickychan.cpp:101 msgid " -- End of List" msgstr "" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "" #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "" #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" znc-1.7.5/modules/po/q.it_IT.po0000644000175000017500000002031013542151610016431 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/q.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "Nome Utente:" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "Per favore inserisci il nome utente." #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "Password:" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "Per favore inserisci una password." #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "Opzioni" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "Salva" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" "AVVISO: Il tuo host verrà occultato la prossima volta che ti riconnetti ad " "IRC. Se vuoi mascherare il tuo host adesso, digita /msg *q Cloak. Puoi " "impostare le tue preferenze con /msg *q Set UseCloakedHost true oppure /msg " "*q Set UseCloakedHost false" #: q.cpp:111 msgid "The following commands are available:" msgstr "Sono disponibili i seguenti comandi:" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "Comando" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "Descrizione" #: q.cpp:116 msgid "Auth [ ]" msgstr "Auth [ ]" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "Prova ad autenticarti con Q. Entrambi i parametri sono opzionali." #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" "Prova ad impostare il tuo usermode +x per nascondere il tuo hostname reale." #: q.cpp:128 msgid "Prints the current status of the module." msgstr "Mostra lo stato corrente del modulo." #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "Richiede nuovamente le informazioni dell'utente corrente da Q." #: q.cpp:135 msgid "Set " msgstr "Set " #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" "Cambia il valore delle impostazioni date. Qui sotto vedi una lista delle " "impostazioni." #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" "Mostra la configurazione corrente. Qui sotto vedi una lista delle " "impostazioni." #: q.cpp:146 msgid "The following settings are available:" msgstr "Sono disponibili le seguenti impostazioni:" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "Impostazioni" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "Tipo" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "Stringa" #: q.cpp:154 msgid "Your Q username." msgstr "Il tuo username Q." #: q.cpp:158 msgid "Your Q password." msgstr "La tua password Q." #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "Booleano" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "Se mascherare il tuo hostname (+x) automaticamente in connessione." #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" "Se utilizzare il meccaniscmo CHALLENGEAUTH per evitare l'invio di passwords " "in chiaro." #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "Se richiedere il voice/op da Q dopo un join/devoice/deop." #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "Se entrare nei canali quando invitato da Q." #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" "Se ritardare l'ingresso ai canali fino a quando non si è stati occultati." #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" "Questo modulo accetta due parametri opzionali: " #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "Le impostazioni del modulo vengono memorizzate durante i riavvii." #: q.cpp:200 msgid "Syntax: Set " msgstr "Sintassi: Set " #: q.cpp:203 msgid "Username set" msgstr "Nome utente impostato" #: q.cpp:206 msgid "Password set" msgstr "Password impostata" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "UseCloakedHost impostato" #: q.cpp:212 msgid "UseChallenge set" msgstr "UseChallenge impostato" #: q.cpp:215 msgid "RequestPerms set" msgstr "RequestPerms impostato" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "JoinOnInvite impostato" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "JoinAfterCloaked impostato" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "Impostazione sconosciuta: {1}" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "Valore" #: q.cpp:253 msgid "Connected: yes" msgstr "Connesso: si" #: q.cpp:254 msgid "Connected: no" msgstr "Connesso: no" #: q.cpp:255 msgid "Cloacked: yes" msgstr "Oscurato (cloacked): yes" #: q.cpp:255 msgid "Cloacked: no" msgstr "Oscurato (cloacked): no" #: q.cpp:256 msgid "Authenticated: yes" msgstr "Autenticato: si" #: q.cpp:257 msgid "Authenticated: no" msgstr "Autenticato: no" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "Errore: Non sei connesso ad IRC." #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "Errore: Sei già stato oscurato (cloaked)!" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "Errore: Sei già stato autenticato!" #: q.cpp:280 msgid "Update requested." msgstr "Aggiornamento richiesto." #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "Comando sconosciuto. Prova 'help'." #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "Oscuramento riuscito: Ora il tuo hostname è mascherato." #: q.cpp:408 msgid "Changes have been saved!" msgstr "I cambiamenti sono stati salvati!" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "Cloak: prova ad oscurare il tuo hostname, impostando +x..." #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" "Devi impostare username e password per usare questo modulo! Vedi 'help' per " "maggiori dettagli." #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "Aut: Richiesta di SFIDA (challenge)..." #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "Aut: Invio richiesta di AUTENTICAZIONE..." #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" "Aut: Sfida ricevuta, stò inviando la richiesta di AUTORIZZAZIONE alla SFIDA " "(challengeauth)..." #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "Autenticazione fallita: {1}" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "Autenticazione avvenuta: {1}" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" "Autenticazione fallita: Q non supporta HMAC-SHA-256 per CHALLENGEAUTH, " "tornando all'AUTENTICAZIONE standard." #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "RequestPerms: Richiesta di op su {1}" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "RequestPerms: Richiesta di voice su {1}" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "Per favore fornisci il tuo sername e password per Q." #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "Ti autorizza con il bot Q di QuakeNet." znc-1.7.5/modules/po/blockuser.it_IT.po0000644000175000017500000000454213542151610020173 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/blockuser.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "L'account è bloccato" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "Il tuo account è stato disabilitato. Contatta il tuo amministratore." #: blockuser.cpp:29 msgid "List blocked users" msgstr "Elenco utenti bloccati" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "Blocca un utente" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "Sblocca un utente" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "Impossibile bloccare {1}" #: blockuser.cpp:76 msgid "Access denied" msgstr "Accesso negato" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "Nessun utente bloccato" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "Utenti bloccati:" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "Utilizzo: Block " #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "Non puoi bloccare te stesso" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "Bloccato {1}" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "Impossibile bloccare {1} (errore di ortografia?)" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "Utilizzo: Unblock " #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "Sbloccato {1}" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "Questo utente non è bloccato" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "Impossibile bloccare {1}" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "L'utente {1} non è bloccato" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "Inserisci uno o più nomi utente. Separali con uno spazio." #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "Blocca il login di determinati utenti." znc-1.7.5/modules/po/admindebug.pot0000644000175000017500000000153313542151610017453 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "" #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "" #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" #: admindebug.cpp:66 msgid "Already enabled." msgstr "" #: admindebug.cpp:68 msgid "Already disabled." msgstr "" #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "" #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "" #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "" #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "" znc-1.7.5/modules/po/kickrejoin.id_ID.po0000644000175000017500000000240213542151610020263 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/kickrejoin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: kickrejoin.cpp:56 msgid "" msgstr "" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "" #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "" znc-1.7.5/modules/po/blockuser.nl_NL.po0000644000175000017500000000461713542151610020170 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/blockuser.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "Account is geblokkeerd" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "Je account is uitgeschakeld. Neem contact op met de beheerder." #: blockuser.cpp:29 msgid "List blocked users" msgstr "Laat geblokkeerde gebruikers zien" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "Gebruiker blokkeren" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "Gebruiker deblokkeren" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "Kon {1} niet blokkeren" #: blockuser.cpp:76 msgid "Access denied" msgstr "Toegang geweigerd" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "Geen gebruikers zijn geblokkeerd" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "Geblokkeerde gebruikers:" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "Gebruik: Block " #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "Je kan jezelf niet blokkeren" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "{1} geblokkeerd" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "Kon {1} niet blokkeren (onjuist gespeld?)" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "Gebruik: Unblock " #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "{1} gedeblokkeerd" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "Deze gebruiker is niet geblokkeerd" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "Kon {1} niet blokkeren" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "Gebruiker {1} is niet geblokkeerd" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "Voer één of meer namen in. Scheid deze met spaties." #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "Blokkeer inloggen door bepaalde gebruikers." znc-1.7.5/modules/po/modpython.ru_RU.po0000644000175000017500000000131713542151610020244 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/modpython.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "Загружает Python-Ñкрипты как модули ZNC" znc-1.7.5/modules/po/buffextras.nl_NL.po0000644000175000017500000000226513542151610020345 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/buffextras.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: buffextras.cpp:45 msgid "Server" msgstr "Server" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "{1} steld modus in: {2} {3}" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "{1} schopt {2} met reden: {3}" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "{1} stopt: {2}" #: buffextras.cpp:73 msgid "{1} joined" msgstr "{1} komt binnen" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "{1} verlaat: {2}" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "{1} staat nu bekend als {2}" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "{1} veranderd het onderwerp naar: {2}" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "Voegt binnenkomers, verlaters enz. toe aan de terugspeel buffer" znc-1.7.5/modules/po/certauth.fr_FR.po0000644000175000017500000000406513542151610020007 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/certauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "" #: certauth.cpp:31 msgid "[pubkey]" msgstr "" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" #: certauth.cpp:35 msgid "id" msgstr "" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "" #: certauth.cpp:37 msgid "List your public keys" msgstr "" #: certauth.cpp:39 msgid "Print your current key" msgstr "" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "" #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "" #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "" #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "" #: certauth.cpp:215 msgid "Removed" msgstr "" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "" znc-1.7.5/modules/po/lastseen.ru_RU.po0000644000175000017500000000306213542151610020040 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/lastseen.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "" #: lastseen.cpp:53 msgid "Access denied" msgstr "" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "" znc-1.7.5/modules/po/sasl.es_ES.po0000644000175000017500000001116313542151610017127 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/sasl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "SASL" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "Usuario:" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "Introduce un nombre de usuario." #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "Contraseña:" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "Introduce una contraseña." #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "Opciones" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "Conectar solo si la autenticación SASL es correcta." #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "Requerir autenticación" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "Mecanismos" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "Nombre" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "Descripción" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "Mecanismos seleccionados y su orden:" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "Guardar" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "Certificado TLS, para usar con el módulo *cert" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" "Negociación en texto plano, debería funcionar siempre si la red soporta SASL" #: sasl.cpp:62 msgid "search" msgstr "búsqueda" #: sasl.cpp:62 msgid "Generate this output" msgstr "Generar esta salida" #: sasl.cpp:64 msgid "[ []]" msgstr "[] []" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" "Establecer usuario y contraseña para los mecanismos que lo necesiten. La " "contraseña es opcional. Sin parámetros, devuelve información sobre los " "ajustes actuales." #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "[mecanismo[...]]" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "Establecer los mecanismos para ser probados (en orden)" #: sasl.cpp:72 msgid "[yes|no]" msgstr "[yes|no]" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "Conectar solo si la autenticación SASL es correcta" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "Mecanismo" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "Están disponibles los siguientes mecanismos:" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "El usuario no está establecido" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "El usuario está establecido a '{1}'" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "La contraseña no está establecida" #: sasl.cpp:114 msgid "Password was supplied" msgstr "Se ha establecido una contraseña" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "El usuario se ha establecido a [{1}]" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "La contraseña se ha establecido a [{1}]" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "Mecanismo establecido: {1}" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "Necesitamos negociación SASL para conectar" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "Conectaremos incluso si falla la autenticación SASL" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "Deshabilitando red, necesitamos autenticación." #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "Ejecuta 'RequireAuth no' para desactivarlo." #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "Mecanismo {1} conseguido." #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "Mecanismo {1} fallido." #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "Añade soporte SASL para la autenticación a un servidor de IRC" znc-1.7.5/modules/po/clearbufferonmsg.it_IT.po0000644000175000017500000000117013542151610021520 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/clearbufferonmsg.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "" "Svuota il buffer di tutti i canali e di tutte le query ogni volta che " "l'utente fa qualche cosa" znc-1.7.5/modules/po/pyeval.fr_FR.po0000644000175000017500000000104313542151610017461 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/pyeval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "" #: pyeval.py:82 msgid "Evaluates python code" msgstr "" znc-1.7.5/modules/po/samplewebapi.fr_FR.po0000644000175000017500000000073213542151610020636 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/samplewebapi.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "" znc-1.7.5/modules/po/partyline.bg_BG.po0000644000175000017500000000157713542151610020146 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/partyline.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "" #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "" #: partyline.cpp:82 msgid "List all open channels" msgstr "" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "" znc-1.7.5/modules/po/bouncedcc.pot0000644000175000017500000000430413542151610017300 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "" #: bouncedcc.cpp:129 msgid "Connected" msgstr "" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "" #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "" #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "" #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" znc-1.7.5/modules/po/autoattach.de_DE.po0000644000175000017500000000426013542151610020264 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/autoattach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "Zur Liste hinzugefügt" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "{1} ist schon hinzugefügt" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "Verwendung: Add [!]<#kanal> " #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "Wildcards sind erlaubt" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "{1} aus der Liste entfernt" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "Verwendung: Del [!]<#Kanal> " #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "Neg" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "Kanal" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "Suche" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "Host" #: autoattach.cpp:138 msgid "You have no entries." msgstr "Du hast keine Einträge." #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "[!]<#Kanal> " #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" "Füge einen Eintrag hinzu, verwende !#Kanal zum Negieren und * als Platzhalter" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "Entferne einen Eintrag, muss genau passen" #: autoattach.cpp:152 msgid "List all entries" msgstr "Liste alle Einträge auf" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "Kann [{1}] nicht hinzufügen" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "Liste an Kanalmasken und Kanalmasken mit führendem !." #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "Verbindet dich wieder mit Kanälen bei Aktivität." znc-1.7.5/modules/po/autoreply.pt_BR.po0000644000175000017500000000211513542151610020216 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/autoreply.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "Define uma nova resposta" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "Mostra a atual resposta de query" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "A resposta atual é: {1} ({2})" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "Nova resposta definida como: {1} ({2})" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "" znc-1.7.5/modules/po/nickserv.pot0000644000175000017500000000227313542151610017202 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: nickserv.cpp:31 msgid "Password set" msgstr "" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "" #: nickserv.cpp:63 msgid "Ok" msgstr "" #: nickserv.cpp:68 msgid "password" msgstr "" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "" #: nickserv.cpp:72 msgid "nickname" msgstr "" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "" #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "" znc-1.7.5/modules/po/log.ru_RU.po0000644000175000017500000000531713542151610017010 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/log.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "" #: log.cpp:62 msgid "Clear all logging rules" msgstr "" #: log.cpp:64 msgid "List all logging rules" msgstr "" #: log.cpp:67 msgid " true|false" msgstr "" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "" #: log.cpp:143 msgid "Usage: SetRules " msgstr "" #: log.cpp:144 msgid "Wildcards are allowed" msgstr "" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "" #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "" #: log.cpp:196 msgid "Will log joins" msgstr "" #: log.cpp:196 msgid "Will not log joins" msgstr "" #: log.cpp:197 msgid "Will log quits" msgstr "" #: log.cpp:197 msgid "Will not log quits" msgstr "" #: log.cpp:199 msgid "Will log nick changes" msgstr "" #: log.cpp:199 msgid "Will not log nick changes" msgstr "" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "" #: log.cpp:211 msgid "Logging joins" msgstr "" #: log.cpp:211 msgid "Not logging joins" msgstr "" #: log.cpp:212 msgid "Logging quits" msgstr "" #: log.cpp:212 msgid "Not logging quits" msgstr "" #: log.cpp:213 msgid "Logging nick changes" msgstr "" #: log.cpp:214 msgid "Not logging nick changes" msgstr "" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "" #: log.cpp:563 msgid "Writes IRC logs." msgstr "" znc-1.7.5/modules/po/dcc.de_DE.po0000644000175000017500000001007413542151610016660 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/dcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: dcc.cpp:88 msgid " " msgstr "" #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "" #: dcc.cpp:91 msgid "" msgstr "" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "" #: dcc.cpp:94 msgid "List current transfers" msgstr "" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "" #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "" #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "" #: dcc.cpp:179 msgid "Usage: Send " msgstr "" #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "" #: dcc.cpp:199 msgid "Usage: Get " msgstr "" #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "" #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "" #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "" #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "" #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "" #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "" #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "" #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "" #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "" #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "" #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "" #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "" #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "" #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "" #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "" #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "" #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "" znc-1.7.5/modules/po/log.pt_BR.po0000644000175000017500000000503313542151610016755 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/log.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "" #: log.cpp:62 msgid "Clear all logging rules" msgstr "" #: log.cpp:64 msgid "List all logging rules" msgstr "" #: log.cpp:67 msgid " true|false" msgstr "" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "" #: log.cpp:143 msgid "Usage: SetRules " msgstr "" #: log.cpp:144 msgid "Wildcards are allowed" msgstr "" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "" #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "" msgstr[1] "" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "" #: log.cpp:196 msgid "Will log joins" msgstr "" #: log.cpp:196 msgid "Will not log joins" msgstr "" #: log.cpp:197 msgid "Will log quits" msgstr "" #: log.cpp:197 msgid "Will not log quits" msgstr "" #: log.cpp:199 msgid "Will log nick changes" msgstr "" #: log.cpp:199 msgid "Will not log nick changes" msgstr "" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "" #: log.cpp:211 msgid "Logging joins" msgstr "" #: log.cpp:211 msgid "Not logging joins" msgstr "" #: log.cpp:212 msgid "Logging quits" msgstr "" #: log.cpp:212 msgid "Not logging quits" msgstr "" #: log.cpp:213 msgid "Logging nick changes" msgstr "" #: log.cpp:214 msgid "Not logging nick changes" msgstr "" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "" #: log.cpp:563 msgid "Writes IRC logs." msgstr "" znc-1.7.5/modules/po/q.pt_BR.po0000644000175000017500000001305613542151610016440 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/q.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" #: q.cpp:111 msgid "The following commands are available:" msgstr "" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "" #: q.cpp:116 msgid "Auth [ ]" msgstr "" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "" #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" #: q.cpp:128 msgid "Prints the current status of the module." msgstr "" #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "" #: q.cpp:135 msgid "Set " msgstr "" #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" #: q.cpp:146 msgid "The following settings are available:" msgstr "" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "" #: q.cpp:154 msgid "Your Q username." msgstr "" #: q.cpp:158 msgid "Your Q password." msgstr "" #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "" #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "" #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "" #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "" #: q.cpp:200 msgid "Syntax: Set " msgstr "" #: q.cpp:203 msgid "Username set" msgstr "" #: q.cpp:206 msgid "Password set" msgstr "" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "" #: q.cpp:212 msgid "UseChallenge set" msgstr "" #: q.cpp:215 msgid "RequestPerms set" msgstr "" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "" #: q.cpp:253 msgid "Connected: yes" msgstr "" #: q.cpp:254 msgid "Connected: no" msgstr "" #: q.cpp:255 msgid "Cloacked: yes" msgstr "" #: q.cpp:255 msgid "Cloacked: no" msgstr "" #: q.cpp:256 msgid "Authenticated: yes" msgstr "" #: q.cpp:257 msgid "Authenticated: no" msgstr "" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "" #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "" #: q.cpp:280 msgid "Update requested." msgstr "" #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "" #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "" #: q.cpp:408 msgid "Changes have been saved!" msgstr "" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "" #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "" #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "" #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "" #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "" znc-1.7.5/modules/po/cyrusauth.pot0000644000175000017500000000263113542151610017403 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" #: cyrusauth.cpp:56 msgid "Access denied" msgstr "" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "" #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" znc-1.7.5/modules/po/fail2ban.it_IT.po0000644000175000017500000000610713542151610017657 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/fail2ban.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "[minuti]" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "" "Il numero di minuti in cui gli IPs restano bloccati dopo un login fallito." #: fail2ban.cpp:28 msgid "[count]" msgstr "[conteggio]" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "Numero di tentativi di accesso (login) falliti consentiti." #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "Vieta (ban) gli host specificati." #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "Rimuove un divieto (ban) da specifici host." #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "Elenco degli host vietati (bannati)." #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" "Argomento non valido, deve essere il numero di minuti in cui gli IP sono " "bloccati dopo un login fallito e può essere seguito dal numero consentito di " "tentativi falliti" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "Accesso negato" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "Utilizzo: Timeout [minuti]" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "Timeout: {1} minuti" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "Utilizzo: Attempts [conteggio]" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "Tentativi: {1}" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "Utilizzo: Ban " #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "Bannato (Banned): {1}" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "Utilizzo: Unban " #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "Sbannato (unbanned): {1}" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "Ignorato: {1}" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "Host" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "Tentativi" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "Nessun divieto (ban)" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" "È possibile inserire il tempo in minuti di ban dell'IP e il numero di " "accessi (login) falliti prima di intraprendere qualsiasi azione." #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "Blocca gli IP per un certo periodo di tempo dopo un login fallito." znc-1.7.5/modules/po/webadmin.ru_RU.po0000644000175000017500000013714613542151610020023 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/webadmin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ канале" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "Ðазвание канала:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "Ðазвание канала." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "Ключ:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "Пароль от канала, еÑли имеетÑÑ." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "Размер буфера:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "Размер буфера." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "Режимы по умолчанию:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "Режимы канала по умолчанию." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "Переключатели" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "СохранÑть в файл конфигурации" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "Модуль {1}" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "Сохранить и вернутьÑÑ" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "Сохранить и продолжить" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "Добавить канал и вернутьÑÑ" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "Добавить канал и продолжить" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "<пароль>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "<Ñеть>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" "Чтобы войти в Ñту Ñеть из вашего клиента IRC, уÑтановите пароль Ñервера в " "{1} либо Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð² {2}" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ Ñети" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" "ОÑтавьте ник, идент, наÑтоÑщее Ð¸Ð¼Ñ Ð¸ хоÑÑ‚ пуÑтыми, чтобы иÑпользовать " "значениÑ, заданные в наÑтройках пользователÑ." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "Ðазвание Ñети:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "Ðазвание Ñтой Ñети IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "Ðик:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "Ваш ник в IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "Второй ник:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "Ваш второй ник, на Ñлучай еÑли первый недоÑтупен." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "Идент:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "Ваш ident, отÑылаетÑÑ Ð½Ð° Ñервер в качеÑтве имени пользователÑ." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "ÐаÑтоÑщее имÑ:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "Ваше наÑтоÑщее имÑ." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "ХоÑÑ‚:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "Сообщение при выходе:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "" "Ð’Ñ‹ можете уÑтановить Ñообщение, которое будет показано, когда вы выходите из " "IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "Сеть активна:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "ПодключатьÑÑ Ðº IRC и автоматичеÑки переподключатьÑÑ" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "Серверы Ñтой Ñети IRC:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "" "По одному Ñерверу в каждой Ñтроке в формате «хоÑÑ‚ [[+]порт] [пароль]», + " "означает SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "ХоÑÑ‚" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "Порт" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "Пароль" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "Отпечатки пальцев SHA-256 доверенных Ñертификатов SSL Ñтой Ñети IRC:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" "ЕÑли Ñервер предоÑтавил один из указанных Ñертификатов, то Ñоединение будет " "продолжено незавиÑимо от времени Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ñертификата, Ð½Ð°Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñи " "извеÑтным центром Ñертификации и имени хоÑта" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "Защита от флуда:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" "Ð’Ñ‹ можете включить защиту от флуда. Это предотвращает ошибки вида «Excess " "flood», которые ÑлучаютÑÑ, когда ZNC шлёт данные на Ñервер Ñлишком быÑтро. " "ПоÑле Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿ÐµÑ€ÐµÐ¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚Ðµ ZNC к Ñерверу." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "Включена" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "СкороÑть флуда:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" "Сколько Ñекунд ждать между отправкой двух Ñтрок. ПоÑле Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ " "переподключите ZNC к Ñерверу." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "{1} Ñекунд на Ñтроку" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "Взрыв флуда:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" "КоличеÑтво Ñтрок, которые могут поÑланы на Ñервер без задержки. ПоÑле " "Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿ÐµÑ€ÐµÐ¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚Ðµ ZNC к Ñерверу." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "{1} Ñтрок отÑылаютÑÑ Ð±ÐµÐ· задержки" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "Задержка входа на каналы:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" "Ð’Ñ€ÐµÐ¼Ñ Ð² Ñекундах, которое надо ждать между уÑтановлением ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð¸ " "заходом на каналы." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "{1} Ñекунд" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "Кодировка Ñимволов, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÐµÐ¼Ð°Ñ Ð¼ÐµÐ¶Ð´Ñƒ ZNC и Ñервером IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "Кодировка Ñервера:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "Каналы" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "ЗдеÑÑŒ поÑле ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñети вы Ñможете добавлÑть и изменÑть каналы." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "Добавить" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "Сохранить" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "Ðазвание" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "Текущие режимы" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "Режимы по умолчанию" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "Размер буфера" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "Опции" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "↠Ðовый канал (открываетÑÑ Ð½Ð° той же Ñтранице)" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "Изменить" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "Удалить" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "Модули" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "Параметры" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "ОпиÑание" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "Загру­Ð¶ÐµÐ½Ð¾ гло­Ð±Ð°Ð»ÑŒÐ½Ð¾" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "Загру­Ð¶ÐµÐ½Ð¾ пользо­Ð²Ð°Ñ‚елем" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "Добавить Ñеть и вернутьÑÑ" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "Добавить Ñеть и продолжить" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "ÐутентификациÑ" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "Пользователь:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "Введите Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "Пароль:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "Введите пароль." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "Подтвердите пароль:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "Введите пароль ещё раз." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "Разрешённые IP-адреÑа:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" "ОÑтавьте пуÑтым, чтобы подключатьÑÑ Ñ Ð»ÑŽÐ±Ð¾Ð³Ð¾ адреÑа.
Иначе, введите по " "одному IP на Ñтроку. Также доÑтупны ÑпецÑимволы * и ?." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ IRC" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" "ОÑтавьте ник, идент, наÑтоÑщее Ð¸Ð¼Ñ Ð¸ хоÑÑ‚ пуÑтыми, чтобы иÑпользовать " "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "Идент отÑылаетÑÑ Ð½Ð° Ñервер в качеÑтве имени пользователÑ." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "ÐŸÑ€ÐµÑ„Ð¸ÐºÑ Ð´Ð»Ñ status" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "ÐŸÑ€ÐµÑ„Ð¸ÐºÑ Ð´Ð»Ñ Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñми и ÑтатуÑом" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "ХоÑÑ‚ Ð´Ð»Ñ DCC:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "Сети" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "Клиенты" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "Текущий Ñервер" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "Ðик" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "↠ÐÐ¾Ð²Ð°Ñ Ñеть (открываетÑÑ Ð½Ð° той же Ñтранице)" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "" "ЗдеÑÑŒ поÑле ÐºÐ»Ð¾Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð²Ñ‹ Ñможете добавлÑть и изменÑть Ñети." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "" "ЗдеÑÑŒ поÑле ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð²Ñ‹ Ñможете добавлÑть и изменÑть Ñети." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "Загружено ÑетÑми" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" "Режимы канала по умолчанию, которые ZNC будет выÑтавлÑть при заходе на " "пуÑтой канал." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "ЕÑли пуÑто, иÑпользуетÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ по умолчанию" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "КоличеÑтво Ñтрок в буферах Ð´Ð»Ñ Ð¸Ñтории каналов. При переполнении из буфера " "удалÑÑŽÑ‚ÑÑ Ñамые Ñтарые Ñтроки. По умолчанию буферы хранÑÑ‚ÑÑ Ð² памÑти." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "Личные ÑообщениÑ" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "МакÑимальное чиÑло буферов:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "" "МакÑимальное чиÑло ÑобеÑедников, личные перепиÑки Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼Ð¸ будут Ñохранены " "в буферах. 0 — без ограничений." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "КоличеÑтво Ñтрок в буферах Ð´Ð»Ñ Ð¸Ñтории личных перепиÑок. При переполнении из " "буфера удалÑÑŽÑ‚ÑÑ Ñамые Ñтарые Ñтроки. По умолчанию буферы хранÑÑ‚ÑÑ Ð² памÑти." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "Поведение ZNC" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" "Можете оÑтавить Ð¿Ð¾Ð»Ñ Ð¿ÑƒÑтыми, чтобы иÑпользовать Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "Формат времени:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" "Формат отметок времени Ð´Ð»Ñ Ð±ÑƒÑ„ÐµÑ€Ð¾Ð², например [%H:%M:%S]. Ð’ Ñовременных " "клиентах, поддерживающих раÑширение server-time, Ñта наÑтройка игнорируетÑÑ, " "при Ñтом формат времени наÑтраиваетÑÑ Ð² Ñамом клиенте." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "ЧаÑовой поÑÑ:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "Ðапример, Asia/Novosibirsk или GMT+3" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "Кодировка Ñимволов, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÐµÐ¼Ð°Ñ Ð¼ÐµÐ¶Ð´Ñƒ клиентом IRC и ZNC." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "Кодировка клиента:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "Попыток входа на канал:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" "Сколько раз ZNC пытаетÑÑ Ð·Ð°Ð¹Ñ‚Ð¸ на канал. ÐеуÑпех может быть, например, из-за " "режимов канала +i или +k или еÑли Ð²Ð°Ñ Ð¾Ñ‚Ñ‚ÑƒÐ´Ð° выгнали." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "СкороÑть входа на каналы:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" "Ðа Ñколько каналов заходить одной командой JOIN. 0 — неограничено, Ñто " "значение по умолчанию. УÑтановите в маленькое положительное чиÑло, еÑли Ð²Ð°Ñ " "отключает Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ¾Ð¹ «Max SendQ Exceeded»" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "Ð’Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð´Ð¾ повторного подключениÑ:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "Ограничение количеÑтва Ñетей IRC:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "" "Ðаибольшее разрешённое чиÑло Ñетей IRC, которые может иметь Ñтот " "пользователь." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "подÑтановки" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "Ответы CTCP:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "По одному ответу в каждой Ñтроке. Пример: TIME Купи чаÑÑ‹!" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "ДоÑтупны {1}" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "ЕÑли пуÑто, Ñтот Ð·Ð°Ð¿Ñ€Ð¾Ñ CTCP игнорируетÑÑ" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "ЗапроÑ" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "Ответ" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "Тема:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "- Ð“Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ð°Ñ -" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "По умолчанию" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "Другие темы не найдены" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "Язык:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "Склонировать и вернутьÑÑ" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "Склонировать и продолжить" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "Создать и вернутьÑÑ" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "Создать и продолжить" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "Склонировать" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "Создать" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "Подтверждение ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñети" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "Ð’Ñ‹ дейÑтвительно хотите удалить Ñеть «{2}» Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Â«{1}»?" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "Да" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "Ðет" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "Подтверждение ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "Ð’Ñ‹ дейÑтвительно хотите удалить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Â«{1}»?" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "" "ZNC Ñобран без поддержки кодировки. Ð”Ð»Ñ Ñтого необходима библиотека {1}." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "Старый режим выключен модулем modpython." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "Ðе гарантировать никакую кодировку (Ñтарый режим, не рекомендуетÑÑ)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "Принимать как UTF-8 и как {1}, отÑылать как UTF-8 (рекомендуетÑÑ)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "Принимать как UTF-8 и как {1}, отÑылать как {1}" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "Принимать и отÑылать только как {1}" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "Ðапример, UTF-8 или CP-1251" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "Добро пожаловать в webadmin ZNC." #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "Ð’Ñе Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ð¾Ð¹Ð´ÑƒÑ‚ в Ñилу Ñразу, как только вы их Ñделаете." #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "Пользователь" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "Удалить" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "Слушающие порты" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "ХоÑÑ‚" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "IPv4" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "IPv6" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "IRC" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "HTTP" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "ÐŸÑ€ÐµÑ„Ð¸ÐºÑ URI" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" "Чтобы удалить порт, Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ которого вы иÑпользуете webadmin, либо " "подключитеÑÑŒ к webadmin через другой порт, либо удалите его из IRC командой /" "znc DelPort" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "Текущий" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "ÐаÑтройки" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "Это значение по умолчанию Ð´Ð»Ñ Ð½Ð¾Ð²Ñ‹Ñ… пользователей." #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "МакÑимальный размер буфера:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "" "УÑтанавливает наибольший размер буфера, который может иметь пользователь." #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "Задержка приÑоединений:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" "Ð’Ñ€ÐµÐ¼Ñ Ð² Ñекундах, которое ZNC ждёт между попытками ÑоединитьÑÑ Ñ Ñерверами " "IRC. Эта наÑтройка не влиÑет на Ñоединение между вашим клиентом IRC и ZNC." #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "ПоÑÐµÑ€Ð²ÐµÑ€Ð½Ð°Ñ Ð·Ð°Ð´ÐµÑ€Ð¶ÐºÐ° приÑоединений:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" "Минимальное Ð²Ñ€ÐµÐ¼Ñ Ð² Ñекундах между попытками приÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ðº одному и тому " "же Ñерверу. Ðекоторые Ñерверы отказывают в Ñоединении, еÑли ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ " "Ñлишком чаÑтые." #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "Ограничение неавторизованных Ñоединений на IP:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "МакÑимальное чиÑло неавторизованных Ñоединений Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ IP-адреÑа." #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "Защита ÑеÑÑий HTTP:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "ПривÑзывать каждую ÑеÑÑию к IP-адреÑу" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "ПрÑтать верÑию ZNC:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "ПрÑтать верÑию программы от тех, кто не ÑвлÑетÑÑ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¼ ZNC" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "MOTD:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "«Сообщение днÑ», показываемое вÑем пользователÑм ZNC." #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "Глобальные модули" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "Загружено пользо­Ð²Ð°Ñ‚елÑми" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "ИнформациÑ" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "Ð’Ñ€ÐµÐ¼Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "Ð’Ñего пользователей" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "Ð’Ñего Ñетей" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "Сетей, к которым приÑоединены клиенты" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "Ð’Ñего Ñоединений Ñ ÐºÐ»Ð¸ÐµÐ½Ñ‚Ð°Ð¼Ð¸" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "Ð’Ñего Ñоединений Ñ IRC" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "Ð¡Ð¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ ÐºÐ»Ð¸ÐµÐ½Ñ‚Ð°Ð¼Ð¸" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "Ð¡Ð¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ IRC" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "Ð’Ñего" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "Пришло" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "Ушло" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "Пользователи" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "Трафик" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "Пользователь" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "Сеть" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "Глобальные наÑтройки" #: webadmin.cpp:93 msgid "Your Settings" msgstr "Мои наÑтройки" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "Трафик" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "Пользователи" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "Ошибка: необходимо Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "Ошибка: пароли не Ñовпадают" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "Ð’Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð½Ðµ может быть меньше 30 Ñекунд!" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "Ðе могу загрузить модуль [{1}]: {2}" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "Ðе могу загрузить модуль [{1}] Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ð°Ð¼Ð¸ [{2}]" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "Ðет такого пользователÑ" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "Ðет такого пользователÑ" #: webadmin.cpp:576 msgid "No such channel" msgstr "Ðет такого канала" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "ПожалуйÑта, не удалÑйте ÑебÑ, ÑамоубийÑтво — не ответ!" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "Пользователь [{1}]" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "Сеть [{1}]" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "Канал [{1}] в Ñети [{2}] Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ [{3}]" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "Канал [{1}]" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "Ðовый канал Ð´Ð»Ñ Ñети [{1}] Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ [{2}]" #: webadmin.cpp:749 msgid "Add Channel" msgstr "Ðовый канал" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "ÐвтоматичеÑки очищать буфер канала" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "ÐвтоматичеÑки очищать буфер канала поÑле воÑпроизведениÑ" #: webadmin.cpp:766 msgid "Detached" msgstr "Отцеплен" #: webadmin.cpp:773 msgid "Enabled" msgstr "Включена" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "Ðеобходимо Ð¸Ð¼Ñ ÐºÐ°Ð½Ð°Ð»Ð°" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "Канал [{1}] уже ÑущеÑтвует" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "Ðе могу добавить канал [{1}]" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "Канал добавлен/изменён, но запиÑать конфигурацию в файл не удалоÑÑŒ" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" "ДоÑтигнуто ограничение на количеÑтво Ñетей. ПопроÑите админиÑтратора поднÑть " "вам лимит или удалите ненужные Ñети в «Моих наÑтройках»" #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "Сеть [{1}] Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ [{2}]" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "ÐÐ¾Ð²Ð°Ñ Ñеть Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ [{1}]" #: webadmin.cpp:911 msgid "Add Network" msgstr "ÐÐ¾Ð²Ð°Ñ Ñеть" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "Ðеобходимо Ð¸Ð¼Ñ Ñети" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "Ðе могу перегрузить модуль [{1}]: {2}" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "Сеть добавлена/изменена, но запиÑать конфигурацию в файл не удалоÑÑŒ" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "У Ñтого Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½ÐµÑ‚ такой Ñети" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "Сеть удалена, но запиÑать конфигурацию в файл не удалоÑÑŒ" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "Ð’ Ñтой Ñети нет такого канала" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "Канал удалён, но запиÑать конфигурацию в файл не удалоÑÑŒ" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "Клон Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ [{1}]" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" "ÐвтоматичеÑки очищать буфер канала поÑле воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ (значение по " "умолчанию Ð´Ð»Ñ Ð½Ð¾Ð²Ñ‹Ñ… каналов)" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "Много клиентов" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "Метка времени в конце" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "Метка времени в начале" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "Запрет загрузки модулей" #: webadmin.cpp:1551 msgid "Admin" msgstr "ÐдминиÑтратор" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "Запрет Ñмены хоÑта" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "ÐвтоматичеÑки очищать буфер личных Ñообщений" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "ÐвтоматичеÑки очищать буфер личных Ñообщений поÑле воÑпроизведениÑ" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "Ошибка: пользователь {1} уже ÑущеÑтвует" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "Ошибка: {1}" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "Пользователь добавлен, но запиÑать конфигурацию в файл не удалоÑÑŒ" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "Пользователь изменён, но запиÑать конфигурацию в файл не удалоÑÑŒ" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "Выберите IPv4, IPv6 или и то, и другое." #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "Выберите IRC, HTTP или и то, и другое." #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "Порт изменён, но запиÑать конфигурацию в файл не удалоÑÑŒ" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "Ðекорректный запроÑ." #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "Указанный порт не найден." #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "ÐаÑтройки изменены, но запиÑать конфигурацию в файл не удалоÑÑŒ" znc-1.7.5/modules/po/notify_connect.pot0000644000175000017500000000056613542151610020402 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: notify_connect.cpp:24 msgid "attached" msgstr "" #: notify_connect.cpp:26 msgid "detached" msgstr "" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "" znc-1.7.5/modules/po/partyline.es_ES.po0000644000175000017500000000160013542151610020167 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/partyline.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "" #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "" #: partyline.cpp:82 msgid "List all open channels" msgstr "" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "" znc-1.7.5/modules/po/controlpanel.it_IT.po0000644000175000017500000005430413542151610020703 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/controlpanel.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "Tipo" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "Variabili" #: controlpanel.cpp:77 msgid "String" msgstr "Stringa" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "Boolean (vero / falso)" #: controlpanel.cpp:79 msgid "Integer" msgstr "Numero intero" #: controlpanel.cpp:80 msgid "Number" msgstr "Numero" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "" "Le seguenti variabili sono disponibili quando utilizzi i comandi Set/Get:" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" "Le seguenti variabili sono disponibili quando utilizzi i camandi SetNetwork/" "GetNetwork:" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" "Le seguenti variabili sono disponibili quando utilizzi i camandi SetChan/" "GetChan:" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" "Puoi usare $user come nome utente e $network come nome del network per " "modificare il tuo nome utente e network." #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "Errore: L'utente [{1}] non esiste!" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "" "Errore: Devi avere i diritti di amministratore per modificare altri utenti!" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "Errore: Non puoi usare $network per modificare altri utenti!" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "Errore: L'utente {1} non ha un nome network [{2}]." #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "Utilizzo: Get [nome utente]" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "Errore: Variabile sconosciuta" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "Utilizzo: Set " #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "Questo bind host è già impostato!" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "Accesso negato!" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "Impostazione fallita, il limite per la dimensione del buffer è {1}" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "La password è stata cambiata" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "Il timeout non può essere inferiore a 30 secondi!" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "Questa sarebbe una cattiva idea!" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "Lingue supportate: {1}" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "Utilizzo: GetNetwork [nome utente] [network]" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" "Errore: Deve essere specificato un network per ottenere le impostazioni di " "un altro utente." #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "Attualmente non sei agganciato ad un network." #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "Errore: Network non valido." #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "Usa: SetNetwork " #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "Utilizzo: AddChan " #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "Errore: L'utente {1} ha già un canale di nome {2}." #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "Il canale {1} per l'utente {2} è stato aggiunto al network {3}." #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" "Impossibile aggiungere il canale {1} per l'utente {2} sul network {3}, " "esiste già?" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "Utilizzo: DelChan " #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" "Errore: L'utente {1} non ha nessun canale corrispondente a [{2}] nel network " "{3}" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "Il canale {1} è eliminato dal network {2} dell'utente {3}" msgstr[1] "I canali {1} sono eliminati dal network {2} dell'utente {3}" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "Utilizzo: GetChan " #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "Errore: Nessun canale corrispondente a [{1}] è stato trovato." #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "" "Utilizzo: SetChan " #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "Nome utente" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "Nome reale" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "è Admin" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "Nick" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "Nick alternativo" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "Ident" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "BindHost" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "No" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "Si" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "" "Errore: Devi avere i diritti di amministratore per aggiungere nuovi utenti!" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "Utilizzo: AddUser " #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "Errore: L'utente {1} è già esistente!" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "Errore: Utente non aggiunto: {1}" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "L'utente {1} è aggiunto!" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "" "Errore: Devi avere i diritti di amministratore per rimuovere gli utenti!" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "Utilizzo: DelUser " #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "Errore: Non puoi eliminare te stesso!" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "Errore: Errore interno!" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "Utente {1} eliminato!" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "" "Usa\n" "Utilizzo: CloneUser " #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "Errore: Clonazione fallita: {1}" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "Utilizzo: AddNetwork [utente] network" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "Numero limite di network raggiunto. Chiedi ad un amministratore di aumentare " "il limite per te, oppure elimina i network non necessari usando /znc " "DelNetwork " #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "Errore: L'utente {1} ha già un network con il nome {2}" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "Il network {1} è stato aggiunto all'utente {2}." #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "Errore: Il network [{1}] non può essere aggiunto per l'utente {2}: {3}" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "Utilizzo: DelNetwork [utente] network" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "" "Il network attualmente attivo può essere eliminato tramite lo stato {1}" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "Il network {1} è stato eliminato per l'utente {2}." #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "Errore: Il network {1} non può essere eliminato per l'utente {2}." #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "Network" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "Su IRC" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "Server IRC" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "Utente IRC" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "Canali" #: controlpanel.cpp:1143 msgid "No networks" msgstr "Nessun network" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "" "Utilizzo: AddServer [[+]porta] [password]" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "Aggiunto il Server IRC {1} al network {2} per l'utente {3}." #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" "Errore: Impossibile aggiungere il server IRC {1} al network {2} per l'utente " "{3}." #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "" "Utilizzo: DelServer [[+]porta] [password]" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "Eliminato il Server IRC {1} del network {2} per l'utente {3}." #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" "Errore: Impossibile eliminare il server IRC {1} dal network {2} per l'utente " "{3}." #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "Utilizzo: Reconnect " #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "Il network {1} dell'utente {2} è in coda per una riconnessione." #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "Utilizzo: Disconnect " #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "Chiusa la connessione IRC al network {1} dell'utente {2}." #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "Richiesta" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "Rispondi" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "Nessuna risposta CTCP per l'utente {1} è stata configurata" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "Risposte CTCP per l'utente {1}:" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "Utilizzo: AddCTCP [utente] [richiesta] [risposta]" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" "Questo farà sì che ZNC risponda al CTCP invece di inoltrarlo ai client." #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "Una risposta vuota causerà il blocco della richiesta CTCP." #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "Le richieste CTCP {1} all'utente {2} verranno ora bloccate." #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "Le richieste CTCP {1} all'utente {2} ora avranno risposta: {3}" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "Utilizzo: DelCTCP [utente] [richiesta]" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "" "Le richieste CTCP {1} all'utente {2} verranno ora inviate al client IRC" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" "Le richieste CTCP {1} all'utente {2} verranno inviate ai client IRC (nulla è " "cambiato)" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "Il caricamento dei moduli è stato disabilitato." #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "Errore: Impossibile caricare il modulo {1}: {2}" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "Modulo caricato: {1}" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "Errore: Impossibile ricaricare il modulo {1}: {2}" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "Modulo ricaricato: {1}" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "Errore: Impossibile caricare il modulo {1} perché è già stato caricato" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "Utilizzo: LoadModule [argomenti]" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "" "Utilizzo: LoadNetModule [argomenti]" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "Per favore usa il comando /znc unloadmod {1}" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "Errore: Impossibile rimuovere il modulo {1}: {2}" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "Rimosso il modulo: {1}" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "Utilizzo: UnloadModule " #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "Utilizzo: UnloadNetModule " #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "Nome" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "Argomenti" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "L'utente {1} non ha moduli caricati." #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "Moduli caricati per l'utente {1}:" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "Il network {1} dell'utente {2} non ha moduli caricati." #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "Moduli caricati per il network {1} dell'utente {2}:" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "[comando] [variabile]" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "Mostra la guida corrispondente a comandi e variabili" #: controlpanel.cpp:1559 msgid " [username]" msgstr " [nome utente]" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "Mostra il valore della variabile per l'utente specificato o corrente" #: controlpanel.cpp:1562 msgid " " msgstr " " #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "Imposta il valore della variabile per l'utente specificato" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr " [nome utente] [network]" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "Mostra il valore della variabaile del network specificato" #: controlpanel.cpp:1568 msgid " " msgstr " " #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "Imposta il valore della variabile per il network specificato" #: controlpanel.cpp:1571 msgid " [username] " msgstr " [nome utente] " #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "Mostra il valore della variabaile del canale specificato" #: controlpanel.cpp:1575 msgid " " msgstr " " #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "Imposta il valore della variabile per il canale specificato" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr " " #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "Aggiunge un nuovo canale" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "Elimina un canale" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "Elenca gli utenti" #: controlpanel.cpp:1586 msgid " " msgstr " " #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "Aggiunge un nuovo utente" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "Elimina un utente" #: controlpanel.cpp:1591 msgid " " msgstr " " #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "Clona un utente" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr " " #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "Aggiunge un nuovo server IRC all'utente specificato o corrente" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "Elimina un server IRC dall'utente specificato o corrente" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr " " #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "Cicla la connessione al server IRC dell'utente" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "Disconnette l'utente dal proprio server IRC" #: controlpanel.cpp:1606 msgid " [args]" msgstr " [argomenti]" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "Carica un modulo per un utente" #: controlpanel.cpp:1609 msgid " " msgstr " " #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "Rimuove un modulo da un utente" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "Mostra un elenco dei moduli caricati per un utente" #: controlpanel.cpp:1616 msgid " [args]" msgstr " [argomenti]" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "Carica un modulo per un network" #: controlpanel.cpp:1620 msgid " " msgstr " " #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "Rimuove un modulo da un network" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "Mostra un elenco dei moduli caricati per un network" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "Elenco delle risposte configurate per il CTCP" #: controlpanel.cpp:1629 msgid " [reply]" msgstr " [risposta]" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "Configura una nuova risposta CTCP" #: controlpanel.cpp:1632 msgid " " msgstr " " #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "Rimuove una risposta CTCP" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "[nome utente] " #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "Aggiunge un network ad un utente" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "Elimina un network da un utente" #: controlpanel.cpp:1643 msgid "[username]" msgstr "[nome utente]" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "Elenca tutti i network di un utente" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" "Configurazione dinamica attraverso IRC. Permette di modificare solo se " "stessi quando non si è amministratori ZNC." znc-1.7.5/modules/po/notify_connect.id_ID.po0000644000175000017500000000125413542151610021160 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/notify_connect.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: notify_connect.cpp:24 msgid "attached" msgstr "" #: notify_connect.cpp:26 msgid "detached" msgstr "" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "" znc-1.7.5/modules/po/ctcpflood.es_ES.po0000644000175000017500000000407413542151610020145 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/ctcpflood.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "Ajustar límite de segundos" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "Ajustar límite de líneas" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "Muestra los límites actuales" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "Límite alcanzado por {1}, bloqueando todos los CTCP" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "Uso: Secs " #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "Uso: Lines " #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "1 mensaje CTCP" msgstr[1] "{1} mensajes CTCP" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "cada segundo" msgstr[1] "cada {1} segundos" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "El límite actual es {1} {2}" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" "Este módulo de usuario tiene de cero a dos parámetros. El primero define el " "número de líneas en el que la protección de flood es activada. El segundo es " "el tiempo en segundos durante el cual se alcanza el número de lineas. El " "ajuste predeterminado es 4 CTCPs en 2 segundos" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "No reenviar floods CTCP a los clientes" znc-1.7.5/modules/po/adminlog.pt_BR.po0000644000175000017500000000255613542151610017775 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/adminlog.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "" #: adminlog.cpp:31 msgid " [path]" msgstr "" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "" #: adminlog.cpp:142 msgid "Access denied" msgstr "Acesso negado" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "" #: adminlog.cpp:170 msgid "Unknown target" msgstr "Alvo desconhecido" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "" znc-1.7.5/modules/po/nickserv.id_ID.po0000644000175000017500000000377313542151610017773 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/nickserv.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: nickserv.cpp:31 msgid "Password set" msgstr "Kata sandi diatur" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "Atur nama NickServ" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "Tidak ada perintah yang dapat diedit. Lihat daftar ViewCommands." #: nickserv.cpp:63 msgid "Ok" msgstr "Oke" #: nickserv.cpp:68 msgid "password" msgstr "sandi" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "Atur kata sandi nickserv anda" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "Bersihkan kata sandi nickserv anda" #: nickserv.cpp:72 msgid "nickname" msgstr "nickname" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" "Atur nama NickServ (Berguna pada jaringan seperti EpiKnet, di mana NickServ " "diberi nama Themis" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "Kembalikan nama NickServ ke standar (NickServ)" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "Tampilkan pola untuk garis, yang dikirim ke NickServ" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "cmd new-pattern" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "Atur pola untuk perintah" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "Silahkan masukkan kata sandi nickserv anda." #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "Auths anda dengan NickServ (lebih memilih modul SASL sebagai gantinya)" znc-1.7.5/modules/po/sample.id_ID.po0000644000175000017500000000423313542151610017420 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/sample.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "" #: sample.cpp:50 msgid "Sample job done" msgstr "" #: sample.cpp:65 msgid "TEST!!!!" msgstr "" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "" #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "" #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "" #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "" #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "" znc-1.7.5/modules/po/modperl.bg_BG.po0000644000175000017500000000074013542151610017570 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/modperl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/route_replies.ru_RU.po0000644000175000017500000000273013542151610021104 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/route_replies.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "" #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "" #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "" znc-1.7.5/modules/po/keepnick.bg_BG.po0000644000175000017500000000220213542151610017712 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/keepnick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "" #: keepnick.cpp:44 msgid "Show the current state" msgstr "" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "" znc-1.7.5/modules/po/watch.id_ID.po0000644000175000017500000001071113542151610017243 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/watch.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "" #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "" #: watch.cpp:397 msgid "Disabled all entries." msgstr "" #: watch.cpp:398 msgid "Enabled all entries." msgstr "" #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "" #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "" #: watch.cpp:593 msgid "Id {1} removed." msgstr "" #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "" #: watch.cpp:609 msgid "List" msgstr "" #: watch.cpp:611 msgid "List all entries being watched." msgstr "" #: watch.cpp:614 msgid "Dump" msgstr "" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "" #: watch.cpp:620 msgid "Del " msgstr "" #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "" #: watch.cpp:625 msgid "Clear" msgstr "" #: watch.cpp:626 msgid "Delete all entries." msgstr "" #: watch.cpp:629 msgid "Enable " msgstr "" #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "" #: watch.cpp:633 msgid "Disable " msgstr "" #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "" #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "" #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "" #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "" #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "" #: watch.cpp:652 msgid "Buffer [Count]" msgstr "" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "" #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "" #: watch.cpp:664 msgid "Help" msgstr "" #: watch.cpp:665 msgid "This help." msgstr "" #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "" #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "" znc-1.7.5/modules/po/admindebug.fr_FR.po0000644000175000017500000000275213542151610020270 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/admindebug.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "Activer le débogage" #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "Désactiver le débogage" #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "Afficher le statut du mode de déboguage" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "Accès refusé !" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" "Échec, ZNC n'est pas lancé dans un TTY (peut-être que l'option --foreground " "est active ?)" #: admindebug.cpp:66 msgid "Already enabled." msgstr "Déjà activé." #: admindebug.cpp:68 msgid "Already disabled." msgstr "Déjà désactivé." #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "Le déboguage est actif." #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "Le débogage est inactif." #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "Journaux envoyés dans stdout." #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "Activer le déboguage dynamiquement." znc-1.7.5/modules/po/block_motd.id_ID.po0000644000175000017500000000147313542151610020257 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/block_motd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: block_motd.cpp:26 msgid "[]" msgstr "" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "" #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "" znc-1.7.5/modules/po/sample.de_DE.po0000644000175000017500000000500713542151610017410 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/sample.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "Beispielauftrag abgebrochen" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "Beispielauftrag zerstört" #: sample.cpp:50 msgid "Sample job done" msgstr "Beispielauftrag erledigt" #: sample.cpp:65 msgid "TEST!!!!" msgstr "TEST!!!!" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "Ich werde mit diesen Argumenten geladen: {1}" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "Ich bin entladen!" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "" #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "" #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "" msgstr[1] "" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "{1} ist jetzt als {2} bekannt" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "{1} hat das Thema von {2} auf {3} geändert" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "Hallo, ich bin dein freundliches Beispiel-Module." #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "Modulbeschreibung kommt hier hin." #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "Als Muster zum Schreiben von Modulen zu verwenden" znc-1.7.5/modules/po/dcc.it_IT.po0000644000175000017500000001451113542151610016730 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/dcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: dcc.cpp:88 msgid " " msgstr " " #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "Invia un file da ZNC a qualcuno" #: dcc.cpp:91 msgid "" msgstr "" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "Invia un file da ZNC al tuo client" #: dcc.cpp:94 msgid "List current transfers" msgstr "Elenca i trasferimenti in corso" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "Devi essere amministratore per usare il modulo DCC" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "Sto tentando di inviare [{1}] a [{2}]." #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "Ricezione del file [{1}] dall'utente [{2}]: File già esistente." #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "Stò tentando di connettermi a [{1} {2}] per scaricare [{3}] da [{4}]." #: dcc.cpp:179 msgid "Usage: Send " msgstr "Utilizzo: Send " #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "Percorso (path) illegale." #: dcc.cpp:199 msgid "Usage: Get " msgstr "Utilizzo: Get " #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "Tipo" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "Stato" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "Velocità" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "Nick" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "IP" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "File" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "In invio" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "In ricezione" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "In attesa" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "{1} KiB/s" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "Non hai trasferimenti DCC attivi." #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "" "Sto tentando di riprendere l'invio della posizione {1} del file [{2}] per " "[{3}]" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "" "Impossibile riprendere il file [{1}] per [{2}]: non sto inviando nulla." #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "File DCC errato (bad): {1}" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "Invio del file [{1}] all'utente [{2}]: File non aperto!" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "Ricezione del file [{1}] dall'utente [{2}]: File non aperto!" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "Invio del file [{1}] all'utente [{2}] : Connessione rifiutata." #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "Ricezione del file [{1}] dall'utente [{2}]: Connessione rifiutata." #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "Invio del file [{1}] all'utente [{2}]: Tempo scaduto (Timeout)." #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "Ricezione del file [{1}] dall'utente [{2}]: Tempo scaduto (Timeout)." #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "Invio del file [{1}] all'utente [{2}]: Errore di socket {3}: {4}" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "Ricezione del file [{1}] dall'utente [{2}]: Errore di socket {3}: {4}" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "Invio del file [{1}] all'utente [{2}]: Trasferimento avviato." #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "Ricezione del file [{1}] dall'utente [{2}]: Trasferimento avviato." #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "Invio del file [{1}] all'utente [{2}]: Troppi dati!" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "Ricezione del file [{1}] dall'utente [{2}]: Troppi dati!" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "L'invio del file [{1}] all'utente [{2}] completato a {3} KiB/s" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "" "La ricezione del file [{1}] inviato da [{2}] è stata completata a {3} KiB/s" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "Invio del file [{1}] all'utente [{2}]: File chiuso prematuramente." #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "" "Ricezione del file [{1}] dall'utente [{2}]: File chiuso prematuramente." #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "Invio del file [{1}] all'utente [{2}]: Errore di lettura del file." #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "" "Ricezione del file [{1}] dall'utente [{2}]: Errore di lettura del file." #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "Invio del file [{1}] all'utente [{2}]: Impossibile aprire il file." #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "" "Ricezione del file [{1}] dall'utente [{2}]: Impossibile aprire il file." #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "" "Ricezione del file [{1}] dall'utente [{2}]: Impossibile aprire il file." #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "Invio del file [{1}] all'utente [{2}]: Non è un file." #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "Invio del file [{1}] all'utente [{2}]: Impossibile aprire il file." #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "Invio del file [{1}] all'utente [{2}]: File troppo grande (>4 GiB)." #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "Questo modulo ti consente di trasferire file da e verso ZNC" znc-1.7.5/modules/po/clientnotify.pt_BR.po0000644000175000017500000000327313542151610020707 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/clientnotify.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" msgstr[1] "" #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "" #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "" #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "" #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "" #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" znc-1.7.5/modules/po/clearbufferonmsg.id_ID.po0000644000175000017500000000102013542151610021452 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/clearbufferonmsg.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "" znc-1.7.5/modules/po/sample.pt_BR.po0000644000175000017500000000427513542151610017464 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/sample.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "" #: sample.cpp:50 msgid "Sample job done" msgstr "" #: sample.cpp:65 msgid "TEST!!!!" msgstr "" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "" #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "" #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "" msgstr[1] "" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "" #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "" #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "" znc-1.7.5/modules/po/awaystore.fr_FR.po0000644000175000017500000000424113542151610020202 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/awaystore.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "" #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "" #: awaystore.cpp:113 msgid "Message erased" msgstr "" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" znc-1.7.5/modules/po/simple_away.de_DE.po0000644000175000017500000000374313542151610020446 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/simple_away.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: simple_away.cpp:56 msgid "[]" msgstr "" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "" #: simple_away.cpp:136 msgid "Away reason set" msgstr "" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" znc-1.7.5/modules/po/certauth.id_ID.po0000644000175000017500000000406313542151610017757 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/certauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "" #: certauth.cpp:31 msgid "[pubkey]" msgstr "" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" #: certauth.cpp:35 msgid "id" msgstr "" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "" #: certauth.cpp:37 msgid "List your public keys" msgstr "" #: certauth.cpp:39 msgid "Print your current key" msgstr "" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "" #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "" #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "" #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "" #: certauth.cpp:215 msgid "Removed" msgstr "" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "" znc-1.7.5/modules/po/perleval.de_DE.po0000644000175000017500000000135513542151610017743 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/perleval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "Führt Perl-Code aus" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "Nur Administratoren können dieses Modul verwenden" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "Fehler: %s" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "Ergebnis: %s" znc-1.7.5/modules/po/raw.nl_NL.po0000644000175000017500000000076013542151610016763 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "Laat al het onbewerkte verkeer zien" znc-1.7.5/modules/po/awaystore.pt_BR.po0000644000175000017500000000426413542151610020217 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/awaystore.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "" #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "" #: awaystore.cpp:113 msgid "Message erased" msgstr "" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" znc-1.7.5/modules/po/alias.fr_FR.po0000644000175000017500000000577513542151610017272 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/alias.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "paramètre requis absent : {1}" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "Alias créé : {1}" #: alias.cpp:203 msgid "Alias already exists." msgstr "L'alias existe déjà." #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "Alias supprimé : {1}" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "L'alias n'existe pas." #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "Alias modifié." #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "Indice invalide." #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "Il n'existe aucun alias." #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "L'alias {1} n'existe pas" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr ", " #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "Actions pour l'alias {1} :" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "Fin des actions pour l'alias {1}." #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "Créé un nouvel alias vide nommé nom." #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "Supprime un alias existant." #: alias.cpp:343 msgid " " msgstr " " #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "Ajoute une ligne à un alias existant." #: alias.cpp:346 msgid " " msgstr " " #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "Insère une ligne dans un alias existant." #: alias.cpp:349 msgid " " msgstr " " #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "Supprime une ligne d'un alias existant." #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "Supprime toutes les lignes d'un alias existant." #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "Liste les alias par nom." #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "Indique les actions réalisées par un alias." #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "Génère une liste des commandes pour copier la configuration des alias." #: alias.cpp:374 msgid "Clearing all of them!" msgstr "Nettoie tous les alias !" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "Fournit un support des alias côté bouncer." znc-1.7.5/modules/po/block_motd.fr_FR.po0000644000175000017500000000147513542151610020307 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/block_motd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: block_motd.cpp:26 msgid "[]" msgstr "" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "" #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "" znc-1.7.5/modules/po/cert.pt_BR.po0000644000175000017500000000336713542151610017141 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/cert.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "" #: cert.cpp:28 msgid "Pem file deleted" msgstr "" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "" #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "" #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "" #: cert.cpp:54 msgid "Show the current certificate" msgstr "" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "" znc-1.7.5/modules/po/admindebug.de_DE.po0000644000175000017500000000271713542151610020233 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/admindebug.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "Debugmodus aktivieren" #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "Debugmodus deaktivieren" #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "Zeige den Debugstatus an" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "Zugriff verweigert!" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" "Fehler: Der Prozess muss in einem TTY laufen (läuft ZNC mit dem Parameter --" "foreground?)" #: admindebug.cpp:66 msgid "Already enabled." msgstr "Bereits aktiviert." #: admindebug.cpp:68 msgid "Already disabled." msgstr "Bereits deaktiviert." #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "Debuggingmodus ist an." #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "Debuggingmodus ist aus." #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "Logge nach: stdout." #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "Aktiviere den Debugmodus dynamisch." znc-1.7.5/modules/po/notify_connect.fr_FR.po0000644000175000017500000000125613542151610021210 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/notify_connect.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: notify_connect.cpp:24 msgid "attached" msgstr "" #: notify_connect.cpp:26 msgid "detached" msgstr "" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "" znc-1.7.5/modules/po/dcc.es_ES.po0000644000175000017500000001370713542151610016724 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/dcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: dcc.cpp:88 msgid " " msgstr " " #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "Enviar un fichero desde ZNC" #: dcc.cpp:91 msgid "" msgstr "" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "Enviar un archivo desde ZNC a tu cliente" #: dcc.cpp:94 msgid "List current transfers" msgstr "Mostrar transferencias actuales" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "Debes ser admin para usar el módulo DCC" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "Intentando enviar [{1}] a [{2}]." #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "Recibiendo [{1}] de [{2}]: ya existe el archivo." #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "Intentando conectar a [{1} {2}] para descargar [{3}] desde [{4}]." #: dcc.cpp:179 msgid "Usage: Send " msgstr "Uso: Send " #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "Ruta inválida." #: dcc.cpp:199 msgid "Usage: Get " msgstr "Uso: Get " #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "Tipo" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "Estado" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "Velocidad" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "Nick" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "IP" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "Archivo" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "Enviando" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "Obteniendo" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "Esperando" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "{1} KiB/s" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "No tienes ninguna transferencia DCC activa." #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "" "Intentando restablecer envío desde la posición {1} del archivo [{2}] para " "[{3}]" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "" "No se ha podido restablecer el archivo [{1}] para [{2}]: no se está enviando " "nada." #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "Archivo DCC corrupto: {1}" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "Enviando [{1}] a [{2}]: archivo no abierto" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "Recibiendo [{1}] de [{2}]: archivo no abierto" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "Enviando [{1}] a [{2}]: conexión rechazada." #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "Recibiendo [{1}] de [{2}]: conexión rechazada." #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "Enviando [{1}] a [{2}]: tiempo de espera agotado." #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "Recibiendo [{1}] de [{2}]: tiempo de espera agotado." #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "Enviando [{1}] a [{2}]: error de socket {3}: {4}" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "Recibiendo [{1}] de [{2}]: error de socket {3}: {4}" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "Enviando [{1}] a [{2}]: transferencia iniciada." #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "Recibiendo [{1}] de [{2}]: transferencia iniciada." #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "Enviando [{1}] a [{2}]: demasiados datos" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "Recibiendo [{1}] de [{2}]: demasiados datos" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "Envío de [{1}] a [{2}] completado en {3} KiB/s" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "Recepción [{1}] de [{2}] completada a {3} KiB/s" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "Enviando [{1}] a [{2}]: archivo cerrado prematuramente." #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "Recibiendo [{1}] de [{2}]: archivo cerrado prematuramente." #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "Enviando [{1}] a [{2}]: error al leer archivo." #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "Recibiendo [{1}] de [{2}]: error al leer archivo." #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "Enviando [{1}] a [{2}]: no se ha podido abrir el archivo." #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "Recibiendo [{1}] de [{2}]: no se ha podido abrir el archivo." #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "Recibiendo [{1}] de [{2}]: no se ha podido abrir el archivo." #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "Enviando [{1}] a [{2}]: no es un archivo." #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "Enviando [{1}] a [{2}]: no se ha podido abrir el archivo." #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "Enviando [{1}] a [{2}]: archivo demasiado grande (>4 GiB)." #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "Este módulo permite transferir archivos a y desde ZNC" znc-1.7.5/modules/po/autoreply.it_IT.po0000644000175000017500000000236113542151610020223 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/autoreply.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "Imposta una nuova risposta" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "Mostra l'attuale risposta alle query" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "La risposta attuale è: {1} ({2})" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "Nuova risposta impostata: {1} ({2})" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" "Puoi specificare un testo di risposta. Essa viene utilizzata automaticamente " "per rispondere alle query se non si è connessi a ZNC." #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "Risponde alle query quando sei assente" znc-1.7.5/modules/po/CMakeLists.txt0000644000175000017500000000162113542151610017366 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(translation) foreach(modpath ${actual_modules}) get_filename_component(mod "${modpath}" NAME_WE) get_filename_component(module "${modpath}" NAME) translation(SHORT "${mod}" FULL "znc-${mod}" SOURCES "${module}" TMPLDIRS "${CMAKE_CURRENT_SOURCE_DIR}/../data/${mod}/tmpl") endforeach() znc-1.7.5/modules/po/cert.it_IT.po0000644000175000017500000000452613542151610017141 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/cert.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "qui" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" "Hai già un certificato impostato, utilizza il modulo sottostante per " "sovrascrivere il certificato corrente. In alternativa, fai click su {1} per " "eliminare il certificato." #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "Non hai ancora un certificato." #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "Certificato" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "File PEM:" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "Aggiornare" #: cert.cpp:28 msgid "Pem file deleted" msgstr "File PEM eliminato" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "" "Il file pem non esiste o si è verificato un errore durante l'eliminazione " "del file pem." #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "Hai un certificato in {1}" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "" "Non hai un certificato. Per favore usa l'interfaccia web per aggiungere un " "certificato" #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "In alternativa puoi metterne uno a {1}" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "Elimina il certificato corrente" #: cert.cpp:54 msgid "Show the current certificate" msgstr "Mostra il certificato corrente" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "Utilizza un certificato ssl per connetterti al server" znc-1.7.5/modules/po/pyeval.id_ID.po0000644000175000017500000000104113542151610017431 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/pyeval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "" #: pyeval.py:82 msgid "Evaluates python code" msgstr "" znc-1.7.5/modules/po/cyrusauth.nl_NL.po0000644000175000017500000000512413542151610020220 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/cyrusauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "Laat huidige instellingen zien" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "yes|clone |no" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" "Maak ZNC gebruikers wanneer deze voor het eerst succesvol inloggen, " "optioneel van een sjabloon" #: cyrusauth.cpp:56 msgid "Access denied" msgstr "Toegang geweigerd" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "Negeer ongeldige SASL wwcheck methode: {1}" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "Ongeldige SASL wwcheck methode genegeerd" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "Benodigd een wwcheck methode als argument (saslauthd, auxprop)" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "SASL kon niet worden geïnitalizeerd - Stoppen met opstarten" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "We zullen geen gebruikers aanmaken wanner zij voor het eerst inloggen" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" "We zullen gebruikers aanmaken wanneer zij voor het eerst inloggen, hiervoor " "gebruiken we sjabloon [{1}]" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "We zullen gebruikers aanmaken wanneer zij voor het eerst inloggen" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "" "Gebruik: CreateUsers yes, CreateUsers no, of CreateUsers clone " "" #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" "Deze globale module accepteert tot en met twee argumenten - de methoden van " "identificatie - auxprop en saslauthd" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" "Sta gebruikers toe te identificeren via SASL wachtwoord verificatie methode" znc-1.7.5/modules/po/buffextras.de_DE.po0000644000175000017500000000231413542151610020276 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/buffextras.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: buffextras.cpp:45 msgid "Server" msgstr "Server" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "{1} hat Modus gesetzt: {2} {3}" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "{1} hat {2} mit folgendem Grund gekickt: {3}" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "{1} hat sich getrennt: {2}" #: buffextras.cpp:73 msgid "{1} joined" msgstr "{1} ist beigetreten" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "{1} hat verlassen: {2}" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "{1} ist jetzt als {2} bekannt" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "{1} änderte das Thema zu: {2}" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "Fügt Joins, Parts, usw. zum Playback-Puffer hinzu" znc-1.7.5/modules/po/stripcontrols.ru_RU.po0000644000175000017500000000130013542151610021140 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/stripcontrols.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "" znc-1.7.5/modules/po/modules_online.es_ES.po0000644000175000017500000000105113542151610021174 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/modules_online.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "Hace que los *módulos de ZNC aparezcan 'conectados'." znc-1.7.5/modules/po/sasl.id_ID.po0000644000175000017500000000652113542151610017103 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/sasl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" #: sasl.cpp:62 msgid "search" msgstr "" #: sasl.cpp:62 msgid "Generate this output" msgstr "" #: sasl.cpp:64 msgid "[ []]" msgstr "" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "" #: sasl.cpp:72 msgid "[yes|no]" msgstr "" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "" #: sasl.cpp:114 msgid "Password was supplied" msgstr "" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "" #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "" #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "" #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "" #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "" znc-1.7.5/modules/po/log.pot0000644000175000017500000000433313542151610016136 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "" #: log.cpp:62 msgid "Clear all logging rules" msgstr "" #: log.cpp:64 msgid "List all logging rules" msgstr "" #: log.cpp:67 msgid " true|false" msgstr "" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "" #: log.cpp:143 msgid "Usage: SetRules " msgstr "" #: log.cpp:144 msgid "Wildcards are allowed" msgstr "" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "" #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "" msgstr[1] "" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "" #: log.cpp:196 msgid "Will log joins" msgstr "" #: log.cpp:196 msgid "Will not log joins" msgstr "" #: log.cpp:197 msgid "Will log quits" msgstr "" #: log.cpp:197 msgid "Will not log quits" msgstr "" #: log.cpp:199 msgid "Will log nick changes" msgstr "" #: log.cpp:199 msgid "Will not log nick changes" msgstr "" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "" #: log.cpp:211 msgid "Logging joins" msgstr "" #: log.cpp:211 msgid "Not logging joins" msgstr "" #: log.cpp:212 msgid "Logging quits" msgstr "" #: log.cpp:212 msgid "Not logging quits" msgstr "" #: log.cpp:213 msgid "Logging nick changes" msgstr "" #: log.cpp:214 msgid "Not logging nick changes" msgstr "" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "" #: log.cpp:563 msgid "Writes IRC logs." msgstr "" znc-1.7.5/modules/po/flooddetach.es_ES.po0000644000175000017500000000506413542151610020444 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/flooddetach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "Muestra los límites actuales" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "Muestra o define el número de segundos en el intervalo de tiempo" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "Muestra o define el número de líneas en el intervalo de tiempo" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "Muestra o ajusta los avisos al adjuntarte o separarte de un flood" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "Flood en {1} finalizado, readjuntando..." #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "El canal {1} ha sido inundado, has sido separado" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "1 línea" msgstr[1] "{1} líneas" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "cada segundo" msgstr[1] "cada {1} segundos" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "El límite actual es {1} {2}" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "El límite de segundos es {1}" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "Ajustado límite de segundos a {1}" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "El límite de líneas es {1}" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "Ajustado límite de líneas a {1}" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "Los mensajes del módulo están desactivados" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "Los mensajes del módulo están activados" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" "Este módulo de usuario tiene hasta dos argumentos: el número de mensajes y " "los segundos." #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "Separarse de canales cuando son inundados" znc-1.7.5/modules/po/route_replies.pt_BR.po0000644000175000017500000000247613542151610021065 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/route_replies.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "" #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "" #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "" znc-1.7.5/modules/po/autocycle.id_ID.po0000644000175000017500000000257013542151610020131 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/autocycle.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "" #: autocycle.cpp:33 msgid "List all entries" msgstr "" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "" #: autocycle.cpp:100 msgid "You have no entries." msgstr "" #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "" #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" znc-1.7.5/modules/po/cert.bg_BG.po0000644000175000017500000000335013542151610017063 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/cert.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "" #: cert.cpp:28 msgid "Pem file deleted" msgstr "" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "" #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "" #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "" #: cert.cpp:54 msgid "Show the current certificate" msgstr "" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "" znc-1.7.5/modules/po/alias.pot0000644000175000017500000000374013542151610016447 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "" #: alias.cpp:203 msgid "Alias already exists." msgstr "" #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "" #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "" #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "" #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "" #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr "" #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "" #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "" #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "" #: alias.cpp:343 msgid " " msgstr "" #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "" #: alias.cpp:346 msgid " " msgstr "" #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "" #: alias.cpp:349 msgid " " msgstr "" #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "" #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "" #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "" #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "" #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "" #: alias.cpp:374 msgid "Clearing all of them!" msgstr "" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "" znc-1.7.5/modules/po/imapauth.id_ID.po0000644000175000017500000000105713542151610017750 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/imapauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "" znc-1.7.5/modules/po/route_replies.bg_BG.po0000644000175000017500000000245713542151610021016 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/route_replies.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "" #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "" #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "" znc-1.7.5/modules/po/shell.de_DE.po0000644000175000017500000000150613542151610017236 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/shell.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "Fehler beim ausführen: {1}" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "Du musst Administrator sein, um das Shell-Modul zu verwenden" #: shell.cpp:169 msgid "Gives shell access" msgstr "Gibt Shell-Zugriff" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "Shell-Zugriff gibt. Nur ZNC Admins können es verwenden." znc-1.7.5/modules/po/listsockets.pt_BR.po0000644000175000017500000000433513542151610020547 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/listsockets.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "" #: listsockets.cpp:62 msgid "[-n]" msgstr "" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "" #: listsockets.cpp:96 msgid "List sockets" msgstr "" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "" #: listsockets.cpp:142 msgid "Listener" msgstr "" #: listsockets.cpp:144 msgid "Inbound" msgstr "" #: listsockets.cpp:147 msgid "Outbound" msgstr "" #: listsockets.cpp:149 msgid "Connecting" msgstr "" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "" #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "" znc-1.7.5/modules/po/notify_connect.it_IT.po0000644000175000017500000000146013542151610021217 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/notify_connect.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: notify_connect.cpp:24 msgid "attached" msgstr "attaccato" #: notify_connect.cpp:26 msgid "detached" msgstr "distaccato" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "{1} {2} da {3}" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "" "Notifica a tutti gli utenti amministratori quando un client si connette o si " "disconnette." znc-1.7.5/modules/po/watch.es_ES.po0000644000175000017500000001420313542151610017271 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/watch.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "Todas las entradas eliminadas." #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "Límite de búfer configurada a {1}" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "Comando desconocido: {1}" #: watch.cpp:397 msgid "Disabled all entries." msgstr "Deshabilitadas todas las entradas." #: watch.cpp:398 msgid "Enabled all entries." msgstr "Habilitadas todas las entradas." #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "Id no válido" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "Id {1} deshabilitado" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "Id {1} habilitado" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "Define DetachedClientOnly para todas las entradas a Yes" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "Define DetachedClientOnly para todas las entradas a No" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "Id {1} ajustado a Sí" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "Id {1} ajustado a No" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "Define DetachedChannelOnly para todas las entradas a Yes" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "Define DetachedChannelOnly para todas las entradas a No" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "Id" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "Máscara" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "Objetivo" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "Patrón" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "Fuentes" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "Desactivado" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "DetachedClientOnly" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "DetachedChannelOnly" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "Sí" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "No" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "No tienes entradas." #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "Fuentes definidas para el id {1}." #: watch.cpp:593 msgid "Id {1} removed." msgstr "Id {1} eliminado." #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "Comando" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "Descripción" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "Add [objetivo] [patrón]" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "Se usa para añadir una entrada a la lista de watch." #: watch.cpp:609 msgid "List" msgstr "Lista" #: watch.cpp:611 msgid "List all entries being watched." msgstr "Listar todas las entradas vigiladas." #: watch.cpp:614 msgid "Dump" msgstr "Volcado" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "Volcar una lista de todas las entradas para usar luego." #: watch.cpp:620 msgid "Del " msgstr "Del " #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "Elimina un id de la lista de entradas a vigilar." #: watch.cpp:625 msgid "Clear" msgstr "Borrar" #: watch.cpp:626 msgid "Delete all entries." msgstr "Borrar todas las entradas." #: watch.cpp:629 msgid "Enable " msgstr "Enable " #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "Habilita un entrada deshabilitada." #: watch.cpp:633 msgid "Disable " msgstr "Disable " #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "Deshabilita (pero no elimina) una entrada." #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "SetDetachedClientOnly " #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "Habilita o deshabilita clientes desvinculados solo para una entrada." #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "SetDetachedChannelOnly " #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "Habilita o deshabilita canales desvinculados solo para una entrada." #: watch.cpp:652 msgid "Buffer [Count]" msgstr "Búfer [Count]" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "" "Muestra/define la cantidad de líneas almacenadas en búfer mientras se está " "desvinculado." #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "SetSources [#canal privado #canal* !#canal]" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "Establece los canales fuente a controlar." #: watch.cpp:664 msgid "Help" msgstr "Ayuda" #: watch.cpp:665 msgid "This help." msgstr "Esta ayuda." #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "La entrada para {1} ya existe." #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "Añadiendo entrada: {1} controlando {2} -> {3}" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "Watch: no hay suficientes argumentos, Prueba Help" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "ATENCIÓN: entrada no válida encontrada durante la carga" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "Copia la actividad de un usuario específico en una ventana separada" znc-1.7.5/modules/po/controlpanel.pt_BR.po0000644000175000017500000003610713542151610020702 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/controlpanel.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "" #: controlpanel.cpp:77 msgid "String" msgstr "" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "" #: controlpanel.cpp:79 msgid "Integer" msgstr "" #: controlpanel.cpp:80 msgid "Number" msgstr "" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "" #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "" #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "" #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "" #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "" #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "" #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "" #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "" #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "" #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "" msgstr[1] "" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "" #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "" #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "" #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "" #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "" #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "" #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "" #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "" #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "" #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "" #: controlpanel.cpp:1143 msgid "No networks" msgstr "" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "" #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "" #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "" #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "" #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "" #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "" #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "" #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "" #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "" #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "" #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "" #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "" #: controlpanel.cpp:1559 msgid " [username]" msgstr "" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "" #: controlpanel.cpp:1562 msgid " " msgstr "" #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr "" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "" #: controlpanel.cpp:1568 msgid " " msgstr "" #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "" #: controlpanel.cpp:1571 msgid " [username] " msgstr "" #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1575 msgid " " msgstr "" #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr "" #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "" #: controlpanel.cpp:1586 msgid " " msgstr "" #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "" #: controlpanel.cpp:1591 msgid " " msgstr "" #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr "" #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr "" #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "" #: controlpanel.cpp:1606 msgid " [args]" msgstr "" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "" #: controlpanel.cpp:1609 msgid " " msgstr "" #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "" #: controlpanel.cpp:1616 msgid " [args]" msgstr "" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "" #: controlpanel.cpp:1620 msgid " " msgstr "" #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "" #: controlpanel.cpp:1629 msgid " [reply]" msgstr "" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "" #: controlpanel.cpp:1632 msgid " " msgstr "" #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "" #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "" #: controlpanel.cpp:1643 msgid "[username]" msgstr "" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" znc-1.7.5/modules/po/lastseen.pt_BR.po0000644000175000017500000000263013542151610020012 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/lastseen.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "" #: lastseen.cpp:53 msgid "Access denied" msgstr "" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "" znc-1.7.5/modules/po/kickrejoin.pt_BR.po0000644000175000017500000000246113542151610020326 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/kickrejoin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: kickrejoin.cpp:56 msgid "" msgstr "" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "" msgstr[1] "" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "" msgstr[1] "" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "" #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "" znc-1.7.5/modules/po/imapauth.es_ES.po0000644000175000017500000000121713542151610017774 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/imapauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "[ servidor [+]puerto [ FormatoCadenaUsuario ] ]" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "Permite autenticar usuarios mediante IMAP." znc-1.7.5/modules/po/webadmin.id_ID.po0000644000175000017500000007673013542151610017740 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/webadmin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "" #: webadmin.cpp:93 msgid "Your Settings" msgstr "" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "" #: webadmin.cpp:576 msgid "No such channel" msgstr "" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "" #: webadmin.cpp:749 msgid "Add Channel" msgstr "" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "" #: webadmin.cpp:766 msgid "Detached" msgstr "" #: webadmin.cpp:773 msgid "Enabled" msgstr "" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "" #: webadmin.cpp:911 msgid "Add Network" msgstr "" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "" #: webadmin.cpp:1551 msgid "Admin" msgstr "" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "" #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "" #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "" #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "" #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "" znc-1.7.5/modules/po/fail2ban.de_DE.po0000644000175000017500000000613413542151610017607 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/fail2ban.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "[Minuten]" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "" "Die Anzahl an Minuten, die IPs nach einem fehlgeschlagenen Anmeldeversuch " "blockiert werden." #: fail2ban.cpp:28 msgid "[count]" msgstr "[Anzahl]" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "Die Anzahl der zulässigen fehlgeschlagenen Anmeldeversuche." #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "Banne die angegebenen Hosts." #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "Entbanne die angegebenen Hosts." #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "Liste gebannte Hosts auf." #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" "Ungültiges Argument, muss die Anzahl an Minuten sein, die IPs nach einem " "fehlgeschlagenen Anmeldeversuch geblockt werden, und kann durch die Anzahl " "zulässiger fehlgeschlagener Anmeldeversuche gefolgt werden" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "Zugriff verweigert" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "Verwendung: Timeout [Minuten]" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "Timeout: {1} Min" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "Verwendung: Attempts [Anzahl]" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "Versuche: {1}" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "Verwendung: Ban " #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "Gebannt: {1}" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "Verwendung: Unban " #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "Entbannt: {1}" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "Ignoriert: {1}" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "Host" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "Versuche" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "Keine Bannungen" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" "Du kannst die Zeit in Minuten eingeben, die IPs gebannt werden, und die " "Anzahl an fehlgeschlagenen Anmeldeversuchen, bevor etwas unternommen wird." #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "Blockiere IPs für eine Weile nach fehlgeschlagenen Anmeldungen." znc-1.7.5/modules/po/notes.ru_RU.po0000644000175000017500000000465013542151610017356 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/notes.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "" #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "" #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "" #: notes.cpp:75 msgid "List notes" msgstr "" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr "" #: notes.cpp:77 msgid "Add a note" msgstr "" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "" #: notes.cpp:81 msgid "Modify a note" msgstr "" #: notes.cpp:94 msgid "Notes" msgstr "" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "" #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "" #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "" znc-1.7.5/modules/po/shell.id_ID.po0000644000175000017500000000124213542151610017243 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/shell.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "" #: shell.cpp:169 msgid "Gives shell access" msgstr "" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "" znc-1.7.5/modules/po/route_replies.nl_NL.po0000644000175000017500000000342113542151610021050 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/route_replies.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "[yes|no]" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "Beslist of time-out berichten laten zien worden of niet" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" "Deze module heeft een time-out geraakt, dit is waarschijnlijk een " "connectiviteitsprobleem." #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" "Maar, als je de stappen kan herproduceren, stuur alsjeblieft een bugrapport " "hier mee." #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "Om dit bericht uit te zetten, doe \"/msg {1} silent yes\"" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "Laatste aanvraag: {1}" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "Verwachte antwoorden:" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "{1} (laatste)" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "Time-out berichten uitgeschakeld." #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "Time-out berichten ingeschakeld." #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "Stuur antwoorden (zoals /who) alleen naar de juiste clients" znc-1.7.5/modules/po/clientnotify.ru_RU.po0000644000175000017500000000355713542151610020742 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/clientnotify.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "" #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "" #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "" #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "" #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" znc-1.7.5/modules/po/savebuff.es_ES.po0000644000175000017500000000366013542151610017771 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/savebuff.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "Establecer contraseña" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "Reproduce el búfer" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "Guardar todos los búfers" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" "Tener la contraseña sin establecer suele significar que el descifrado a " "fallado. Puedes establecer la contraseña apropiada para que las cosas " "comiencen a funcionar, o establecer una nueva contraseña y guardar para " "reinicializarlo" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "Contraseña establecida a [{1}]" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "Reproducido {1}" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "No se ha podido descifrar el archivo {1}" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" "Este módulo de usuario tiene hasta un argumento. Introduce --ask-pass o la " "contraseña misma (la cual puede contener espacios) o nada" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "Almacena búfers de privados y canales en el disco, cifrados" znc-1.7.5/modules/po/stripcontrols.it_IT.po0000644000175000017500000000116313542151610021123 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/stripcontrols.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "" "Elimina i codici di controllo (Colori, Grassetto, ..) dal canale e dai " "messaggi privati." znc-1.7.5/modules/po/sample.bg_BG.po0000644000175000017500000000425613542151610017415 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/sample.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "" #: sample.cpp:50 msgid "Sample job done" msgstr "" #: sample.cpp:65 msgid "TEST!!!!" msgstr "" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "" #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "" #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "" msgstr[1] "" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "" #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "" #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "" znc-1.7.5/modules/po/modpython.id_ID.po0000644000175000017500000000074013542151610020157 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/modpython.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/partyline.ru_RU.po0000644000175000017500000000205013542151610020225 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/partyline.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "" #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "" #: partyline.cpp:82 msgid "List all open channels" msgstr "" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "" znc-1.7.5/modules/po/modpython.pt_BR.po0000644000175000017500000000076513542151610020224 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/modpython.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/adminlog.es_ES.po0000644000175000017500000000334513542151610017762 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/adminlog.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "Muestra el objeto de registro" #: adminlog.cpp:31 msgid " [path]" msgstr " [ruta]" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "Configura el objeto a registrar" #: adminlog.cpp:142 msgid "Access denied" msgstr "Acceso denegado" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "Registrando en fichero" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "Registrando solo en syslog" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "Registrando en syslog y fichero" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "Uso: Target [ruta]" #: adminlog.cpp:170 msgid "Unknown target" msgstr "Objeto desconocido" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "Activado registro a fichero" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "Activado registro a syslog" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "Activado registro a fichero y syslog" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "El fichero de registro será escrito en {1}" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "Registrar eventos de ZNC a fichero y/o syslog" znc-1.7.5/modules/po/kickrejoin.it_IT.po0000644000175000017500000000422013542151610020323 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/kickrejoin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: kickrejoin.cpp:56 msgid "" msgstr "" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "" "Imposta il ritardo del rientro automatico (rejoin) (valore 0 per " "disabilitare)" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "Mostra il ritardo del rientro automatico (rejoin)" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "Argomento non accettato, deve essere 0 oppure un numero positivo" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "" "Impostare il ritardo del rientro automatico (rejoin) con numeri negativi non " "ha alcun senso!" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "Il ritardo del rientro automatico (rejoin) è impostato a 1 secondo" msgstr[1] "" "Il ritardo del rientro automatico (rejoin) è impostato a {1} secondi" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "Il ritardo del rientro automatico (rejoin) è disabilitato" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "" "Il ritardo del rientro automatico (rejoin) è stato impostato a 1 secondo" msgstr[1] "" "Il ritardo del rientro automatico (rejoin) è stato impostato a {1} secondi" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "Il ritardo del rientro automatico (rejoin) è stato disabilitato" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "" "Puoi inserire il numero di secondi che Znc deve attendere prima di rientrare " "automaticamente (rejoining)." #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "Rientra automaticamente dopo un kick (Autorejoins)" znc-1.7.5/modules/po/block_motd.pt_BR.po0000644000175000017500000000152013542151610020306 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/block_motd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: block_motd.cpp:26 msgid "[]" msgstr "" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "" #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "" znc-1.7.5/modules/po/modules_online.fr_FR.po0000644000175000017500000000075713542151610021210 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/modules_online.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "" znc-1.7.5/modules/po/keepnick.nl_NL.po0000644000175000017500000000301013542151610017752 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/keepnick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "Probeer je primaire naam te krijgen" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "Probeer niet langer je primaire naam te krijgen" #: keepnick.cpp:44 msgid "Show the current state" msgstr "Laat huidige status zien" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "ZNC probeert deze naam al ge krijgen" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "Niet mogelijk om naam {1} te krijgen: {2}, {3}" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "Niet mogelijk om naam {1} te krijgen" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "Proberen je primaire naam te krijgen" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "Momenteel proberen je primaire naam te krijgen" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "Op dit moment uitgeschakeld, probeer 'enable'" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "Blijft proberen je primaire naam te krijgen" znc-1.7.5/modules/po/missingmotd.nl_NL.po0000644000175000017500000000102213542151610020517 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/missingmotd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "Stuurt 422 naar clients wanneer zij inloggen" znc-1.7.5/modules/po/simple_away.nl_NL.po0000644000175000017500000000565213542151610020511 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/simple_away.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: simple_away.cpp:56 msgid "[]" msgstr "[]" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" "Toont of stelt de afwezigheids reden in (%awaytime% wordt vervangen door de " "tijd dat je afwezig gezet werd, ExpandString is ondersteund voor " "vervangingen)" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "" "Toont de huidige tijd die je moet wachten tot je op afwezig gezet zal worden" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "Stelt de tijd in die je moet wachten voor je afwezig gezet zal worden" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "Schakelt de wachttijd uit voordat je op afwezig gesteld zal worden" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "" "Toon of stel in het minimum aantal clients voordat je op afwezig gezet zal " "worden" #: simple_away.cpp:136 msgid "Away reason set" msgstr "Afwezigheidsreden ingesteld" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "Afwezigheidsreden: {1}" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "Huidige afwezigheidsreden zou zijn: {1}" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "Huidige timer instelling: 1 seconde" msgstr[1] "Huidige timer instelling: {1} seconden" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "Timer uitgeschakeld" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "Timer ingesteld op 1 seconde" msgstr[1] "Timer ingesteld op {1} seconden" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "Huidige MinClients instelling: {1}" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "MinClients ingesteld op {1}" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" "Accepteert 3 argumenten, zoals -notimer afwezigheidsbericht of -timer 6 " "afwezigheidsbericht." #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" "Deze module zal je automatisch op afwezig zetten op IRC als je loskoppelt " "van ZNC." znc-1.7.5/modules/po/partyline.fr_FR.po0000644000175000017500000000220013542151610020164 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/partyline.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "Il n'y a pas de salons ouverts." #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "Salon" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "Utilisateurs" #: partyline.cpp:82 msgid "List all open channels" msgstr "Lister tous les canaux ouverts" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" "Vous pouvez entrer une liste de salons que l'utilisateur rejoint, quand il " "entre dans le réseau IRC interne." #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "Salons et requêtes internes pour les utilisateurs connectés à ZNC" znc-1.7.5/modules/po/kickrejoin.bg_BG.po0000644000175000017500000000244213542151610020257 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/kickrejoin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: kickrejoin.cpp:56 msgid "" msgstr "" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "" msgstr[1] "" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "" msgstr[1] "" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "" #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "" znc-1.7.5/modules/po/cert.es_ES.po0000644000175000017500000000435313542151610017125 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/cert.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "aquí" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" "Ya tienes un certiicado configurado, usa el siguiente formulario para " "sobreescribirlo. También puedes pulsar {1} para eliminarlo." #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "No tienes un certificado aún." #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "Certificado" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "Fichero PEM:" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "Actualizar" #: cert.cpp:28 msgid "Pem file deleted" msgstr "Fichero PEM eliminado" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "El fichero pem no existe o hay un error al eliminarlo." #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "Tienes un certificado en {1}" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "No tienes ningún certificado. Usa la interfaz web para añadir uno" #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "También puedes colocar uno en {1}" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "Borrar el certiicado actual" #: cert.cpp:54 msgid "Show the current certificate" msgstr "Mostrar el certificado actual" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "Usa un certificado SSL para conectar a un servidor" znc-1.7.5/modules/po/route_replies.fr_FR.po0000644000175000017500000000245313542151610021050 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/route_replies.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "" #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "" #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "" znc-1.7.5/modules/po/kickrejoin.de_DE.po0000644000175000017500000000357713542151610020271 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/kickrejoin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: kickrejoin.cpp:56 msgid "" msgstr "" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "Setze die Wiederbetreten-Verzögerung" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "Zeige die Wiederbetreten-Verzögerung" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "Ungültiges Argument, muss eine positive Zahl oder 0 sein" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "Negative Verzögerungen machen keinen Sinn!" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "Wiederbetretenverzögerung auf 1 Sekunde gesetzt" msgstr[1] "Wiederbetretenverzögerung auf {1} Sekunden gesetzt" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "Wiederbetretenverzögerung deaktiviert" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "Wiederbetretenverzögerung ist auf 1 Sekunde gesetzt" msgstr[1] "Wiederbetretenverzögerung ist auf {1} Sekunden gesetzt" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "Wiederbetretenverzögerung ist deaktiviert" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "" "Du kannst eine Anzahl an Sekunden angeben, die vor dem Wiederbetreten " "gewartet wird." #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "Automatisches wiederbetreten nach einem rauswurf" znc-1.7.5/modules/po/buffextras.fr_FR.po0000644000175000017500000000171313542151610020336 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/buffextras.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: buffextras.cpp:45 msgid "Server" msgstr "" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "" #: buffextras.cpp:73 msgid "{1} joined" msgstr "" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "" znc-1.7.5/modules/po/watch.de_DE.po0000644000175000017500000001071413542151610017236 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/watch.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "" #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "" #: watch.cpp:397 msgid "Disabled all entries." msgstr "" #: watch.cpp:398 msgid "Enabled all entries." msgstr "" #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "" #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "" #: watch.cpp:593 msgid "Id {1} removed." msgstr "" #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "" #: watch.cpp:609 msgid "List" msgstr "" #: watch.cpp:611 msgid "List all entries being watched." msgstr "" #: watch.cpp:614 msgid "Dump" msgstr "" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "" #: watch.cpp:620 msgid "Del " msgstr "" #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "" #: watch.cpp:625 msgid "Clear" msgstr "" #: watch.cpp:626 msgid "Delete all entries." msgstr "" #: watch.cpp:629 msgid "Enable " msgstr "" #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "" #: watch.cpp:633 msgid "Disable " msgstr "" #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "" #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "" #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "" #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "" #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "" #: watch.cpp:652 msgid "Buffer [Count]" msgstr "" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "" #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "" #: watch.cpp:664 msgid "Help" msgstr "" #: watch.cpp:665 msgid "This help." msgstr "" #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "" #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "" znc-1.7.5/modules/po/identfile.id_ID.po0000644000175000017500000000303013542151610020074 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/identfile.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: identfile.cpp:30 msgid "Show file name" msgstr "" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "" #: identfile.cpp:34 msgid "Show file format" msgstr "" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "" #: identfile.cpp:38 msgid "Show current state" msgstr "" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "" #: identfile.cpp:78 msgid "identfile is free" msgstr "" #: identfile.cpp:86 msgid "Access denied" msgstr "" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "" #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "" znc-1.7.5/modules/po/q.pot0000644000175000017500000001236013542151610015614 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" #: q.cpp:111 msgid "The following commands are available:" msgstr "" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "" #: q.cpp:116 msgid "Auth [ ]" msgstr "" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "" #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" #: q.cpp:128 msgid "Prints the current status of the module." msgstr "" #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "" #: q.cpp:135 msgid "Set " msgstr "" #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" #: q.cpp:146 msgid "The following settings are available:" msgstr "" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "" #: q.cpp:154 msgid "Your Q username." msgstr "" #: q.cpp:158 msgid "Your Q password." msgstr "" #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "" #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "" #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "" #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "" #: q.cpp:200 msgid "Syntax: Set " msgstr "" #: q.cpp:203 msgid "Username set" msgstr "" #: q.cpp:206 msgid "Password set" msgstr "" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "" #: q.cpp:212 msgid "UseChallenge set" msgstr "" #: q.cpp:215 msgid "RequestPerms set" msgstr "" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "" #: q.cpp:253 msgid "Connected: yes" msgstr "" #: q.cpp:254 msgid "Connected: no" msgstr "" #: q.cpp:255 msgid "Cloacked: yes" msgstr "" #: q.cpp:255 msgid "Cloacked: no" msgstr "" #: q.cpp:256 msgid "Authenticated: yes" msgstr "" #: q.cpp:257 msgid "Authenticated: no" msgstr "" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "" #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "" #: q.cpp:280 msgid "Update requested." msgstr "" #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "" #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "" #: q.cpp:408 msgid "Changes have been saved!" msgstr "" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "" #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "" #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "" #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "" #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "" znc-1.7.5/modules/po/route_replies.id_ID.po0000644000175000017500000000245113542151610021020 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/route_replies.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "" #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "" #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "" znc-1.7.5/modules/po/autoreply.bg_BG.po0000644000175000017500000000167013542151610020155 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/autoreply.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "" znc-1.7.5/modules/po/kickrejoin.es_ES.po0000644000175000017500000000353513542151610020321 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/kickrejoin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: kickrejoin.cpp:56 msgid "" msgstr "" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "Establece el tiempo de espera de rejoin" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "Muestra el tiempo de espera de rejoin" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "Argumento no válido, debe ser un número positivo o cero" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "Tiempos de espera en negativo no tienen sentido!" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "Tiempo de espera de reentrada establecido a 1 segundo" msgstr[1] "Tiempo de espera de reentrada establecido a {1} segundos" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "Tiempo de espera de rejoin desactivado" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "Tiempo de espera de reentrada establecido a 1 segundo" msgstr[1] "Tiempo de espera de rejoin establecido a {1} segundos" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "Tiempo de espera de rejoin desactivado" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "Introduce el número de segundos a esperar antes de reentrar." #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "Reentra a un canal tras un kick" znc-1.7.5/modules/po/send_raw.nl_NL.po0000644000175000017500000000561213542151610017775 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/send_raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "Stuur een onbewerkte IRC regel" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "Gebruiker:" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "Om gebruiker te veranderen, klik de Netwerk schakelaar" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "Gebruiker/Netwerk:" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "Stuur naar:" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "Client" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "Server" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "Regel:" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "Stuur" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "[{1}] gestuurd naard {2}/{3}" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "Netwerk {1} niet gevonden voor gebruiker {2}" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "Gebruiker {1} niet gevonden" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "[{1}] gestuurd naard IRC server van {2}/{3}" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "Alleen beheerders kunnen deze module laden" #: send_raw.cpp:82 msgid "Send Raw" msgstr "Stuur onbewerkt" #: send_raw.cpp:92 msgid "User not found" msgstr "Gebruiker niet gevonden" #: send_raw.cpp:99 msgid "Network not found" msgstr "Netwerk niet gevonden" #: send_raw.cpp:116 msgid "Line sent" msgstr "Regel gestuurd" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "[gebruiker] [netwerk] [data om te sturen]" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "De data zal gestuurd naar de gebruiker's IRC client(s)" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "" "De data zal gestuurd worden naar de IRC server waar de gebruiker mee " "verbonden is" #: send_raw.cpp:147 msgid "[data to send]" msgstr "[data om te sturen]" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "De data zal gestuurd worden naar je huidige client" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "Laat je onbewerkte IRC regels als/naar iemand anders sturen" znc-1.7.5/modules/po/clearbufferonmsg.pt_BR.po0000644000175000017500000000104513542151610021517 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/clearbufferonmsg.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "" znc-1.7.5/modules/po/partyline.it_IT.po0000644000175000017500000000213513542151610020205 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/partyline.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "Non ci sono canali aperti." #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "Canale" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "Utenti" #: partyline.cpp:82 msgid "List all open channels" msgstr "Mostra tutti i canali aperti" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" "Puoi inserire un elenco di canali a cui l'utente può entrare quando accede " "al partyline interno." #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "Canali e query interne per gli utenti connessi allo ZNC" znc-1.7.5/modules/po/webadmin.it_IT.po0000644000175000017500000012444613542151610017776 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/webadmin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "Informazioni sul canale" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "Nome del canale:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "Il nome del canale." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "Chiave:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "La password del canale, se presente." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "Dimensione del Buffer:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "Il conteggio del buffer." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "Modes predefiniti:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "I modi di default del canale." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "Flags" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "Salva in confg" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "Modulo {1}" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "Salva e ritorna" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "Salva e continua" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "Aggiungi canale e ritorna" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "Aggiungi canale e continua" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "<password>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "<network>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" "Per connetterti a questo network dal tuo client IRC, puoi impostare il campo " "password del server come {1} o il campo username come {2}" "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "Informazioni del Network" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" "Campi come Nickname, Nickname alternativo, Ident, Nome reale ed il ed il " "BindHost possono essere lasciati vuoti per utilizzare i valori dell'utente." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "Nome del Network:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "Il nome del network IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "Nickname:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "Il nickname che vuoi avere su IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "Nickname alternativo:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "Il tuo secondo nickname, se il primo non fosse disponibile su IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "Ident: (userID)" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "Il tuo ident (userID)." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "Nome reale:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "Il tuo nome reale." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "BindHost:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "Messaggio di Quit:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "È possibile definire un messaggio da mostrare quando si esce da IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "Attivo:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "Connetti ad IRC & riconnetti automaticamente" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "Fidati di tutti i certificati:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "" "Disabilita la convalida del certificato (ha la precedenza su TrustPKI). " "INSICURO!" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "Fidati del PKI:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" "Se impostato su falso, verranno considerati attendibili solo i certificati " "per cui sono state aggiunte le \"impronte digitali\" (fingerprints)." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "Elenco dei Server IRC di questo Network:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "" "Un server per linea, “host [[+]porta] [password]â€, (il + significa che la " "porta sarà SSL)" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "Hostname" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "Porta" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "Password" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "" "Impronte digitali (fingerprints) SHA-256 dei certificati SSL attendibili di " "questo network IRC:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" "Quando vengono rilevati questi certificati, i controlli per hostname, date " "di scadenza e CA vengono saltati" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "Protezione Flood:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" "È possibile abilitare la protezione dai flood (inondazione di messaggi). " "Questo previene errori di \"flood eccessivi\", che si verificano quando il " "bot IRC ne viene colpito. Dopo averlo modificato, ricollegare lo ZNC al " "server." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "Abilitato" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "Tasso di protezione dai flood:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" "Il numero di secondi per riga. Dopo averlo modificato, ricollegare lo ZNC al " "server." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "{1} secondi per linea" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "Scoppio di protezione dai flood:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" "Definisce il numero di righe che possono essere inviate immediatamente. Dopo " "averlo modificato, ricollegare lo ZNC al server." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "{1} linee possono essere spedite immediatamente" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "Ritardo per l'ingresso al canale:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" "Definisce il ritardo in secondi, per l'ingresso dei canali dopo la " "connessione." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "{1} secondi" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "Codifica caratteri utilizzata tra lo ZNC ed il server IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "Codifica del server:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "Canali" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "" "Qui potrai aggiungere e modificare i canali dopo aver creato il network." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "Inserisci" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "Salva" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "Nome" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "Modes correnti" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "Modes di default" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "Dimensione Buffer" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "Opzioni" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "↠Aggiungi un canale (si apre nella stessa pagina)" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "Modifica" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "Elimina" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "Moduli" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "Argomenti" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "Descrizione" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "Caricato globalmente" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "Caricato dell'utente" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "Aggiungi Network e ritorna" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "Aggiungi Network e continua" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "Autenticazione" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "Username:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "Per favore inserisci un username." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "Password:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "Pe favore inserisci una password." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "Conferma password:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "Per favore inserisci nuovamente la password inserita sopra." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "Aut. solo tramite modulo:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" "Consente l'autenticazione utente solo da moduli esterni, disabilitando " "l'autenticazione password integrata." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "IPs consentiti:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" "Lascia vuoto questo campo per accedere allo ZNC da tutti i tuoi indirizzi IP." "
Altrimenti, inserisci un indirizzo IP per riga. Sono disponibili le " "wildcards * e ? come caratteri jolly." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "Informazioni IRC" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" "Campi come Nickname, Nickname alternativo, Ident, Nome reale ed il messaggio " "di Quit possono essere lasciati vuoti. Lo ZNC utilizzerà i dati impostati di " "default." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "L'ident è inviato al serveer come username." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "Prefisso di Status:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "Il prefisso per lo status e il modulo delle query." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "DCCBindHost:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "Networks" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "Clients" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "Server attuale" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "Nick" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "↠Aggiungi un network (si apre nella stessa pagina)" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "" "Qui potrai aggiungere e modificare i networks dopo aver clonato l'utente." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "" "Qui potrai aggiungere e modificare i networks dopo aver creato l'utente." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "Caricato dai networks" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" "Queste sono le modalità predefinite che lo ZNC imposterà quando entri in un " "canale vuoto." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "Vuoto = usa valori standard" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Questa è la quantità di linee che il playback buffer (buffer di " "riproduzione) memorizzerà per i canali prima di eliminare la linea più " "vecchia. I buffer sono memorizzati nella memoria per impostazione " "predefinita." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "Interrogazioni" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "Buffers massimo:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "Numero massimo dei buffers delle query. 0 è illimitato." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Questa è la quantità di linee che il playback buffer (buffer di " "riproduzione) memorizzerà per le query prima di eliminare la riga più " "vecchia. I buffer sono memorizzati nella memoria per impostazione " "predefinita." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "Comportamento dello ZNC" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" "Ognuna delle seguenti caselle di testo può essere lasciata vuota per " "utilizzare il valore predefinito." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "Formato Timestamp:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" "Il formato per i timestamps utilizzati nei buffer, ad esempio [% H:% M:% S]. " "Questa impostazione viene ignorata nei nuovi client IRC, che utilizzano " "l'ora del server. Se il tuo client supporta l'ora del server, modifica " "invece il formato data/ora nelle impostazioni del client." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "Fuso orario:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "Esempio: Europa/Berlino, o GMT-6" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "Codifica dei caratteri utilizzata tra client IRC e ZNC." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "Codifica del client:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "Tentativo d'ingresso:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" "Questo definisce quante volte lo ZNC tenta di entrare in un canale qual'ora " "il primo tentativo fallisce, ad esempio a causa della modalità canale +i/+k " "o se sei stato bannato." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "Velocità d'ingresso:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" "Quanti canali possono entrare in un solo comando di JOIN. 0 è illimitato " "(impostazione predefinita). Impostare un valore positivo piccolo se si viene " "disconnessi con “Max SendQ Exceededâ€" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "Timeout prima della riconnessione:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" "Quanto tempo (in secondi) lo ZNC attende fino a ricevere qualcosa dal " "network o dichiarare il timeout della connessione. Ciò accade dopo i " "tentativi di ping del peer." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "Numero massimo di IRC Networks:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "Numero massimo di networks IRC consentiti per questo utente." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "Sostituzioni" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "Risposte CTCP:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "Una risposta per linea. Esempio: TIME Compra un orologio!" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "{1} sono disponibili" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "Un valore vuoto indica che questa richiesta CTCP verrà ignorata" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "Richiesta" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "Risposta" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "Aspetto:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "- Globale -" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "Predefinito" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "Nessuna skin trovata" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "Linguaggio:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "Clona e ritorna" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "Clona e continua" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "Crea e ritorna" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "Crea e continua" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "Clona" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "Crea" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "Conferma l'eliminazione del Network" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "Sei sicuro di voler eliminare il network “{2}†dell'utente “{1}â€?" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "Si" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "No" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "Conferma l'eliminazione dell'utente" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "Sei sicuro di voler eliminare l'utente “{1}â€?" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "" "Lo ZNC è compilato senza supporto per le codifiche. {1} è richiesto per " "questo." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "La modalità legacy è disabilitata da modpython." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "Non assicura alcuna codifica (la modalità legacy, non consigliata)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "" "Prova ad analizzare come UTF-8 e come {1}, invia come UTF-8 (raccomandato)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "Prova ad analizzare come UTF-8 e come {1}, invia come {1}" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "Analizza e invia solo come {1}" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "Esempio: UTF-8, o ISO-8859-15" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "Benvenuto nel modulo di amministrazione dello ZNC via web." #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "" "Tutte le modifiche apportate avranno effetto immediato dopo averle salvate." #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "Username" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "Elimina" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "Porta(e) in ascolto" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "BindHost" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "IPv4" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "IPv6" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "IRC" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "HTTP" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "Prefisso URI" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" "Per eliminare la porta che usi per accedere a webadmin, connettersi al " "webadmin tramite un'altra porta o farlo in IRC (/znc DelPort)" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "Attuale" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "Impostazioni" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "Predefinito solamente per i nuovi utenti." #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "Dimensione massima del Buffer:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "" "Imposta globalmente la dimensione massima del buffer che un utente può avere." #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "Ritardo della connessione (Delay):" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" "Il tempo in secondi tra un tenativo di connessione e l'altro verso i server " "IRC. Ciò influisce sulla connessione tra ZNC e il server IRC; non la " "connessione tra il tuo client IRC e lo ZNC." #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "Server Throttle:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" "Il tempo minimo in secondi tra due tentativi di connessione allo stesso " "hostname. Alcuni server rifiutano la connessione se ti riconnetti troppo " "velocemente." #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "Limite connessioni anonime per IP:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "Limita il numero di connessioni non identificate per IP." #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "Protezione sezioni Web:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "Non consentire la modifica dell'IP durante ciascuna sessione Web" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "Nascondi la versione dello ZNC:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "Nascondi il numero di versione dagli utenti non ZNC" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "Consente l'autenticazione utente solo da moduli esterni" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "MOTD:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "" "“Messaggio del giornoâ€, inviato a tutti gli utenti dello ZNC alla " "connessione." #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "Moduli Globali" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "Caricato dagli utenti" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "Informazioni" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "Tempo di attività" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "Utenti totali" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "Networks totali" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "Networks attaccati" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "Connessioni totali del Client" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "Connessioni IRC totali" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "Connessioni del client" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "Connessione IRC" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "Totale" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "Entrata" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "Uscita" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "Utente" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "Traffico" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "Utente" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "Network" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "Impostazione moduli" #: webadmin.cpp:93 msgid "Your Settings" msgstr "Le tue impostazioni" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "Informazioni del traffico" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "Gestione utenti" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "Invio non valido [nome utente richiesto]" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "Invio non valido [Le password non corrispondono]" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "Il timeout non può essere inferiore a 30 secondi!" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "Impossibile caricare il modulo [{1}]: {2}" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "Impossibile caricare il modulo [{1}] con gli argomenti [{2}]" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "Nessun utente" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "Nessun utente o network" #: webadmin.cpp:576 msgid "No such channel" msgstr "Nessun canale" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "Per favore, non cancellarti, il suicidio non è la risposta!" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "Modifica utente [{1}]" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "Modifica Network [{1}]" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "Modifica canale [{1}] del Network [{2}] dell'utente [{3}]" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "Modifica canale [{1}]" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "Aggiungi canale al Network [{1}] dell'utente [{2}]" #: webadmin.cpp:749 msgid "Add Channel" msgstr "Aggiungi canale" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "Auto cancellazione del Buffer sui canali" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "" "Cancella automaticamente il buffer del canale dopo la riproduzione (Playback)" #: webadmin.cpp:766 msgid "Detached" msgstr "Distaccati" #: webadmin.cpp:773 msgid "Enabled" msgstr "Abilitato" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "Il nome del canale è un argomento obbligatorio" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "Canale [{1}] già esistente" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "Impossibile aggiungere il canale [{1}]" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "" "Il canale è stato aggiunto/modificato, ma il file di configurazione non è " "stato scritto" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" "Raggiunto il numero limite di Network consentiti. Chiedi ad un " "amministratore di aumentare il limite per te, o elimina un network che non " "ritieni più necessario attraverso le tue impostazioni." #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "Modifica Network [{1}] dell'utente [{2}]" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "Aggiungi Network per l'utente [{1}]" #: webadmin.cpp:911 msgid "Add Network" msgstr "Aggiungi Network" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "Il nome del network è un argomento richiesto" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "Impossibile ricaricare il modulo [{1}]: {2}" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "" "Il network è stato aggiunto/modificato, ma il file di configurazione non è " "stato scritto" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "Quel canale non esiste per questo utente" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "" "Il network è stato eliminato, ma il file di configurazione non è stato " "scritto" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "Quel canale non esiste per questo network" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "" "Il canale è stato eliminato, ma il file di configurazione non è stato scritto" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "Clona l'utente [{1}]" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" "Cancella automaticamente il buffer del canale dopo la riproduzione " "(Playback) (valore di default per i nuovi canali)" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "Clients multipli" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "Aggiungi Timestamps (orologio)" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "Anteponi il Timestamps" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "Nega LoadMod" #: webadmin.cpp:1551 msgid "Admin" msgstr "Admin" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "Nega SetBindHost" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "Auto cancellazione del Buffer sulle Query" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "" "Cancella automaticamente il buffer della Query dopo la riproduzione " "(Playback)" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "Invio non valido: L'utente {1} è già esistente" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "Invio non valido: {1}" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "" "L'utente è stato aggiunto, ma il file di configurazione non è stato scritto" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "" "L'utente è stato modificato, ma il file di configurazione non è stato scritto" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "Scegli tra IPv4 o IPv6 o entrambi." #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "Scegli tra IRC o HTTP o entrambi." #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "" "La porta è stata cambiata, ma il file di configurazione non è stato scritto" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "Richiesta non valida." #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "L'ascoltatore specificato non è stato trovato." #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "" "Le impostazioni sono state cambiate, ma il file di configurazione non è " "stato scritto" znc-1.7.5/modules/po/notes.fr_FR.po0000644000175000017500000000437313542151610017322 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/notes.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "" #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "" #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "" #: notes.cpp:75 msgid "List notes" msgstr "" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr "" #: notes.cpp:77 msgid "Add a note" msgstr "" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "" #: notes.cpp:81 msgid "Modify a note" msgstr "" #: notes.cpp:94 msgid "Notes" msgstr "" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "" #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "" #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "" znc-1.7.5/modules/po/chansaver.it_IT.po0000644000175000017500000000106013542151610020144 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/chansaver.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "Mantiene la configurazione aggiornata quando un utente entra/esce." znc-1.7.5/modules/po/raw.pt_BR.po0000644000175000017500000000074013542151610016765 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "" znc-1.7.5/modules/po/dcc.fr_FR.po0000644000175000017500000001007313542151610016715 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/dcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: dcc.cpp:88 msgid " " msgstr "" #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "" #: dcc.cpp:91 msgid "" msgstr "" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "" #: dcc.cpp:94 msgid "List current transfers" msgstr "" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "" #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "" #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "" #: dcc.cpp:179 msgid "Usage: Send " msgstr "" #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "" #: dcc.cpp:199 msgid "Usage: Get " msgstr "" #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "" #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "" #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "" #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "" #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "" #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "" #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "" #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "" #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "" #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "" #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "" #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "" #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "" #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "" #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "" #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "" #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "" znc-1.7.5/modules/po/controlpanel.pot0000644000175000017500000003537613542151610020070 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "" #: controlpanel.cpp:77 msgid "String" msgstr "" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "" #: controlpanel.cpp:79 msgid "Integer" msgstr "" #: controlpanel.cpp:80 msgid "Number" msgstr "" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "" #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "" #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "" #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "" #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "" #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "" #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "" #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "" #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "" #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "" msgstr[1] "" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "" #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "" #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "" #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "" #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "" #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "" #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "" #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "" #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "" #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "" #: controlpanel.cpp:1143 msgid "No networks" msgstr "" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "" #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "" #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "" #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "" #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "" #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "" #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "" #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "" #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "" #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "" #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "" #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "" #: controlpanel.cpp:1559 msgid " [username]" msgstr "" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "" #: controlpanel.cpp:1562 msgid " " msgstr "" #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr "" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "" #: controlpanel.cpp:1568 msgid " " msgstr "" #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "" #: controlpanel.cpp:1571 msgid " [username] " msgstr "" #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1575 msgid " " msgstr "" #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr "" #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "" #: controlpanel.cpp:1586 msgid " " msgstr "" #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "" #: controlpanel.cpp:1591 msgid " " msgstr "" #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr "" #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr "" #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "" #: controlpanel.cpp:1606 msgid " [args]" msgstr "" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "" #: controlpanel.cpp:1609 msgid " " msgstr "" #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "" #: controlpanel.cpp:1616 msgid " [args]" msgstr "" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "" #: controlpanel.cpp:1620 msgid " " msgstr "" #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "" #: controlpanel.cpp:1629 msgid " [reply]" msgstr "" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "" #: controlpanel.cpp:1632 msgid " " msgstr "" #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "" #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "" #: controlpanel.cpp:1643 msgid "[username]" msgstr "" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" znc-1.7.5/modules/po/cyrusauth.ru_RU.po0000644000175000017500000000357113542151610020256 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/cyrusauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" #: cyrusauth.cpp:56 msgid "Access denied" msgstr "" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "" #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" znc-1.7.5/modules/po/certauth.bg_BG.po0000644000175000017500000000407113542151610017746 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/certauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "" #: certauth.cpp:31 msgid "[pubkey]" msgstr "" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" #: certauth.cpp:35 msgid "id" msgstr "" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "" #: certauth.cpp:37 msgid "List your public keys" msgstr "" #: certauth.cpp:39 msgid "Print your current key" msgstr "" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "" #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "" #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "" #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "" #: certauth.cpp:215 msgid "Removed" msgstr "" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "" znc-1.7.5/modules/po/disconkick.nl_NL.po0000644000175000017500000000133213542151610020307 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/disconkick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "Je bent losgekoppeld van de server" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" "Verlaat alle kanalen wanneer de verbinding met de IRC server verloren is" znc-1.7.5/modules/po/notes.bg_BG.po0000644000175000017500000000437713542151610017270 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/notes.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "" #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "" #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "" #: notes.cpp:75 msgid "List notes" msgstr "" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr "" #: notes.cpp:77 msgid "Add a note" msgstr "" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "" #: notes.cpp:81 msgid "Modify a note" msgstr "" #: notes.cpp:94 msgid "Notes" msgstr "" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "" #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "" #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "" znc-1.7.5/modules/po/nickserv.nl_NL.po0000644000175000017500000000401013542151610020006 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/nickserv.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: nickserv.cpp:31 msgid "Password set" msgstr "Wachtwoord ingesteld" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "NickServ naam ingesteld" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "Geen aanpasbaar commando. Zie ViewCommands voor een lijst." #: nickserv.cpp:63 msgid "Ok" msgstr "Oké" #: nickserv.cpp:68 msgid "password" msgstr "wachtwoord" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "Stel je nickserv wachtwoord in" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "Leegt je nickserv wachtwoord" #: nickserv.cpp:72 msgid "nickname" msgstr "naam" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" "Stel NickServ naam in (nuttig op netwerken zoals EpiKnet waar NickServ " "Themis heet)" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "Reset de naam van NickServ naar de standaard (NickServ)" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "Laat patroon voor de regels zien die gestuurd worden naar NickServ" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "cmd nieuw-patroon" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "Stel patroon in voor commando's" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "Voer alsjeblieft je nickserv wachtwoord in." #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "Authenticeert je met NickServ (SASL module heeft de voorkeur)" znc-1.7.5/modules/po/shell.pt_BR.po0000644000175000017500000000126713542151610017310 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/shell.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "" #: shell.cpp:169 msgid "Gives shell access" msgstr "" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "" znc-1.7.5/modules/po/send_raw.it_IT.po0000644000175000017500000000563113542151610020004 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/send_raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "Inviare una linea raw IRC" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "Utente:" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "Per cambiare utente, fai clic su selettore del Network" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "Utente/Network:" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "Inviare a:" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "Client" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "Server" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "Linea:" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "Inviare" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "Inviato [{1}] a {2}/{3}" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "Il Network {1} non è stato trovato per l'utente {2}" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "L'utente {1} non è stato trovato" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "Inviato [{1}] al server IRC di {2}/{3}" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "" "È necessario disporre dei privilegi di amministratore per caricare questo " "modulo" #: send_raw.cpp:82 msgid "Send Raw" msgstr "Inviare Raw" #: send_raw.cpp:92 msgid "User not found" msgstr "L'utente non è stato trovato" #: send_raw.cpp:99 msgid "Network not found" msgstr "Network non trovato" #: send_raw.cpp:116 msgid "Line sent" msgstr "Linea inviata" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "[utente] [network] [dati da inviare]" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "I dati verranno inviati ai client IRC dell'utente" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "I dati verranno inviati al server IRC a cui l'utente è connesso" #: send_raw.cpp:147 msgid "[data to send]" msgstr "[dati da inviare]" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "I dati verranno inviati al tuo attuale client" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "" "Consente di inviare alcune righe IRC non elaborate come/a qualcun altro" znc-1.7.5/modules/po/awaystore.nl_NL.po0000644000175000017500000000613513542151610020212 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/awaystore.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "Je bent gemarkeerd als afwezig" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "Welkom terug!" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "{1} bericht(en) verwijderd" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "Gebruik: delete " #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "Onjuist berichtnummer aangevraagd" #: awaystore.cpp:113 msgid "Message erased" msgstr "Bericht verwijderd" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "Bericht opgeslagen naar schijf" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "Er zijn geen berichten om op te slaan" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "Wachtwoord bijgewerkt naar [{1}]" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "Corrupt bericht! [{1}]" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "Corrupte tijdstempel! [{1}]" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "#--- Eind van berichten" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "Timer ingesteld op 300 seconden" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "Timer uitgeschakeld" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "Timer ingesteld op {1} second(en)" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "Huidige timer instelling: {1} second(en)" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" "These module heeft een wachtwoord als argument nodig voor versleuteling" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" "Ontsleutelen van opgeslagen berichten mislukt - Heb je wel het juiste " "wachtwoord als argument voor deze module ingevoerd?" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "Je hebt {1} bericht(en)!" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "Buffer niet gevonden" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "Niet mogelijk om versleutelde bericht(en) te ontsleutelen" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" "[ -notimer | -timer N ] [-kanalen] wachtw00rd . N is het aantal seconden, " "standaard is dit 600." #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" "Voegt automatisch afwezig met bijhouden van logboek, Handig wanneer je ZNC " "van meerdere locaties gebruikt" znc-1.7.5/modules/po/awaystore.de_DE.po0000644000175000017500000000622613542151610020151 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/awaystore.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "Sie wurden als abwesend markiert" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "Willkommen zurück!" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "{1} Nachrichten gelöscht" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "Verwendung: delete " #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "Ungültige Nachrichtennummer angefragt" #: awaystore.cpp:113 msgid "Message erased" msgstr "Nachricht gelöscht" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "Nachrichten auf der Festplatte gespeichert" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "Es gibt keine Nachrichten zu speichern" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "Password geändert auf [{1}]" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "Unbrauchbare Nachricht! [{1}]" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "Unbrauchbarer Zeitstempel! [{1}]" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "#-- Ende der Nachrichten" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "Timer auf 300 Sekunden gesetzt" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "Timer deaktiviert" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "Timer auf {1} Sekunden gesetzt" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "Aktuelle Timereinstellung: {1} Sekunden" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" "Dieses Modul benötigt als Argument eine Schlüsselphrase zur Verschlüsselung" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" "Konnte deine gespeicherte Nachrichten nicht entschlüssel - Hast du den " "richtigen Verschlüsselungsschlüssel als Modulargument angegeben?" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "Du hast {1} Nachrichten!" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "Kann Puffer nicht finden" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "Kann verschlüsselte Nachrichten nicht dekodieren" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" "[ -notimer | -timer N ] [-chans] passw0rd . N ist Anzahl an Sekunden, " "standardmäßig 600." #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" "Fügt automatische Abwesenheit mit Protokollierung hinzu, nützlich wenn du " "ZNC von verschiedenen Orten verwendest" znc-1.7.5/modules/po/missingmotd.it_IT.po0000644000175000017500000000102713542151610020532 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/missingmotd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "Invia 422 ai client quando effettuano l'accesso" znc-1.7.5/modules/po/imapauth.bg_BG.po0000644000175000017500000000106513542151610017737 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/imapauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "" znc-1.7.5/modules/po/samplewebapi.nl_NL.po0000644000175000017500000000076713542151610020652 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/samplewebapi.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "Voorbeeld van Web API module." znc-1.7.5/modules/po/autovoice.es_ES.po0000644000175000017500000000552713542151610020172 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/autovoice.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: autovoice.cpp:120 msgid "List all users" msgstr "Muestra todos los usuarios" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr " [canal]..." #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "Añade canales a un usuario" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "Borra canales de un usuario" #: autovoice.cpp:128 msgid " [channels]" msgstr " [canales]" #: autovoice.cpp:129 msgid "Adds a user" msgstr "Añade un usuario" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "Borra un usuario" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "Uso: AddUser [canales]" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "Uso: DelUser " #: autovoice.cpp:238 msgid "There are no users defined" msgstr "No hay usuarios definidos" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "Usuario" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "Máscara" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "Canales" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "Uso: AddChans [canal] ..." #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "No existe el usuario" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "Canal(es) añadido(s) al usuario {1}" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "Uso: DelChans [canal] ..." #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "Canal(es) borrado(s) del usuario {1}" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "Usuario {1} eliminado" #: autovoice.cpp:341 msgid "That user already exists" msgstr "Ese usuario ya existe" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "Usuario {1} añadido con la(s) máscara(s) {2}" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" "Cada argumento es un canal en el que quieres autovoz (el cual puede incluir " "comodines) o, si comienza por !, omitirlo para dar autovoz." #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "AutoVoz a gente conocida" znc-1.7.5/modules/po/modpython.it_IT.po0000644000175000017500000000101713542151610020215 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/modpython.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "Carica gli script di python come moduli ZNC" znc-1.7.5/modules/po/notes.pt_BR.po0000644000175000017500000000441613542151610017330 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/notes.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "" #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "" #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "" #: notes.cpp:75 msgid "List notes" msgstr "" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr "" #: notes.cpp:77 msgid "Add a note" msgstr "" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "" #: notes.cpp:81 msgid "Modify a note" msgstr "" #: notes.cpp:94 msgid "Notes" msgstr "" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "" #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "" #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "" znc-1.7.5/modules/po/autoreply.id_ID.po0000644000175000017500000000166213542151610020166 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/autoreply.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "" znc-1.7.5/modules/po/block_motd.nl_NL.po0000644000175000017500000000205713542151610020310 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/block_motd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: block_motd.cpp:26 msgid "[]" msgstr "[]" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" "Forceer dit blok met dit commando. Kan optioneel ingeven welke server te " "vragen." #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "Je bent niet verbonden met een IRC server." #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "MOTD geblokkeerd door ZNC" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "" "Blokkeert de MOTD van IRC zodat deze niet naar je client(s) verstuurd wordt." znc-1.7.5/modules/po/autocycle.pt_BR.po0000644000175000017500000000261513542151610020167 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/autocycle.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "" #: autocycle.cpp:33 msgid "List all entries" msgstr "" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "" #: autocycle.cpp:100 msgid "You have no entries." msgstr "" #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "" #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" znc-1.7.5/modules/po/flooddetach.id_ID.po0000644000175000017500000000345513542151610020420 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/flooddetach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "" #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "" znc-1.7.5/modules/po/identfile.pot0000644000175000017500000000234713542151610017323 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: identfile.cpp:30 msgid "Show file name" msgstr "" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "" #: identfile.cpp:34 msgid "Show file format" msgstr "" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "" #: identfile.cpp:38 msgid "Show current state" msgstr "" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "" #: identfile.cpp:78 msgid "identfile is free" msgstr "" #: identfile.cpp:86 msgid "Access denied" msgstr "" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "" #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "" znc-1.7.5/modules/po/perleval.ru_RU.po0000644000175000017500000000147513542151610020042 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/perleval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "" znc-1.7.5/modules/po/listsockets.bg_BG.po0000644000175000017500000000431613542151610020500 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/listsockets.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "" #: listsockets.cpp:62 msgid "[-n]" msgstr "" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "" #: listsockets.cpp:96 msgid "List sockets" msgstr "" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "" #: listsockets.cpp:142 msgid "Listener" msgstr "" #: listsockets.cpp:144 msgid "Inbound" msgstr "" #: listsockets.cpp:147 msgid "Outbound" msgstr "" #: listsockets.cpp:149 msgid "Connecting" msgstr "" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "" #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "" znc-1.7.5/modules/po/autoop.it_IT.po0000644000175000017500000001126313542151610017507 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/autoop.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: autoop.cpp:154 msgid "List all users" msgstr "Elenca tutti gli utenti" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr " [canale] ..." #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "Aggiunge canali ad un utente" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "Rimuove canali da un utente" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr " ,[maschera] ..." #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "Aggiunge una maschera (mask) ad un utente" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "Rimuove una maschera (mask) da un utente" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr " [,...] [canali]" #: autoop.cpp:170 msgid "Adds a user" msgstr "Aggiunge un utente" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "Rimuove un utente" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "Utilizzo: AddUser [,...] [channels]" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "Utilizzo: DelUser " #: autoop.cpp:300 msgid "There are no users defined" msgstr "Non ci sono utenti definiti" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "Utente" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "Hostmasks" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "Key" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "Canali" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "Usa: AddChans [channel] ..." #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "Utente inesistente" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "Canali aggiunti all'utente {1}" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "Utilizzo: DelChans [channel] ..." #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "Canali rimossi dall'utente {1}" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "Usa: AddMasks ,[mask] ..." #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "Hostmasks(s) Aggiunta all'utente {1}" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "Usa: DelMasks ,[mask] ..." #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "Utente rimosso {1} con chiave {2} e canali {3}" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "Hostmasks(s) Rimossa dall'utente {1}" #: autoop.cpp:478 msgid "User {1} removed" msgstr "Rimosso l'utente {1}" #: autoop.cpp:484 msgid "That user already exists" msgstr "Questo utente esiste già" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "L'utente {1} viene aggiunto con la hostmask(s) {2}" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "" "[{1}] ci ha inviato una challenge ma loro non sono operatori in nessuno dei " "canali definiti." #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "" "[{1}] ci ha inviato una challenge ma loro non corrispondono a nessuno degli " "utenti definiti." #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "ATTENZIONE! [{1}] ha inviato una challenge non valida." #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "" "[{1}] ha inviato una risposta in contrastante. Questo potrebbe essere " "dovuto ad un ritardo (lag)." #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" "ATTENZIONE! [{1}] inviato una risposta errata. Per favore verifica di avere " "la loro password corretta." #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "" "ATTENZIONE! [{1}] ha inviato una risposta, ma non corrisponde ad alcun " "utente definito." #: autoop.cpp:644 msgid "Auto op the good people" msgstr "Auto Op le buone persone" znc-1.7.5/modules/po/stripcontrols.es_ES.po0000644000175000017500000000116213542151610021110 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/stripcontrols.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "" "Eliminar códigos de control (colores, negrita, ...) de canales y mensajes " "privados." znc-1.7.5/modules/po/modperl.it_IT.po0000644000175000017500000000100413542151610017632 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/modperl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "Carica gli script Perl come moduli ZNC" znc-1.7.5/modules/po/autovoice.ru_RU.po0000644000175000017500000000445413542151610020226 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/autovoice.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: autovoice.cpp:120 msgid "List all users" msgstr "" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr "" #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "" #: autovoice.cpp:128 msgid " [channels]" msgstr "" #: autovoice.cpp:129 msgid "Adds a user" msgstr "" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "" #: autovoice.cpp:238 msgid "There are no users defined" msgstr "" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "" #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "" #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "" #: autovoice.cpp:341 msgid "That user already exists" msgstr "" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "" znc-1.7.5/modules/po/certauth.ru_RU.po0000644000175000017500000000434213542151610020043 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/certauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "" #: certauth.cpp:31 msgid "[pubkey]" msgstr "" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" #: certauth.cpp:35 msgid "id" msgstr "" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "" #: certauth.cpp:37 msgid "List your public keys" msgstr "" #: certauth.cpp:39 msgid "Print your current key" msgstr "" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "" #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "" #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "" #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "" #: certauth.cpp:215 msgid "Removed" msgstr "" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "" znc-1.7.5/modules/po/certauth.pot0000644000175000017500000000340313542151610017171 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "" #: certauth.cpp:31 msgid "[pubkey]" msgstr "" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" #: certauth.cpp:35 msgid "id" msgstr "" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "" #: certauth.cpp:37 msgid "List your public keys" msgstr "" #: certauth.cpp:39 msgid "Print your current key" msgstr "" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "" #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "" #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "" #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "" #: certauth.cpp:215 msgid "Removed" msgstr "" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "" znc-1.7.5/modules/po/perform.es_ES.po0000644000175000017500000000505513542151610017642 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/perform.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "Ejecutar" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "Comandos a ejecutar:" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "Comandos enviados al IRC al conectar, uno por línea." #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "Guardar" #: perform.cpp:24 msgid "Usage: add " msgstr "Uso: add " #: perform.cpp:29 msgid "Added!" msgstr "¡Añadido!" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "Número # no encontrado" #: perform.cpp:41 msgid "Command Erased." msgstr "Comando eliminado." #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "Id" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "Ejecutar" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "Expandido" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "No hay comandos en tu lista." #: perform.cpp:73 msgid "perform commands sent" msgstr "Comandos a ejecutar enviados" #: perform.cpp:86 msgid "Commands Swapped." msgstr "Comandos intercambiados." #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "Añade comandos a ejecutar cuando se conecta a un servidor" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "Elimina un comando a ejecutar" #: perform.cpp:100 msgid "List the perform commands" msgstr "Muestra los comandos a ejecutar" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "Enviar ahora los comandos a ejecutar en el servidor" #: perform.cpp:105 msgid " " msgstr " " #: perform.cpp:106 msgid "Swap two perform commands" msgstr "Intercambiar dos comandos a ejecutar" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "Guarda una lista de comandos a ejecutar cuando ZNC se conecta al IRC." znc-1.7.5/modules/po/perform.id_ID.po0000644000175000017500000000375613542151610017622 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/perform.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "" #: perform.cpp:24 msgid "Usage: add " msgstr "" #: perform.cpp:29 msgid "Added!" msgstr "" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "" #: perform.cpp:41 msgid "Command Erased." msgstr "" #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "" #: perform.cpp:73 msgid "perform commands sent" msgstr "" #: perform.cpp:86 msgid "Commands Swapped." msgstr "" #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "" #: perform.cpp:100 msgid "List the perform commands" msgstr "" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "" #: perform.cpp:105 msgid " " msgstr "" #: perform.cpp:106 msgid "Swap two perform commands" msgstr "" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "" znc-1.7.5/modules/po/samplewebapi.de_DE.po0000644000175000017500000000077313542151610020605 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/samplewebapi.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "Beispiel-Modul für die Web-API." znc-1.7.5/modules/po/ctcpflood.fr_FR.po0000644000175000017500000000274113542151610020144 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/ctcpflood.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "" #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "" #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "" msgstr[1] "" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "" znc-1.7.5/modules/po/simple_away.es_ES.po0000644000175000017500000000555513542151610020507 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/simple_away.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: simple_away.cpp:56 msgid "[]" msgstr "[]" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" "Muestra o establece el motivo de ausencia (%awaytime% se reemplaza por el " "tiempo que estás ausente, soporta sustituciones ExpandString)" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "Muestra el tiempo a esperar antes de marcarte como ausente" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "Establece el tiempo a esperar antes de marcarte como ausente" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "Deshabilita el tiempo a esperar antes de marcarte como ausente" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "Obtiene o define el mínimo de clientes antes de marcarte como ausente" #: simple_away.cpp:136 msgid "Away reason set" msgstr "Motivo de ausencia establecido" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "Motivo de ausencia: {1}" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "El motivo de ausencia quedaría como: {1}" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "Tiempo establecido: 1 segundo" msgstr[1] "Tiempo establecido: {1} segundos" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "Temporizador deshabilitado" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "Temporizador establecido a 1 segundo" msgstr[1] "Temporizador establecido a {1} segundos" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "MinClients establecido a: {1}" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "MinClients establecido a: {1}" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" "Puedes poner hasta 3 argumentos, como -notimer mensajeausencia o -timer 5 " "mensajeausencia." #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" "Este módulo te pondrá ausente en el IRC mientras estás desconectado de ZNC." znc-1.7.5/modules/po/awaystore.ru_RU.po0000644000175000017500000000451613542151610020245 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/awaystore.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "" #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "" #: awaystore.cpp:113 msgid "Message erased" msgstr "" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" znc-1.7.5/modules/po/route_replies.es_ES.po0000644000175000017500000000356213542151610021052 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/route_replies.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "[yes | no]" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "Indica si mostrar los mensajes de tiempo de espera agotado o no" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" "Este módulo ha agotado el tiempo de espera, lo que puede ser un problema de " "conectividad." #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" "Sin embargo, si puedes proporcionar los pasos a seguir para reproducir este " "problema, por favor informa del fallo." #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "Para desactivar este mensaje escribe \"/msg {1} silent yes\"" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "Ultima petición: {1}" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "Respuesta esperada:" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "{1} (última)" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "Los mensajes de tiempo de espera agotado están desactivados." #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "Los mensajes de tiempo de espera agotado están activados." #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "Envía respuestas (por ej. /who) solo al cliente correcto" znc-1.7.5/modules/po/fail2ban.ru_RU.po0000644000175000017500000000456313542151610017707 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/fail2ban.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "" #: fail2ban.cpp:28 msgid "[count]" msgstr "" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "" #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "" #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "" #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "" #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "" #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "" #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "" znc-1.7.5/modules/po/webadmin.bg_BG.po0000644000175000017500000007673613542151610017736 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/webadmin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "" #: webadmin.cpp:93 msgid "Your Settings" msgstr "" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "" #: webadmin.cpp:576 msgid "No such channel" msgstr "" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "" #: webadmin.cpp:749 msgid "Add Channel" msgstr "" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "" #: webadmin.cpp:766 msgid "Detached" msgstr "" #: webadmin.cpp:773 msgid "Enabled" msgstr "" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "" #: webadmin.cpp:911 msgid "Add Network" msgstr "" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "" #: webadmin.cpp:1551 msgid "Admin" msgstr "" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "" #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "" #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "" #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "" #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "" znc-1.7.5/modules/po/notes.id_ID.po0000644000175000017500000000437113542151610017272 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/notes.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "" #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "" #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "" #: notes.cpp:75 msgid "List notes" msgstr "" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr "" #: notes.cpp:77 msgid "Add a note" msgstr "" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "" #: notes.cpp:81 msgid "Modify a note" msgstr "" #: notes.cpp:94 msgid "Notes" msgstr "" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "" #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "" #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "" znc-1.7.5/modules/po/imapauth.fr_FR.po0000644000175000017500000000106113542151610017771 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/imapauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "" znc-1.7.5/modules/po/dcc.ru_RU.po0000644000175000017500000001350513542151610016756 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/dcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: dcc.cpp:88 msgid " " msgstr "<ник> <файл>" #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "Отправить файл из ZNC кому-либо" #: dcc.cpp:91 msgid "" msgstr "<файл>" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "Отправить файл из ZNC на ваш клиент" #: dcc.cpp:94 msgid "List current transfers" msgstr "СпиÑок текущих передач" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "Ð’Ñ‹ должны быть админиÑтратором Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ DCC" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "Попытка отправить [{1}] [{2}]." #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "Получение [{1}] Ñ [{2}]: файл уже ÑущеÑтвует." #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "Попытка подключитьÑÑ Ðº [{1} {2}], чтобы загрузить [{3}] Ñ [{4}]." #: dcc.cpp:179 msgid "Usage: Send " msgstr "ИÑпользование: Send <ник> <файл>" #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "Ðекорректный путь." #: dcc.cpp:199 msgid "Usage: Get " msgstr "ИÑпользование: Get <файл>" #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "Тип" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "СоÑтоÑние" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "СкороÑть" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "Ðик" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "IP" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "Файл" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "Отправка" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "Получение" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "Ожидание" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "{1} Кб/Ñек" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "У Ð²Ð°Ñ Ð½ÐµÑ‚ активных передач DCC." #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "Попытка возобновить отправку от позиции {1} файла [{2}] на [{3}]" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "" "Ðе удалоÑÑŒ возобновить отправку файла [{1}] [{2}]: не отправлено ничего." #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "Плохой файл DCC: {1}" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "Отправка [{1}] [{2}]: файл не открыт!" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "Получение [{1}] Ñ [{2}]: файл не открыт!" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "Отправка [{1}] [{2}]: Отказанное Ñоединение." #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "Получение [{1}] Ñ [{2}]: Отказанное Ñоединение." #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "Отправка [{1}] Ñ [{2}]: Ð²Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð¸Ñтекло." #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "Получение[{1}] Ñ [{2}]: Ð²Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð¸Ñтекло." #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "Отправка [{1}] [{2}]: ошибка Ñокета {3}: {4}" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "Получение [{1}] Ñ [{2}]: ошибка Ñокета {3}: {4}" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "" #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "" #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "" #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "" #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "" #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "" #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "" #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "" #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "" #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "" #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "" znc-1.7.5/modules/po/keepnick.de_DE.po0000644000175000017500000000301713542151610017717 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/keepnick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "Versuche deinen Hauptnick zu bekommen" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "Versuche nicht länger deinen Hauptnick zu bekommen" #: keepnick.cpp:44 msgid "Show the current state" msgstr "Zeige den aktuellen Zustand an" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "ZNC versucht bereits diesen Nicknamen zu bekommen" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "Kann Nick {1} nicht bekommen: {2}, {3}" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "Kann Nick {1} nicht bekommen" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "Versuche deinen Hauptnick zu bekommen" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "Versuche aktuell deinen Hauptnick zu bekommen" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "Aktuell deaktiviert, versuche 'enable'" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "Versucht weiterhin deinen Hauptnick zu bekommen" znc-1.7.5/modules/po/lastseen.es_ES.po0000644000175000017500000000316013542151610020001 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/lastseen.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "Usuario" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "Última conexión" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "Info" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "Acción" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "Editar" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "Borrar" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "Última conexión:" #: lastseen.cpp:53 msgid "Access denied" msgstr "Acceso denegado" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "Usuario" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "Última conexión" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "nunca" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "Muestra una lista de usuarios y cuando conectaron por última vez" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "Recopila datos sobre la última conexión de un usuario." znc-1.7.5/modules/po/perform.it_IT.po0000644000175000017500000000505313542151610017652 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/perform.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "Perform" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "Comandi Perform:" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "Comandi inviati al server IRC durante la connessione, uno per linea." #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "Salva" #: perform.cpp:24 msgid "Usage: add " msgstr "Usa: add " #: perform.cpp:29 msgid "Added!" msgstr "Aggiunto!" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "Numero # non trovato" #: perform.cpp:41 msgid "Command Erased." msgstr "Comando cancellato." #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "ID" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "Perform" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "Espanso" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "Nessun comando nella tua lista dei Perform." #: perform.cpp:73 msgid "perform commands sent" msgstr "comandi perform inviati" #: perform.cpp:86 msgid "Commands Swapped." msgstr "Comandi scambiati." #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "" "Aggiunge dei comandi (Perform) da inviare al server durante la connessione" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "Elimina i comandi Perform" #: perform.cpp:100 msgid "List the perform commands" msgstr "Elenco dei comandi Perform" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "Invia i comandi Perform al server adesso" #: perform.cpp:105 msgid " " msgstr " " #: perform.cpp:106 msgid "Swap two perform commands" msgstr "Scambia due comandi Perform" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "" "Mantiene una lista di comandi da eseguire quando lo ZNC si connette ad IRC." znc-1.7.5/modules/po/dcc.pt_BR.po0000644000175000017500000001011613542151610016723 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/dcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: dcc.cpp:88 msgid " " msgstr "" #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "" #: dcc.cpp:91 msgid "" msgstr "" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "" #: dcc.cpp:94 msgid "List current transfers" msgstr "" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "" #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "" #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "" #: dcc.cpp:179 msgid "Usage: Send " msgstr "" #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "" #: dcc.cpp:199 msgid "Usage: Get " msgstr "" #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "" #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "" #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "" #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "" #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "" #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "" #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "" #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "" #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "" #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "" #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "" #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "" #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "" #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "" #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "" #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "" #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "" znc-1.7.5/modules/po/flooddetach.pot0000644000175000017500000000302413542151610017625 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "" #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "" msgstr[1] "" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "" znc-1.7.5/modules/po/disconkick.pt_BR.po0000644000175000017500000000120013542151610020305 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/disconkick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" znc-1.7.5/modules/po/samplewebapi.pot0000644000175000017500000000024413542151610020023 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "" znc-1.7.5/modules/po/lastseen.id_ID.po0000644000175000017500000000260313542151610017754 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/lastseen.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "" #: lastseen.cpp:53 msgid "Access denied" msgstr "" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "" znc-1.7.5/modules/po/sasl.de_DE.po0000644000175000017500000000652413542151610017076 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/sasl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" #: sasl.cpp:62 msgid "search" msgstr "" #: sasl.cpp:62 msgid "Generate this output" msgstr "" #: sasl.cpp:64 msgid "[ []]" msgstr "" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "" #: sasl.cpp:72 msgid "[yes|no]" msgstr "" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "" #: sasl.cpp:114 msgid "Password was supplied" msgstr "" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "" #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "" #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "" #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "" #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "" znc-1.7.5/modules/po/sasl.bg_BG.po0000644000175000017500000000652713542151610017101 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/sasl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" #: sasl.cpp:62 msgid "search" msgstr "" #: sasl.cpp:62 msgid "Generate this output" msgstr "" #: sasl.cpp:64 msgid "[ []]" msgstr "" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "" #: sasl.cpp:72 msgid "[yes|no]" msgstr "" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "" #: sasl.cpp:114 msgid "Password was supplied" msgstr "" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "" #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "" #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "" #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "" #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "" znc-1.7.5/modules/po/samplewebapi.id_ID.po0000644000175000017500000000073013542151610020606 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/samplewebapi.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "" znc-1.7.5/modules/po/watch.pot0000644000175000017500000001023413542151610016460 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "" #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "" #: watch.cpp:397 msgid "Disabled all entries." msgstr "" #: watch.cpp:398 msgid "Enabled all entries." msgstr "" #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "" #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "" #: watch.cpp:593 msgid "Id {1} removed." msgstr "" #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "" #: watch.cpp:609 msgid "List" msgstr "" #: watch.cpp:611 msgid "List all entries being watched." msgstr "" #: watch.cpp:614 msgid "Dump" msgstr "" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "" #: watch.cpp:620 msgid "Del " msgstr "" #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "" #: watch.cpp:625 msgid "Clear" msgstr "" #: watch.cpp:626 msgid "Delete all entries." msgstr "" #: watch.cpp:629 msgid "Enable " msgstr "" #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "" #: watch.cpp:633 msgid "Disable " msgstr "" #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "" #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "" #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "" #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "" #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "" #: watch.cpp:652 msgid "Buffer [Count]" msgstr "" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "" #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "" #: watch.cpp:664 msgid "Help" msgstr "" #: watch.cpp:665 msgid "This help." msgstr "" #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "" #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "" znc-1.7.5/modules/po/modpython.de_DE.po0000644000175000017500000000100513542151610020142 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/modpython.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "Lade Python-Skripte als ZNC-Module" znc-1.7.5/modules/po/ctcpflood.pot0000644000175000017500000000225613542151610017334 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "" #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "" #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "" msgstr[1] "" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "" znc-1.7.5/modules/po/autocycle.pot0000644000175000017500000000210713542151610017342 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "" #: autocycle.cpp:33 msgid "List all entries" msgstr "" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "" #: autocycle.cpp:100 msgid "You have no entries." msgstr "" #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "" #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" znc-1.7.5/modules/po/lastseen.nl_NL.po0000644000175000017500000000317213542151610020010 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/lastseen.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "Gebruiker" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "Laatst gezien" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "Info" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "Actie" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "Bewerk" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "Verwijderen" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "Laatst ingelogd:" #: lastseen.cpp:53 msgid "Access denied" msgstr "Toegang geweigerd" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "Gebruiker" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "Laatst gezien" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "nooit" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "" "Laat lijst van gebruikers zien en wanneer deze voor het laatst ingelogd zijn" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "Houd bij wanneer gebruikers voor het laatst ingelogd zijn." znc-1.7.5/modules/po/autoattach.id_ID.po0000644000175000017500000000324013542151610020271 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/autoattach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "" #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "" #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "" #: autoattach.cpp:138 msgid "You have no entries." msgstr "" #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "" #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "" #: autoattach.cpp:152 msgid "List all entries" msgstr "" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "" #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "" znc-1.7.5/modules/po/alias.de_DE.po0000644000175000017500000000616013542151610017221 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/alias.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "Fehlendes erforderliches Argument: {1}" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "Alias angelegt: {1}" #: alias.cpp:203 msgid "Alias already exists." msgstr "Alias existiert bereits." #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "Alias gelöscht: {1}" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "Alias existiert nicht." #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "Alias modifiziert." #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "Ungültiger Index." #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "Es gibt keine Aliase." #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "Der folgende Alias existiert: {1}" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr ", " #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "Aktionen für Alias {1}:" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "Ende der Aktionen für Alias {1}." #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "Legt einen neuen, leeren Alias namens Name an." #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "Löscht einen existierenden Alias." #: alias.cpp:343 msgid " " msgstr " " #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "Fügt eine Zeile zu einem existierenden Alias hinzu." #: alias.cpp:346 msgid " " msgstr " " #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "Fügt eine Zeile in einen existierenden Alias ein." #: alias.cpp:349 msgid " " msgstr " " #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "Entfernt eine Zeile von einem existierenden Alias." #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "Entfernt alle Zeile von einem existierenden Alias." #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "Zeigt alle Aliase nach Namen an." #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "Zeigt die Aktionen an, die vom Alias durchgeführt werden." #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "" "Erzeugt eine Liste an Befehlen um ihre Alias-Konfiguration zu kopieren." #: alias.cpp:374 msgid "Clearing all of them!" msgstr "Alle von ihnen werden gelöscht!" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "Bietet Alias-Unterstützung im Bouncer an." znc-1.7.5/modules/po/autoop.nl_NL.po0000644000175000017500000001146713542151610017507 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/autoop.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: autoop.cpp:154 msgid "List all users" msgstr "Laat alle gebruikers zien" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr " [kanaal] ..." #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "Voegt kanaal toe aan een gebruiker" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "Verwijdert kanaal van een gebruiker" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr " ,[masker] ..." #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "Voegt masker toe aan gebruiker" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "Verwijdert masker van gebruiker" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr " [,...] [kanalen]" #: autoop.cpp:170 msgid "Adds a user" msgstr "Voegt een gebruiker toe" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "Verwijdert een gebruiker" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "" "Gebruik: AddUser [,...] " "[kanalen]" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "Gebruik: DelUser " #: autoop.cpp:300 msgid "There are no users defined" msgstr "Er zijn geen gebruikers gedefinieerd" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "Gebruiker" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "Hostmaskers" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "Sleutel" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "Kanalen" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "Gebruik: AddChans [kanaal] ..." #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "Gebruiker onbekend" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "Kana(a)l(en) toegevoegd aan gebruiker {1}" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "Gebruik: DelChans [kanaal] ..." #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "Kana(a)l(en) verwijderd van gebruiker {1}" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "Gebruik: AddMasks ,[masker] ..." #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "Hostmasker(s) toegevoegd aan gebruiker {1}" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "Gebruik: DelMasks ,[masker] ..." #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "Gebruiker {1} met sleutel {2} en kanalen {3} verwijderd" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "Hostmasker(s) verwijderd van gebruiker {1}" #: autoop.cpp:478 msgid "User {1} removed" msgstr "Gebruiker {1} verwijderd" #: autoop.cpp:484 msgid "That user already exists" msgstr "Die gebruiker bestaat al" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "Gebruiker {1} toegevoegd met hostmasker(s) {2}" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "" "[{1}] heeft ons een uitdaging gestuurd maar zijn geen beheerder in enige " "gedefinieerde kanalen." #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "" "[{1}] heeft ons een uitdaging gestuurd maar past niet bij een gedefinieerde " "gebruiker." #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "WAARSCHUWING! [{1}] heeft een ongeldige uitdaging gestuurd." #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "" "[{1}] heeft een ongeldige uitdaging gestuurd. Dit kan door vertraging komen." #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" "WAARSCHUWING! [{1}] heeft een verkeerd antwoord gestuurd. Controleer of je " "hun juiste wachtwoord hebt." #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "" "WAARSCHUWING! [{1}] heeft een antwoord verstuurd maar past niet bij een " "gedefinieerde gebruiker." #: autoop.cpp:644 msgid "Auto op the good people" msgstr "Geeft goede gebruikers automatisch beheerderrechten" znc-1.7.5/modules/po/webadmin.es_ES.po0000644000175000017500000012235313542151610017757 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/webadmin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "Información de canal" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "Nombre de canal:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "El nombre del canal." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "Clave:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "La contraseña del canal, si la hay." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "Tamaño búfer:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "Líneas de búfer." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "Modos predeterminados:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "Los modos por defecto del canal." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "Banderas" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "Guardar configuración" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "Módulo {1}" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "Guardar y volver" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "Guardar y continuar" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "Añadir canal y volver" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "Añadir canal y continuar" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "<contraseña>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "<red>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" "Para conectar a esta red desde tu cliente de IRC, puedes definir la " "contraseña del servidor como {1} o el nombre de usuario como " "{2}" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "Información de red" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" "Apodo, ApodoAlt, Ident, RealName, BindHost pueden dejarse vacíos para usar " "los valores del usuario." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "Nombre de red:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "El nombre de la red de IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "Apodo:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "Tu apodo en el IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "Apodo alternativo:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "Tu apodo secundario, si el primero no está disponible en IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "Ident:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "Tu ident." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "Nombre real:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "Tu nombre real." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "BindHost:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "Mensaje de salida:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "Puedes definir un mensaje a mostrar cuando sales del IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "Activo:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "Conectar a IRC & reconectar automáticamente" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "Confiar en todos los certificados:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "" "Deshabilitar validación de certificados (prevalece sobre TrustPKI). " "¡INSEGURO!" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "Confiar en el PKI:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" "Al dejar esta opción como Falso se confiará solamente en los certificados a " "los que hayas añadido una huella digital." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "Servidores de esta red de IRC:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "" "Un servidor por línea, \"host [[+]puerto] [contraseña\", + significa SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "Nombre de host" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "Puerto" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "Contraseña" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "" "Huellas digitales SHA-256 de certificados SSL de confianza de esta red de " "IRC:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" "Cuando se encuentren estos certificados se omitirán las comprobaciones de " "nombre de host, fecha de expiración, y CA" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "Protección de flood:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" "Es aconsejable activar la protección de flood. Esto previene errores de " "\"Excess flood\", que suelen ocurrir cuando tu cliente de IRC es inundado a " "comandos. Al cambiar esto, reconecta ZNC al servidor." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "[Protección de flood] Activada" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "Flujo de flood:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" "El número de segundos por línea. Al cambiar esto, reconecta ZNC al servidor." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "{1} segundos por línea" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "Ráfaga de flood:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" "Número de líneas que pueden enviarse inmediatamente. Al cambiar esto, " "reconecta ZNC al servidor." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "{1} líneas que pueden enviarse inmediatamente" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "Tiempo de unión a canales:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" "Tiempo de espera antes de unirse a canales justo al conectar al servidor." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "{1} segundos" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "Codificación de caracteres usada entre ZNC y el servidor de IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "Codificación del servidor:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "Canales" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "Aquí podrás añadir y modificar canales cuando hayas creado la red." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "Añadir" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "Guardar" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "Nombre" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "Modos" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "ModosPredet" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "Tamaño búfer" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "Opciones" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "↠Añade un canal (abre en la misma página)" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "Editar" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "Borrar" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "Módulos" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "Parámetros" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "Descripción" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "Cargado globalmente" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "Cargado por el usuario" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "Añadir red y volver" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "Añadir red y continuar" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "Autenticación" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "Usuario:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "Introduce un nombre de usuario." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "Contraseña:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "Introduce una contraseña." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "Confirma la contraseña:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "Re-introduce la misma contraseña." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "Autenticación solo vía módulo" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" "Permitir autenticación de usuario solo por módulos externos, deshabilitando " "la autenticación integrada por contraseña." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "IPs permitidas:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" "Dejar vacío para permitir conexiones desde todas las IPs.
De lo " "contrario, una entrada por linea. Puedes usar comodines * y ?." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "Información de IRC" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" "Apodo, ApodoAlt, Ident, RealName y Quit pueden dejarse vacíos para usar los " "valores predeterminados." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "La ident es enviada al servidor como nombre de usuario." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "Prefijo de Status:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "El prefijo para el status y los privados de módulos" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "DCCBindHost:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "Redes" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "Clientes" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "Servidor actual" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "Apodo" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "↠Añade una red (se abre en la misma página)" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "Podrás añadir y modificar redes aquí cuando hayas clonado al usuario." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "Podrás añadir y modificar redes aquí cuando hayas creado al usuario." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "Cargado por redes" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" "Estos son los modos predeterminados que ZNC pondrá cuando entres a un canal " "vacío." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "Vacio = Usa el valor estándar" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Cantidad de líneas por canal que se guardarán en búfer antes de borrar las " "más antiguas. Los búfers se guardan por defecto en memoria." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "Privados" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "Max búfers:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "Número máximo de búfers de privados. 0 es ilimitado." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Cantidad de líneas de privados que se guardarán en búfer antes de borrar las " "más antiguas. Los búfers se guardan por defecto en memoria." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "Comportamiento de ZNC" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" "Cualquiera de estas cajas de texto pueden dejarse vacías para usar sus " "valores predeterminados." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "Formato de tiempo:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" "El formato de tiempo usado en los búfers, por ejemplo [%H:%M:%S]. Este " "parámetro se ignora en nuevos clientes de IRC, los cuales usan server-time. " "Si tu cliente soporta server-time, cambia el formato de tiempo en sus " "ajustes." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "Zona horaria:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "Ej: Europe/Madrid, o GMT+1" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "Codificación de caracteres usada entre tu cliente de IRC y ZNC." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "Codificación de caracteres:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "Intentos de unión:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" "Número de veces que ZNC intentará entrar a un canal si la primera ha " "fallado, por ej. por modos de canal +i/+k o si estás baneado." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "Velocidad de entrada:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" "Número de canales que habrá en un comando JOIN. 0 es ilimitado " "(predeterminado). Pon un valor positivo inferior si eres desconectado por " "\"Max SendQ Exceeded\"" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "Tiempo de espera antes de reconectar:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" "Tiempo que ZNC espera (en segundos) hasta que recibe algo de la red o " "declara la conexión perdida." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "Máximo de redes de IRC:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "Número máximo de redes IRC permitidas para este usuario." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "Sustituciones" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "Respuestas CTCP:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "" "Una respuesta por linea. Ejemplo: TIME ¡Cómprate un reloj!" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "{1} están disponibles" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "Un valor vacío hará que la solicitud CTCP será ignorada" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "Solicitud" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "Respuesta" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "Apariencia:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "- Global -" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "Predeterminada" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "No se han encontrado otras apariencias" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "Idioma:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "Clonar y volver" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "Clonar y continuar" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "Crear y volver" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "Crear y continuar" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "Clonar" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "Crear" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "Confirmar borrado de red" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "" "¿Estás seguro de que quieres eliminar la red \"{2}\" del usuario \"{1}\"?" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "Sí" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "No" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "Confirmación borrado de usuario" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "¿Estás seguro de que quieres eliminar al usuario \"{1}\"?" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "" "ZNC está compilado sin soporte de codificaciones. Se requiere {1} para ello." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "Modo heredado deshabilitado por modpython." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "No realizar ninguna codificación (modo heredado, no recomendado)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "" "Intentar analizar como UTF-8 y como {1}, enviar como UTF-8 (recomendado)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "Intentar analizar como UTF-8 y como {1}, enviar como {1}" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "Analizar y enviar como {1} solamente" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "Ej. UTF-8, o ISO-8859-15" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "Bienvenido al módulo webadmin de ZNC." #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "" "Todos los cambios que hagas harán efecto inmediatamente cuando los envíes." #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "Nombre de usuario" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "Borrar" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "Puerto(s) de escucha" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "BindHost" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "IPv4" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "IPv6" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "IRC" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "HTTP" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "PrefijoURI" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" "Para eliminar el puerto que usas para acceder al webmin, conecta por otro " "puerto, o hazlo por IRC (/znc DelPort)" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "Actual" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "Ajustes" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "Predeterminado solo para nuevos usuarios." #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "Tamaño máximo del búfer:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "Define el tamaño máximo global que un usuario puede tener." #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "Tiempo de espera para conectar:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" "Tiempo entre intentos de conexión a los servidores de IRC, en segundos. Esto " "afecta a la conexión entre ZNC y el servidor IRC, no a la conexión entre tu " "cliente y ZNC." #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "Regulador de conexión:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" "Tiempo mínimo entre intentos de conexión al mismo host, en segundos. Algunos " "servidores rechazan tu conexión si intentas reconectar demasiado rápido." #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "Límite de conexiones anónimas por IP:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "Limita el número de conexiones sin identificar por IP." #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "Proteger sesiones web:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "No permitir cambio de IP durante la sesión web" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "Ocultar versión de ZNC" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "Ocultar número de versión a usuarios no-ZNC" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "Permitir autenticación de usuario solo por módulos externos" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "MOTD:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "\"Mensaje del día\", enviado a todos los usuarios de ZNC al conectar." #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "Módulos globales" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "Cargados por usuarios" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "Información" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "Uptime" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "Total usuarios" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "Total redes" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "Redes unidas" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "Total conexiones cliente" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "Total conexiones IRC" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "Conexiones cliente" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "Conexiones IRC" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "Total" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "Entrada" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "Salida" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "Usuarios" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "Tráfico" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "Usuario" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "Red" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "Ajustes globales" #: webadmin.cpp:93 msgid "Your Settings" msgstr "Tus ajustes" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "Info de tráfico" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "Gestionar usuarios" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "Envío no válido [Nombre de usuario requerido]" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "Envío no válido [Las contraseñas no coinciden]" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "¡El tiempo de espera no puede ser inferior a 30 segundos!" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "No se ha podido cargar el módulo [{1}]: {2}" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "No se ha podido cargar el módulo [{1}] con parámetros {2}" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "No existe el usuario" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "No existe el usuario o la red" #: webadmin.cpp:576 msgid "No such channel" msgstr "No existe el canal" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "No te elimines a ti mismo, el suicidio no es la solución" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "Editar usuario [{1}]" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "Editar red [{1}]" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "Editar canal [{1}] o red [{2}] del usuario [{3}]" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "Editar canal [{1}]" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "Añadir canal a red [{1}] del usuario [{2}]" #: webadmin.cpp:749 msgid "Add Channel" msgstr "Añadir canal" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "Autoborrar búfer de canal" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "Borrar automáticamente búfers de canales tras reproducirlos" #: webadmin.cpp:766 msgid "Detached" msgstr "Separado" #: webadmin.cpp:773 msgid "Enabled" msgstr "Habilitado" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "El nombre de canal es un parámetro obligatorio" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "El canal [{1}] ya existe" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "No se ha podido añadir el canal [{1}]" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "" "El canal fue añadido/modificado, pero el fichero de configuración no ha sido " "escrito" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" "Límite de redes superado. Pídele a un admin que te incremente el límite, o " "elimina redes innecesarias de tus ajustes." #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "Editar red [{1}] del usuario [{2}]" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "Añadir red para el usuario [{1}]" #: webadmin.cpp:911 msgid "Add Network" msgstr "Añadir red" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "El nombre de la red es un parámetro obligatorio" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "No se ha podido recargar el módulo [{1}]: {2}" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "" "La red fue añadida/modificada, pero el fichero de configuración no se ha " "podido escribir" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "La red no existe para este usuario" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "" "La red fue eliminada, pero el fichero de configuración no se ha podido " "escribir" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "Ese canal no existe para esta red" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "" "El canal fue eliminado, pero el fichero de configuración no se ha podido " "escribir" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "Clonar usuario [{1}]" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" "Borrar automáticamente búfers de canales tras reproducirlos (el valor " "predeterminado para nuevos canales)" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "Multi clientes" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "Anexar marcas de tiempo" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "Preceder marcas de tiempo" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "Bloquear LoadMod" #: webadmin.cpp:1551 msgid "Admin" msgstr "Admin" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "Bloquear SetBindHost" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "Autoborrar búfer de privados" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "Borrar automáticamente búfers de privados tras reproducirlos" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "Envío no válido: el usuario {1} ya existe" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "Envío no válido: {1}" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "" "El usuario fue añadido, pero el fichero de configuración no se ha podido " "escribir" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "" "El usuario fue editado, pero el fichero de configuración no se ha podido " "escribir" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "Elige IPv4, IPv6 o ambos." #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "Elige IRC, HTTP o ambos." #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "" "El puerto fue cambiado, pero el fichero de configuración no se ha podido " "escribir" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "Petición inválida." #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "El puerto de escucha especificado no se ha encontrado." #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "" "Los ajustes fueron cambiados, pero el fichero de configuración no se ha " "podido escribir" znc-1.7.5/modules/po/nickserv.pt_BR.po0000644000175000017500000000300013542151610020010 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/nickserv.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: nickserv.cpp:31 msgid "Password set" msgstr "" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "" #: nickserv.cpp:63 msgid "Ok" msgstr "" #: nickserv.cpp:68 msgid "password" msgstr "" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "" #: nickserv.cpp:72 msgid "nickname" msgstr "" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "" #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "" znc-1.7.5/modules/po/certauth.pt_BR.po0000644000175000017500000000411013542151610020006 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/certauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "" #: certauth.cpp:31 msgid "[pubkey]" msgstr "" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" #: certauth.cpp:35 msgid "id" msgstr "" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "" #: certauth.cpp:37 msgid "List your public keys" msgstr "" #: certauth.cpp:39 msgid "Print your current key" msgstr "" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "" #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "" #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "" #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "" #: certauth.cpp:215 msgid "Removed" msgstr "" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "" znc-1.7.5/modules/po/stripcontrols.pt_BR.po0000644000175000017500000000104613542151610021121 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/stripcontrols.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "" znc-1.7.5/modules/po/perform.bg_BG.po0000644000175000017500000000376413542151610017611 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/perform.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "" #: perform.cpp:24 msgid "Usage: add " msgstr "" #: perform.cpp:29 msgid "Added!" msgstr "" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "" #: perform.cpp:41 msgid "Command Erased." msgstr "" #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "" #: perform.cpp:73 msgid "perform commands sent" msgstr "" #: perform.cpp:86 msgid "Commands Swapped." msgstr "" #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "" #: perform.cpp:100 msgid "List the perform commands" msgstr "" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "" #: perform.cpp:105 msgid " " msgstr "" #: perform.cpp:106 msgid "Swap two perform commands" msgstr "" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "" znc-1.7.5/modules/po/simple_away.it_IT.po0000644000175000017500000000556413542151610020521 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/simple_away.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: simple_away.cpp:56 msgid "[]" msgstr "[]" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" "Mostra o imposta il motivo dell'away (% awaytime% viene sostituito con il " "tempo impostato, supporta le sostituzioni utilizzando ExpandString)" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "Mostra il tempo d'attesa attuale prima di passare all'away" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "Imposta il tempo d'attesa prima di passare all'away" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "Disabilita il tempo di attesa prima di impostare l'away" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "Ottieni o imposta il numero minimo di client prima di andare away" #: simple_away.cpp:136 msgid "Away reason set" msgstr "Imposta il motivo dell'assenza (away)" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "Motivo dell'away: {1}" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "Il motivo dell'assenza (away) attuale sarebbe: {1}" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "Impostazione del timer corrente: 1 secondo" msgstr[1] "Impostazione del timer corrente: {1} secondi" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "Timer disabilitato" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "Timer impostato a 1 secondo" msgstr[1] "Timer impostato a: {1} secondi" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "Impostazione corrente di MinClients: {1}" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "MinClients impostato a {1}" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" "Puoi inserire fino a 3 argomenti, come -notimer awaymessage o -timer 5 " "awaymessage." #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" "Questo modulo imposterà automaticamente l'away su IRC mentre sei disconnesso " "dallo ZNC." znc-1.7.5/modules/po/ctcpflood.de_DE.po0000644000175000017500000000403113542151610020100 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/ctcpflood.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "Setzt das Sekundenlimit" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "Setzt das Zeilenlimit" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "Zeige aktuelle Limits" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "Limit von {1} erreicht, blockiere alle CTCP" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "Verwendung: Secs " #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "Verwendung: Lines " #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "1 CTCP-Nachricht" msgstr[1] "{1} CTCP-Nachrichten" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "jede Sekunde" msgstr[1] "alle {1} Sekunden" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "Aktuelles Limit ist {1} {2}" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" "Dieses Modul bekommt kein oder zwei Argumente. Das erste Argument ist die " "Anzahl an Zeilen, die den Flood-Schutz auslösen. Das zweite Argument ist die " "Zeit (Sek) in der das Zeilenlimit erreicht werden muss. Die " "Standardeinstellung ist 4 CTCPs in 2 Sekunden" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "Leite CTCP-Floods nicht an Klienten weiter" znc-1.7.5/modules/po/keepnick.it_IT.po0000644000175000017500000000305513542151610017771 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/keepnick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "Porova ad ottenere il tuo nick principale" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "Non sto più cercando di ottenere il tuo nick principale" #: keepnick.cpp:44 msgid "Show the current state" msgstr "Mostra lo stato corrente" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "ZNC stà già cercando di ottenere questo nickname" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "Impossibile ottenere il nick {1}: {2}, {3}" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "Impossibile ottenere il nick {1}" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "Cercando di ottenere il tuo nick principale" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "Sto cercando di ottenere il tuo nick principale" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "Attualmente disabilitato, prova ad abilitarlo (enable)" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "Contino a provare il tuo nick principale" znc-1.7.5/modules/po/log.nl_NL.po0000644000175000017500000000752213542151610016756 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/log.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "" "Stel logboek regels in, gebruik !#kanaal of !query om te verwijderen, * is " "toegestaan" #: log.cpp:62 msgid "Clear all logging rules" msgstr "Verwijder alle logboek regels" #: log.cpp:64 msgid "List all logging rules" msgstr "Laat alle logboek regels zien" #: log.cpp:67 msgid " true|false" msgstr " true|false" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "" "Stelt een van de volgende opties in: toetredingen, verlatingen, naam " "aanpassingen" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "Laat huidige instellingen zie die ingesteld zijn door het Set commando" #: log.cpp:143 msgid "Usage: SetRules " msgstr "Gebruik: SetRules " #: log.cpp:144 msgid "Wildcards are allowed" msgstr "Jokers zijn toegestaan" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "Geen logboek regels. Alles wordt bijgehouden." #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "1 regel verwijderd: {2}" msgstr[1] "{1} regels verwijderd: {2}" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "Regel" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "Logboek ingeschakeld" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "" "Gebruik: Set true|false, waar is een van de " "volgende: joins, quits, nickchanges" #: log.cpp:196 msgid "Will log joins" msgstr "Zal toetredingen vastleggen" #: log.cpp:196 msgid "Will not log joins" msgstr "Zal toetredingen niet vastleggen" #: log.cpp:197 msgid "Will log quits" msgstr "Zal verlatingen vastleggen" #: log.cpp:197 msgid "Will not log quits" msgstr "Zal verlatingen niet vastleggen" #: log.cpp:199 msgid "Will log nick changes" msgstr "Zal naamaanpassingen vastleggen" #: log.cpp:199 msgid "Will not log nick changes" msgstr "Zal naamaanpassingen niet vastleggen" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "Onbekende variabele. Bekende variabelen: joins, quits, nickchanges" #: log.cpp:211 msgid "Logging joins" msgstr "Toetredingen worden vastgelegd" #: log.cpp:211 msgid "Not logging joins" msgstr "Toetredingen worden niet vastgelegd" #: log.cpp:212 msgid "Logging quits" msgstr "Verlatingen worden vastgelegd" #: log.cpp:212 msgid "Not logging quits" msgstr "Verlatingen worden niet vastgelegd" #: log.cpp:213 msgid "Logging nick changes" msgstr "Naamaanpassingen worden vastgelegd" #: log.cpp:214 msgid "Not logging nick changes" msgstr "Naamaanpassingen worden niet vastgelegd" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" "Ongeldige argumenten [{1}]. Maar één logboekpad is toegestaan. Controleer of " "er geen spaties in het pad voorkomen." #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "Ongeldig logboekpad [{1}]" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "Logboek schrijven naar [{1}]. Gebruik tijdstempel: '{2}'" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "[-sanitize] Optioneel pad waar het logboek opgeslagen moet worden." #: log.cpp:563 msgid "Writes IRC logs." msgstr "Schrijft IRC logboeken." znc-1.7.5/modules/po/pyeval.it_IT.po0000644000175000017500000000120013542151610017466 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/pyeval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "Devi avere i privilegi di amministratore per caricare questo modulo." #: pyeval.py:82 msgid "Evaluates python code" msgstr "Valuta il codice python" znc-1.7.5/modules/po/modules_online.bg_BG.po0000644000175000017500000000076313542151610021147 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/modules_online.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "" znc-1.7.5/modules/po/identfile.it_IT.po0000644000175000017500000000410213542151610020135 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/identfile.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: identfile.cpp:30 msgid "Show file name" msgstr "Mostra il nome del file" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "Imposta il nome del file" #: identfile.cpp:34 msgid "Show file format" msgstr "Mostra il formato del file" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "Imposta il formato del file" #: identfile.cpp:38 msgid "Show current state" msgstr "Mostra lo stato corrente" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "File impostato su: {1}" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "Il file è stato impostato su: {1}" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "Il formato è stato impostato su: {1}" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "Il formato verrà espanso su: {1}" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "Il formato è impostato su: {1}" #: identfile.cpp:78 msgid "identfile is free" msgstr "l'identfile è libero" #: identfile.cpp:86 msgid "Access denied" msgstr "Accesso negato" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" "Connessione interrotta, un altro utente o network è attualmente connesso " "utilizzando un file ident spoof" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "[{1}] non può essere scritto, riprovo..." #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "Scrive l'ident di un utente in un file quando tenta di connettersi." znc-1.7.5/modules/po/chansaver.bg_BG.po0000644000175000017500000000076013542151610020102 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/chansaver.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "" znc-1.7.5/modules/po/watch.nl_NL.po0000644000175000017500000001421013542151610017273 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/watch.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "Alle gebruikers gewist." #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "Buffer aantal is ingesteld op {1}" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "Onbekend commando: {1}" #: watch.cpp:397 msgid "Disabled all entries." msgstr "Alle gebruikers uitgeschakeld." #: watch.cpp:398 msgid "Enabled all entries." msgstr "Alle gebruikers ingeschakeld." #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "Ongeldige ID" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "Id {1} uitgeschakeld" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "Id {1} ingeschakeld" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "Stel DetachedClientOnly voor alle gebruikers in op Ja" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "Stel DetachedClientOnly voor alle gebruikers in op Nee" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "Id {1} ingesteld op Ja" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "Id {1} ingesteld op Nee" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "DetachedChannelOnly voor alle gebruikers insteld op Ja" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "DetachedChannelOnly voor alle gebruikers insteld op Nee" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "Id" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "Hostmasker" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "Doel" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "Patroon" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "Bronnen" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "Uit" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "DetachedClientOnly" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "DetachedChannelOnly" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "Ja" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "Nee" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "Je hebt geen gebruikers." #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "Bronnen ingesteld voor Id {1}." #: watch.cpp:593 msgid "Id {1} removed." msgstr "Id {1} verwijderd." #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "Commando" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "Beschrijving" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "Add [doel] [patroon}" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "Gebruikt om een gebruiker toe te voegen om naar uit te kijken." #: watch.cpp:609 msgid "List" msgstr "Lijst" #: watch.cpp:611 msgid "List all entries being watched." msgstr "Toon alle gebruikers waar naar uitgekeken wordt." #: watch.cpp:614 msgid "Dump" msgstr "Storten" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "Stort een lijst met alle huidige gebruikers om later te gebruiken." #: watch.cpp:620 msgid "Del " msgstr "Del " #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "Verwijdert Id van de lijst van de naar uit te kijken gebruikers." #: watch.cpp:625 msgid "Clear" msgstr "Wissen" #: watch.cpp:626 msgid "Delete all entries." msgstr "Verwijder alle gebruikers." #: watch.cpp:629 msgid "Enable " msgstr "Enable " #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "Schakel een uitgeschakelde gebruiker in." #: watch.cpp:633 msgid "Disable " msgstr "Disable " #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "Schakel een ingeschakelde gebruiker uit (maar verwijder deze niet)." #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "SetDetachedClientOnly " #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "Schakel een losgekoppelde client in of uit voor een gebruiker." #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "SetDetachedChannelOnly " #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "Schakel een losgekoppeld kanaal in of uit voor een gebruiker." #: watch.cpp:652 msgid "Buffer [Count]" msgstr "Buffer [aantal]" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "Toon/Stel in de aantal gebufferde regels wanneer losgekoppeld." #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "SetSources [#kanaal priv #foo* !#bar]" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "Stel the bronkanalen in waar je om geeft." #: watch.cpp:664 msgid "Help" msgstr "Help" #: watch.cpp:665 msgid "This help." msgstr "Deze hulp." #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "Gebruiker {1} bestaat al." #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "Voeg gebruiker toe: {1}, kijk uit naar [{2}] -> {3}" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "Watch: Niet genoeg argumenten. Probeer Help" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "WAARSCHUWING: ongeldige gebruiker gevonden terwijl deze geladen werd" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "Kopiëer activiteit van een specifieke gebruiker naar een apart venster" znc-1.7.5/modules/po/autoattach.es_ES.po0000644000175000017500000000423213542151610020321 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/autoattach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "Añadido a la lista" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "{1} ya está añadido" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "Uso: Add [!]<#canal> " #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "Comodines permitidos" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "Borrado {1} de la lista" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "Uso: Del[!]<#canal> " #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "Neg" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "Canal" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "Patrón" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "Host" #: autoattach.cpp:138 msgid "You have no entries." msgstr "No tienes entradas." #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "[!]<#canal> " #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "Añade una entrada, usa !#canal para negarla y * para usar comodines" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "Borra una entrada, necesita coincidir exactamente" #: autoattach.cpp:152 msgid "List all entries" msgstr "Muestra todas las entradas" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "Imposible añadir [{1}]" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "Lista de máscaras de canales y máscaras de canales con ! delante." #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "Te reune a los canales cuando hay actividad." znc-1.7.5/modules/po/perleval.it_IT.po0000644000175000017500000000136213542151610020011 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/perleval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "Valuta il codice perl" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "Solo gli amministrati possono caricare questo modulo" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "Errore: %s" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "Risultato: %s" znc-1.7.5/modules/po/block_motd.de_DE.po0000644000175000017500000000212213542151610020237 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/block_motd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: block_motd.cpp:26 msgid "[]" msgstr "[]" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" "Überschreibe die Blockade mit diesem Befehl. Kann optional angeben welcher " "Server befragt werden soll." #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "Du bist nicht zu einem IRC-Server verbunden." #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "MOTD durch ZNC blockiert" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "" "Blockiere die MOTD aus dem IRC, so dass sie nicht zu deinen Klienten " "gesendet wird." znc-1.7.5/modules/po/crypt.pot0000644000175000017500000000436513542151610016523 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "" #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "" #: crypt.cpp:204 msgid "List all keys" msgstr "" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "" #: crypt.cpp:213 msgid "[Prefix]" msgstr "" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "" #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "" #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "" #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "" #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "" #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "" #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "" #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "" #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "" #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "" #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "" znc-1.7.5/modules/po/sasl.pt_BR.po0000644000175000017500000000654613542151610017150 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/sasl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" #: sasl.cpp:62 msgid "search" msgstr "" #: sasl.cpp:62 msgid "Generate this output" msgstr "" #: sasl.cpp:64 msgid "[ []]" msgstr "" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "" #: sasl.cpp:72 msgid "[yes|no]" msgstr "" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "" #: sasl.cpp:114 msgid "Password was supplied" msgstr "" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "" #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "" #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "" #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "" #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "" znc-1.7.5/modules/po/perform.ru_RU.po0000644000175000017500000000423513542151610017677 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/perform.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "" #: perform.cpp:24 msgid "Usage: add " msgstr "" #: perform.cpp:29 msgid "Added!" msgstr "" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "" #: perform.cpp:41 msgid "Command Erased." msgstr "" #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "" #: perform.cpp:73 msgid "perform commands sent" msgstr "" #: perform.cpp:86 msgid "Commands Swapped." msgstr "" #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "" #: perform.cpp:100 msgid "List the perform commands" msgstr "" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "" #: perform.cpp:105 msgid " " msgstr "" #: perform.cpp:106 msgid "Swap two perform commands" msgstr "" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "" znc-1.7.5/modules/po/send_raw.pt_BR.po0000644000175000017500000000432413542151610020000 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/send_raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "" #: send_raw.cpp:82 msgid "Send Raw" msgstr "" #: send_raw.cpp:92 msgid "User not found" msgstr "" #: send_raw.cpp:99 msgid "Network not found" msgstr "" #: send_raw.cpp:116 msgid "Line sent" msgstr "" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "" #: send_raw.cpp:147 msgid "[data to send]" msgstr "" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "" znc-1.7.5/modules/po/autocycle.es_ES.po0000644000175000017500000000350513542151610020156 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/autocycle.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "[!]<#canal>" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "Añadir una entrada, usa !#canal para negarla y * para usar comodín" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "Borrar una entrada, necesita coincidir exactamente" #: autocycle.cpp:33 msgid "List all entries" msgstr "Mostrar todas las entradas" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "Imposible de añadir {1}" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "{1} ya está añadido" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "Añadido {1} a la lista" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "Uso: Add [!]<#canal>" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "Borrado {1} de la lista" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "Uso: Del [!]<#canal>" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "Canal" #: autocycle.cpp:100 msgid "You have no entries." msgstr "No tienes entradas." #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "Lista de máscaras de canales y máscaras de canales con ! delante." #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" "Re-entra a los canales para obtener Op si eres el único usuario del canal" znc-1.7.5/modules/po/autoattach.nl_NL.po0000644000175000017500000000427013542151610020327 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/autoattach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "Toegevoegd aan lijst" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "{1} is al toegevoegd" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "Gebruik: Add [!]<#kanaal> " #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "Jokers zijn toegestaan" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "{1} van lijst verwijderd" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "Gebruik: Del [!]<#kanaal> " #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "Verwijderd" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "Kanaal" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "Zoek" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "Host" #: autoattach.cpp:138 msgid "You have no entries." msgstr "Je hebt geen kanalen toegevoegd." #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "[!]<#kanaal> " #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" "Voeg een kanaal toe, gebruik !#kanaal om te verwijderen en gebruik * voor " "jokers" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "Verwijder een kanaal, moet een exacte overeenkomst zijn" #: autoattach.cpp:152 msgid "List all entries" msgstr "Laat alle kanalen zien" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "Kan [{1}] niet toevoegen" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "Lijst van kanaal maskers en kanaal maskers met ! er voor." #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "Verbind je met kanalen als er activiteit is." znc-1.7.5/modules/po/send_raw.pot0000644000175000017500000000361713542151610017163 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "" #: send_raw.cpp:82 msgid "Send Raw" msgstr "" #: send_raw.cpp:92 msgid "User not found" msgstr "" #: send_raw.cpp:99 msgid "Network not found" msgstr "" #: send_raw.cpp:116 msgid "Line sent" msgstr "" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "" #: send_raw.cpp:147 msgid "[data to send]" msgstr "" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "" znc-1.7.5/modules/po/modperl.es_ES.po0000644000175000017500000000101013542151610017615 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/modperl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "Carga scripts perl como módulos de ZNC" znc-1.7.5/modules/po/sample.ru_RU.po0000644000175000017500000000456113542151610017510 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/sample.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "" #: sample.cpp:50 msgid "Sample job done" msgstr "" #: sample.cpp:65 msgid "TEST!!!!" msgstr "" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "" #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "" #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "" #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "" #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "" znc-1.7.5/modules/po/savebuff.de_DE.po0000644000175000017500000000370713542151610017735 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/savebuff.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "Setzt das Password" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "Spielt den Puffer ab" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "Speichert alle Puffer" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" "Passwort ist nicht gesagt, was üblicherweise bedeutet, dass die " "Entschlüsselung fehlgeschlagen ist. Du kannst setpass benutzen um das " "richtige Passwort zu setzen und alles sollte funktionieren, oder setpass ein " "neues Passwort und save für einen Neubeginn" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "Password auf [{1}] gesetzt" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "{1} abgespielt" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "Kann verschlüsselte Datei {1} nicht dekodieren" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" "Dieses Modul bekommt bis zu einem Argument. Entweder --ask-pass oder das " "Password selbst (welches Leerzeichen enthalten darf), oder nichts" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "Speichert Kanal- und Querypuffer auf der Festplatte, verschlüsselt" znc-1.7.5/modules/po/ctcpflood.pt_BR.po0000644000175000017500000000276413542151610020161 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/ctcpflood.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "" #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "" #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "" msgstr[1] "" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "" znc-1.7.5/modules/po/blockuser.es_ES.po0000644000175000017500000000460413542151610020160 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/blockuser.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "Cuenta bloqueada" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "Tu cuenta ha sido desactivada. Contacta con tu administrador." #: blockuser.cpp:29 msgid "List blocked users" msgstr "Muestra los usuarios bloqueados" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "Bloquea un usuario" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "Desbloquea un usuario" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "No se pudo bloquear a {1}" #: blockuser.cpp:76 msgid "Access denied" msgstr "Acceso denegado" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "No hay usuarios bloqueados" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "Usuarios bloqueados:" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "Uso: Block " #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "No puedes bloquearte a ti mismo" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "{1} bloqueado" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "No se pudo bloquear a {1} (¿mal escrito?)" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "Uso: Unblock " #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "{1} desbloqueado" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "Este usuario no está bloqueado" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "No se ha podido bloquear a {1}" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "El usuario {1} no está bloqueado" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "Introduce uno o varios nombres de usuario. Separalos con espacios." #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "Bloquea ciertos usuarios para conectarse." znc-1.7.5/modules/po/stickychan.it_IT.po0000644000175000017500000000514513542151610020342 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/stickychan.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "Nome" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "Appiccicoso" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "Salva" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "Canale è appiccicoso (sticky)" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "<#canale> [chiave]" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "Attacca/Aggancia/Appiccica un canale" #: stickychan.cpp:30 msgid "<#channel>" msgstr "<#canale>" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "Scolla un canale (Unsticks)" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "Elenco dei canali appiccicosi (sticky)" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "Usa: Stick <#canale> [chiave]" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "Appiccicato {1}" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "Usa: Unstick <#canale>" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "Scollato {1}" #: stickychan.cpp:101 msgid " -- End of List" msgstr " -- Fine della lista" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "Impossibile entrare in {1} (# prefisso mancante?)" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "Canali appiccicosi" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "I cambiamenti sono stati salvati!" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "Il canale è diventato appiccicoso! (sticky)" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "Il canale ha smesso di essere appiccicoso (sticky)!" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "" "Impossibile entrare nel canale {1}, non è un nome di canale valido ed è " "stato scollegato (Unsticking)." #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "Elenco dei canali, separati dalla virgola." #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" "configura i canali meno appiccicosi, ti mantiene lì molto appiccicosamente" znc-1.7.5/modules/po/clientnotify.pot0000644000175000017500000000256213542151610020066 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" msgstr[1] "" #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "" #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "" #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "" #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "" #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" znc-1.7.5/modules/po/clearbufferonmsg.nl_NL.po0000644000175000017500000000114313542151610021512 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/clearbufferonmsg.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "" "Schoont alle kanaal en privébericht buffers op wanneer de gebruiker iets doet" znc-1.7.5/modules/po/admindebug.bg_BG.po0000644000175000017500000000321313542151610020223 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/admindebug.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "Ðктивиране на Debug " #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "Деактивиране на Debug " #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "Покажи ÑтатуÑа на Debug мода" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "ДоÑтъпът е отказан!" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" "Повреда. ТрÑбва да работим Ñ TTY. (Може би ZNC е подкаран Ñ Ð¾Ð¿Ñ†Ð¸Ñта -" "foreground?)" #: admindebug.cpp:66 msgid "Already enabled." msgstr "Вече е активиран." #: admindebug.cpp:68 msgid "Already disabled." msgstr "Вече е деактивиран." #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "Debugging mode е включен." #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "Debugging mode е изключен." #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "Влизане в: stdout." #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "Ðктивирайте Debug модула динамично." znc-1.7.5/modules/po/q.fr_FR.po0000644000175000017500000002064113542151610016426 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/q.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "Nom d'utilisateur :" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "Veuillez entrer un nom d'utilisateur." #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "Mot de passe :" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "Veuillez entrer un mot de passe." #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "Options" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "Enregistrer" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" "Note : Votre nom d'hôte sera remplacé par votre cloak la prochaine fois que " "vous vous reconnectez à IRC. Si vous voulez que ce soit fait maintenant, " "tapez /msg *q Cloak. Vous pouvez modifier vos préférences avec /msg *q Set " "UseCloakedHost true/false." #: q.cpp:111 msgid "The following commands are available:" msgstr "Les commandes suivantes sont disponibles :" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "Commande" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "Description" #: q.cpp:116 msgid "Auth [ ]" msgstr "Auth [ ]" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "Tente de vous identifier avec Q. Tous les paramètres sont optionnels." #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" "Tente d'ajouter le mode +x à l'utilisateur pour cacher votre nom d'hôte." #: q.cpp:128 msgid "Prints the current status of the module." msgstr "Affiche le statut actuel du module." #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "Redemande les informations utilisateur actuelles à Q." #: q.cpp:135 msgid "Set " msgstr "Set " #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" "Change la valeur du paramètre voulu. Voir la liste des paramètres ci-dessous." #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" "Affiche la configuration actuelle. Voir la liste des paramètres ci-dessous." #: q.cpp:146 msgid "The following settings are available:" msgstr "Les paramètres suivants sont disponibles :" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "Paramètre" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "Type" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "Chaîne" #: q.cpp:154 msgid "Your Q username." msgstr "Votre nom d'utilisateur Q." #: q.cpp:158 msgid "Your Q password." msgstr "Votre mot de passe Q." #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "Booléen" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "" "Activer ou non le cloak du nom d'hôte (+x) automatiquement à la connexion." #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" "Utiliser ou non le mécanisme CHALLENGEAUTH pour éviter d'envoyer des mots de " "passe en clair." #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "" "Demander ou non parole/opérateur de Q à l'entrée/privation de parole/" "privation d'opérateur." #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "Rejoindre ou non un salon si Q vous y invite." #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" "Instaurer ou non un délai à la connexion des salons après activation du " "cloak." #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" "Ce module nécessite 2 paramètres optionnels : " #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "Les réglages du module sont sauvegardés après redémarrage." #: q.cpp:200 msgid "Syntax: Set " msgstr "Syntaxe : Set " #: q.cpp:203 msgid "Username set" msgstr "Nom d'utilisateur indiqué" #: q.cpp:206 msgid "Password set" msgstr "Mot de passe indiqué" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "UseCloakedHost paramétré" #: q.cpp:212 msgid "UseChallenge set" msgstr "UseChallenge paramétré" #: q.cpp:215 msgid "RequestPerms set" msgstr "RequestPerms paramétré" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "JoinOnInvite paramétré" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "JoinAfterCloaked paramétré" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "Réglage inconnu : {1}" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "Valeur" #: q.cpp:253 msgid "Connected: yes" msgstr "Connecté : oui" #: q.cpp:254 msgid "Connected: no" msgstr "Connecté : non" #: q.cpp:255 msgid "Cloacked: yes" msgstr "Cloaké : oui" #: q.cpp:255 msgid "Cloacked: no" msgstr "Cloaké : non" #: q.cpp:256 msgid "Authenticated: yes" msgstr "Identifié : oui" #: q.cpp:257 msgid "Authenticated: no" msgstr "Identifié : non" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "Erreur : vous n'êtes pas connectés à IRC." #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "Erreur : le cloak est déjà actif !" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "Erreur : vous êtes déjà identifié !" #: q.cpp:280 msgid "Update requested." msgstr "Mise à jour demandée." #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "Commande inconnue. Essayez 'help'." #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "Cloak réussi : votre nom d'hôte est maintenant caché." #: q.cpp:408 msgid "Changes have been saved!" msgstr "Les changements ont été enregistrés !" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "Cloak : tentative d'anonymisation de l'hôte, ajout du mode +x..." #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" "Vous devez indiquer un nom d'utilisateur et un mot de passe pour utiliser ce " "module ! Voyez 'help' pour plus de détails." #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "Identification : demande du message CHALLENGE..." #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "Identification : envoi de la requête AUTH..." #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" "Identification : message CHALLENGE reçu, envoi de la requête CHALLENGEAUTH..." #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "Échec de l'identification : {1}" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "Identification réussie : {1}" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" "Échec de l'identification : Q ne supporte pas HMAC-SHA-256 pour le message " "CHALLENGEAUTH, rétrograde à AUTH standard." #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "RequestPerms : Demande de statut opérateur sur {1}" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "RequestPerms : Demande la parole sur {1}" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "" "Veuillez indiquer votre nom d'utilisateur et votre mot de passe pour Q." #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "Vous identifie avec le robot Q de QuakeNet." znc-1.7.5/modules/po/cyrusauth.es_ES.po0000644000175000017500000000473513542151610020223 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/cyrusauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "Muestra los ajustes actuales" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "yes|clone |no" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" "Crear usuarios ZNC al primer login correcto, opcionalmente desde una " "plantilla" #: cyrusauth.cpp:56 msgid "Access denied" msgstr "Acceso denegado" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "Ignorando método pwcheck SASL inválido: {1}" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "Ignorado método pwcheck SASL inválido" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "Se necesita un método pwcheck como argumento (saslauthd, auxprop)" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "SASL no se ha podido iniciar - Deteniendo arranque" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "No se crearán usuarios en su primer login" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" "Se crearán usuarios en su primer login, usando el usuario [{1}] como " "plantilla" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "Se crearán usuarios en su primer login" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "Uso: CreateUsers yes, CreateUsers no, o CreateUsers clone " #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" "Este módulo global tiene hasta dos parámetros - los métodos de autenticación " "- auxprop y saslauthd" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" "Permitir autenticacón de usuarios vía método de verificación de contraseña " "SASL" znc-1.7.5/modules/po/bouncedcc.bg_BG.po0000644000175000017500000000477313542151610020065 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/bouncedcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "" #: bouncedcc.cpp:129 msgid "Connected" msgstr "" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "" #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "" #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "" #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" znc-1.7.5/modules/po/webadmin.pot0000644000175000017500000007625013542151610017152 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "" #: webadmin.cpp:93 msgid "Your Settings" msgstr "" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "" #: webadmin.cpp:576 msgid "No such channel" msgstr "" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "" #: webadmin.cpp:749 msgid "Add Channel" msgstr "" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "" #: webadmin.cpp:766 msgid "Detached" msgstr "" #: webadmin.cpp:773 msgid "Enabled" msgstr "" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "" #: webadmin.cpp:911 msgid "Add Network" msgstr "" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "" #: webadmin.cpp:1551 msgid "Admin" msgstr "" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "" #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "" #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "" #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "" #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "" znc-1.7.5/modules/po/crypt.es_ES.po0000644000175000017500000000711013542151610017323 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/crypt.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "<#canal|Nick>" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "Elimina una clave de un nick o canal" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "<#canal|Nick> " #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "Ajusta una clave para un nick o canal" #: crypt.cpp:204 msgid "List all keys" msgstr "Muestra todas las claves" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "Comenzar un intercambio de claves DH1080 con un nick" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "Mostrar el prefijo del nick" #: crypt.cpp:213 msgid "[Prefix]" msgstr "[Prefijo]" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "Ajusta el prefijo de nick, sin argumentos se deshabilita." #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "Recibida clave pública DH1080 de {1}, enviando la mía..." #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "Clave para {1} ajustada correctamente." #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "Error en {1} con {2}: {3}" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "no hay clave secreta computada" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "Destino [{1}] eliminado" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "Destino [{1}] no encontrado" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "Uso: DelKey <#canal|nick>" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "Ajustada clave de cifrado para [{1}] a [{2}]" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "Uso: SetKey <#canal|nick> " #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "Enviada mi clave pública DH1080 a {1}, esperando respuesta..." #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "Error generando claves, no se ha enviado nada." #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "Uso: KeyX " #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "Prefijo de nick deshabilitado." #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "Prefijo de nick: {1}" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" "No puedes usar ':' como prefijo de nick, incluso seguido de otros símbolos." #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" "Solapamiento con prefijo de Status ({1}), no se usará este prefijo de nick" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "Deshabilitando prefijo de nick." #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "Ajustando prefijo de nick a {1}" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "Destino" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "Clave" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "No tienes claves de cifrado definidas." #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "Cifrado de canales/privados" znc-1.7.5/modules/po/pyeval.pot0000644000175000017500000000036313542151610016654 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "" #: pyeval.py:82 msgid "Evaluates python code" msgstr "" znc-1.7.5/modules/po/kickrejoin.fr_FR.po0000644000175000017500000000243613542151610020320 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/kickrejoin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: kickrejoin.cpp:56 msgid "" msgstr "" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "" msgstr[1] "" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "" msgstr[1] "" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "" #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "" znc-1.7.5/modules/po/modules_online.it_IT.po0000644000175000017500000000103513542151610021210 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/modules_online.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "Crea i *modules ZNC's per essere \"online\"." znc-1.7.5/modules/po/blockuser.id_ID.po0000644000175000017500000000346213542151610020133 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/blockuser.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "" #: blockuser.cpp:29 msgid "List blocked users" msgstr "" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "" #: blockuser.cpp:76 msgid "Access denied" msgstr "" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "" #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "" #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "" #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "" znc-1.7.5/modules/po/savebuff.nl_NL.po0000644000175000017500000000372513542151610017777 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/savebuff.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "Stelt het wachtwoord in" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "Speelt de buffer opnieuw af" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "Slaat alle buffers op" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" "Wachtwoord die geleegd is betekent meestal dat de ontsleuteling gefaalt " "heeft. Je kan setpass gebruiken om het juiste wachtwoord in te stellen en " "dan zou het moeten werken. Of setpass naar een nieuw wachtwoord en opslaan " "om opnieuw te starten" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "Wachtwoord ingesteld naar [{1}]" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "{1} afgespeeld" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "Niet mogelijk om versleuteld bestand te ontsleutelen: {1}" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" "Deze gebruikersmodule accepteert maximaal één argument. --ask-pass of het " "wachtwoord zelf (welke spaties mag bevatten) of niks" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "" "Slaat kanaal en privé berichten buffers op de harde schijf op, versleuteld" znc-1.7.5/modules/po/flooddetach.nl_NL.po0000644000175000017500000000507113542151610020446 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/flooddetach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "Laat huidige limieten zien" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "[]" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "Laat zien of pas aan het aantal seconden in de tijdsinterval" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "Laat zien of pas aan het aantal regels in de tijdsinterval" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "" "Laat zien of pas aan of je een melding wil krijgen van het los en terug " "aankoppelen" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "Overstroming in {1} is voorbij, opnieuw aan het aankoppelen..." #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "Kanaal {1} was overstroomd, je bent losgekoppeld" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "1 regel" msgstr[1] "{1} regels" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "elke seconde" msgstr[1] "elke {1} seconden" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "Huidige limiet is {1} {2}" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "Seconden limiet is {1}" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "Seconden limiet ingesteld op {1}" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "Regellimiet is {1}" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "Regellimiet ingesteld op {1}" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "Module berichten zijn uitgeschakeld" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "Module berichten zijn ingeschakeld" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" "Deze gebruikersmodule accepteert tot en met twee argumenten. Argumenten zijn " "het aantal berichten en seconden." #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "Loskoppelen van kanalen wanneer overstroomd" znc-1.7.5/modules/po/cyrusauth.bg_BG.po0000644000175000017500000000332013542151610020152 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/cyrusauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" #: cyrusauth.cpp:56 msgid "Access denied" msgstr "" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "" #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" znc-1.7.5/modules/po/cert.ru_RU.po0000644000175000017500000000534413542151610017164 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/cert.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "Ñюда" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" "У Ð²Ð°Ñ ÑƒÐ¶Ðµ еÑть Ñертификат, Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ формы ниже можно его изменить. Чтобы " "удалить Ñертификат, нажмите {1}." #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "У Ð²Ð°Ñ Ð¿Ð¾ÐºÐ° нет Ñертификата." #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "Сертификат" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "Файл PEM:" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "Обновить" #: cert.cpp:28 msgid "Pem file deleted" msgstr "Файл Pem удалён" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "Файл Pem не ÑущеÑтвовал, или произошла ошибка при его удалении." #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "Ваш Ñертификат лежит в {1}" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "У Ð²Ð°Ñ Ð½ÐµÑ‚ Ñертификата. ПожалуйÑта, добавьте его через веб-интерфейÑ." #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "Либо вы можете положить его в {1}" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "Удалить текущий Ñертификат" #: cert.cpp:54 msgid "Show the current certificate" msgstr "Показать текущий Ñертификат" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "Соединение Ñ Ñервером Ñ Ð¿Ð¾Ð¼Ð¾ÑˆÑŒÑŽ Ñертификата SSL" znc-1.7.5/modules/po/pyeval.de_DE.po0000644000175000017500000000116513542151610017430 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/pyeval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "Du benötigst Administratorrechte um dieses Modul zu laden." #: pyeval.py:82 msgid "Evaluates python code" msgstr "Führt Python-Code aus" znc-1.7.5/modules/po/partyline.de_DE.po0000644000175000017500000000157413542151610020143 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/partyline.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "" #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "" #: partyline.cpp:82 msgid "List all open channels" msgstr "" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "" znc-1.7.5/modules/po/listsockets.nl_NL.po0000644000175000017500000000501513542151610020537 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/listsockets.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "Naam" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "Gemaakt" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "Status" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "SSL" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "Lokaal" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "Extern" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "Data In" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "Data Uit" #: listsockets.cpp:62 msgid "[-n]" msgstr "[-n]" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "" "Weergeeft een lijst van actieve sockets. Geef -n om IP addressen te laten " "zien" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "Je moet een beheerder zijn om deze module te mogen gebruiken" #: listsockets.cpp:96 msgid "List sockets" msgstr "Laat sockets zien" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "Ja" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "Nee" #: listsockets.cpp:142 msgid "Listener" msgstr "Luisteraar" #: listsockets.cpp:144 msgid "Inbound" msgstr "Inkomend" #: listsockets.cpp:147 msgid "Outbound" msgstr "Uitgaand" #: listsockets.cpp:149 msgid "Connecting" msgstr "Verbinden" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "ONBEKEND" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "Je hebt geen openstaande sockets." #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "In" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "Uit" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "Laat actieve sockets zien" znc-1.7.5/modules/po/cert.nl_NL.po0000644000175000017500000000454013542151610017127 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/cert.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "hier" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" "Je hebt al een certificaat ingesteld, gebruik het onderstaande formulier om " "deze te overschrijven. Of klik op {1} om je certificaat te verwijderen." #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "Je hebt nog geen certificaat." #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "Certificaat" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "PEM Bestand:" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "Bijwerken" #: cert.cpp:28 msgid "Pem file deleted" msgstr "PEM bestand verwijderd" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "" "Het PEM bestand bestsaat niet of er was een foutmelding tijdens het " "verwijderen van het PEM bestand." #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "Je hebt een certificaat in {1}" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "" "Je hebt geen certificaat. Gebruik de webomgeving om een certificaat toe te " "voegen" #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "In plaats daarvan kan je deze ook plaatsen in {1}" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "Verwijder het huidige certificaat" #: cert.cpp:54 msgid "Show the current certificate" msgstr "Laat het huidige certificaat zien" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "Gebruik een SSL certificaat om te verbinden naar de server" znc-1.7.5/modules/po/raw.it_IT.po0000644000175000017500000000075713542151610016777 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "Visualizza tutto il traffico raw" znc-1.7.5/modules/po/ctcpflood.id_ID.po0000644000175000017500000000270513542151610020116 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/ctcpflood.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "" #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "" #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "" znc-1.7.5/modules/po/autocycle.de_DE.po0000644000175000017500000000354513542151610020124 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/autocycle.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "[!]<#Kanal>" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" "Füge einen Eintrag hinzu, verwende !#Kanal zum Negieren und * als Platzhalter" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "Entferne einen Eintrag, muss genau passen" #: autocycle.cpp:33 msgid "List all entries" msgstr "Liste alle Einträge auf" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "Kann {1} nicht hinzufügen" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "{1} ist schon hinzugefügt" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "{1} zur Liste hinzugefügt" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "Verwendung: Add [!]<#Kanal>" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "{1} aus der Liste entfernt" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "Verwendung: Del [!]<#Kanal>" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "Kanal" #: autocycle.cpp:100 msgid "You have no entries." msgstr "Du hast keine Einträge." #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "Liste an Kanalmasken und Kanalmasken mit führendem !." #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" "Betritt den Channel erneut, um OP zu bekommen, falls du der letzt User im " "Channel bist" znc-1.7.5/modules/po/cert.fr_FR.po0000644000175000017500000000334413542151610017124 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/cert.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "" #: cert.cpp:28 msgid "Pem file deleted" msgstr "" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "" #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "" #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "" #: cert.cpp:54 msgid "Show the current certificate" msgstr "" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "" znc-1.7.5/modules/po/modules_online.pt_BR.po0000644000175000017500000000100213542151610021200 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/modules_online.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "" znc-1.7.5/modules/po/listsockets.id_ID.po0000644000175000017500000000431013542151610020502 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/listsockets.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "" #: listsockets.cpp:62 msgid "[-n]" msgstr "" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "" #: listsockets.cpp:96 msgid "List sockets" msgstr "" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "" #: listsockets.cpp:142 msgid "Listener" msgstr "" #: listsockets.cpp:144 msgid "Inbound" msgstr "" #: listsockets.cpp:147 msgid "Outbound" msgstr "" #: listsockets.cpp:149 msgid "Connecting" msgstr "" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "" #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "" znc-1.7.5/modules/po/autovoice.pot0000644000175000017500000000351413542151610017353 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: autovoice.cpp:120 msgid "List all users" msgstr "" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr "" #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "" #: autovoice.cpp:128 msgid " [channels]" msgstr "" #: autovoice.cpp:129 msgid "Adds a user" msgstr "" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "" #: autovoice.cpp:238 msgid "There are no users defined" msgstr "" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "" #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "" #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "" #: autovoice.cpp:341 msgid "That user already exists" msgstr "" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "" znc-1.7.5/modules/po/sasl.it_IT.po0000644000175000017500000001131413542151610017137 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/sasl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "SASL" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "Nome utente:" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "Per favore inserisci un username." #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "Password:" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "Per favore inserisci una password." #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "Opzioni" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "Connette solo se l'autenticazione SASL ha esito positivo." #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "Richiede l'autenticazione" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "Meccanismi" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "Nome" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "Descrizione" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "Meccanismi selezionati ed il loro ordine:" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "Salva" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "Certificato TLS, da utilizzare con il modulo *cert" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" "La negoziazione del testo semplice, dovrebbe funzionare sempre se il network " "supporta SASL" #: sasl.cpp:62 msgid "search" msgstr "ricerca" #: sasl.cpp:62 msgid "Generate this output" msgstr "Genera questo output" #: sasl.cpp:64 msgid "[ []]" msgstr "[ []]" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" "Imposta username e password per i meccanismi che ne hanno bisogno. La " "password è facoltativa. Senza parametri, restituisce informazioni sulle " "impostazioni correnti." #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "[meccanismo[ ...]]" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "Imposta i meccanismi da tentare (in ordine)" #: sasl.cpp:72 msgid "[yes|no]" msgstr "[si|no]" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "Non connettersi a meno che l'autenticazione SASL non abbia successo" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "Meccanismo" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "Sono disponibili i seguenti meccanismi:" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "L'username non è attualmente impostato" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "L'username è attualmente impostato a '{1}'" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "La password non è stata fornita" #: sasl.cpp:114 msgid "Password was supplied" msgstr "La password è stata fornita" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "L'username è stato impostato a [{1}]" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "La password è stata impostata a [{1}]" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "Meccanismi correnti impostati: {1}" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "Noi richiediamo la negoziazione SASL per connettersi" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "Ci collegheremo anche se SASL fallisce" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "Disabilitando il network, è rischiesta l'autenticazione." #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "Usa 'RequireAuth no' per disabilitare." #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "{1} meccanismo riuscito." #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "{1} meccanismo fallito." #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "" "Aggiunge il supporto per la funzionalità di autenticazione sasl per " "l'autenticazione al server IRC" znc-1.7.5/modules/po/alias.it_IT.po0000644000175000017500000000603013542151610017265 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/alias.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "manca il parametro obbligatorio: {1}" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "Alias creato: {1}" #: alias.cpp:203 msgid "Alias already exists." msgstr "Alias già esistente." #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "Alias eliminato: {1}" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "Alias inesistente." #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "Alias modificato." #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "Indice non valido." #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "Non ci sono alias." #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "Esistono i seguenti alias: {1}" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr ", " #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "Azioni per l'alias {1}:" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "Fine delle azioni per l'alias {1}." #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "Crea un nuovo alias vuoto, chiamato nome." #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "Elimina un alias esistente." #: alias.cpp:343 msgid " " msgstr " " #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "Aggiunge una linea ad un alias esistente." #: alias.cpp:346 msgid " " msgstr " " #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "Inserisce una linea in un alias esistente." #: alias.cpp:349 msgid " " msgstr " " #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "Rimuove una linea da un alias esistente." #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "Rimuove tutte le linee da un alias esistente." #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "Elenca tutti gli alias per nome." #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "Riporta le azioni eseguite da un alias." #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "" "Genera una lista di comandi da copiare nella configurazione dei tuoi alias." #: alias.cpp:374 msgid "Clearing all of them!" msgstr "Pulisco tutti!" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "Fornisce supporto ai comandi alias lato bouncer." znc-1.7.5/modules/po/alias.nl_NL.po0000644000175000017500000000611613542151610017264 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/alias.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "verplichte parameter ontbreekt: {1}" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "Alias aangemaakt: {1}" #: alias.cpp:203 msgid "Alias already exists." msgstr "Alias bestaat al." #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "Alias verwijderd: {1}" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "Alias bestaat niet." #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "Alias aangepast." #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "Ongeldige index." #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "Er zijn geen aliassen." #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "De volgende aliassen bestaan: {1}" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr ", " #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "Acties voor alias {1}:" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "Einde van acties voor alias {1}." #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "Maakt een nieuwe, lege alias aan genaamd naam." #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "Verwijdert een bestaande alias." #: alias.cpp:343 msgid " " msgstr " " #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "Voegt een regel toe aan een bestaande alias." #: alias.cpp:346 msgid " " msgstr " " #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "Voegt een regel in bij een bestaande alias." #: alias.cpp:349 msgid " " msgstr " " #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "Verwijdert een regel van een bestaande alias." #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "Verwijdert alle regels van een bestaande alias." #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "Somt alle aliassen op bij naam." #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "Laat de acties zien die uitgevoerd worden door een alias." #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "" "Genereert een lijst van commando's die je naar je alias configuratie kan " "kopieëren." #: alias.cpp:374 msgid "Clearing all of them!" msgstr "Alle verwijderen!" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "Voorziet alias ondersteuning aan de kant van de bouncer." znc-1.7.5/modules/po/awaystore.id_ID.po0000644000175000017500000000423713542151610020161 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/awaystore.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "" #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "" #: awaystore.cpp:113 msgid "Message erased" msgstr "" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" znc-1.7.5/modules/po/notify_connect.es_ES.po0000644000175000017500000000142613542151610021207 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/notify_connect.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: notify_connect.cpp:24 msgid "attached" msgstr "adjuntado" #: notify_connect.cpp:26 msgid "detached" msgstr "separado" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "{1} {2} desde {3}" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "Notifica todos los admins cuando un usuario conecta o desconecta." znc-1.7.5/modules/po/savebuff.fr_FR.po0000644000175000017500000000250213542151610017763 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/savebuff.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "" znc-1.7.5/modules/po/clearbufferonmsg.ru_RU.po0000644000175000017500000000127713542151610021554 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/clearbufferonmsg.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "" znc-1.7.5/modules/po/autovoice.id_ID.po0000644000175000017500000000417513542151610020142 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/autovoice.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: autovoice.cpp:120 msgid "List all users" msgstr "" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr "" #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "" #: autovoice.cpp:128 msgid " [channels]" msgstr "" #: autovoice.cpp:129 msgid "Adds a user" msgstr "" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "" #: autovoice.cpp:238 msgid "There are no users defined" msgstr "" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "" #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "" #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "" #: autovoice.cpp:341 msgid "That user already exists" msgstr "" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "" znc-1.7.5/modules/po/clearbufferonmsg.de_DE.po0000644000175000017500000000113113542151610021445 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/clearbufferonmsg.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "Löscht alle Kanal- und Query-Puffer immer wenn der Benutzer etwas tut" znc-1.7.5/modules/po/crypt.pt_BR.po0000644000175000017500000000506713542151610017344 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/crypt.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "" #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "" #: crypt.cpp:204 msgid "List all keys" msgstr "" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "" #: crypt.cpp:213 msgid "[Prefix]" msgstr "" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "" #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "" #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "" #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "" #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "" #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "" #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "" #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "" #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "" #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "" #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "" znc-1.7.5/modules/po/awaystore.bg_BG.po0000644000175000017500000000424513542151610020150 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/awaystore.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "" #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "" #: awaystore.cpp:113 msgid "Message erased" msgstr "" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" znc-1.7.5/modules/po/autovoice.it_IT.po0000644000175000017500000000563313542151610020202 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/autovoice.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: autovoice.cpp:120 msgid "List all users" msgstr "Elenca tutti gli utenti" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr " [canale] ..." #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "Aggiunge canali ad un utente" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "Rimuove canali ad un utente" #: autovoice.cpp:128 msgid " [channels]" msgstr " [canali]" #: autovoice.cpp:129 msgid "Adds a user" msgstr "Aggiungi un utente" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "Rimuovi un utente" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "Usa: AddUser [canali]" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "Usa: DelUser " #: autovoice.cpp:238 msgid "There are no users defined" msgstr "Non ci sono utenti definiti" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "Utente" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "Hostmask" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "Canali" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "Utilizzo: AddChans [canale] ..." #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "Utente inesistente" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "Canale(i) aggiunti all'utente {1}" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "Usa: DelChans [canale] ..." #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "Canale(i) rimossi dall'utente {1}" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "L'utente {1} è stato rimosso" #: autovoice.cpp:341 msgid "That user already exists" msgstr "Questo utente già esiste" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "L'utente {1} è stato aggiunto con la seguente hostmask {2}" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" "Ogni argomento è un canale per il quale si vuole l'autovoice (che può " "includere caratteri jolly) oppure, se inizia con !, è un'eccezione per " "l'autovoice." #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "Assegna automaticamente il voice alle buone persone" znc-1.7.5/modules/po/clearbufferonmsg.bg_BG.po0000644000175000017500000000102613542151610021450 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/clearbufferonmsg.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "" znc-1.7.5/modules/po/ctcpflood.it_IT.po0000644000175000017500000000414513542151610020156 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/ctcpflood.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "Imposta il limite in secondi" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "Imposta il limite delle linee" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "Mostra i limiti correnti" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "Limite raggiunto da {1}, blocco tutti i CTCP" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "Utilizzo: Secs " #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "Utilizzo: Lines " #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "1 messaggio CTCP" msgstr[1] "{1} Messaggi CTCP" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "ogni secondo" msgstr[1] "ogni {1} secondi" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "Il limite corrente è {1} {2}" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" "Questo modulo utente accetta da zero a due argomenti. Il primo argomento è " "il numero di linee dopo le quali viene attivata la protezione contro i flood " "(flood-protection). Il secondo argomento è il tempo (in secondi) in cui il " "numero di linee viene raggiunto. L'impostazione predefinita è 4 CTCP in 2 " "secondi" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "Non inoltrare i flussi CTCP (floods) ai client" znc-1.7.5/modules/po/cert.de_DE.po0000644000175000017500000000447213542151610017071 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/cert.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "hier" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" "Du hast bereits ein Zertifikat gesetzt. Verwende das untenstehende Formular " "um es zu überschreiben. Alternativ, klicke {1} um es zu löschen." #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "Du hast bisher kein Zertifikat." #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "Zertifikat" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "PEM-Datei:" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "Aktualisieren" #: cert.cpp:28 msgid "Pem file deleted" msgstr "PEM-Datei gelöscht" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "" "Die PEM-Datei existiert nicht oder es trat ein Fehler beim Löschen auf." #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "Dein Zertifikat ist in {1}" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "" "Du hast kein Zertifikat. Bitte verwende das Web-Interface um ein Zertifikat " "hinzuzufügen" #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "Alternativ kannst du eines in {1} platzieren" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "Löscht das aktuelle Zertifikat" #: cert.cpp:54 msgid "Show the current certificate" msgstr "Zeigt das aktuelle Zertifikat an" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "Verwende ein SSL-Zertifikat um zu einem Server zu verbinden" znc-1.7.5/modules/po/autoop.de_DE.po0000644000175000017500000001142313542151610017435 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/autoop.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: autoop.cpp:154 msgid "List all users" msgstr "Zeige alle Benutzer an" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr " [Kanal] ..." #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "Fügt Kanäle zu Benutzern hinzu" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "Entfernt Kanäle von Benutzern" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr " ,[Maske] ..." #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "Fügt Masken zu Benutzern hinzu" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "Entfernt Masken von Benutzern" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr " [,...] [Kanäle]" #: autoop.cpp:170 msgid "Adds a user" msgstr "Fügt einen Benutzer hinzu" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "Entfernt einen Benutzer" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "" "Verwendung: AddUser [,...] " "[Kanäle]" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "Verwendung: DelUser " #: autoop.cpp:300 msgid "There are no users defined" msgstr "Es sind keine Benutzer definiert" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "Benutzer" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "Hostmasken" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "Schlüssel" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "Kanäle" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "Verwendung: AddChans [Kanal] ..." #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "Kein solcher Benutzer" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "Kanal/Kanäle zu Benutzer {1} hinzugefügt" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "Verwendung: DelChans [Kanal] ..." #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "Kanal/Kanäle von Benutzer {1} entfernt" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "Verwendung: AddMasks ,[Maske] ..." #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "Hostmaske(n) zu Benutzer {1} hinzugefügt" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "Verwendung: DelMasks ,[Maske] ..." #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "Benutzer {1} mit Schlüssel {2} und Kanälen {3} entfernt" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "Hostmaske(n) von Benutzer {1} entfernt" #: autoop.cpp:478 msgid "User {1} removed" msgstr "Benutzer {1} entfernt" #: autoop.cpp:484 msgid "That user already exists" msgstr "Dieser Benutzer ist bereits vorhanden" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "Benutzer {1} mit Hostmaske(n) {2} hinzugefügt" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "" "[{1}] hat uns eine Challenge gesendet, aber ist in keinem der definierten " "Kanäle geopt." #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "" "[{1}] hat uns eine Challenge gesendet, aber entspricht keinem definierten " "Benutzer." #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "WARNUNG! [{1}] hat eine ungültige Challenge gesendet." #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "" "[{1}] hat eine unangeforderte Antwort gesendet. Dies könnte an Lag liegen." #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" "WARNUNG! [{1}] hat eine schlechte Antwort gesendet. Bitte überprüfe, dass du " "deren korrektes Passwort hast." #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "" "WARNUNG! [{1}] hat eine Antwort gesendet, aber entspricht keinem definierten " "Benutzer." #: autoop.cpp:644 msgid "Auto op the good people" msgstr "Gebe automatisch Op an die guten Leute" znc-1.7.5/modules/po/ctcpflood.nl_NL.po0000644000175000017500000000412013542151610020141 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/ctcpflood.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "Stel seconden limiet in" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "Stel regel limiet in" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "Laat de huidige limieten zien" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "Limiet bereikt met {1}, alle CTCPs zullen worden geblokkeerd" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "Gebruik: Secs " #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "Gebruik: Lines " #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "1 CTCP bericht" msgstr[1] "{1} CTCP berichten" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "Elke seconde" msgstr[1] "Elke {2} seconden" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "Huidige limit is {1} {2}" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" "Deze gebruikersmodule accepteert geen tot twee argumenten. Het eerste " "argument is het aantal regels waarna de overstroom-bescherming in gang gezet " "zal worden. Het tweede argument is de tijd (seconden) in welke dit aantal " "bereikt wordt. De standaard instelling is 4 CTCP berichten in 2 seconden" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "Stuur CTCP overstromingen niet door naar clients" znc-1.7.5/modules/po/alias.bg_BG.po0000644000175000017500000000442313542151610017221 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/alias.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "" #: alias.cpp:203 msgid "Alias already exists." msgstr "" #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "" #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "" #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "" #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "" #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr "" #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "" #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "" #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "" #: alias.cpp:343 msgid " " msgstr "" #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "" #: alias.cpp:346 msgid " " msgstr "" #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "" #: alias.cpp:349 msgid " " msgstr "" #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "" #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "" #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "" #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "" #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "" #: alias.cpp:374 msgid "Clearing all of them!" msgstr "" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "" znc-1.7.5/modules/po/keepnick.id_ID.po0000644000175000017500000000217413542151610017732 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/keepnick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "" #: keepnick.cpp:44 msgid "Show the current state" msgstr "" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "" znc-1.7.5/modules/po/perleval.id_ID.po0000644000175000017500000000121613542151610017747 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/perleval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "" znc-1.7.5/modules/po/adminlog.de_DE.po0000644000175000017500000000351013542151610017716 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/adminlog.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "Das Log-Ziel anzeigen" #: adminlog.cpp:31 msgid " [path]" msgstr " [Pfad]" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "Das Log-Ziel setzen" #: adminlog.cpp:142 msgid "Access denied" msgstr "Zutritt verweigert" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "Es wird jetzt ein Datei-Protokoll geschrieben" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "Es wird nun ins Syslog geschrieben" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "Es wird nun ins Syslog und eine Protokoll-Datei geschrieben" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "Verwendung: Target [Pfad]" #: adminlog.cpp:170 msgid "Unknown target" msgstr "Unbekanntes Ziel" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "Es wird ein Datei-Protokoll geschrieben" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "Es wird ins Syslog geschrieben" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "Es wird sowohl eine Protokoll-Datei als auch ins Syslog geschrieben" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "Datei-Protokoll wird nach {1} geschrieben" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "Protokolliere ZNC-Ereignisse in eine Datei und/order ins Syslog." znc-1.7.5/modules/po/chansaver.de_DE.po0000644000175000017500000000106613542151610020102 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/chansaver.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "Hält die Konfiguration aktuell, wenn Benutzer Kanäle betritt/verlässt." znc-1.7.5/modules/po/notify_connect.bg_BG.po0000644000175000017500000000126213542151610021147 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/notify_connect.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: notify_connect.cpp:24 msgid "attached" msgstr "" #: notify_connect.cpp:26 msgid "detached" msgstr "" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "" znc-1.7.5/modules/po/autocycle.ru_RU.po0000644000175000017500000000304713542151610020215 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/autocycle.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "" #: autocycle.cpp:33 msgid "List all entries" msgstr "" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "" #: autocycle.cpp:100 msgid "You have no entries." msgstr "" #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "" #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" znc-1.7.5/modules/po/clientnotify.de_DE.po0000644000175000017500000000470513542151610020642 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/clientnotify.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "Setzt die Benachrichtigungsmethode" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "" "Schaltet Benachrichtigungen für bisher nicht gesehene IP-Adressen an oder aus" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "Schaltet Benachrichtungen für sich trennende Klienten an oder aus" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "Zeigt die aktuellen Einstellungen an" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" msgstr[1] "" "Ein anderer Client hat sich als dein Benutzer authentifiziert. Verwende den " "'ListClients'-Befehl um alle {1} Clients zu sehen." #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "Verwendung: Method " #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "Gespeichert." #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "Verwendung: NewOnly " #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "Verwendung: OnDisconnect " #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" "Aktuelle Einstellung: Methode: {1}, nur für ungesehene IP-Adressen: {2}, " "benachrichtige bei sich trennenden Klienten: {3}" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" "Benachrichtigt dicht wenn ein anderer IRC-Client in deinen Account ein- oder " "aus deinem Account ausloggt. Konfigurierbar." znc-1.7.5/modules/po/stripcontrols.id_ID.po0000644000175000017500000000102113542151610021054 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/stripcontrols.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "" znc-1.7.5/modules/po/sample.it_IT.po0000644000175000017500000000614313542151610017462 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/sample.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "Campione di lavoro annullato" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "Campione di lavoro distrutto" #: sample.cpp:50 msgid "Sample job done" msgstr "Campione di lavoto fatto" #: sample.cpp:65 msgid "TEST!!!!" msgstr "TEST!!!!" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "Mi stanno caricando gli argomenti: {1}" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "Mi stanno scaricando! (unloaded)" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "Ti sei connesso BoyOh." #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "Ti sei disconnesso BoyOh." #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "{1} {2} imposta i mode su {3} {4}{5} {6}" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "{1} {2} assegna lo stato di op a {3} su {4}" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "{1} {2} rimuove lo stato di op a {3} su {4}" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "{1} {2} assegna lo stato di voice a {3} su {4}" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "{1} {2} rimuove lo stato di voice a {3} su {4}" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "* {1} imposta i mode: {2} {3} su {4}" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "{1} kicked {2} da {3} con il messaggio {4}" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "* {1} ({2}@{3}) quits ({4}) dal canale: {6}" msgstr[1] "* {1} ({2}@{3}) quits ({4}) da {5} canali: {6}" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "Tentando di entrare {1}" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "* {1} ({2}@{3}) entra {4}" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "* {1} ({2}@{3}) lascia {4}" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "{1} ti ha invitato su {2}, ignorando gli inviti su {2}" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "{1} ti ha invitato su {2}" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "{1} è ora conosciuto come {2}" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "{1} cambia topic su {2} in {3}" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "Ciao, sono il tuo amichevole modulo campione." #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "La descrizione degli argomenti del modulo va qui." #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "Da utilizzare come campione per la scrittura di moduli" znc-1.7.5/modules/po/dcc.id_ID.po0000644000175000017500000001007113542151610016665 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/dcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: dcc.cpp:88 msgid " " msgstr "" #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "" #: dcc.cpp:91 msgid "" msgstr "" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "" #: dcc.cpp:94 msgid "List current transfers" msgstr "" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "" #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "" #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "" #: dcc.cpp:179 msgid "Usage: Send " msgstr "" #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "" #: dcc.cpp:199 msgid "Usage: Get " msgstr "" #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "" #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "" #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "" #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "" #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "" #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "" #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "" #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "" #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "" #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "" #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "" #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "" #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "" #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "" #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "" #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "" #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "" znc-1.7.5/modules/po/modperl.de_DE.po0000644000175000017500000000077513542151610017600 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/modperl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "Lade Perl-Skripte als ZNC-Module" znc-1.7.5/modules/po/shell.pot0000644000175000017500000000056513542151610016467 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "" #: shell.cpp:169 msgid "Gives shell access" msgstr "" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "" znc-1.7.5/modules/po/missingmotd.de_DE.po0000644000175000017500000000102413542151610020457 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/missingmotd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "Sende 422 an Klienten wenn sie sich verbinden" znc-1.7.5/modules/po/cyrusauth.it_IT.po0000644000175000017500000000477013542151610020234 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/cyrusauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "Mostra le impostazioni correnti" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "yes|clone |no" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" "Crea utenti ZNC al primo accesso riuscito, facoltativamente da un modello." #: cyrusauth.cpp:56 msgid "Access denied" msgstr "Accesso negato" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "Ignoro il metodo non valido SASL pwcheck: {1}" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "Ignoro il metodo non valido SASL pwcheck" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "Serve un metodo pwcheck come argomento (saslauthd, auxprop)" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "SASL non può essere inizializzato - Arrestato l'avvio" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "Non creeremo gli utenti al loro primo accesso" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" "Creeremo gli utenti al loro primo accesso, utilizzando l'utente [{1}] come " "modello (template)" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "Creeremo gli utenti al loro primo accesso" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "" "Utilizzo: CreateUsers yes, CreateUsers no, oppure CreateUsers clone " #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" "Questo modulo globale richiede fino a due argomenti - metodi di " "autenticazione - auxprop e saslauthd" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" "Permetti agli utenti di autenticarsi tramite il metodo di verifica password " "SASL" znc-1.7.5/modules/po/notify_connect.ru_RU.po0000644000175000017500000000153313542151610021244 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/notify_connect.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: notify_connect.cpp:24 msgid "attached" msgstr "" #: notify_connect.cpp:26 msgid "detached" msgstr "" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "" znc-1.7.5/modules/po/sample.es_ES.po0000644000175000017500000000573013542151610017451 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/sample.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "Tarea cancelada" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "Tarea destruída" #: sample.cpp:50 msgid "Sample job done" msgstr "Tarea hecha" #: sample.cpp:65 msgid "TEST!!!!" msgstr "PRUEBA!!!!" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "Voy a ser cargado con los argumentos: {1}" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "Estoy siendo descargado!" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "Has sido conectado." #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "Has sido desconectado." #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "{1} {2} cambia modo en {3} {4}{5} {6}" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "{1} {2} da op a {3} en {4}" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "{1} {2} quita op a {3} en {4}" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "{1} {2} da voz a {3} en {4}" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "{1} {2} quita voz a {3} en {4}" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "* {1} cambia modo: {2} {3} en {4}" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "{1} ha expulsado a {2} de {3} por {4}" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "* {1} ({2}@{3}) se desconecta ({4}) del canal: {6}" msgstr[1] "* {1} ({2}@{3}) se desconecta ({4}) de {5} canales: {6}" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "Intentando entrar {1}" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "* {1} ({2}@{3}) entra {4}" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "* {1} ({2}@{3}) sale {4}" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "{1} te invita a {2}, ignorando invites a {2}" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "{1} te invita a {2}" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "{1} es ahora {2}" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "{1} cambia el topic de {2} a {3}" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "Hola, soy tu módulo amigable de muestra." #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "La descripción de los argumentos del módulo va aquí." #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "Para ser usado como muestra para escribir módulos" znc-1.7.5/modules/po/raw.de_DE.po0000644000175000017500000000075713542151610016727 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "Zeigt den gesamten Roh-Verkehr an" znc-1.7.5/modules/po/clientnotify.es_ES.po0000644000175000017500000000447613542151610020705 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/clientnotify.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "Define el método de notificación" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "Activa o desactiva las notificaciones de direcciones IP nunca vistas" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "" "Activa o desactiva notificaciones de clientes conectando y desconectandose" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "Muestra los ajustes actuales" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" msgstr[1] "" "Otro cliente se ha autenticado con tu usuario. Usa el comando 'ListClients' " "para ver todos los clientes de {1}." #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "Uso: Method " #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "Guardado." #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "Uso: NewOnly " #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "Uso: OnDisconnect " #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" "Ajustes actuales: Método: {1}, para direcciones IP nunca vistas: {2}, " "notificación de clientes desconectando: {3}" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" "Te notifica cuando otro cliente IRC se conecta o se desconecta de tu cuenta. " "Configurable." znc-1.7.5/modules/po/controlpanel.nl_NL.po0000644000175000017500000005460513542151610020701 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/controlpanel.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "Type" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "Variabelen" #: controlpanel.cpp:77 msgid "String" msgstr "Tekenreeks" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "Boolean (waar/onwaar)" #: controlpanel.cpp:79 msgid "Integer" msgstr "Heel getal" #: controlpanel.cpp:80 msgid "Number" msgstr "Nummer" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "" "De volgende variabelen zijn beschikbaar bij het gebruik van de Set/Get " "commando's:" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" "De volgende variabelen zijn beschikbaar bij het gebruik van de SetNetwork/" "GetNetwork commando's:" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" "De volgende variabelen zijn beschikbaar bij het gebruik van de SetChan/" "GetChan commando's:" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" "Je kan $user als gebruiker en $network als netwerknaam gebruiken bij het " "aanpassen van je eigen gebruiker en network." #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "Fout: Gebruiker [{1}] bestaat niet!" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "" "Fout: Je moet beheerdersrechten hebben om andere gebruikers aan te passen!" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "Fout: Je kan $network niet gebruiken om andere gebruiks aan te passen!" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "Fout: Gebruiker {1} heeft geen netwerk genaamd [{2}]." #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "Gebruik: Get [gebruikersnaam]" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "Fout: Onbekende variabele" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "Gebruik: Get " #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "Deze bindhost is al ingesteld!" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "Toegang geweigerd!" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "Configuratie gefaald, limiet van buffer grootte is {1}" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "Wachtwoord is aangepast!" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "Time-out kan niet minder dan 30 seconden zijn!" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "Dat zou een slecht idee zijn!" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "Ondersteunde talen: {1}" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "Gebruik: GetNetwork [gebruikersnaam] [netwerk]" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" "Fout: Een netwerk moet ingevoerd worden om de instellingen van een andere " "gebruiker op te halen." #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "Je bent op het moment niet verbonden met een netwerk." #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "Fout: Onjuist netwerk." #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "Gebruik: SetNetwork " #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "Gebruik: AddChan " #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "Fout: Gebruiker {1} heeft al een kanaal genaamd {2}." #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "Kanaal {1} voor gebruiker {2} toegevoegd aan netwerk {3}." #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" "Kon kanaal {1} voor gebruiker {2} op netwerk {3} niet toevoegen, bestaat " "deze al?" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "Gebruik: DelChan " #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" "Fout: Gebruiker {1} heeft geen kanaal die overeen komt met [{2}] in netwerk " "{3}" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "Kanaal {1} is verwijderd van netwerk {2} van gebruiker {3}" msgstr[1] "Kanalen {1} zijn verwijderd van netwerk {2} van gebruiker {3}" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "Gebruik: GetChan " #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "Fout: Geen overeenkomst met kanalen gevonden: [{1}]." #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "" "Gebruik: SetChan " #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "Gebruikersnaam" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "Echte naam" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "IsBeheerder" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "Naam" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "AlternatieveNaam" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "Identiteit" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "BindHost" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "Nee" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "Ja" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "Fout: Je moet beheerdersrechten hebben om gebruikers toe te voegen!" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "Gebruik: AddUser " #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "Fout: Gebruiker {1} bestaat al!" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "Fout: Gebruiker niet toegevoegd: {1}" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "Gebruiker {1} toegevoegd!" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "Fout: Je moet beheerdersrechten hebben om gebruikers te verwijderen!" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "Gebruik: DelUser " #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "Fout: Je kan jezelf niet verwijderen!" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "Fout: Interne fout!" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "Gebruiker {1} verwijderd!" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "Gebruik: CloneUser " #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "Fout: Kloon mislukt: {1}" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "Gebruik: AddNetwork [gebruiker] netwerk" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "Limiet van aantal netwerken bereikt. Vraag een beheerder om deze limit aan " "te passen voor je, of verwijder onnodige netwerken door middel van /znc " "DelNetwork " #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "Fout: Gebruiker {1} heeft al een netwerk met de naam {2}" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "Netwerk {1} aan gebruiker {2} toegevoegd." #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "Fout: Netwerk [{1}] kon niet toegevoegd worden voor gebruiker {2}: {3}" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "Gebruik: DelNetwork [gebruiker] netwerk" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "Het huidige actieve netwerk kan worden verwijderd via {1}status" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "Netwerk {1} verwijderd voor gebruiker {2}." #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "Fout: Netwerk [{1}] kon niet verwijderd worden voor gebruiker {2}." #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "Netwerk" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "OpIRC" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "IRC Server" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "IRC Gebruiker" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "Kanalen" #: controlpanel.cpp:1143 msgid "No networks" msgstr "Geen netwerken" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "" "Gebruik: AddServer [[+]poort] " "[wachtwoord]" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "IRC Server {1} toegevegd aan netwerk {2} van gebruiker {3}." #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" "Fout: kon IRC server {1} niet aan netwerk {2} van gebruiker {3} toevoegen." #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "" "Gebruik: DelServer [[+]poort] " "[wachtwoord]" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "IRC Server {1} verwijderd van netwerk {2} van gebruiker {3}." #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" "Fout: kon IRC server {1} niet van netwerk {2} van gebruiker {3} verwijderen." #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "Gebruik: Reconnect " #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "Netwerk {1} van gebruiker {2} toegevoegd om opnieuw te verbinden." #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "Gebruik: Disconnect " #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "IRC verbinding afgesloten voor netwerk {1} van gebruiker {2}." #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "Aanvraag" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "Antwoord" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "Geen CTCP antwoorden voor gebruiker {1} zijn ingesteld" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "CTCP antwoorden voor gebruiker {1}:" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "Gebruik: AddCTCP [gebruikersnaam] [aanvraag] [antwoord]" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" "Dit zorgt er voor dat ZNC antwoord op de CTCP aanvragen in plaats van deze " "door te sturen naar clients." #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "" "Een leeg antwoord zorgt er voor dat deze CTCP aanvraag geblokkeerd zal " "worden." #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "CTCP aanvraag {1} naar gebruiker {2} zal nu worden geblokkeerd." #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "CTCP aanvraag {1} naar gebruiker {2} zal nu als antwoord krijgen: {3}" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "Gebruik: DelCTCP [gebruikersnaam] [aanvraag]" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "CTCP aanvraag {1} naar gebruiker {2} zal nu doorgestuurd worden" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" "CTCP aanvraag {1} naar gebruiker {2} zal nu doorgestuurd worden (niets " "veranderd)" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "Het laden van modulen is uit gezet." #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "Fout: Niet mogelijk om module te laden, {1}: {2}" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "Module {1} geladen" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "Fout: Niet mogelijk om module te herladen, {1}: {2}" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "Module {1} opnieuw geladen" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "Fout: Niet mogelijk om module {1} te laden, deze is al geladen" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "Gebruik: LoadModule [argumenten]" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "" "Gebruik: LoadNetModule [argumenten]" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "Gebruik a.u.b. /znc unloadmod {1}" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "Fout: Niet mogelijk om module to stoppen, {1}: {2}" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "Module {1} gestopt" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "Gebruik: UnloadModule " #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "Gebruik: UnloadNetModule " #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "Naam" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "Argumenten" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "Gebruiker {1} heeft geen modulen geladen." #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "Modulen geladen voor gebruiker {1}:" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "Netwerk {1} van gebruiker {2} heeft geen modulen geladen." #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "Modulen geladen voor netwerk {1} van gebruiker {2}:" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "[commando] [variabele]" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "Laat help zien voor de overeenkomende commando's en variabelen" #: controlpanel.cpp:1559 msgid " [username]" msgstr " [gebruikersnaam]" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "" "Laat de waarde van de variabele voor de ingevoerde of huidige gebruiker zien" #: controlpanel.cpp:1562 msgid " " msgstr " " #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "Stelt de waarde voor de variabele voor de ingevoerde gebruiker in" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr " [gebruikersnaam] [netwerk]" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "" "Laat de huidige waarde voor de variabele van het ingevoerde netwerk zien" #: controlpanel.cpp:1568 msgid " " msgstr " " #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "Stelt de waarde voor de variabele voor het ingevoerde netwerk in" #: controlpanel.cpp:1571 msgid " [username] " msgstr " [gebruikersnaam] " #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "" "Laat de huidige waarde voor de variabele van het ingevoerde kanaal zien" #: controlpanel.cpp:1575 msgid " " msgstr " " #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "Stelt de waarde voor de variabele voor het ingevoerde kanaal in" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr " " #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "Voegt een nieuw kanaal toe" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "Verwijdert een kanaal" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "Weergeeft gebruikers" #: controlpanel.cpp:1586 msgid " " msgstr " " #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "Voegt een nieuwe gebruiker toe" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "Verwijdert een gebruiker" #: controlpanel.cpp:1591 msgid " " msgstr " " #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "Kloont een gebruiker" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr " " #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "" "Voegt een nieuwe IRC server toe voor de ingevoerde of huidige gebruiker" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "Verwijdert een IRC server voor de ingevoerde of huidige gebruiker" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr " " #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "Verbind opnieuw met de IRC server" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "Stopt de verbinding van de gebruiker naar de IRC server" #: controlpanel.cpp:1606 msgid " [args]" msgstr " [argumenten]" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "Laad een module voor een gebruiker" #: controlpanel.cpp:1609 msgid " " msgstr " " #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "Stopt een module van een gebruiker" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "Laat de lijst van modulen voor een gebruiker zien" #: controlpanel.cpp:1616 msgid " [args]" msgstr " [argumenten]" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "Laad een module voor een netwerk" #: controlpanel.cpp:1620 msgid " " msgstr " " #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "Stopt een module van een netwerk" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "Laat de lijst van modulen voor een netwerk zien" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "Laat de ingestelde CTCP antwoorden zien" #: controlpanel.cpp:1629 msgid " [reply]" msgstr " [antwoord]" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "Stel een nieuw CTCP antwoord in" #: controlpanel.cpp:1632 msgid " " msgstr " " #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "Verwijder een CTCP antwoord" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "[gebruikersnaam] " #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "Voeg een netwerk toe voor een gebruiker" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "Verwijder een netwerk van een gebruiker" #: controlpanel.cpp:1643 msgid "[username]" msgstr "[gebruikersnaam]" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "Laat alle netwerken van een gebruiker zien" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" "Dynamische configuratie door IRC. Staat alleen toe voor je eigen gebruiker " "als je geen ZNC beheerder bent." znc-1.7.5/modules/po/missingmotd.fr_FR.po0000644000175000017500000000074613542151610020527 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/missingmotd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "" znc-1.7.5/modules/po/notify_connect.nl_NL.po0000644000175000017500000000144513542151610021214 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/notify_connect.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: notify_connect.cpp:24 msgid "attached" msgstr "aangekoppeld" #: notify_connect.cpp:26 msgid "detached" msgstr "losgekoppeld" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "{1} {2} van {3}" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "" "Stuurt een melding naar alle beheerders wanneer een client los of aankoppeld." znc-1.7.5/modules/po/notify_connect.de_DE.po0000644000175000017500000000142513542151610021150 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/notify_connect.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: notify_connect.cpp:24 msgid "attached" msgstr "verbunden" #: notify_connect.cpp:26 msgid "detached" msgstr "getrennt" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "{1} {2} von {3}" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "Benachrichtigt alle Admins wenn ein Klient sich verbindet oder trennt." znc-1.7.5/modules/po/block_motd.bg_BG.po0000644000175000017500000000150113542151610020237 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/block_motd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: block_motd.cpp:26 msgid "[]" msgstr "" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "" #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "" znc-1.7.5/modules/po/disconkick.ru_RU.po0000644000175000017500000000143213542151610020342 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/disconkick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" znc-1.7.5/modules/po/keepnick.ru_RU.po0000644000175000017500000000245313542151610020016 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/keepnick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "" #: keepnick.cpp:44 msgid "Show the current state" msgstr "" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "" znc-1.7.5/modules/po/savebuff.pt_BR.po0000644000175000017500000000252513542151610020000 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/savebuff.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "" znc-1.7.5/modules/po/flooddetach.fr_FR.po0000644000175000017500000000351113542151610020437 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/flooddetach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "" #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "" msgstr[1] "" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "" znc-1.7.5/modules/po/perleval.es_ES.po0000644000175000017500000000136213542151610017777 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/perleval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "Evalua código perl" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "Solo los administradores pueden cargar este módulo" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "Error: %s" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "Resultados: %s" znc-1.7.5/modules/po/q.ru_RU.po0000644000175000017500000001331013542151610016457 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/q.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" #: q.cpp:111 msgid "The following commands are available:" msgstr "" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "" #: q.cpp:116 msgid "Auth [ ]" msgstr "" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "" #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" #: q.cpp:128 msgid "Prints the current status of the module." msgstr "" #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "" #: q.cpp:135 msgid "Set " msgstr "" #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" #: q.cpp:146 msgid "The following settings are available:" msgstr "" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "" #: q.cpp:154 msgid "Your Q username." msgstr "" #: q.cpp:158 msgid "Your Q password." msgstr "" #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "" #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "" #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "" #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "" #: q.cpp:200 msgid "Syntax: Set " msgstr "" #: q.cpp:203 msgid "Username set" msgstr "" #: q.cpp:206 msgid "Password set" msgstr "" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "" #: q.cpp:212 msgid "UseChallenge set" msgstr "" #: q.cpp:215 msgid "RequestPerms set" msgstr "" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "" #: q.cpp:253 msgid "Connected: yes" msgstr "" #: q.cpp:254 msgid "Connected: no" msgstr "" #: q.cpp:255 msgid "Cloacked: yes" msgstr "" #: q.cpp:255 msgid "Cloacked: no" msgstr "" #: q.cpp:256 msgid "Authenticated: yes" msgstr "" #: q.cpp:257 msgid "Authenticated: no" msgstr "" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "" #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "" #: q.cpp:280 msgid "Update requested." msgstr "" #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "" #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "" #: q.cpp:408 msgid "Changes have been saved!" msgstr "" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "" #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "" #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "" #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "" #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "" znc-1.7.5/modules/po/bouncedcc.id_ID.po0000644000175000017500000000476513542151610020076 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/bouncedcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "" #: bouncedcc.cpp:129 msgid "Connected" msgstr "" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "" #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "" #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "" #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" znc-1.7.5/modules/po/q.nl_NL.po0000644000175000017500000001303313542151610016427 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/q.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" #: q.cpp:111 msgid "The following commands are available:" msgstr "" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "" #: q.cpp:116 msgid "Auth [ ]" msgstr "" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "" #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" #: q.cpp:128 msgid "Prints the current status of the module." msgstr "" #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "" #: q.cpp:135 msgid "Set " msgstr "" #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" #: q.cpp:146 msgid "The following settings are available:" msgstr "" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "" #: q.cpp:154 msgid "Your Q username." msgstr "" #: q.cpp:158 msgid "Your Q password." msgstr "" #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "" #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "" #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "" #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "" #: q.cpp:200 msgid "Syntax: Set " msgstr "" #: q.cpp:203 msgid "Username set" msgstr "" #: q.cpp:206 msgid "Password set" msgstr "" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "" #: q.cpp:212 msgid "UseChallenge set" msgstr "" #: q.cpp:215 msgid "RequestPerms set" msgstr "" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "" #: q.cpp:253 msgid "Connected: yes" msgstr "" #: q.cpp:254 msgid "Connected: no" msgstr "" #: q.cpp:255 msgid "Cloacked: yes" msgstr "" #: q.cpp:255 msgid "Cloacked: no" msgstr "" #: q.cpp:256 msgid "Authenticated: yes" msgstr "" #: q.cpp:257 msgid "Authenticated: no" msgstr "" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "" #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "" #: q.cpp:280 msgid "Update requested." msgstr "" #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "" #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "" #: q.cpp:408 msgid "Changes have been saved!" msgstr "" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "" #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "" #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "" #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "" #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "" znc-1.7.5/modules/po/imapauth.ru_RU.po0000644000175000017500000000133613542151610020034 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/imapauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "" znc-1.7.5/modules/po/bouncedcc.nl_NL.po0000644000175000017500000000642013542151610020116 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/bouncedcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "Type" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "Status" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "Snelheid" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "Naam" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "IP-adres" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "Bestand" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "Chat" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "Overdracht" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "Wachten" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "Halverwege" #: bouncedcc.cpp:129 msgid "Connected" msgstr "Verbonden" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "Je hebt geen actieve DCCs." #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "Gebruik client IP: {1}" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "Laat alle actieve DCCs zien" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "Verander de optie om het IP van de client te gebruiken" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "Chat" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "Overdracht" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "DCC {1} Bounce ({2}): Te lange regel ontvangen" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "DCC {1} Bounce ({2}): Time-out tijdens verbinden naar {3} {4}" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "DCC {1} Bounce ({2}): Time-out tijdens verbinden." #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" "DCC {1} Bounce ({2}): Time-out tijdens wachten op inkomende verbinding op " "{3} {4}" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "" "DCC {1} Bounce ({2}): Verbinding geweigerd tijdens verbinden naar {3} {4}" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "DCC {1} Bounce ({2}): Verbinding gewijgerd tijdens verbinden." #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "DCC {1} Bounce ({2}): Socket foutmelding op {3} {4}: {5}" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "DCC {1} Bounce ({2}): Socket foutmelding: {3}" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" "Bounced DCC overdrachten door ZNC in plaats van direct naar de gebruiker te " "versturen." znc-1.7.5/modules/po/clearbufferonmsg.fr_FR.po0000644000175000017500000000102213542151610021502 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/clearbufferonmsg.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "" znc-1.7.5/modules/po/route_replies.it_IT.po0000644000175000017500000000344013542151610021057 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/route_replies.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "[si|no]" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "Decide se mostrare o meno i messaggi di timeout" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" "Questo modulo ha riscontrato un timeout che probabilmente è un problema di " "connettività." #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" "Tuttavia, se puoi fornire i passaggi per riprodurre questo problema, segnala " "un bug." #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "Per disabilitare questo messaggio, digita \"/msg {1} silent yes\"" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "Ultima richiesta: {1}" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "Risposte attese:" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "{1} (ultimo)" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "I messaggi di timeout sono disabilitati." #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "I messaggi di timeout sono abilitati." #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "Invia le risposte (come ad esempio /who) solamente al cliente giusto" znc-1.7.5/modules/po/notes.it_IT.po0000644000175000017500000000572513542151610017336 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/notes.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "Aggiunge Una Nota" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "Parola chiave:" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "Nota:" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "Aggiungi Nota" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "Non hai note da visualizzare." #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "Parola chiave" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "Nota" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "[del]" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "" "Questa nota esiste già. Usa MOD per sovrascrivere." #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "Aggiunta la nota {1}" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "Impossibile aggiungere la nota {1}" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "Imposta la nota per {1}" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "Questa nota non esiste." #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "Eliminata la nota {1}" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "Impossibile eliminare la nota {1}" #: notes.cpp:75 msgid "List notes" msgstr "Elenca le note inserite" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr " " #: notes.cpp:77 msgid "Add a note" msgstr "Aggiunge una nota" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "Elimina la nota" #: notes.cpp:81 msgid "Modify a note" msgstr "Modifica una nota" #: notes.cpp:94 msgid "Notes" msgstr "Note" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "" "Questa nota esiste già. Usa /#+ per sovrascrivere." #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "Non hai voci." #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" "Questo modulo utente accetta fino ad un argomento. Può essere disabilitato " "con il comando -disableNotesOnLogin per non mostrare le note all'accesso del " "client" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "Conserva e riproduce le note" znc-1.7.5/modules/po/stripcontrols.pot0000644000175000017500000000033413542151610020277 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "" znc-1.7.5/modules/po/disconkick.it_IT.po0000644000175000017500000000136713542151610020325 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/disconkick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "Sei stato disconnesso dal server IRC" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" "Butta fuori (kick) il client da tutti i canali quando la connessione al " "server IRC viene persa" znc-1.7.5/modules/po/autocycle.it_IT.po0000644000175000017500000000357313542151610020175 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/autocycle.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "[!]<#canale>" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" "Aggiunge una voce, usa !#canale per negare e * per i caratteri jolly " "(wildcards)" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "Rimuove una voce, deve essere una corrispondenza esatta" #: autocycle.cpp:33 msgid "List all entries" msgstr "Elenca tutte le voci inserite" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "Impossibile aggiungere {1}" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "{1} è già aggiunto" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "Aggiunto {1} alla lista" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "Usa: Add [!]<#canale>" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "Rimosso {1} dalla lista" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "Usa: Del [!]<#canale>" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "Canale" #: autocycle.cpp:100 msgid "You have no entries." msgstr "Non hai voci." #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "" "Elenco delle maschere di canale e delle maschere di canali con il simbolo ! " "che li precede." #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" "Rientra (rejoins) nei canali per ottenere l'Op se sei l'unico utente rimasto" znc-1.7.5/modules/po/nickserv.bg_BG.po0000644000175000017500000000276113542151610017757 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/nickserv.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: nickserv.cpp:31 msgid "Password set" msgstr "" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "" #: nickserv.cpp:63 msgid "Ok" msgstr "" #: nickserv.cpp:68 msgid "password" msgstr "" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "" #: nickserv.cpp:72 msgid "nickname" msgstr "" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "" #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "" znc-1.7.5/modules/po/block_motd.ru_RU.po0000644000175000017500000000202713542151610020337 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/block_motd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: block_motd.cpp:26 msgid "[]" msgstr "[<Ñервер>]" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "" #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "MOTD блокирован ZNC" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "" znc-1.7.5/modules/po/log.bg_BG.po0000644000175000017500000000501413542151610016706 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/log.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "" #: log.cpp:62 msgid "Clear all logging rules" msgstr "" #: log.cpp:64 msgid "List all logging rules" msgstr "" #: log.cpp:67 msgid " true|false" msgstr "" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "" #: log.cpp:143 msgid "Usage: SetRules " msgstr "" #: log.cpp:144 msgid "Wildcards are allowed" msgstr "" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "" #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "" msgstr[1] "" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "" #: log.cpp:196 msgid "Will log joins" msgstr "" #: log.cpp:196 msgid "Will not log joins" msgstr "" #: log.cpp:197 msgid "Will log quits" msgstr "" #: log.cpp:197 msgid "Will not log quits" msgstr "" #: log.cpp:199 msgid "Will log nick changes" msgstr "" #: log.cpp:199 msgid "Will not log nick changes" msgstr "" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "" #: log.cpp:211 msgid "Logging joins" msgstr "" #: log.cpp:211 msgid "Not logging joins" msgstr "" #: log.cpp:212 msgid "Logging quits" msgstr "" #: log.cpp:212 msgid "Not logging quits" msgstr "" #: log.cpp:213 msgid "Logging nick changes" msgstr "" #: log.cpp:214 msgid "Not logging nick changes" msgstr "" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "" #: log.cpp:563 msgid "Writes IRC logs." msgstr "" znc-1.7.5/modules/po/raw.ru_RU.po0000644000175000017500000000117213542151610017013 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "" znc-1.7.5/modules/po/imapauth.pot0000644000175000017500000000037713542151610017171 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "" znc-1.7.5/modules/po/stripcontrols.bg_BG.po0000644000175000017500000000102713542151610021052 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/stripcontrols.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "" znc-1.7.5/modules/po/q.es_ES.po0000644000175000017500000001304013542151610016421 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/q.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" #: q.cpp:111 msgid "The following commands are available:" msgstr "" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "" #: q.cpp:116 msgid "Auth [ ]" msgstr "" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "" #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" #: q.cpp:128 msgid "Prints the current status of the module." msgstr "" #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "" #: q.cpp:135 msgid "Set " msgstr "" #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" #: q.cpp:146 msgid "The following settings are available:" msgstr "" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "" #: q.cpp:154 msgid "Your Q username." msgstr "" #: q.cpp:158 msgid "Your Q password." msgstr "" #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "" #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "" #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "" #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "" #: q.cpp:200 msgid "Syntax: Set " msgstr "" #: q.cpp:203 msgid "Username set" msgstr "" #: q.cpp:206 msgid "Password set" msgstr "" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "" #: q.cpp:212 msgid "UseChallenge set" msgstr "" #: q.cpp:215 msgid "RequestPerms set" msgstr "" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "" #: q.cpp:253 msgid "Connected: yes" msgstr "" #: q.cpp:254 msgid "Connected: no" msgstr "" #: q.cpp:255 msgid "Cloacked: yes" msgstr "" #: q.cpp:255 msgid "Cloacked: no" msgstr "" #: q.cpp:256 msgid "Authenticated: yes" msgstr "" #: q.cpp:257 msgid "Authenticated: no" msgstr "" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "" #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "" #: q.cpp:280 msgid "Update requested." msgstr "" #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "" #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "" #: q.cpp:408 msgid "Changes have been saved!" msgstr "" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "" #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "" #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "" #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "" #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "" znc-1.7.5/modules/po/log.it_IT.po0000644000175000017500000000737613542151610016773 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/log.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "" "Imposta le regole di registrazione (logging), usa !#canale o !query per " "negare e * " #: log.cpp:62 msgid "Clear all logging rules" msgstr "Cancella tutte le regole di registrazione (logging rules)" #: log.cpp:64 msgid "List all logging rules" msgstr "Elenca tutte le regole di registrazione" #: log.cpp:67 msgid " true|false" msgstr " vero|falso" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "Imposta una delle seguenti opzioni: joins, quits, nickchanges" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "Mostra le impostazioni correnti impostate dal comando Set" #: log.cpp:143 msgid "Usage: SetRules " msgstr "Utilizzo: SetRules " #: log.cpp:144 msgid "Wildcards are allowed" msgstr "Le wildcards (caratteri jolly) sono permesse" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "Nessuna regola di registrazione. Tutto viene loggato." #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "1 regola rimssa {2}" msgstr[1] "{1} regole rimosse: {2}" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "Ruolo" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "Logging abilitato" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "" "Usa: Set true|false, dove è una tra: joins, quits, " "nickchanges" #: log.cpp:196 msgid "Will log joins" msgstr "Loggerà i joins" #: log.cpp:196 msgid "Will not log joins" msgstr "Non loggerà i joins" #: log.cpp:197 msgid "Will log quits" msgstr "Loggerà i quits" #: log.cpp:197 msgid "Will not log quits" msgstr "Non loggerà i quits" #: log.cpp:199 msgid "Will log nick changes" msgstr "Loggerà i cambi di nick" #: log.cpp:199 msgid "Will not log nick changes" msgstr "Non registrerà i cambi di nick" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "Variabile sconosciuta. Variabili conosciute: joins, quits, nickchanges" #: log.cpp:211 msgid "Logging joins" msgstr "Registrazione dei joins" #: log.cpp:211 msgid "Not logging joins" msgstr "Non si registrano join" #: log.cpp:212 msgid "Logging quits" msgstr "Registrazione dei quits" #: log.cpp:212 msgid "Not logging quits" msgstr "Non si registrano i quits" #: log.cpp:213 msgid "Logging nick changes" msgstr "Registrazione del cambio nick" #: log.cpp:214 msgid "Not logging nick changes" msgstr "Non si registrano cambi di nick" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" "Argomento non valido [{1}]. È consentito un solo percorso per la " "registrazione dei log. Verifica che non ci siano spazi nel percorso." #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "Percorso di log non valido [{1}]" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "Accesso a [{1}]. Utilizzando il formato timestamp '{2}'" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "[-sanitize] Percorso opzionale dove archiviare i registri (logs)." #: log.cpp:563 msgid "Writes IRC logs." msgstr "Scrive un logs IRC." znc-1.7.5/modules/po/keepnick.pt_BR.po0000644000175000017500000000222113542151610017761 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/keepnick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "" #: keepnick.cpp:44 msgid "Show the current state" msgstr "" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "" znc-1.7.5/modules/po/autoreply.de_DE.po0000644000175000017500000000237413542151610020157 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/autoreply.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "Setzt eine neue Antwort" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "Zeigt die aktuelle Query-Antwort an" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "Aktuelle Antwort ist: {1} ({2})" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "Neue Antwort gesetzt auf: {1} ({2})" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" "Erlaubt es einen Antwort-Text zu setzen. Dieser wird verwendet wenn " "automatisch Queries beantwortet werden, falls du nicht zu ZNC verbunden bist." #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "Auf Queries antworten when du nicht da bist" znc-1.7.5/modules/po/autoreply.es_ES.po0000644000175000017500000000236313542151610020213 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/autoreply.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "Añade una nueva respuesta" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "Muestra la respuesta configurada" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "La respuesta actual es: {1} ({2})" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "Nueva respuesta configurada: {1} ({2})" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" "Puedes especificar un texto de respuesta. Se usa para responder " "automáticamente los privados si no estás conectado a ZNC." #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "Responde a los privados cuando estás ausente" znc-1.7.5/modules/po/stickychan.bg_BG.po0000644000175000017500000000365213542151610020273 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/stickychan.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "" #: stickychan.cpp:30 msgid "<#channel>" msgstr "" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "" #: stickychan.cpp:101 msgid " -- End of List" msgstr "" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "" #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "" #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" znc-1.7.5/modules/po/buffextras.ru_RU.po0000644000175000017500000000217013542151610020372 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/buffextras.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: buffextras.cpp:45 msgid "Server" msgstr "" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "" #: buffextras.cpp:73 msgid "{1} joined" msgstr "" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "" znc-1.7.5/modules/po/perleval.bg_BG.po0000644000175000017500000000122413542151610017736 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/perleval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "" znc-1.7.5/modules/po/modperl.fr_FR.po0000644000175000017500000000073413542151610017631 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/modperl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/pyeval.nl_NL.po0000644000175000017500000000114313542151610017466 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/pyeval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "Alleen beheerders kunnen deze module laden." #: pyeval.py:82 msgid "Evaluates python code" msgstr "Evalueert python code" znc-1.7.5/modules/po/shell.es_ES.po0000644000175000017500000000150713542151610017275 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/shell.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "Error al ejecutar: {1}" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "Debes ser admin para usar el módulo Shell" #: shell.cpp:169 msgid "Gives shell access" msgstr "Proporciona acceso a la shell" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "Proporciona acceso a la Shell. Solo lo pueden usar admins de ZNC." znc-1.7.5/modules/po/autoreply.pot0000644000175000017500000000120113542151610017370 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "" znc-1.7.5/modules/po/autoreply.fr_FR.po0000644000175000017500000000166413542151610020216 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/autoreply.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "" znc-1.7.5/modules/po/autoop.id_ID.po0000644000175000017500000000630013542151610017443 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/autoop.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: autoop.cpp:154 msgid "List all users" msgstr "" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr "" #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr "" #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr "" #: autoop.cpp:170 msgid "Adds a user" msgstr "" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "" #: autoop.cpp:300 msgid "There are no users defined" msgstr "" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "" #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "" #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "" #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "" #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "" #: autoop.cpp:478 msgid "User {1} removed" msgstr "" #: autoop.cpp:484 msgid "That user already exists" msgstr "" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "" #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "" #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "" #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "" #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "" #: autoop.cpp:644 msgid "Auto op the good people" msgstr "" znc-1.7.5/modules/po/autocycle.bg_BG.po0000644000175000017500000000257613542151610020127 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/autocycle.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "" #: autocycle.cpp:33 msgid "List all entries" msgstr "" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "" #: autocycle.cpp:100 msgid "You have no entries." msgstr "" #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "" #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" znc-1.7.5/modules/po/disconkick.bg_BG.po0000644000175000017500000000116113542151610020245 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/disconkick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" znc-1.7.5/modules/po/alias.ru_RU.po0000644000175000017500000000467413542151610017325 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/alias.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "" #: alias.cpp:203 msgid "Alias already exists." msgstr "" #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "" #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "" #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "" #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "" #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr "" #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "" #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "" #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "" #: alias.cpp:343 msgid " " msgstr "" #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "" #: alias.cpp:346 msgid " " msgstr "" #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "" #: alias.cpp:349 msgid " " msgstr "" #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "" #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "" #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "" #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "" #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "" #: alias.cpp:374 msgid "Clearing all of them!" msgstr "" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "" znc-1.7.5/modules/po/autoop.fr_FR.po0000644000175000017500000001047513542151610017501 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/autoop.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: autoop.cpp:154 msgid "List all users" msgstr "Lister tous les utilisateurs" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr " [channel]..." #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "Ajoute des salons à un utilisateur" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "Retire des salons d'un utilisateur" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr " ,[mask] ..." #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "Ajoute des masques à un utilisateur" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "Supprime des masques d'un utilisateur" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr " [,...] [channels]" #: autoop.cpp:170 msgid "Adds a user" msgstr "Ajoute un utilisateur" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "Supprime un utilisateur" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "" "Utilisation : AddUser [,...] " " [channels]" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "Utilisation : DelUser " #: autoop.cpp:300 msgid "There are no users defined" msgstr "Il n'y a pas d'utilisateurs définis" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "Utilisateur" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "Masque réseau" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "Clé" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "Salons" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "Utilisation : AddChans [channel] ..." #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "Utilisateur inconnu" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "Salon(s) ajouté(s) à l'utilisateur {1}" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "Utilisation : DelChans [channel] ..." #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "Salons(s) supprimés de l'utilisateur {1}" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "Utilisation : AddMasks ,[mask] ..." #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "Masques(s) ajouté(s) à l'utilisateur {1}" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "Utilisation : DelMasks ,[mask] ..." #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "Utilisateur {1} avec la clé {2} et les salons {3} supprimé" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "Masques(s) supprimé(s) de l'utilisateur {1}" #: autoop.cpp:478 msgid "User {1} removed" msgstr "Utilisateur {1} supprimé" #: autoop.cpp:484 msgid "That user already exists" msgstr "Cet utilisateur existe déjà" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "Utilisateur {1} ajouté avec le(s) masque(s) {2}" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "" #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "" #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "" #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "" #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "" #: autoop.cpp:644 msgid "Auto op the good people" msgstr "" znc-1.7.5/modules/po/alias.es_ES.po0000644000175000017500000000610213542151610017253 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/alias.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "falta un parámetro: {1}" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "Alias creado: {1}" #: alias.cpp:203 msgid "Alias already exists." msgstr "El alias ya existe." #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "Allias borrado: {1}" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "El alias no existe." #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "Alias modificado." #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "Ãndice no válido." #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "No hay aliases." #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "El siguiente alias ya existe: {1}" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr "[lista | separador] ," #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "Acciones para el alias {1}:" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "Fin de acciones para el alias {1}." #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "Crea un nuevo alias vacío llamado nombre." #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "Elimina un alias existente," #: alias.cpp:343 msgid " " msgstr " " #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "Añade una línea a un alias existente." #: alias.cpp:346 msgid " " msgstr " " #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "Inserta una nueva línea en un alias existente." #: alias.cpp:349 msgid " " msgstr " " #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "Borra una línea de un alias existente." #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "Borra todas las lineas de un alias existente." #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "Muestra todos los alias por nombre." #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "Muestra las acciones ejecutadas por un alias." #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "Genera una lista de comandos para copiar en tu configuración de alias." #: alias.cpp:374 msgid "Clearing all of them!" msgstr "¡Borrados todos los alias!" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "Proporciona soporte de aliases por parte del bouncer." znc-1.7.5/modules/po/admindebug.id_ID.po0000644000175000017500000000221513542151610020234 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/admindebug.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "" #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "" #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" #: admindebug.cpp:66 msgid "Already enabled." msgstr "" #: admindebug.cpp:68 msgid "Already disabled." msgstr "" #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "" #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "" #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "" #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "" znc-1.7.5/modules/po/send_raw.ru_RU.po0000644000175000017500000000715313542151610020031 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/send_raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "Отправить Ñырую Ñтроку IRC" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "Пользователь:" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "Чтобы изменить пользователÑ, щёлкните на Ñелектор Ñети" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "Пользователь/Ñеть:" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "Отправить:" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "Клиент" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "Сервер" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "Строка:" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "Отправить" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "Отправил [{1}] {2}/{3}" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "Сеть {1} не найдена Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ {2}" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "Пользователь {1} не найден" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "ПоÑлал [{1}] к IRC Ñерверу {2}/{3}" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "Ð’Ñ‹ должны иметь привилегии админиÑтратора Ð´Ð»Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸ Ñтого модулÑ" #: send_raw.cpp:82 msgid "Send Raw" msgstr "Отправить Ñырым" #: send_raw.cpp:92 msgid "User not found" msgstr "Пользователь не найден" #: send_raw.cpp:99 msgid "Network not found" msgstr "Сеть не найдена" #: send_raw.cpp:116 msgid "Line sent" msgstr "Строка отправлена" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "[пользователь] [Ñеть] [данные Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸]" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "Данные будут отправлены IRC-клиент(ам) Ñтого пользователÑ" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "" "Данные будут передаватьÑÑ Ð½Ð° IRC-Ñервер, еÑли пользователь подключен к нему" #: send_raw.cpp:147 msgid "[data to send]" msgstr "[данные Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸]" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "Данные будут отправлены на ваш текущий клиент" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "ПозволÑет отправлÑть некоторые Ñырые Ñтроки IRC кому-либо" znc-1.7.5/modules/po/listsockets.de_DE.po0000644000175000017500000000502713542151610020500 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/listsockets.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "Name" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "Erzeugt" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "Zustand" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "SSL" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "Lokal" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "Entfernt" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "Daten Ein" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "Daten Aus" #: listsockets.cpp:62 msgid "[-n]" msgstr "[-n]" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "" "Zeigt die Liste aktiver Verbindungen. Gebe -n an um IP-Adressen anzuzeigen" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "Du musst Administrator sein um dieses Modul zu verwenden" #: listsockets.cpp:96 msgid "List sockets" msgstr "Liste Verbindungen auf" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "Ja" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "Nein" #: listsockets.cpp:142 msgid "Listener" msgstr "Listener" #: listsockets.cpp:144 msgid "Inbound" msgstr "Eingehend" #: listsockets.cpp:147 msgid "Outbound" msgstr "Ausgehend" #: listsockets.cpp:149 msgid "Connecting" msgstr "Verbindend" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "UNBEKANNT" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "Du hast keine offenen Verbindungen." #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "Ein" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "Aus" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "Liste aktive Verbindungen auf" znc-1.7.5/modules/po/autoattach.fr_FR.po0000644000175000017500000000431013542151610020316 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/autoattach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "Ajouté à la liste" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "{1} est déjà présent" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "Usage : Add [!]<#salon> " #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "Les jokers sont autorisés" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "{1} retiré de la liste" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "Usage : Del[!]<#salon> " #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "Neg" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "Salon" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "Recherche" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "Hôte" #: autoattach.cpp:138 msgid "You have no entries." msgstr "Vous n'avez aucune entrée." #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "[!]<#salon> " #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "Ajoute une entrée, utilisez !#salon pour inverser et * comme joker" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "Retire une entrée, requiert une correspondance exacte" #: autoattach.cpp:152 msgid "List all entries" msgstr "Liste toutes les entrées" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "Impossible d'ajouter [{1}]" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "Liste les masques de salons, y compris préfixés par !." #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "Vous réattache automatiquement aux salons lorsqu'ils sont actifs." znc-1.7.5/modules/po/modules_online.ru_RU.po0000644000175000017500000000123413542151610021235 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/modules_online.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "" znc-1.7.5/modules/po/fail2ban.id_ID.po0000644000175000017500000000430413542151610017614 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/fail2ban.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "" #: fail2ban.cpp:28 msgid "[count]" msgstr "" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "" #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "" #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "" #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "" #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "" #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "" #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "" znc-1.7.5/modules/po/perleval.pt_BR.po0000644000175000017500000000124313542151610020005 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/perleval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "" znc-1.7.5/modules/po/buffextras.pt_BR.po0000644000175000017500000000173613542151610020353 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/buffextras.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: buffextras.cpp:45 msgid "Server" msgstr "" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "" #: buffextras.cpp:73 msgid "{1} joined" msgstr "" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "" znc-1.7.5/modules/po/modperl.pt_BR.po0000644000175000017500000000075713542151610017646 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/modperl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/notes.de_DE.po0000644000175000017500000000437413542151610017265 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/notes.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "" #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "" #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "" #: notes.cpp:75 msgid "List notes" msgstr "" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr "" #: notes.cpp:77 msgid "Add a note" msgstr "" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "" #: notes.cpp:81 msgid "Modify a note" msgstr "" #: notes.cpp:94 msgid "Notes" msgstr "" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "" #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "" #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "" znc-1.7.5/modules/po/simple_away.bg_BG.po0000644000175000017500000000374613542151610020451 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/simple_away.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: simple_away.cpp:56 msgid "[]" msgstr "" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "" #: simple_away.cpp:136 msgid "Away reason set" msgstr "" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" znc-1.7.5/modules/po/flooddetach.ru_RU.po0000644000175000017500000000405213542151610020476 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/flooddetach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "" #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "" znc-1.7.5/modules/po/watch.bg_BG.po0000644000175000017500000001071713542151610017241 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/watch.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "" #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "" #: watch.cpp:397 msgid "Disabled all entries." msgstr "" #: watch.cpp:398 msgid "Enabled all entries." msgstr "" #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "" #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "" #: watch.cpp:593 msgid "Id {1} removed." msgstr "" #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "" #: watch.cpp:609 msgid "List" msgstr "" #: watch.cpp:611 msgid "List all entries being watched." msgstr "" #: watch.cpp:614 msgid "Dump" msgstr "" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "" #: watch.cpp:620 msgid "Del " msgstr "" #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "" #: watch.cpp:625 msgid "Clear" msgstr "" #: watch.cpp:626 msgid "Delete all entries." msgstr "" #: watch.cpp:629 msgid "Enable " msgstr "" #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "" #: watch.cpp:633 msgid "Disable " msgstr "" #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "" #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "" #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "" #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "" #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "" #: watch.cpp:652 msgid "Buffer [Count]" msgstr "" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "" #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "" #: watch.cpp:664 msgid "Help" msgstr "" #: watch.cpp:665 msgid "This help." msgstr "" #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "" #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "" znc-1.7.5/modules/po/fail2ban.bg_BG.po0000644000175000017500000000431213542151610017603 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/fail2ban.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "" #: fail2ban.cpp:28 msgid "[count]" msgstr "" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "" #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "" #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "" #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "" #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "" #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "" #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "" znc-1.7.5/modules/po/alias.id_ID.po0000644000175000017500000000441513542151610017232 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/alias.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: alias.cpp:141 msgid "missing required parameter: {1}" msgstr "" #: alias.cpp:201 msgid "Created alias: {1}" msgstr "" #: alias.cpp:203 msgid "Alias already exists." msgstr "" #: alias.cpp:210 msgid "Deleted alias: {1}" msgstr "" #: alias.cpp:213 alias.cpp:224 alias.cpp:246 alias.cpp:265 alias.cpp:276 #: alias.cpp:333 msgid "Alias does not exist." msgstr "" #: alias.cpp:222 alias.cpp:244 alias.cpp:263 alias.cpp:274 msgid "Modified alias." msgstr "" #: alias.cpp:236 alias.cpp:256 msgid "Invalid index." msgstr "" #: alias.cpp:282 alias.cpp:298 msgid "There are no aliases." msgstr "" #: alias.cpp:289 msgid "The following aliases exist: {1}" msgstr "" #: alias.cpp:290 msgctxt "list|separator" msgid ", " msgstr "" #: alias.cpp:324 msgid "Actions for alias {1}:" msgstr "" #: alias.cpp:331 msgid "End of actions for alias {1}." msgstr "" #: alias.cpp:338 alias.cpp:341 alias.cpp:352 alias.cpp:357 msgid "" msgstr "" #: alias.cpp:339 msgid "Creates a new, blank alias called name." msgstr "" #: alias.cpp:341 msgid "Deletes an existing alias." msgstr "" #: alias.cpp:343 msgid " " msgstr "" #: alias.cpp:344 msgid "Adds a line to an existing alias." msgstr "" #: alias.cpp:346 msgid " " msgstr "" #: alias.cpp:347 msgid "Inserts a line into an existing alias." msgstr "" #: alias.cpp:349 msgid " " msgstr "" #: alias.cpp:350 msgid "Removes a line from an existing alias." msgstr "" #: alias.cpp:353 msgid "Removes all lines from an existing alias." msgstr "" #: alias.cpp:355 msgid "Lists all aliases by name." msgstr "" #: alias.cpp:358 msgid "Reports the actions performed by an alias." msgstr "" #: alias.cpp:362 msgid "Generate a list of commands to copy your alias config." msgstr "" #: alias.cpp:374 msgid "Clearing all of them!" msgstr "" #: alias.cpp:409 msgid "Provides bouncer-side command alias support." msgstr "" znc-1.7.5/modules/po/notify_connect.pt_BR.po0000644000175000017500000000130113542151610021207 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/notify_connect.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: notify_connect.cpp:24 msgid "attached" msgstr "" #: notify_connect.cpp:26 msgid "detached" msgstr "" #: notify_connect.cpp:41 msgid "{1} {2} from {3}" msgstr "" #: notify_connect.cpp:52 msgid "Notifies all admin users when a client connects or disconnects." msgstr "" znc-1.7.5/modules/po/raw.fr_FR.po0000644000175000017500000000071513542151610016757 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "" znc-1.7.5/modules/po/cert.id_ID.po0000644000175000017500000000334213542151610017074 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/cert.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "" #: cert.cpp:28 msgid "Pem file deleted" msgstr "" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "" #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "" #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "" #: cert.cpp:54 msgid "Show the current certificate" msgstr "" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "" znc-1.7.5/modules/po/stripcontrols.fr_FR.po0000644000175000017500000000102313542151610021104 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/stripcontrols.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "" znc-1.7.5/modules/po/sasl.nl_NL.po0000644000175000017500000001123513542151610017133 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/sasl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "SASL" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "Gebruikersnaam:" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "Voer alsjeblieft een gebruikersnaam in." #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "Wachtwoord:" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "Voer alsjeblieft een wachtwoord in." #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "Opties" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "Verbind alleen als SASL authenticatie lukt." #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "Vereis authenticatie" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "Mechanismen" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "Naam" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "Beschrijving" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "Geselecteerde mechanismen en hun volgorde:" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "Opslaan" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "TLS certificaat, te gebruiken met de *cert module" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" "Open text onderhandeling, dit zou altijd moeten werken als het netwerk SASL " "ondersteund" #: sasl.cpp:62 msgid "search" msgstr "Zoek" #: sasl.cpp:62 msgid "Generate this output" msgstr "Genereer deze uitvoer" #: sasl.cpp:64 msgid "[ []]" msgstr "[ []]" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" "Stel gebruikersnaam en wachtwoord in voor de mechanismen die deze nodig " "hebben. Wachtwoord is optioneel. Zonder parameters zal deze de huidige " "informatie tonen." #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "[mechanisme[ ...]]" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "Stelt de mechanismen om te gebruiken in (op volgorde)" #: sasl.cpp:72 msgid "[yes|no]" msgstr "[yes|no]" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "Verbind alleen als SASL authenticatie lukt" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "Mechanism" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "De volgende mechanismen zijn beschikbaar:" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "Gebruikersnaam is niet ingesteld" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "Gebruikersnaam is ingesteld op '{1}'" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "Wachtwoord was niet ingevoerd" #: sasl.cpp:114 msgid "Password was supplied" msgstr "Wachtwoord was ingevoerd" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "Gebruikersnaam is ingesteld op [{1}]" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "Wachtwoord is ingesteld op [{1}]" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "Huidige mechanismen ingesteld: {1}" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "We vereisen SASL onderhandeling om te mogen verbinden" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "We zullen verbinden ook als SASL faalt" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "Netwerk uitgeschakeld, we eisen authenticatie." #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "Gebruik 'RequireAuth no' om uit te schakelen." #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "{1} mechanisme gelukt." #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "{1} mechanisme gefaalt." #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "" "Voegt ondertsteuning voor SASL authenticatie mogelijkheden toe om te kunnen " "authenticeren naar een IRC server" znc-1.7.5/modules/po/partyline.id_ID.po0000644000175000017500000000157113542151610020150 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/partyline.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "" #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "" #: partyline.cpp:82 msgid "List all open channels" msgstr "" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "" znc-1.7.5/modules/po/listsockets.it_IT.po0000644000175000017500000000502413542151610020545 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/listsockets.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "Nome" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "Creato" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "Stato" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "SSL" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "Locale" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "Remoto" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "Dati in entrata" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "Dati in uscita" #: listsockets.cpp:62 msgid "[-n]" msgstr "[-n]" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "" "Mostra l'elenco dei sockets attivi. Passa -n per mostrare gli indirizzi IP" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "Devi essere amministratore per usare questo modulo" #: listsockets.cpp:96 msgid "List sockets" msgstr "Elenca sockets" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "Si" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "No" #: listsockets.cpp:142 msgid "Listener" msgstr "Listener (in ascolto)" #: listsockets.cpp:144 msgid "Inbound" msgstr "In entrata" #: listsockets.cpp:147 msgid "Outbound" msgstr "In uscita" #: listsockets.cpp:149 msgid "Connecting" msgstr "Collegamento" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "SCONOSCIUTO" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "Non hai sockets aperti." #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "Dentro" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "Fuori" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "Elenca i sockets attivi" znc-1.7.5/modules/po/sample.pot0000644000175000017500000000357213542151610016642 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "" #: sample.cpp:50 msgid "Sample job done" msgstr "" #: sample.cpp:65 msgid "TEST!!!!" msgstr "" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "" #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "" #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "" msgstr[1] "" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "" #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "" #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "" znc-1.7.5/modules/po/send_raw.fr_FR.po0000644000175000017500000000430113542151610017763 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/send_raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "" #: send_raw.cpp:82 msgid "Send Raw" msgstr "" #: send_raw.cpp:92 msgid "User not found" msgstr "" #: send_raw.cpp:99 msgid "Network not found" msgstr "" #: send_raw.cpp:116 msgid "Line sent" msgstr "" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "" #: send_raw.cpp:147 msgid "[data to send]" msgstr "" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "" znc-1.7.5/modules/po/certauth.de_DE.po0000644000175000017500000000556313542151610017755 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/certauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "Einen Schlüssel hinzufügen" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "Schlüssel:" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "Schlüssel hinzufügen" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "Du hast keine Schlüssel." #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "Schlüssel" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "lösch" #: certauth.cpp:31 msgid "[pubkey]" msgstr "[öffentlicher Schlüssel]" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" "Einen öffentlichen Schlüssel hinzufügen. Falls kein Schlüssel angegeben " "wird, dann wird der aktuelle Schlüsse verwunden" #: certauth.cpp:35 msgid "id" msgstr "id" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "Lösche einen Schlüssels durch seine Nummer in der Liste" #: certauth.cpp:37 msgid "List your public keys" msgstr "Öffentliche Schlüssel auflisten" #: certauth.cpp:39 msgid "Print your current key" msgstr "Aktuellen Schlüssel ausgeben" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "Du bist nicht mit einem gültigen öffentlichen Schlüssel verbunden" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "Dein aktuelle öffentlicher Schlüssel ist: {1}" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "" "Es wurde kein öffentlicher Schlüssel angegeben oder zum Verbinden verwendet." #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "Schlüssel '{1}' hinzugefügt." #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "Der Schlüssel '{1}' wurde bereits hinzugefügt." #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "Id" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "Schlüssel" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "Keine Schlüssel für deinen Benutzer gesetzt" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "Ungültige #, prüfe \"list\"" #: certauth.cpp:215 msgid "Removed" msgstr "Entfernt" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "" "Ermöglicht es Benutzern sich über SSL-Client-Zertifikate zu authentifizieren." znc-1.7.5/modules/po/identfile.fr_FR.po0000644000175000017500000000303213542151610020124 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/identfile.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: identfile.cpp:30 msgid "Show file name" msgstr "" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "" #: identfile.cpp:34 msgid "Show file format" msgstr "" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "" #: identfile.cpp:38 msgid "Show current state" msgstr "" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "" #: identfile.cpp:78 msgid "identfile is free" msgstr "" #: identfile.cpp:86 msgid "Access denied" msgstr "" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "" #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "" znc-1.7.5/modules/po/route_replies.de_DE.po0000644000175000017500000000357513542151610021020 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/route_replies.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "[ja|nein]" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "" "Entscheidet ob eine Zeitüberschreitungsnachricht angezeigt werden soll oder " "nicht" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" "Dieses Modul hatte eine Zeitüberschreitung, was wahrscheinlich ein " "Verbindungsproblem ist." #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" "Falls du allerdings die Schritte zum Reproduzieren dieses Problems angeben " "kannst, dann erstelle bitte einen Fehlerbericht." #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "Um diese Nachricht zu deaktivieren, mache \"/msg {1} silent yes\"" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "Letzte Anfrage: {1}" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "Erwartete Antworten:" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "{1} (letzte)" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "Zeitüberschreitungsnachrichten sind deaktiviert." #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "Zeitüberschreitungsnachrichten sind aktiviert." #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "Sende Antworten (z.B. auf /who) nur zum richtigen Klienten" znc-1.7.5/modules/po/crypt.ru_RU.po0000644000175000017500000000532113542151610017363 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/crypt.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "" #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "" #: crypt.cpp:204 msgid "List all keys" msgstr "" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "" #: crypt.cpp:213 msgid "[Prefix]" msgstr "" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "" #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "" #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "" #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "" #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "" #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "" #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "" #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "" #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "" #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "" #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "" znc-1.7.5/modules/po/nickserv.de_DE.po0000644000175000017500000000404213542151610017751 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/nickserv.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: nickserv.cpp:31 msgid "Password set" msgstr "Passwort gesetzt" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "NickServe-Name gesetzt" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "" "Kein solcher bearbeitbarer Befehl. Sieh dir ViewCommands für eine Liste an." #: nickserv.cpp:63 msgid "Ok" msgstr "Ok" #: nickserv.cpp:68 msgid "password" msgstr "Passwort" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "Setzt dein Nickserv-Passwort" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "Löscht dein Nickserv-Passwort" #: nickserv.cpp:72 msgid "nickname" msgstr "Nickname" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" "Setzt den Nickserv-Namen (Nützlich für Netzwerke wie EpiKnet, wo Nickserv " "Themis heißt Themis" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "Setzt Nickserv-Name auf Standard zurück (NickServ)" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "Zeige Muster für Linien, die an NickServ geschickt werden" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "Befehl neues-Muster" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "Setzt Muster für Befehle" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "Bitte gebe dein Nickserv-Passwort ein." #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "" "Authentifiziert dich mit NickServ (präferiere statt dessen das SASL-Modul)" znc-1.7.5/modules/po/route_replies.pot0000644000175000017500000000176413542151610020243 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: route_replies.cpp:209 msgid "[yes|no]" msgstr "" #: route_replies.cpp:210 msgid "Decides whether to show the timeout messages or not" msgstr "" #: route_replies.cpp:350 msgid "This module hit a timeout which is probably a connectivity issue." msgstr "" #: route_replies.cpp:353 msgid "" "However, if you can provide steps to reproduce this issue, please do report " "a bug." msgstr "" #: route_replies.cpp:356 msgid "To disable this message, do \"/msg {1} silent yes\"" msgstr "" #: route_replies.cpp:358 msgid "Last request: {1}" msgstr "" #: route_replies.cpp:359 msgid "Expected replies:" msgstr "" #: route_replies.cpp:363 msgid "{1} (last)" msgstr "" #: route_replies.cpp:435 msgid "Timeout messages are disabled." msgstr "" #: route_replies.cpp:436 msgid "Timeout messages are enabled." msgstr "" #: route_replies.cpp:457 msgid "Send replies (e.g. to /who) to the right client only" msgstr "" znc-1.7.5/modules/po/webadmin.nl_NL.po0000644000175000017500000012317713542151610017770 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/webadmin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "Kanaal informatie" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "Kanaal naam:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "De naam van het kanaal." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "Sleutel:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "Het wachtwoord van het kanaal, als er een is." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "Buffer grootte:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "Buffer aantal." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "Standaard modes:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "De standaard modes van het kanaal." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "Vlaggen" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "Opslaan naar configuratie" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "Module {1}" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "Opslaan en terugkeren" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "Opslaan en doorgaan" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "Voeg kanaal toe en keer terug" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "Voeg kanaal toe en ga door" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "<wachtwoord>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "<netwerk>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" "Om verbinding te maken met dit netwerk vanaf je IRC client, kan je het " "server wachtwoord instellen {1} of gebruikersnaam veld als " "{2}" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "Netwerk informatie" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" "Naam, AltNaam, identiteit, EchteNaam, BindHost kunnen leeg gelaten worden om " "de standaard instellingen van de gebruiker te gebruiken." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "Netwerk naam:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "De naam van het IRC netwerk." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "Bijnaam:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "Jouw bijnaam op IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "Alternatieve Bijnaam:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "Je tweede bijnaam, als de eerste niet beschikbaar is op IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "Identiteit:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "Jouw identiteit." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "Echte naam:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "Je echte naam." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "Bindhost:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "Verlaatbericht:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "Je kan een bericht ingeven die weergeven wordt als je IRC verlaat." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "Actief:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "Verbind met IRC & verbind automatisch opnieuw" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "Vertrouw alle certificaten:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "Schakel certificaatvalidatie uit (komt vóór TrustPKI). NIET VEILIG!" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "Vertrouw de PKI:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" "Als je deze uitschakelt zal ZNC alleen certificaten vertrouwen waar je de " "vingerafdrukken er voor toe hebt gevoegd." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "Servers van dit IRC netwerk:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "Één server per regel, \"host [[+]poort] [wachtwoord]\", + betekent SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "Hostnaam" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "Poort" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "Wachtwoord" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "" "SHA-256 vingerafdruk van vertrouwde SSL certificaten van dit IRC netwerk:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" "Wanneer deze certificaten gezien worden, controles voor hostname, " "vervaldatum en CA worden overgeslagen" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "Overstroom beveiliging:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" "Je kan overstroom-beveiliging inschakelen. Dit stop \"excess flood\" " "foutmeldingen die verscheinen als je IRC bot overstroomd of gespammed wordt " "met commando's. Na het aanpassen van deze instelling moet je ZNC opnieuw " "verbinden." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "Ingeschakeld" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "Overstroming bescherming verhouding:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" "Het aantal seconden per regel. Na het aanpassen moet ZNC opnieuw verbinden " "met IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "{1} seconden per regel" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "Overstroming bescherming uitbarsting:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" "Definieert het aantal regels die tegelijkertijd gestuurd kunnen worden. Na " "het aanpassen moet ZNC opnieuw verbinden met IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "{1} regels kunnen tegelijkertijd verstuurd worden" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "Kanaal toetreedvertraging:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" "Definieert de vertraging in seconden totdat tot kanalen toegetreden wordt na " "verbonden te zijn." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "{1} seconden" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "Karakter codering gebruikt tussen ZNC en de IRC server." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "Server codering:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "Kanalen" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "" "Hier kan je kanalen toevoegen en aanpassen nadat je een netwerk aangemaakt " "hebt." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "Toevoegen" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "Opslaan" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "Naam" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "CurModes" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "DefModes" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "BufferSize" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "Opties" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "↠Voeg een kanaal toe (opent op dezelfde pagina)" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "Bewerk" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "Verwijder" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "Modulen" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "Argumenten" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "Beschrijving" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "Algemeen geladen" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "Geladen door gebruiker" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "Voeg netwerk toe en keer terug" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "Voeg netwerk toe en ga verder" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "Authenticatie" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "Gebruikersnaam:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "Voer alsjeblieft een gebruikersnaam in." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "Wachtwoord:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "Voer alsjeblieft een wachtwoord in." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "Bevestig wachtwoord:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "Voer hetzelfde wachtwoord opnieuw in." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "Authenticatie alleen via module:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" "Stelt een gebruiker in staat the authenticeren alleen met behulp van externe " "modulen, hierdoor zal wachtwoordauthenticatie uitgescakeld worden." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "Toegestane IP-adressen:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" "Laat leeg om verbinding van alle IP-adressen toe te staan.
Anders, één " "adres per regel, jokers * en ? zijn beschikbaar." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "IRC Informatie" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" "Naam, AltNaam, identiteit, EchteNaam en VerlaatBericht kunnen leeg gelaten " "worden om de standaard instellingen te gebruiken." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "De identiteit wordt verstuurd naar de server als gebruikersnaam." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "Status voorvoegsel:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "Het voorvoegsel voor de status en module berichten." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "DCCBindHost:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "Netwerken" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "Clients" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "Huidige server" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "Bijnaam" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "↠Voeg een netwerk toe (opent op dezelfde pagina)" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "" "Hier kan je netwerken toevoegen en aanpassen nadat je een gebruiker gekloont " "hebt." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "" "Hier kan je netwerken toevoegen en aanpassen nadat je een gebruiker " "aangemaakt hebt." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "Geladen door netwerken" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" "Dit zijn de standaard modes die ZNC in zal stellen wanneer je een leeg " "kanaal toetreed." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "Leeg = gebruik standaard waarde" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Dit is het aantal regels dat de terugspeel buffer op zal slaan voor kanalen " "voordat deze de oudste regels laat vallen. Deze buffers worden standaard in " "het werkgeheugen opgeslagen." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "Privé berichten" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "Maximale buffers:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "Maximale aantal privé bericht buffers, 0 is onbeperkt." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Dit is het aantal regels dat de terugspeel buffer op zal slaan voor privé " "berichten voordat deze de oudste regels laat vallen. Deze buffers worden " "standaard in het werkgeheugen opgeslagen." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "ZNC gedrag" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" "De volgende textboxen kunnen leeg gelaten worden om de standaard waarden te " "gebruiken." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "Tijdstempel formaat:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" "Het formaat voor de tijdstempels die gebruikt worden in buffers, " "bijvoorbeeld [%H:%M:%S]. Deze instelling wordt genegeerd in nieuwe IRC " "clients, welke server-time gebruiken. Als je client server-time ondersteund " "kan je deze stempel veranderen in je client." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "Tijdzone:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "Bijvoorbeeld Europe/Amsterdam, of GMT+1" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "Karakter codering die gebruikt wordt tussen de IRC client en ZNC." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "Client codering:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "Aantal x proberen toe te treden:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" "Dit definieërt hoe vaak ZNC probeert tot een kanaal toe te treden mocht de " "eerste keer falen, bijvoorbeeld door channel modes +i/+k of als je verbannen " "bent." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "Toetreed snelheid:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" "Hoeveel channels toegetreden worden met één JOIN commando. 0 is onbeperkt " "(standaard). Stel dit in naar een klein getal als je de verbinding kwijt " "raakt met “Max SendQ Exceededâ€" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "Time-out voor opnieuw verbinden:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" "Hoeveel tijd ZNC wacht (in seconden) tot deze iets ontvangt van het netwerk " "of anders de verbinding time-out verklaren. Dit gebeurt na pogingen de " "server te pingen." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "Maximaal aantal IRC netwerken:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "Maximaal aantal IRC netwerken toegestaan voor deze gebruiker." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "Vervangingen" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "CTCP Antwoorden:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "Één antwoord per regel. Voorbeeld: TIME Buy a watch!" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "{1} zijn beschikbaar" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "Lege waarde betekend dat de CTCP aanvraag genegeerd zal worden" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "Aanvraag" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "Antwoord" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "Thema:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "- Globaal -" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "Standaard" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "Geen andere thema's gevonden" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "Taal:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "Kloon en keer terug" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "Kloon en ga verder" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "Maken en keer terug" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "Maken en ga door" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "Kloon" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "Maak" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "Bevestig verwijderen van netwerk" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "" "Weet je zeker dat je net \"{2}\" van gebruiker \"{1}\" wilt verwijderen?" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "Ja" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "Nee" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "Bevestig verwijderen van gebruiker" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "Weet je zeker dat je gebruiker \"{1}\" wilt verwijderen?" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "" "ZNC is gecompileerd zonder coderings ondersteuning. {1} is benodigd hiervoor." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "Legacy modus is uitgeschakeld door modpython." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "Verzeker geen codering (legacy modus, niet aangeraden)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "Probeer te ontleden als UTF-* en als {1}, stuur als UTF-8 (aangeraden)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "Probeer te ontleden als UTF-* en als {1}, stuur als {1}" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "Ontleed en stuur alleen als {1}" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "Bijvoorbeeld UTF-8, of ISO-8859-15" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "Welkom bij de ZNC webadministratie module." #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "" "Alle wijzigingen die je maakt zullen meteen toegepast worden nadat ze " "doorgestuurd zijn." #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "Gebruikersnaam" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "Verwijderen" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "Luister op po(o)rt(en)" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "BindHost" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "IPv4" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "IPv6" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "IRC" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "HTTP" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "URIVoorvoegsel" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" "Om de poort te verwijderen die in gebruik is voor de webadmin op dit moment " "moet je via een andere poort verbinden, of doen via IRC (/znc DelPort)" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "Huidige" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "Instellingen" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "Standaard voor nieuwe gebruikers alleen." #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "Maximale buffergrootte:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "" "Stelt de algemene maximale buffergrootte in die een gebruiker kan hebben." #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "Verbind vertraging:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" "De tijd tussen verbindingen die gemaakt worden naar IRC servers, in " "seconden. Dit beinvloed de verbinding tussen ZNC en de IRC server; niet de " "verbinding van je IRC client naar ZNC." #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "Server wurging:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" "De minimale tijd tussen twee verbindingspogingen naar de zelfde hostname, in " "seconden. Sommige servers weigeren de verbinding als je te snel verbind." #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "Anonieme verbindingslimiet per IP-adres:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "Limiteert het aantal niet geïdentificeerde verbinding per IP." #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "Bescherm web sessies:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "Sta IP-adres wijzigingen niet toe tijdens een websessie" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "Verberg ZNC versie:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "Verbergt het versie nummer voor non-ZNC gebruikers" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "Sta gebruikers toe alleen te authenticeren via externe modules" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "MOTD:" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "" "Bericht van de dag, wordt gestuurd naar alle gebruikers als ze verbinden." #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "Algemene modulen" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "Geladen door gebruikers" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "Informatie" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "Uptime" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "Total aantal gebruikers" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "Totaal aantal netwerken" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "Aangekoppelde netwerken" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "Totaal aantal client verbindingen" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "Totaal aantal IRC verbindingen" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "Client verbindingen" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "IRC Verbindingen" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "Totaal" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "In" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "Uit" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "Gebruikers" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "Verkeer" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "Gebruiker" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "Netwerk" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "Algemene instellingen" #: webadmin.cpp:93 msgid "Your Settings" msgstr "Jouw instellingen" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "Verkeer informatie" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "Beheer gebruikers" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "Ongeldige inzending [Gebruikersnaam is verplicht]" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "Ongeldige inzending [Wachtwoord komt niet overeen]" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "Time-out mag niet minder zijn dan 30 seconden!" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "Niet mogelijk module te laden [{1}]: {2}" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "Niet mogelijk module te laden [{1}] met argumenten [{2}]" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "Gebruiker onbekend" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "Gebruiker of netwerk onbekend" #: webadmin.cpp:576 msgid "No such channel" msgstr "Kanaal onbekend" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "Verwijder jezelf alsjeblieft niet, zelfmoord is niet het antwoord!" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "Bewerk gebruiker [{1}]" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "Bewerk netwerk [{1}]" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "Bewerk kanaal [{1}] van netwerk [{2}] van gebruiker [{3}]" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "Bewerk kanaal [{1}]" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "Voeg kanaal aan netwerk [{1}] van gebruiker [{2}]" #: webadmin.cpp:749 msgid "Add Channel" msgstr "Voeg kanaal toe" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "Automatisch kanaalbuffer legen" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "Leegt automatisch de kanaalbuffer na het afspelen" #: webadmin.cpp:766 msgid "Detached" msgstr "Losgekoppeld" #: webadmin.cpp:773 msgid "Enabled" msgstr "Ingeschakeld" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "Kanaalnaam is een vereist argument" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "Kanaal [{1}] bestaat al" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "Kon kanaal [{1}] niet toevoegen" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "Kanaal was toegevoegd/aangepast maar configuratie was niet opgeslagen" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" "Limiet van aantal netwerken bereikt. Vraag een beheerder om deze limit aan " "te passen voor je, of verwijder onnodige netwerken van Jouw instellingen." #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "Pas netwerk [{1}] van gebruiker [{2}] aan" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "Voeg netwerk toe voor gebruiker [{1}]" #: webadmin.cpp:911 msgid "Add Network" msgstr "Voeg netwerk toe" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "Netwerknaam is een vereist argument" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "Niet mogelijk module te herladen [{1}]: {2}" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "Netwerk was toegevoegd/aangepast maar configuratie was niet opgeslagen" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "Dat netwerk bestaat niet voor deze gebruiker" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "Netwerk was verwijderd maar configuratie was niet opgeslagen" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "Dat kanaal bestaat niet voor dit netwerk" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "Kanaal was verwijderd maar configuratie was niet opgeslagen" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "Kloon gebruiker [{1}]" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" "Leeg kanaal buffer automatisch na afspelen (standaard waarde voor nieuwe " "kanalen)" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "Meerdere clients" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "Tijdstempel toevoegen" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "Tijdstempel voorvoegen" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "Sta LoadMod niet toe" #: webadmin.cpp:1551 msgid "Admin" msgstr "Beheerder" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "Sta SetBindHost niet toe" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "Automatisch privéberichtbuffer legen" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "Leegt automatisch de privéberichtbuffer na het afspelen" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "Ongeldige inzending: Gebruiker {1} bestaat al" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "Ongeldige inzending: {1}" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "Gebruiker was toegevoegd maar configuratie was niet opgeslagen" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "Gebruiker was aangepast maar configuratie was niet opgeslagen" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "Kies IPv4 of IPv6 of beide." #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "Kies IRC of HTTP of beide." #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "Poort was aangepast maar configuratie was niet opgeslagen" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "Ongeldig verzoek." #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "De opgegeven luisteraar was niet gevonden." #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "Instellingen waren aangepast maar configuratie was niet opgeslagen" znc-1.7.5/modules/po/blockuser.bg_BG.po0000644000175000017500000000347013542151610020122 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/blockuser.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "" #: blockuser.cpp:29 msgid "List blocked users" msgstr "" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "" #: blockuser.cpp:76 msgid "Access denied" msgstr "" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "" #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "" #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "" #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "" znc-1.7.5/modules/po/q.bg_BG.po0000644000175000017500000001303713542151610016371 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/q.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" #: q.cpp:111 msgid "The following commands are available:" msgstr "" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "" #: q.cpp:116 msgid "Auth [ ]" msgstr "" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "" #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" #: q.cpp:128 msgid "Prints the current status of the module." msgstr "" #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "" #: q.cpp:135 msgid "Set " msgstr "" #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" #: q.cpp:146 msgid "The following settings are available:" msgstr "" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "" #: q.cpp:154 msgid "Your Q username." msgstr "" #: q.cpp:158 msgid "Your Q password." msgstr "" #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "" #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "" #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "" #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "" #: q.cpp:200 msgid "Syntax: Set " msgstr "" #: q.cpp:203 msgid "Username set" msgstr "" #: q.cpp:206 msgid "Password set" msgstr "" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "" #: q.cpp:212 msgid "UseChallenge set" msgstr "" #: q.cpp:215 msgid "RequestPerms set" msgstr "" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "" #: q.cpp:253 msgid "Connected: yes" msgstr "" #: q.cpp:254 msgid "Connected: no" msgstr "" #: q.cpp:255 msgid "Cloacked: yes" msgstr "" #: q.cpp:255 msgid "Cloacked: no" msgstr "" #: q.cpp:256 msgid "Authenticated: yes" msgstr "" #: q.cpp:257 msgid "Authenticated: no" msgstr "" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "" #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "" #: q.cpp:280 msgid "Update requested." msgstr "" #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "" #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "" #: q.cpp:408 msgid "Changes have been saved!" msgstr "" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "" #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "" #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "" #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "" #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "" znc-1.7.5/modules/po/block_motd.es_ES.po0000644000175000017500000000206313542151610020301 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/block_motd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: block_motd.cpp:26 msgid "[]" msgstr "[]" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" "Sobreescribe el bloqueo con este comando. Puedes, opcionalmente, especificar " "el servidor a consultar." #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "No estás conectado a un servidor de IRC." #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "MOTD bloqueado por ZNC" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "Bloquea el MOTD del IRC para que no se envíe a tu cliente." znc-1.7.5/modules/po/perform.pt_BR.po0000644000175000017500000000400313542151610017642 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/perform.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "" #: perform.cpp:24 msgid "Usage: add " msgstr "" #: perform.cpp:29 msgid "Added!" msgstr "" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "" #: perform.cpp:41 msgid "Command Erased." msgstr "" #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "" #: perform.cpp:73 msgid "perform commands sent" msgstr "" #: perform.cpp:86 msgid "Commands Swapped." msgstr "" #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "" #: perform.cpp:100 msgid "List the perform commands" msgstr "" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "" #: perform.cpp:105 msgid " " msgstr "" #: perform.cpp:106 msgid "Swap two perform commands" msgstr "" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "" znc-1.7.5/modules/po/kickrejoin.pot0000644000175000017500000000175213542151610017507 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: kickrejoin.cpp:56 msgid "" msgstr "" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "" msgstr[1] "" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "" msgstr[1] "" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "" #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "" znc-1.7.5/modules/po/webadmin.fr_FR.po0000644000175000017500000012505413542151610017760 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/webadmin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "Information du salon" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "Nom du salon :" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "Le nom du salon." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "Clé :" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "Le mot de passe du salon, si nécessaire." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "Taille du tampon :" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "La taille du tampon." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "Modes par défaut :" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "Les modes par défaut du salon." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "Marqueurs" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "Sauvegarder la configuration" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "Module {1}" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "Sauvegarder et revenir" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "Sauvegarder et continuer" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "Ajouter le salon et revenir" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "Ajouter le salon et continuer" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "<mot de passe>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "<réseau>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" "Pour vous connecter à ce réseau avec votre client IRC, vous pouvez définir " "le mot de passe du serveur comme {1} ou l'identifiant comme " "{2}" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "Information du réseau" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" "Pseudonyme, Pseudonyme Alternatif, Identité, Vrai nom et Hôte lié peuvent " "être laissés vide pour utiliser la valeur par défaut." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "Nom du réseau :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "Le nom du réseau IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "Pseudonyme :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "Votre pseudonyme sur IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "Pseudonyme alternatif :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "" "Votre pseudonyme secondaire, si le premier n'est pas disponible sur IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "Identité :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "Votre identité." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "Nom réel :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "Votre vrai nom." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "Hôte :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "Message de départ :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "" "Vous pouvez définir un message qui sera affiché lorsque vous quittez IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "Actif :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "Se connecter à IRC & se reconnecter automatiquement" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "Avoir confiance en tous les certificats :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "" "Désactiver la validation des certificats (prioritaire devant TrustPKI). NON " "SÉCURISÉ !" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "Approuver le PKI :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" "Configurer ce paramètre à faux n'autorisera que les certificats dont vous " "avez ajouté les empreintes." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "Serveurs de ce réseau IRC :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "" "Un serveur par ligne, \"hôte [[+]port] [mot de passe]\", + signifie SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "Nom d'hôte" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "Port" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "Mot de passe" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "Empreintes SHA-256 des certificats SSL de confiance pour ce réseau :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" "Lorsque ces certificats sont reçus, les vérifications pour le nom d'hôte, la " "date d'expiration et l'autorité de certification sont ignorées" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "Protection contre le spam :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" "Vous pouvez activer la protection contre le spam. Cela permet d'éviter les " "erreurs d'excès de message, qui apparaissent lorsque votre bot IRC est " "spammé ou reçoit trop de message. Reconnectez ZNC au serveur après avoir " "modifié ce paramètre." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "Activé" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "Protection contre le spam :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" "Nombre de secondes par ligne. Reconnectez ZNC au serveur après avoir changé " "ce paramètre." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "{1} secondes par ligne" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "Protection instantanée contre le spam :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" "Définit le nombre de lignes pouvant être envoyées immédiatement. Reconnectez " "ZNC au serveur après avoir changé ce paramètre." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "{1} lignes peuvent être envoyées immédiatement" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "Délai de connexion à un salon :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" "Définit le délai (en secondes) entre la connexion à un serveur et la " "connexion aux salons." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "{1} secondes" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "Encodage de caractères utilisé entre ZNC et le serveur IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "Encodage du serveur :" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "Salons" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "" "Vous pourrez ajouter ou modifier des salons ici après avoir créé le réseau." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "Ajouter" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "Sauvegarder" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "Nom" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "CurModes" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "DefModes" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "Taille du tampon" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "Paramètres" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "↠Ajouter un salon (s'ouvre dans la même page)" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "Modifier" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "Supprimer" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "Modules" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "Arguments" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "Description" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "Chargé globalement" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "Chargé par l'utilisateur" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "Ajouter le réseau et revenir" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "Ajouter le réseau et continuer" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "Autentification" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "Identifiant :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "Veuillez saisir un identifiant." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "Mot de passe :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "Veuillez saisir un mot de passe." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "Veuillez confirmer le mot de passe :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "Veuillez saisir à nouveau le mot de passe." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "Authentification seulement par module :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" "N'autorise l'authentification des utilisateurs que par des modules externes, " "en désactivant l'authentification par mot de passe intégrée." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "Adresses IP autorisées :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" "Laisser vide pour autoriser des connexions de n'importe quel IP.
Autremement, une IP par ligne, les jokers * et ? sont autorisés." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "Information IRC" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" "Pseudonyme, Pseudonyme Alternatif, Vrai nom et Message de départ peuvent " "être laissés vide pour utiliser la valeur par défaut." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "L'Identité est envoyée au serveur comme identifiant." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "Préfix du statut :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "Le préfixe pour les requêtes de statut et de modules." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "DCCBindHost:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "Réseaux" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "Clients" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "Serveur actuel" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "Pseudo" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "↠Ajouter un réseau (s'ouvre dans la même page)" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "" "Vous pourrez ajouter ou modifier des réseaux ici après avoir cloné " "l'utilisateur." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "" "Vous pourrez ajouter ou modifier des réseaux ici après avoir créé " "l'utilisateur." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "Chargé par les réseaux" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" "Ces paramètres sont les modes par défaut utilisés par ZNC lorsque vous " "rejoignez un salon vide." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "Vide = utilise la valeur par défaut" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Ce paramètre contrôle le nombre de lignes que le tampon stocke pour les " "salons avant de supprimer les plus anciennes. Les tampons sont stockés en " "mémoire par défaut." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "Sessions privées" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "Nombre max de tampons :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "" "Nombre maximal de tampons de sessions privées. 0 correspond à aucune limite." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Ce paramètre contrôle le nombre de lignes que le tampon stocke pour les " "messages privés avant de supprimer les plus anciennes. Les tampons sont " "stockés en mémoire par défaut." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "Comportement de ZNC" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" "Tous les paramètres suivants peuvent être laissés vide pour utiliser la " "valeur par défaut." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "Format d'horodatage :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" "Le format d'horodatage utilisé dans les tampons, par exemple [%H:%M:%S]. Ce " "paramètre est ignoré dans les clients IRC récents, qui utilisent l'heure du " "serveur. Si votre client utilise l'heure du serveur, modifiez ce paramètre " "sur votre client." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "Fuseau horaire :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "Par exemple, Europe/Paris ou GMT-6" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "Encodage de caractères utilisé entre le client IRC et ZNC." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "Encodage du client :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "Nombre d'essais pour rejoindre :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" "Ce paramètre définit combien de fois ZNC tente de rejoindre un salon après " "un échec, par exemple si vous êtes banni ou si le salon est en mode +i/+k." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "Vitesse d'ajout :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" "Combien de salons sont rejoints en une seule commande JOIN. 0 est illimité " "(par défaut). Configurez ce paramètre sur une petite valeur si vous êtes " "déconnecté avec le message \"Max SendQ Exceeded\"" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "Délai avant reconnexion :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" "Délai (en secondes) d'absence de communication avec le réseau avant que ZNC " "ne déclare la connexion expirée. Ceci se déclenche après les tests de ping " "des pairs." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "Nombre maximal de réseaux IRC :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "Nombre maximal de réseaux IRC autorisés pour cet utilisateur." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "Substitutions" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "Réponses CTCP :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "" "Une réponse par ligne. Par exemple : TIME Achète une montre !" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "{1} sont disponibles" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "Une valeur vide signifie que cette requête CTCP sera ignorée" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "Requête" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "Réponse" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "Thème :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "- Global -" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "Défaut" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "Pas d'autre thème trouvé" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "Langue :" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "Dupliquer et revenir" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "Dupliquer et continuer" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "Créer et revenir" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "Créer et continuer" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "Dupliquer" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "Créer" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "Confirmer la suppression du réseau" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "" "Êtes-vous sûr de vouloir supprimer le réseau \"{2}\" de l'utilisateur " "\"{1}\" ?" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "Oui" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "Non" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "Confirmez la suppression de l'utilisateur" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "Êtes-vous sûr de vouloir supprimer l'utilisateur \"{1}\" ?" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "ZNC est compilé sans le support des encodages. {1} est requis." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "Le mode \"obsolète\" est désactivé par modpython." #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "Ne vérifier aucun encodage (mode obsolète, non recommandé)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "" "Essayer de décoder comme UTF-8 et {1}, envoyer comme UTF-8 (recommandé)" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "Essayer de décoder comme UTF-8 et {1}, envoyer comme {1}" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "Décoder et envoyer comme {1} seulement" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "Par exemple, UTF-8 ou ISO-8859-15" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "Bienvenue sur le module d'administration web de ZNC." #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "" "Tous les changements que vous allez effectuer seront pris en compte " "immédiatement après votre validation." #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "Identifiant" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "Supprimer" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "Port(s) d'écoute" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "Hôte" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "IPv4" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "IPv6" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "IRC" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "HTTP" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "URIPrefix" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" "Pour supprimer le port via lequel vous accéder à l'administration web, " "connectez-vous à l'interface via un autre port ou passez par IRC (/znc " "DelPort)" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "Actuel" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "Paramètres" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "Défaut pour les nouveaux utilisateurs." #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "Taille maximale du tampon :" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "" "Configure globalement la taille maximale du tampon pour les utilisateurs." #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "Délai avant connexion :" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" "Le délai (en secondes) entre deux tentatives successives de connexion à un " "serveur IRC. Cela affecte la connexion entre ZNC et le serveur, pas la " "connexion entre votre client et ZNC." #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "Limite du serveur :" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" "Le temps minimal (en secondes) entre deux tentatives de connexion avec le " "même nom d'hôte. Certains serveurs refusent votre connexion si vous " "réessayez trop rapidement." #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "Nombre limite de connexions anonymes par IP :" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "Limite le nombre de connexions non-identifiées par IP." #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "Protéger les sessions web :" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "Interdit le changement d'IP pendant une session web" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "Cacher la version de ZNC :" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "Dissimule la version de ZNC aux anonymes" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "" "Autorise l'authentification des utilisateurs par les modules externes " "seulement" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "Message du jour :" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "" "\"Message du jour\", envoyé à tous les utilisateurs de ZNC à la connexion." #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "Module globaux" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "Chargé par les utilisateurs" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "Information" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "En service" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "Nombre total d'utilisateurs" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "Nombre total de réseaux" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "Réseaux attachés" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "Nombre total de connexions des clients" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "Nombre total de connexions IRC" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "Connexions du client" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "Connexions IRC" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "Total" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "Entrée" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "Sortie" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "Utilisateurs" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "Trafic" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "Utilisateur" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "Réseau" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "Paramètres globaux" #: webadmin.cpp:93 msgid "Your Settings" msgstr "Vos paramètres" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "Informations sur le trafic" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "Gérer les utilisateurs" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "Soumission invalide [l'identifiant est nécessaire]" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "Soumission invalide [les mots de passe ne correspondent pas]" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "Le délai d'expiration ne peut être inférieur à 30 secondes !" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "Impossible de charger le module [{1}] : {2}" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "Impossible de charger le module [{1}] avec les arguments [{2}]" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "Utilisateur inconnu" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "Utilisateur ou réseau inconnu" #: webadmin.cpp:576 msgid "No such channel" msgstr "Salon inconnu" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "Veuillez ne pas vous supprimer, le suicide n'est pas la solution !" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "Modifier l'utilisateur [{1}]" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "Modifier le réseau [{1}]" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "Modifier le salon [{1}] du réseau [{2}] de l'utilisateur [{3}]" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "Modifier le salon [{1}]" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "Ajouter un salon au réseau [{1}] de l'utilisateur [{2}]" #: webadmin.cpp:749 msgid "Add Channel" msgstr "Ajouter un salon" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "Vider automatiquement le tampon des salons" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "Vider automatiquement le tampon des salons après l'avoir rejoué" #: webadmin.cpp:766 msgid "Detached" msgstr "Détaché" #: webadmin.cpp:773 msgid "Enabled" msgstr "Activé" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "Le nom du salon est un argument requis" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "Le salon [{1}] existe déjà" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "Impossible d'ajouter le salon [{1}]" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "" "Le salon a été ajouté ou modifié, mais la configuration n'a pas pu être " "sauvegardée" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" "Le nombre maximal de réseaux a été atteint. Demandez à un administrateur " "d'augmenter cette limite pour vous ou bien supprimez des réseaux obsolètes " "de vos paramètres." #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "Modifier le réseau [{1}] de l'utilisateur [{2}]" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "Ajouter un réseau pour l'utilisateur [{1}]" #: webadmin.cpp:911 msgid "Add Network" msgstr "Ajouter un réseau" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "Le nom du réseau est un argument requis" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "Impossible de recharger le module [{1}] : {2}" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "" "Le réseau a été ajouté ou modifié, mais la configuration n'a pas pu être " "sauvegardée" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "Le réseau n'existe pas pour cet utilisateur" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "" "Le réseau a été supprimé, mais la configuration n'a pas pu être sauvegardée" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "Le salon n'existe pas pour ce réseau" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "" "Le salon a été supprimé, mais la configuration n'a pas pu être sauvegardée" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "Dupliquer l'utilisateur [{1}]" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" "Vider automatiquement le tampon des salons après l'avoir rejoué (valeur par " "défaut pour les nouveaux salons)" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "Multi Clients" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "Ajouter un horodatage après" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "Ajouter un horodatage avant" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "Interdire LoadMod" #: webadmin.cpp:1551 msgid "Admin" msgstr "Admin" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "Interdire SetBindHost" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "Vider automatiquement le tampon des messages privés" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "" "Vider automatiquement le tampon des messages privés après l'avoir rejoué" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "Requête invalide : l'utilisateur {1} existe déjà" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "Requête invalide : {1}" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "" "L'utilisateur a été ajouté, mais la configuration n'a pas pu être sauvegardée" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "" "L'utilisateur a été modifié, mais la configuration n'a pas pu être " "sauvegardée" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "Choisissez IPv4 ou IPv6 (ou les deux)." #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "Choisissez IRC ou HTTP (ou les deux)." #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "" "Le port a été modifié, mais la configuration n'a pas pu être sauvegardée" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "Requête non valide." #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "Le canal d'écoute spécifié est introuvable." #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "" "Les paramètres ont été changés, mais la configuration n'a pas pu être " "sauvegardée" znc-1.7.5/modules/po/savebuff.ru_RU.po0000644000175000017500000000275713542151610020035 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/savebuff.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "" znc-1.7.5/modules/po/imapauth.de_DE.po0000644000175000017500000000121613542151610017735 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/imapauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "[ Server [+]Port [UserFormatString] ]" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "Erlaube es Benutzern sich via IMAP zu authentifizieren." znc-1.7.5/modules/po/imapauth.nl_NL.po0000644000175000017500000000122013542151610017772 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/imapauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "[ server [+]poort [ UserFormatString ] ]" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "Stelt gebruikers in staat om te identificeren via IMAP." znc-1.7.5/modules/po/raw.es_ES.po0000644000175000017500000000076213542151610016761 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "Ver todo el tráfico sin formato" znc-1.7.5/modules/po/log.de_DE.po0000644000175000017500000000712713542151610016715 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/log.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "Setze Logging-Regeln, !#chan oder !query zum Negieren und * " #: log.cpp:62 msgid "Clear all logging rules" msgstr "Alle Regeln löschen" #: log.cpp:64 msgid "List all logging rules" msgstr "Alle Regeln auflisten" #: log.cpp:67 msgid " true|false" msgstr " true|false" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "Setze eine der folgenden Optionen: joins, quits, nickchanges" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "Aktuelle Einstellungen durch \"set\"-Kommando anzeigen" #: log.cpp:143 msgid "Usage: SetRules " msgstr "Benutzung: SetRules " #: log.cpp:144 msgid "Wildcards are allowed" msgstr "Wildcards können verwendet werden" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "Keine Logging-Regeln - alles wird geloggt." #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "" msgstr[1] "{1} Regeln entfernt: {2}" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "Regel" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "Logging aktiviert" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "" "Benutzung: Set true|false, wobei entweder joins, quits oder " "nickchanges ist" #: log.cpp:196 msgid "Will log joins" msgstr "Joins werden geloggt" #: log.cpp:196 msgid "Will not log joins" msgstr "Joins werden nicht geloggt" #: log.cpp:197 msgid "Will log quits" msgstr "Quits werden geloggt" #: log.cpp:197 msgid "Will not log quits" msgstr "Quits werden nicht geloggt" #: log.cpp:199 msgid "Will log nick changes" msgstr "Nick-Wechsel werden geloggt" #: log.cpp:199 msgid "Will not log nick changes" msgstr "Nick-Wechsel werden nicht geloggt" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "Unbekannte Variable. Gültig sind: joins, quits, nickchanges" #: log.cpp:211 msgid "Logging joins" msgstr "Joins werden geloggt" #: log.cpp:211 msgid "Not logging joins" msgstr "Joins werden nicht geloggt" #: log.cpp:212 msgid "Logging quits" msgstr "Quits werden geloggt" #: log.cpp:212 msgid "Not logging quits" msgstr "Quits werden nicht geloggt" #: log.cpp:213 msgid "Logging nick changes" msgstr "Nick-Wechsel werden geloggt" #: log.cpp:214 msgid "Not logging nick changes" msgstr "Nick-Wechsel werden nicht geloggt" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" "Ungültige Argumente [{1}]. Nur ein Logging-Pfad ist erlaubt. Prüfe, dass der " "Pfad keine Leerzeichen enthält." #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "Ungültiger Log-Pfad [{1}]" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "Logge nach [{1}] mit Zeitstempelformat '{2}'" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "[-sanitize] Optionaler Pfad zum Speichern von Logs." #: log.cpp:563 msgid "Writes IRC logs." msgstr "Schreibt IRC-Logs." znc-1.7.5/modules/po/crypt.nl_NL.po0000644000175000017500000000734113542151610017335 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/crypt.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "<#kanaal|Naam>" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "Verwijder een sleutel voor een naam of kanaal" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "<#kanaal|Naam> " #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "Stel een sleutel in voor naam of kanaal" #: crypt.cpp:204 msgid "List all keys" msgstr "Laat alle sleutels zien" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "Begint een DH1080 sleutel uitwisseling met naam" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "Laat het voorvoegsel van de naam zien" #: crypt.cpp:213 msgid "[Prefix]" msgstr "[Voorvoegsel]" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "" "Stel het voorvoegsel voor de naam in, zonder argumenten zal deze " "uitgeschakeld worden." #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "DH1080 publieke sleutel ontvangen van {1}, nu mijne sturen..." #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "Sleutel voor {1} ingesteld." #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "Fout in {1} met {2}: {3}" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "Geen geheime sleutel berekend" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "Doel [{1}] verwijderd" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "Doel [{1}] niet gevonden" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "Gebruik: DelKey <#kanaal|Naam>" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "Sleutel voor versleuteling ingesteld voor [{1}] op [{2}]" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "Gebruik: SetKey <#kanaal|Naam> " #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "" "Mijn DH1080 publieke sleutel verzonden naar {1}, wachten op antwoord ..." #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "Fout tijdens genereren van onze sleutels, niets verstuurd." #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "Gebruik: KeyX " #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "Naam voorvoegsel uit gezet." #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "Naam voorvoegsel: {1}" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" "Je kan : niet gebruiken, ook niet als hierna nog extra symbolen komen, als " "Naam voorvoegsel." #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" "Overlap met Status voorvoegsel ({1}), deze Naam voorvoegsel zal niet worden " "gebruikt!" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "Naam voorvoegsel aan het uitzetten." #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "Naam voorvoegsel naar {1} aan het zetten" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "Doel" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "Sleutel" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "Je hebt geen versleutel sleutels ingesteld." #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "Versleuteling voor kanaal/privé berichten" znc-1.7.5/modules/po/missingmotd.bg_BG.po0000644000175000017500000000075213542151610020466 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/missingmotd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "" znc-1.7.5/modules/po/blockuser.pt_BR.po0000644000175000017500000000350713542151610020171 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/blockuser.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "" #: blockuser.cpp:29 msgid "List blocked users" msgstr "" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "" #: blockuser.cpp:76 msgid "Access denied" msgstr "" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "" #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "" #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "" #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "" znc-1.7.5/modules/po/bouncedcc.de_DE.po0000644000175000017500000000641413542151610020057 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/bouncedcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "Typ" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "Status" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "Geschwindigkeit" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "Nickname" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "IP" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "Datei" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "Chat" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "Xfer" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "Bitte warten" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "Fast geschafft" #: bouncedcc.cpp:129 msgid "Connected" msgstr "Verbunden" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "Du hast keine aktiven DCCs." #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "Benutze Client-IP: {1}" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "Liste alle aktiven DCCs auf" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "Ändere die Option, um die Client-IP zu nutzen" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "Chat" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "Xfer" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "DCC {1} Bounce ({2}): Empfangene Zeile ist zu lang" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "DCC {1} Bounce ({2}): Zeitüberschreitung beim Verbinden mit {3} {4}" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "DCC {1} Bounce ({2}): Zeitüberschreitung beim Verbindungsaufbau." #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" "DCC {1} Bounce ({2}): Zeitüberschreitung beim Warten auf eingehende " "Verbindung von {3} {4}" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "DCC {1} Bounce ({2}): Verbindungsversuch zu {3} {4} zurückgewiesen" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "DCC {1} Bounce ({2}): Verbindungsversuch abgewiesen." #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "DCC {1} Bounce ({2}): Socketfehler bei {3} {4}: {5}" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "DCC {1} Bounce ({2}): Sockefehler: {3}" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" "Leitet DCC-Übertragungen durch ZNC, anstatt sie direkt zum Benutzer zu " "schicken. " znc-1.7.5/modules/po/fail2ban.pt_BR.po0000644000175000017500000000433113542151610017652 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/fail2ban.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "" #: fail2ban.cpp:28 msgid "[count]" msgstr "" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "" #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "" #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "" #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "" #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "" #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "" #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "" znc-1.7.5/modules/po/chansaver.ru_RU.po0000644000175000017500000000123113542151610020170 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/chansaver.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "" znc-1.7.5/modules/po/raw.id_ID.po0000644000175000017500000000071313542151610016727 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "" znc-1.7.5/modules/po/notes.nl_NL.po0000644000175000017500000000577513542151610017335 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/notes.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "Voeg een notitie toe" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "Sleutel:" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "Notitie:" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "Voeg notitie toe" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "Je hebt geen notities om weer te geven." #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "Sleutel" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "Notitie" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "[delete]" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "" "Die notitie bestaat al. Gebruik MOD om te overschrijven." #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "Notitie toegevoegd: {1}" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "Niet mogelijk om notitie toe te voegen: {1}" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "Notitie ingesteld voor {1}" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "Deze notitie bestaat niet." #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "Notitie verwijderd: {1}" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "Kon notitie niet verwijderen: {1}" #: notes.cpp:75 msgid "List notes" msgstr "Lijst van notities" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr " " #: notes.cpp:77 msgid "Add a note" msgstr "Voeg een notitie toe" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "Verwijder een notitie" #: notes.cpp:81 msgid "Modify a note" msgstr "Pas een notitie aan" #: notes.cpp:94 msgid "Notes" msgstr "Notities" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "" "Die notitie bestaat al. Gebruik /#+ om te overschrijven." #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "Je hebt geen notities." #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" "Deze gebruikersmodule accepteert maximaal 1 argument. Dit kan -" "disableNotesOnLogin zodat notities niet worden laten zien wanneer een " "gebruiker inlogd" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "Hou en speel notities opnieuw af" znc-1.7.5/modules/po/lastseen.bg_BG.po0000644000175000017500000000261113542151610017743 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/lastseen.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "" #: lastseen.cpp:53 msgid "Access denied" msgstr "" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "" znc-1.7.5/modules/po/notes.es_ES.po0000644000175000017500000000555713542151610017327 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/notes.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/notes/tmpl/index.tmpl:7 msgid "Add A Note" msgstr "Añadir nota" #: modules/po/../data/notes/tmpl/index.tmpl:11 msgid "Key:" msgstr "Clave:" #: modules/po/../data/notes/tmpl/index.tmpl:15 msgid "Note:" msgstr "Nota:" #: modules/po/../data/notes/tmpl/index.tmpl:19 msgid "Add Note" msgstr "Añadir nota" #: modules/po/../data/notes/tmpl/index.tmpl:27 msgid "You have no notes to display." msgstr "No tienes notas para mostrar." #: modules/po/../data/notes/tmpl/index.tmpl:34 notes.cpp:164 notes.cpp:169 msgid "Key" msgstr "Clave" #: modules/po/../data/notes/tmpl/index.tmpl:35 notes.cpp:165 notes.cpp:170 msgid "Note" msgstr "Nota" #: modules/po/../data/notes/tmpl/index.tmpl:41 msgid "[del]" msgstr "[del]" #: notes.cpp:32 msgid "That note already exists. Use MOD to overwrite." msgstr "Esta nota ya existe. Utiliza MOD para sobreescribirla." #: notes.cpp:35 notes.cpp:137 msgid "Added note {1}" msgstr "Añadida nota {1}" #: notes.cpp:37 notes.cpp:48 notes.cpp:142 msgid "Unable to add note {1}" msgstr "No se ha podido añadir la nota {1}" #: notes.cpp:46 notes.cpp:139 msgid "Set note for {1}" msgstr "Establecida nota {1}" #: notes.cpp:56 msgid "This note doesn't exist." msgstr "Esta nota no existe." #: notes.cpp:66 notes.cpp:116 msgid "Deleted note {1}" msgstr "Borrada nota {1}" #: notes.cpp:68 notes.cpp:118 msgid "Unable to delete note {1}" msgstr "No se ha podido eliminar la nota {1}" #: notes.cpp:75 msgid "List notes" msgstr "Mostrar notas" #: notes.cpp:77 notes.cpp:81 msgid " " msgstr " " #: notes.cpp:77 msgid "Add a note" msgstr "Añadir nota" #: notes.cpp:79 notes.cpp:83 msgid "" msgstr "" #: notes.cpp:79 msgid "Delete a note" msgstr "Eliminar nota" #: notes.cpp:81 msgid "Modify a note" msgstr "Modificar nota" #: notes.cpp:94 msgid "Notes" msgstr "Notas" #: notes.cpp:133 msgid "That note already exists. Use /#+ to overwrite." msgstr "Esta nota ya existe. Utiliza /#+ para sobreescribirla." #: notes.cpp:185 notes.cpp:187 msgid "You have no entries." msgstr "No tienes entradas." #: notes.cpp:223 msgid "" "This user module takes up to one arguments. It can be -disableNotesOnLogin " "not to show notes upon client login" msgstr "" "Este módulo de usuario puede tener un argumento. Puede ser -" "disableNotesOnLogin para no mostrar las notas hasta que el cliente conecta" #: notes.cpp:227 msgid "Keep and replay notes" msgstr "Guardar y reproducir notas" znc-1.7.5/modules/po/autoop.pt_BR.po0000644000175000017500000001132013542151610017477 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/autoop.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: autoop.cpp:154 msgid "List all users" msgstr "Lista todos os usuários" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr " [channel] ..." #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "Adiciona canais a um usuário" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "Remove canais de um usuário" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr " ,[mask] ..." #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "Adiciona uma máscara a um usuário" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "Remove máscaras de um usuário" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr " [,...] [channels]" #: autoop.cpp:170 msgid "Adds a user" msgstr "Adiciona um usuário" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "Remove um usuário" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "Uso: AddUser [,...] [channels]" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "Uso: DelUser " #: autoop.cpp:300 msgid "There are no users defined" msgstr "Não há usuários definidos" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "Usuário" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "Máscaras de Host" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "Chave" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "Canais" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "Uso: AddChans [channel] ..." #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "Nenhum usuário encontrado" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "Canal(ais) adicionado(s) ao usuário {1}" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "Uso: DelChans [channel] ..." #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "Canal(ais) removido(s) do usuário {1}" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "Uso: AddMasks ,[mask] ..." #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "Máscara(s) de host adicionada(s) ao usuário {1}" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "Uso: DelMasks ,[mask] ..." #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "Usuário {1} com chave {2} e {3} canais foi removido" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "Máscara(s) de host removida(s) do usuário {1}" #: autoop.cpp:478 msgid "User {1} removed" msgstr "Usuário {1} removido" #: autoop.cpp:484 msgid "That user already exists" msgstr "Esse usuário já existe" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "Usuário {1} adicionado com a(s) máscara(s) de host {2}" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "" "[{1}] enviou um desafio, mas não possui status de operador em qualquer canal " "definido." #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "" "[{1}] enviou um desafio, mas não corresponde a qualquer usuário definido." #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "AVISO! [{1}] enviou um desafio inválido." #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "" "[{1}] enviou uma resposta sem desafio. Isso pode ocorrer devido a um lag." #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" "AVISO! [{1}] enviou uma má resposta. Por favor, verifique se você tem a " "senha correta." #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "" "WARNING! [{1}] enviou uma resposta mas não corresponde a qualquer usuário " "definido." #: autoop.cpp:644 msgid "Auto op the good people" msgstr "Automaticamente torna operador as pessoas boas" znc-1.7.5/modules/po/clearbufferonmsg.es_ES.po0000644000175000017500000000114513542151610021510 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/clearbufferonmsg.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "" "Borra todos los búfers de canales y privados cuando el usuario envía algo" znc-1.7.5/modules/po/chansaver.es_ES.po0000644000175000017500000000110613542151610020133 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/chansaver.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "" "Guarda una configuración actualizada del canal cuando un usuario entra o " "sale." znc-1.7.5/modules/po/autocycle.nl_NL.po0000644000175000017500000000355113542151610020163 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/autocycle.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "[!]<#kanaal>" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" "Voeg een kanaal toe, gebruik !#kanaal om te verwijderen en gebruik * voor " "jokers" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "Verwijder een kanaal, moet een exacte overeenkomst zijn" #: autocycle.cpp:33 msgid "List all entries" msgstr "Laat alle kanalen zien" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "Kan {1} niet toevoegen" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "{1} bestaat al" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "{1} toegevoegd aan lijst" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "Gebruik: Add [!]<#kanaal>" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "{1} verwijderd van lijst" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "Gebruik: Del [!]<#kanaal>" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "Kanaal" #: autocycle.cpp:100 msgid "You have no entries." msgstr "Je hebt geen kanalen toegvoegd." #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "Lijst van kanaal maskers en kanaal maskers met ! er voor." #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" "Verbind opnieuw met een kanaal om beheer te krijgen als je de enige " "gebruiker nog bent" znc-1.7.5/modules/po/sasl.fr_FR.po0000644000175000017500000000652313542151610017133 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/sasl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" #: sasl.cpp:62 msgid "search" msgstr "" #: sasl.cpp:62 msgid "Generate this output" msgstr "" #: sasl.cpp:64 msgid "[ []]" msgstr "" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "" #: sasl.cpp:72 msgid "[yes|no]" msgstr "" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "" #: sasl.cpp:114 msgid "Password was supplied" msgstr "" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "" #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "" #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "" #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "" #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "" znc-1.7.5/modules/po/crypt.fr_FR.po0000644000175000017500000000504413542151610017327 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/crypt.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "" #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "" #: crypt.cpp:204 msgid "List all keys" msgstr "" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "" #: crypt.cpp:213 msgid "[Prefix]" msgstr "" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "" #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "" #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "" #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "" #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "" #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "" #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "" #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "" #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "" #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "" #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "" znc-1.7.5/modules/po/autocycle.fr_FR.po0000644000175000017500000000352213542151610020155 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/autocycle.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: autocycle.cpp:27 autocycle.cpp:30 msgid "[!]<#chan>" msgstr "[!]<#salon>" #: autocycle.cpp:28 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "Ajoute une entrée, utilisez !#salon pour inverser et * comme joker" #: autocycle.cpp:31 msgid "Remove an entry, needs to be an exact match" msgstr "Retire une entrée, requiert une correspondance exacte" #: autocycle.cpp:33 msgid "List all entries" msgstr "Liste toutes les entrées" #: autocycle.cpp:46 msgid "Unable to add {1}" msgstr "Impossible d'ajouter {1}" #: autocycle.cpp:66 msgid "{1} is already added" msgstr "{1} est déjà présent" #: autocycle.cpp:68 msgid "Added {1} to list" msgstr "{1} ajouté à la liste" #: autocycle.cpp:70 msgid "Usage: Add [!]<#chan>" msgstr "Usage: Add [!]<#salon>" #: autocycle.cpp:78 msgid "Removed {1} from list" msgstr "{1} retiré de la liste" #: autocycle.cpp:80 msgid "Usage: Del [!]<#chan>" msgstr "Usage: Del[!]<#salon>" #: autocycle.cpp:85 autocycle.cpp:89 autocycle.cpp:94 msgid "Channel" msgstr "Salon" #: autocycle.cpp:100 msgid "You have no entries." msgstr "Vous n'avez aucune entrée." #: autocycle.cpp:229 msgid "List of channel masks and channel masks with ! before them." msgstr "Liste les masques de salons, y compris préfixés par !." #: autocycle.cpp:234 msgid "Rejoins channels to gain Op if you're the only user left" msgstr "" "Rejoint un salon automatiquement si vous êtes le dernier utilisateur pour " "devenir Op" znc-1.7.5/modules/po/awaystore.it_IT.po0000644000175000017500000000610113542151610020211 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/awaystore.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "Sei contrassegnato come assente (away)" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "Bentornato!" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "Eliminato {1} messaggi" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "UTILIZZA: delete " #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "Messaggio illegale # richiesto" #: awaystore.cpp:113 msgid "Message erased" msgstr "Messaggio cancellato" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "Messaggi salvati su disco" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "Non sono presenti messaggi da salvare" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "Password aggiornata a [{1}]" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "Messaggio corrotto! [{1}]" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "Time stamp corrotto! [{1}]" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "#--- Fine dei messaggi" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "Timer impostato a 300 secondi" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "Timer disabilitato" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "Timer impostato a {1} secondi" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "Impostazioni del timer corrente: {1} secondi" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" "Questo mudulo necessita di un argomento come frase chiave utilizzata per la " "crittografia" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" "Impossibile decriptare i messaggi salvati. Hai fornito la chiave di " "crittografia giusta come argomento per questo modulo?" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "Hai {1} messaggi!" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "Impossibile trovare il buffer" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "Impossibile decriptare i messaggi crittografati" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" "[ -notimer | -timer N ] [-chans] passw0rd . N è il numero di secondi, 600 " "di default." #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" "Aggiunge un auto-away con logging, utile quando si utilizza ZNC da diverse " "posizioni" znc-1.7.5/modules/po/samplewebapi.ru_RU.po0000644000175000017500000000120713542151610020672 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/samplewebapi.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "" znc-1.7.5/modules/po/disconkick.fr_FR.po0000644000175000017500000000115513542151610020306 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/disconkick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" znc-1.7.5/modules/po/autovoice.nl_NL.po0000644000175000017500000000575513542151610020201 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/autovoice.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: autovoice.cpp:120 msgid "List all users" msgstr "Laat alle gebruikers zien" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr " [kanaal] ..." #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "Voegt kanalen toe aan een gebruiker" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "Verwijdert kanalen van een gebruiker" #: autovoice.cpp:128 msgid " [channels]" msgstr " [kanalen]" #: autovoice.cpp:129 msgid "Adds a user" msgstr "Voegt een gebruiker toe" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "Verwijdert een gebruiker" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "Gebruik: AddUser [kanalen]" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "Gebruik: DelUser " #: autovoice.cpp:238 msgid "There are no users defined" msgstr "Er zijn geen gebruikers gedefinieerd" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "Gebruiker" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "Hostmasker" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "Kanalen" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "Gebruik: AddChans [kanaal] ..." #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "Deze gebruiker bestaat niet" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "Kana(a)l(en) toegevoegd aan gebruiker {1}" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "Gebruik: DelChans [kanaal] ..." #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "Kana(a)l(en) verwijderd van gebruiker {1}" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "Gebruiker {1} verwijderd" #: autovoice.cpp:341 msgid "That user already exists" msgstr "Die gebruiker bestaat al" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "Gebruiker {1} toegevoegd met hostmasker {2}" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" "Elk argument is een kanaal waar je autovoice in wilt stellen (jokers mogen " "gebruikt worden), of, als het begint met !, dan is het een uitzondering voor " "autovoice." #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "Geeft goede gebruikers automatisch een stem" znc-1.7.5/modules/po/watch.fr_FR.po0000644000175000017500000001104513542151610017272 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/watch.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "Toutes les entrées sont effacées." #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "" #: watch.cpp:397 msgid "Disabled all entries." msgstr "" #: watch.cpp:398 msgid "Enabled all entries." msgstr "Toutes les entrées sont activées." #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "Identifiant invalide" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "" #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "" #: watch.cpp:593 msgid "Id {1} removed." msgstr "" #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "" #: watch.cpp:609 msgid "List" msgstr "" #: watch.cpp:611 msgid "List all entries being watched." msgstr "" #: watch.cpp:614 msgid "Dump" msgstr "" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "" #: watch.cpp:620 msgid "Del " msgstr "" #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "" #: watch.cpp:625 msgid "Clear" msgstr "" #: watch.cpp:626 msgid "Delete all entries." msgstr "" #: watch.cpp:629 msgid "Enable " msgstr "" #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "" #: watch.cpp:633 msgid "Disable " msgstr "" #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "" #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "" #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "" #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "" #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "" #: watch.cpp:652 msgid "Buffer [Count]" msgstr "" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "" #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "" #: watch.cpp:664 msgid "Help" msgstr "" #: watch.cpp:665 msgid "This help." msgstr "" #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "" #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "" znc-1.7.5/modules/po/partyline.nl_NL.po0000644000175000017500000000157313542151610020204 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/partyline.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "" #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "" #: partyline.cpp:82 msgid "List all open channels" msgstr "" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "" znc-1.7.5/modules/po/clientnotify.id_ID.po0000644000175000017500000000323113542151610020643 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/clientnotify.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "" #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "" #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "" #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "" #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" znc-1.7.5/modules/po/modpython.pot0000644000175000017500000000025713542151610017377 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/partyline.pot0000644000175000017500000000111013542151610017352 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "" #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "" #: partyline.cpp:82 msgid "List all open channels" msgstr "" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "" znc-1.7.5/modules/po/bouncedcc.pt_BR.po0000644000175000017500000000501213542151610020116 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/bouncedcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "" #: bouncedcc.cpp:129 msgid "Connected" msgstr "" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "" #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "" #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "" #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" znc-1.7.5/modules/po/stickychan.pot0000644000175000017500000000316213542151610017514 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "" #: stickychan.cpp:30 msgid "<#channel>" msgstr "" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "" #: stickychan.cpp:101 msgid " -- End of List" msgstr "" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "" #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "" #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" znc-1.7.5/modules/po/samplewebapi.bg_BG.po0000644000175000017500000000073613542151610020604 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/samplewebapi.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "" znc-1.7.5/modules/po/kickrejoin.nl_NL.po0000644000175000017500000000373313542151610020325 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/kickrejoin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: kickrejoin.cpp:56 msgid "" msgstr "" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "Stel de vertraging voor het opnieuw toetreden in" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "Laat de vertraging voor het opnieuw toetreden zien" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "Ongeldig argument, moet 0 of een getal boven de 0 zijn" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "Vertragingen van minder dan 0 seconden slaan nergens op!" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "Vertraging voor het opnieuw toetreden ingesteld op 1 seconde" msgstr[1] "Vertraging voor het opnieuw toetreden ingesteld op {1} seconden" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "Vertraging voor het opnieuw toetreden uitgeschakeld" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "Vertraging voor het opnieuw toetreden ingesteld op 1 seconde" msgstr[1] "Vertraging voor het opnieuw toetreden ingesteld op {1} seconden" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "Vertraging voor het opnieuw toetreden is uitgeschakeld" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "" "Je kan het aantal seconden voor het wachten voor het opnieuw toetreden " "invoeren." #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "Automatisch opnieuw toetreden wanneer geschopt" znc-1.7.5/modules/po/certauth.nl_NL.po0000644000175000017500000000536013542151610020012 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/certauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "Voeg een sleutel toe" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "Sleutel:" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "Voeg sleutel toe" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "Je hebt geen sleutels." #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "Sleutel" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "Verwijder" #: certauth.cpp:31 msgid "[pubkey]" msgstr "[publieke sleutel]" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" "Voeg een publieke sleutel toe. Als deze niet ingevoerd word zal de huidige " "sleutel gebruikt worden" #: certauth.cpp:35 msgid "id" msgstr "id" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "Verwijder een sleutel naar aanleiding van het nummer in de lijst" #: certauth.cpp:37 msgid "List your public keys" msgstr "Laat je publieke sleutels zien" #: certauth.cpp:39 msgid "Print your current key" msgstr "Laat je huidige sleutel zien" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "Je bent niet verbonden met een geldige publieke sleutel" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "Je huidige publieke slutel is: {1}" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "Je hebt geen publieke sleutel ingevoerd of verbonden hiermee." #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "Sleutel '{1}' toegevoegd." #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "De sleutel '{1}' is al toegevoegd." #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "Id" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "Sleutel" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "Geen sleutels ingesteld voor gebruiker" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "Ongeldig #, controleer \"list\"" #: certauth.cpp:215 msgid "Removed" msgstr "Verwijderd" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "" "Staat gebruikers toe zich te identificeren via SSL client certificaten." znc-1.7.5/modules/po/autoattach.bg_BG.po0000644000175000017500000000324613542151610020267 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/autoattach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "" #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "" #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "" #: autoattach.cpp:138 msgid "You have no entries." msgstr "" #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "" #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "" #: autoattach.cpp:152 msgid "List all entries" msgstr "" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "" #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "" znc-1.7.5/modules/po/flooddetach.bg_BG.po0000644000175000017500000000351513542151610020405 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/flooddetach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "" #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "" msgstr[1] "" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "" znc-1.7.5/modules/po/block_motd.it_IT.po0000644000175000017500000000204513542151610020313 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/block_motd.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: block_motd.cpp:26 msgid "[]" msgstr "[]" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" "Ignora il blocco con questo comando. Opzionalmente puoi specificare quale " "server interrogare." #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "Non sei connesso ad un server IRC." #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "MOTD bloccato da ZNC" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "Blocca il MOTD da IRC in modo che non venga inviato ai tuoi client." znc-1.7.5/modules/po/blockuser.pot0000644000175000017500000000300113542151610017335 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "" #: blockuser.cpp:29 msgid "List blocked users" msgstr "" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "" #: blockuser.cpp:76 msgid "Access denied" msgstr "" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "" #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "" #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "" #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "" znc-1.7.5/modules/po/autoop.bg_BG.po0000644000175000017500000000630613542151610017441 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/autoop.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: autoop.cpp:154 msgid "List all users" msgstr "" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr "" #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr "" #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr "" #: autoop.cpp:170 msgid "Adds a user" msgstr "" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "" #: autoop.cpp:300 msgid "There are no users defined" msgstr "" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "" #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "" #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "" #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "" #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "" #: autoop.cpp:478 msgid "User {1} removed" msgstr "" #: autoop.cpp:484 msgid "That user already exists" msgstr "" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "" #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "" #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "" #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "" #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "" #: autoop.cpp:644 msgid "Auto op the good people" msgstr "" znc-1.7.5/modules/po/watch.it_IT.po0000644000175000017500000001411413542151610017304 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/watch.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "Tutte le voci cancellate." #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "Buffer count è impostato a {1}" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "Comando sconosciuto: {1}" #: watch.cpp:397 msgid "Disabled all entries." msgstr "Disabilitate tutte le voci" #: watch.cpp:398 msgid "Enabled all entries." msgstr "Abilitate tutte le voci" #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "Id non valido" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "Id {1} disabilitato" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "Id {1} abilitato" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "Imposta il DetachedClientOnly per tutte le voci su Sì" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "Imposta il DetachedClientOnly per tutte le voci su No" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "Id {1} impostato a Si" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "Id {1} impostato a No" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "Imposta il DetachedChannelOnly per tutte le voci su Yes" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "Imposta il DetachedChannelOnly per teutte le voci a No" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "Id" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "HostMask" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "Target" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "Modello" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "Sorgenti" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "Off" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "DetachedClientOnly" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "DetachedChannelOnly" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "Si" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "No" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "Non hai voci" #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "Sorgenti impostate per Id {1}." #: watch.cpp:593 msgid "Id {1} removed." msgstr "Id {1} rimosso." #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "Comando" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "Descrizione" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "Add [Target] [Modello]" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "Utilizzato per aggiungere una voce da tenere d'occhio." #: watch.cpp:609 msgid "List" msgstr "Lista" #: watch.cpp:611 msgid "List all entries being watched." msgstr "Elenca tutte le voci che si stanno guardando" #: watch.cpp:614 msgid "Dump" msgstr "Scarica" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "Scarica un elenco di tutte le voci correnti da utilizzare in seguito." #: watch.cpp:620 msgid "Del " msgstr "Elimina " #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "Elimina l'ID dall'elenco delle voci osservate." #: watch.cpp:625 msgid "Clear" msgstr "Cancella" #: watch.cpp:626 msgid "Delete all entries." msgstr "Elimina tutte le voci." #: watch.cpp:629 msgid "Enable " msgstr "Abilita " #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "Abilita una voce disabilitata" #: watch.cpp:633 msgid "Disable " msgstr "Disabilita " #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "Disabilita (ma non elimina) una voce." #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "SetDetachedClientOnly " #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "Abilita o disabilita il client separato (detached) solo per una voce." #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "SetDetachedChannelOnly " #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "Abilita o disabilita il canale separato (detached) solo per una voce." #: watch.cpp:652 msgid "Buffer [Count]" msgstr "Buffer [Count]" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "" "Mostra/Imposta la quantità di linee bufferizzate mentre è " "distaccata(detached)." #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "SetSources [#canale priv #foo* !#bar]" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "Imposta i canali sorgente che ti interessano." #: watch.cpp:664 msgid "Help" msgstr "Aiuto" #: watch.cpp:665 msgid "This help." msgstr "Questo aiuto." #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "La voce per {1} esiste già." #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "Aggiunta voce: {1} in cerca di [{2}] -> {3}" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "Guarda: argomenti insufficienti. Prova aiuto" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "ATTENZIONE: rilevata immissione errata durante il caricamento" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "Copia l'attività di uno specifico utente in una finestra separata" znc-1.7.5/modules/po/bouncedcc.it_IT.po0000644000175000017500000000651213542151610020126 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/bouncedcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "Tipo" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "Stato" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "Velocità" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "Nick" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "IP" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "File" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "Chat" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "Xfer" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "In attesa" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "A metà strada (Halfway)" #: bouncedcc.cpp:129 msgid "Connected" msgstr "Connesso" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "Non hai DCCs attive." #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "Usa client IP: {1}" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "Elenco di tutte le DCCs attive" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "Cambia l'opzione per utilizzare l'indirizzo IP del client" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "Chat" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "Xfer" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "DCC {1} Bounce ({2}): Linea ricevuta troppo lunga" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "" "DCC {1} Bounce ({2}): (Timeout) Tempo scaduto durante la connessione a {3} " "{4}" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "DCC {1} Bounce ({2}): (Timeout) Tempo scaduto durante la connessione." #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" "DCC {1} Bounce ({2}): (Timeout) Tempo scaduto in attesa della connessione in " "arrivo {3} {4}" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "" "DCC {1} Bounce ({2}): Connessione rifiutata durante la connessione a {3} {4}" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "DCC {1} Bounce ({2}): Connessione rifiutata durante la connessione." #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "DCC {1} Bounce ({2}): Errore di socket su {3} {4}: {5}" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "DCC {1} Bounce ({2}): Errore socket: {3}" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" "Rimbalza (bounce) i trasferimenti DCC tramite ZNC invece di inviarli " "direttamente all'utente. " znc-1.7.5/modules/po/buffextras.pot0000644000175000017500000000122713542151610017525 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: buffextras.cpp:45 msgid "Server" msgstr "" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "" #: buffextras.cpp:73 msgid "{1} joined" msgstr "" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "" znc-1.7.5/modules/po/modperl.nl_NL.po0000644000175000017500000000077513542151610017642 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/modperl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "Laad perl scripts als ZNC modulen" znc-1.7.5/modules/po/cyrusauth.id_ID.po0000644000175000017500000000331213542151610020163 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/cyrusauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" #: cyrusauth.cpp:56 msgid "Access denied" msgstr "" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "" #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" znc-1.7.5/modules/po/admindebug.es_ES.po0000644000175000017500000000266113542151610020267 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/admindebug.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "Habilitar modo de depuración" #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "Desactivar modo de depuración" #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "Muestra el estado del modo de depuración" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "¡Acceso denegado!" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" #: admindebug.cpp:66 msgid "Already enabled." msgstr "Ya está habilitado." #: admindebug.cpp:68 msgid "Already disabled." msgstr "Ya está deshabilitado." #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "Modo depuración activado." #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "Modo depuración desactivado." #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "Registrando a: stdout." #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "Habilita el modo de depuración dinámicamente." znc-1.7.5/modules/po/send_raw.de_DE.po0000644000175000017500000000430213542151610017726 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/send_raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "" #: send_raw.cpp:82 msgid "Send Raw" msgstr "" #: send_raw.cpp:92 msgid "User not found" msgstr "" #: send_raw.cpp:99 msgid "Network not found" msgstr "" #: send_raw.cpp:116 msgid "Line sent" msgstr "" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "" #: send_raw.cpp:147 msgid "[data to send]" msgstr "" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "" znc-1.7.5/modules/po/nickserv.fr_FR.po0000644000175000017500000000275513542151610020020 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/nickserv.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: nickserv.cpp:31 msgid "Password set" msgstr "" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "" #: nickserv.cpp:63 msgid "Ok" msgstr "" #: nickserv.cpp:68 msgid "password" msgstr "" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "" #: nickserv.cpp:72 msgid "nickname" msgstr "" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "" #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "" znc-1.7.5/modules/po/autoattach.it_IT.po0000644000175000017500000000432213542151610020333 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/autoattach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "Aggiunto alla lista" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "{1} è già stato aggiunto" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "Usa: Add [!]<#canale> " #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "Sono ammesse wildcards (caratteri jolly)" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "Rimosso {1} dalla lista" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "Usa: Del [!]<#canale> " #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "Neg" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "Canale" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "Cerca" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "Host" #: autoattach.cpp:138 msgid "You have no entries." msgstr "Non hai voci." #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "[!]<#canale> " #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" "Aggiunge una voce, usa !#canale per negare e * come wildcard (caratteri " "jolly)" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "Rimuove una voce, deve essere una corrispondenza esatta" #: autoattach.cpp:152 msgid "List all entries" msgstr "Elenca tutte le voci" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "Impossibile aggiungere [{1}]" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "" "Elenco delle maschere di canale e delle maschere di canale con il ! " "antecedente." #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "Ricollega i canali quando c'è attività." znc-1.7.5/modules/po/bouncedcc.fr_FR.po0000644000175000017500000000476713542151610020126 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/bouncedcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "" #: bouncedcc.cpp:129 msgid "Connected" msgstr "" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "" #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "" #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "" #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" znc-1.7.5/modules/po/clientnotify.fr_FR.po0000644000175000017500000000325013542151610020672 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/clientnotify.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" msgstr[1] "" #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "" #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "" #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "" #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "" #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" znc-1.7.5/modules/po/send_raw.id_ID.po0000644000175000017500000000427713542151610017751 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/send_raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/send_raw/tmpl/index.tmpl:9 msgid "Send a raw IRC line" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:14 msgid "User:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:15 msgid "To change user, click to Network selector" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:19 msgid "User/Network:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:32 msgid "Send to:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:34 msgid "Client" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:35 msgid "Server" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:40 msgid "Line:" msgstr "" #: modules/po/../data/send_raw/tmpl/index.tmpl:45 msgid "Send" msgstr "" #: send_raw.cpp:32 msgid "Sent [{1}] to {2}/{3}" msgstr "" #: send_raw.cpp:36 send_raw.cpp:56 msgid "Network {1} not found for user {2}" msgstr "" #: send_raw.cpp:40 send_raw.cpp:60 msgid "User {1} not found" msgstr "" #: send_raw.cpp:52 msgid "Sent [{1}] to IRC server of {2}/{3}" msgstr "" #: send_raw.cpp:75 msgid "You must have admin privileges to load this module" msgstr "" #: send_raw.cpp:82 msgid "Send Raw" msgstr "" #: send_raw.cpp:92 msgid "User not found" msgstr "" #: send_raw.cpp:99 msgid "Network not found" msgstr "" #: send_raw.cpp:116 msgid "Line sent" msgstr "" #: send_raw.cpp:140 send_raw.cpp:143 msgid "[user] [network] [data to send]" msgstr "" #: send_raw.cpp:141 msgid "The data will be sent to the user's IRC client(s)" msgstr "" #: send_raw.cpp:144 msgid "The data will be sent to the IRC server the user is connected to" msgstr "" #: send_raw.cpp:147 msgid "[data to send]" msgstr "" #: send_raw.cpp:148 msgid "The data will be sent to your current client" msgstr "" #: send_raw.cpp:159 msgid "Lets you send some raw IRC lines as/to someone else" msgstr "" znc-1.7.5/modules/po/webadmin.de_DE.po0000644000175000017500000011325313542151610017720 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/webadmin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "Kanal-Info" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "Kanalname:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "Name des Kanals." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "Schlüssel:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "Das Passwort für den Kanal, sofern vorhanden." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "Puffergröße:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "Anzahl der Puffer." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "Standardmodi:" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "Die Standard-Kanalmodi." #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "Optionen" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "In der ZNC-Konfiguration speichern" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "Modul {1}" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "Speichern und zurück" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "Speichern und fortfahren" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "Channel hinzufügen und zurück" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "Channel hinzufügen und fortfahren" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "<Passwort>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "<Netzwerk>" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" "Um einen IRC-Client zu diesem Netzwerk zu verbinden, kannst Du {1} als Serverpasswort oder {2} als Benutzernamen eintragen" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "Netzwerkinfo" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" "Nick, AltNick, Ident, RealName, BindHost können leer gelassen werden, um die " "Werte des Benutzers zu nutzen." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "Netzwerkname:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "Der Name des IRC-Netzwerks." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "Nickname:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "Dein Nickname im IRC." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "Alt. Nickname:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "Dein alternativer Nickname, falls der primäre nicht verfügbar ist." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "Ident:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "Dein Ident." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "Echter Name:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "Dein echter Name." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "BindHost:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "Quit-Nachricht:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "" "Diese Nachricht wird anderen angezeigt, wenn Du die Verbindung zum IRC " "trennst." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "Aktiv:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "Verbinden und automatisch neu verbinden" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "Allen Zertifikaten vertrauen:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "" "Zertifikatsprüfung deaktivieren (hat Vorrang vor \"Vertraue dem PKI\"). " "UNSICHER!" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "Vertraue dem PKI:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" "Wenn diese Option nicht gesetzt ist, wird nur den Zertifikaten vertraut, für " "die Du Fingerprints hinzugefügt hast." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "Server dieses IRC-Netzwerks:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "Ein Server pro Zeile, “Host [[+]Port] [Passwort]â€, das + steht für SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "Hostname" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "Port" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "SSL" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "Passwort" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "" "SHA-256-Fingerprints von vertrauenswürdigen SSL-Zertifikaten dieses IRC-" "Netzwerks:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" "Bei diesen Zertifikaten werden Hostnamen, Ablaufdaten und CA beim Handshake " "nicht validiert" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "Flooding-Schutz:" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" "Der Flooding-Schutz vermeidet \"excess flood\"-Fehler, die auftreten, wenn " "Dein IRC-Client zu viel Text oder zu viele Kommandos in kurzer Zeit schickt. " "Nach dem Ändern dieser Option musst Du ZNC neu zum IRC verbinden." #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "Aktueller Server" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "Nick" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "↠Ein Netzwerk hinzufügen (öffnet sich in diesem Tab)" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "" "Du kannst Netzwerke hier hinzufügen und bearbeiten, nachdem Du den Benutzer " "geklont hast." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "" "Du kannst Netzwerke hier hinzufügen und bearbeiten, nachdem Du den Benutzer " "erstellt hast." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "Durch Netzwerke geladen" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" "Die Standard-Kanalmodi, die ZNC beim Betreten eines leeren Kanals setzen " "wird." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "Leer = benutze Vorgabewert" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Die Anzahl der Zeilen, die der Playback-Puffer pro Kanal vorhält, bevor die " "älteste Zeile gelöscht wird. Die Puffer werden standardmäßig im Speicher " "gehalten." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "Queries (Private Konversationen)" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "Max. Pufferanzahl:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "Maximale Zahl an Playback-Puffern für Queries. 0 für unbegrenzt." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" "Die Anzahl der Zeilen, die der Playback-Puffer pro Query vorhält, bevor die " "älteste Zeile gelöscht wird. Die Puffer werden standardmäßig im Speicher " "gehalten." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "ZNC-Verhalten" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" "Die folgenden Textfelder können leer gelassen werden, um den Vorgabewert zu " "benutzen." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "Zeitstempelformat:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" "Das Format für die Zeitstempel, die in Puffern genutzt werden, z. B. [%H:%M:" "%S]. Diese Einstellung wird in modernen IRC-Clients ignoriert, wenn sie " "server-time nutzen. Wenn Dein Client server-time unterstützt, ändere das " "Format in Deinem Client." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "Zeitzone:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "z.B. Europe/Berlin oder GMT-6" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "Zeichenkodierung zwischen IRC-Client und ZNC." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "Client-Zeichenkodierung:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "Join-Versuche:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" "Wie oft ZNC versuchen wird, einem Kanal beizutreten, falls der erste Versuch " "fehlschlägt (z.B. weil Modus +i/+k gesetzt ist oder Du gebannt bist)." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "Kanäle pro Join:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" "Wie viele Kanäle in einem JOIN-Kommando benutzt werden. 0 heißt unbegrenzt " "(Standard). Solltest Du mit der Meldung \"Max SendQ Exceeded\" getrennt " "werden, während ZNC gerade Kanäle betritt, setze dies auf eine einstellige " "positive Zahl." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "Zeitüberschreitung vor Neuverbinden:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" "Wie viele Sekunden ZNC nach dem Pingen des IRC-Servers auf Antwort wartet, " "bevor ZNC eine Zeitüberschreitung deklariert." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "Max. Anzahl an IRC-Netzwerken:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "" "Die maximale Anzahl an IRC-Netzwerken, die diesem Benutzer erlaubt werden." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "Ersetzungen/Variablen" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "CTCP-Antworten:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "" "Eine Antwort pro Zeile. Beispiel: Anfrage TIME, Antwort " "Kauf' Dir eine Uhr!" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "Es kann mit {1} gearbeitet werden." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "" "Wenn das Antwort-Feld leer gelassen wird, wird die CTCP-Anfrage ignoriert." #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "Anfrage" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "Antwort" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "Oberfläche:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "- Global -" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "Standard" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "Keine anderen Oberflächen gefunden" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "Sprache:" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "Klonen und zurück" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "Klonen und fortfahren" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "Anlegen und zurück" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "Erstellen und fortsetzen" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "Klonen" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "Erstellen" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "Löschen des Netzwerks bestätigen" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "" "Bist Du sicher, dass Du das Netzwerk “{2}†des Benutzers “{1}†löschen " "möchtest?" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "Ja" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "IRC-Verbindungen" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "Gesamt" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "Eingehend" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "Ausgehend" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "Benutzer" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "Traffic" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "Benutzer" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "Netzwerk" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "Globale Einstellungen" #: webadmin.cpp:93 msgid "Your Settings" msgstr "Deine Einstellungen" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "Traffic-Zähler" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "Benutzer verwalten" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "Ungültige Daten [Benutzername muss ausgefüllt sein]" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "Ungültige Daten [Passwörter stimmen nicht überein]" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "Zeitüberschreitung darf nicht weniger als 30 Sekunden sein!" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "Kann Modul {1} nicht laden: {2}" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "Kann Modul {1} mit Argumenten {2} nicht laden" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "Benutzer existiert nicht" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "Benutzer oder Netzwerk existiert nicht" #: webadmin.cpp:576 msgid "No such channel" msgstr "Kanal existiert nicht" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "Bitte lösche Dich nicht, Suizid ist keine Lösung!" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "Benutzer [{1}] bearbeiten" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "Netzwerk [{1}] bearbeiten" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "Kanal [{1}] in Netzwerk [{2}] von Benutzer [{3}] bearbeiten" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "Kanal [{1}] bearbeiten" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "Kanal zum Netzwerk [{1}] von Benutzer [{2}] hinzufügen" #: webadmin.cpp:749 msgid "Add Channel" msgstr "Kanal hinzufügen" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "Automatisch Kanal-Puffer leeren" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "" "Den Playback-Puffer eines Kanals automatisch nach dem Wiedergeben leeren" #: webadmin.cpp:766 msgid "Detached" msgstr "Abgetrennt" #: webadmin.cpp:773 msgid "Enabled" msgstr "Aktiviert" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "Kanalname ist ein notwendiger Parameter" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "Kanal [{1}] existiert bereits" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "Kanal [{1}] konnte nicht hinzugefügt werden" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "" "Channel wurde hinzugefügt/bearbeitet, aber die Konfigurationsdatei wurde " "nicht gespeichert" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" "Maximale Anzahl an Netzwerken erreicht. Bitte einen Administrator, Dein " "Limit zu erhöhen, oder entferne nicht benötigte Netzwerke aus Deinen " "Einstellungen." #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "Netzwerk [{1}] von Benutzer [{2}] bearbeiten" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "Netzwerk für Benutzer [{1}] hinzufügen" #: webadmin.cpp:911 msgid "Add Network" msgstr "Netzwerk hinzufügen" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "Netzwerkname ist ein notwendiger Parameter" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "Kann Modul {1} nicht neu laden: {2}" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "" "Netzwerk wurde hinzugefügt/bearbeitet, aber die Konfigurationsdatei wurde " "nicht gespeichert" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "Dieser Nutzer hat dieses Netzwerk nicht" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "" "Netzwerk wurde entfernt, aber die Konfigurationsdatei wurde nicht gespeichert" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "Dieser Kanal existiert in diesem Netzwerk nicht" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "" "Kanal wurde entfernt, aber die Konfigurationsdatei wurde nicht gespeichert" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "Benutzer [{1}] klonen" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" "Kanal-Puffer nach Wiedergabe automatisch leeren (Vorgabewert für neue Kanäle)" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "Erlaube mehrere Clients" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "Zeitstempel am Ende anfügen" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "" #: webadmin.cpp:1551 msgid "Admin" msgstr "" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "" #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "" #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "" #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "" #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "" znc-1.7.5/modules/po/keepnick.pot0000644000175000017500000000151413542151610017144 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "" #: keepnick.cpp:44 msgid "Show the current state" msgstr "" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "" znc-1.7.5/modules/po/partyline.pt_BR.po0000644000175000017500000000161613542151610020206 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/partyline.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: partyline.cpp:60 msgid "There are no open channels." msgstr "" #: partyline.cpp:66 partyline.cpp:73 msgid "Channel" msgstr "" #: partyline.cpp:67 partyline.cpp:74 msgid "Users" msgstr "" #: partyline.cpp:82 msgid "List all open channels" msgstr "" #: partyline.cpp:733 msgid "" "You may enter a list of channels the user joins, when entering the internal " "partyline." msgstr "" #: partyline.cpp:739 msgid "Internal channels and queries for users connected to ZNC" msgstr "" znc-1.7.5/modules/po/disconkick.pot0000644000175000017500000000047113542151610017475 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" znc-1.7.5/modules/po/identfile.es_ES.po0000644000175000017500000000406613542151610020134 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/identfile.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: identfile.cpp:30 msgid "Show file name" msgstr "Mostrar nombre de archivo" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "Definir nombre de archivo" #: identfile.cpp:34 msgid "Show file format" msgstr "Mostrar formato de archivo" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "Definir formato de archivo" #: identfile.cpp:38 msgid "Show current state" msgstr "Mostrar estado actual" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "Archivo definido a: {1}" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "El archivo se ha establecido a: {1}" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "El formato se ha establecido a: {1}" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "El formato será expandido a: {1}" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "Formato establecido a: {1}" #: identfile.cpp:78 msgid "identfile is free" msgstr "identfile vacío" #: identfile.cpp:86 msgid "Access denied" msgstr "Acceso denegado" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" "Conexión cancelada, otro usuario o red ya se está conectando usando el " "archivo de ident" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "[{1}] no se ha podido escribir, reintentando..." #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "Escribe el ident de un usuario a un archivo cuando intentan conectar." znc-1.7.5/modules/po/perleval.nl_NL.po0000644000175000017500000000134213542151610020001 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/perleval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "Evalueert perl code" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "Alleen beheerders kunnen deze module laden" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "Fout: %s" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "Resultaat: %s" znc-1.7.5/modules/po/awaystore.pot0000644000175000017500000000355613542151610017401 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "" #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "" #: awaystore.cpp:113 msgid "Message erased" msgstr "" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" znc-1.7.5/modules/po/autoattach.ru_RU.po0000644000175000017500000000351713542151610020364 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/autoattach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "" #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "" #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "" #: autoattach.cpp:138 msgid "You have no entries." msgstr "" #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "" #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "" #: autoattach.cpp:152 msgid "List all entries" msgstr "" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "" #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "" znc-1.7.5/modules/po/keepnick.es_ES.po0000644000175000017500000000276613542151610017767 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/keepnick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "Intenta conseguir tu nick primario" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "Dejando de intentar conseguir tu nick primario" #: keepnick.cpp:44 msgid "Show the current state" msgstr "Mostrar estado actual" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "ZNC ya está intentando conseguir este nick" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "No se ha podido obtener el nick {1}: {2}, {3}" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "No se ha podido obtener el nick {1}" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "Intentando obtener tu nick primario" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "Intentando obtener tu nick primario" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "Actualmente deshabilitado, escribe 'enable'" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "Intenta conseguir tu nick primario" znc-1.7.5/modules/po/clientnotify.it_IT.po0000644000175000017500000000457313542151610020715 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/clientnotify.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "Imposta il metodo di notifica" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "" "Attiva o disattiva le notifiche per gli indirizzi IP nascosti (ON - OFF)" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "" "Attiva o disattiva le notifiche per i client che si disconnettono (ON - OFF)" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "Mostra le impostazioni correnti" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" msgstr[1] "" "Un altro client si è autenticato con il tuo nome utente. Utilizza il comando " "'ListClients' per vedere tutti i {1} clients." #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "Utilizzo: Metodo " #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "Salvato." #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "Usa: NewOnly " #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "Usa: OnDisconnect " #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" "Impostazioni correnti: Metodo: {1}, solo per indirizzi IP non visibili: {2}, " "notifica la disconnessione dei clients: {3}" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" "Notifica quando un altro client IRC entra o esce dal tuo account. " "Configurabile." znc-1.7.5/modules/po/block_motd.pot0000644000175000017500000000101113542151610017460 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: block_motd.cpp:26 msgid "[]" msgstr "" #: block_motd.cpp:27 msgid "" "Override the block with this command. Can optionally specify which server to " "query." msgstr "" #: block_motd.cpp:36 msgid "You are not connected to an IRC Server." msgstr "" #: block_motd.cpp:58 msgid "MOTD blocked by ZNC" msgstr "" #: block_motd.cpp:104 msgid "Block the MOTD from IRC so it's not sent to your client(s)." msgstr "" znc-1.7.5/modules/po/watch.pt_BR.po0000644000175000017500000001073613542151610017310 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/watch.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "" #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "" #: watch.cpp:397 msgid "Disabled all entries." msgstr "" #: watch.cpp:398 msgid "Enabled all entries." msgstr "" #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "" #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "" #: watch.cpp:593 msgid "Id {1} removed." msgstr "" #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "" #: watch.cpp:609 msgid "List" msgstr "" #: watch.cpp:611 msgid "List all entries being watched." msgstr "" #: watch.cpp:614 msgid "Dump" msgstr "" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "" #: watch.cpp:620 msgid "Del " msgstr "" #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "" #: watch.cpp:625 msgid "Clear" msgstr "" #: watch.cpp:626 msgid "Delete all entries." msgstr "" #: watch.cpp:629 msgid "Enable " msgstr "" #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "" #: watch.cpp:633 msgid "Disable " msgstr "" #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "" #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "" #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "" #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "" #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "" #: watch.cpp:652 msgid "Buffer [Count]" msgstr "" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "" #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "" #: watch.cpp:664 msgid "Help" msgstr "" #: watch.cpp:665 msgid "This help." msgstr "" #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "" #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "" znc-1.7.5/modules/po/blockuser.fr_FR.po0000644000175000017500000000346413542151610020163 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/blockuser.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "" #: blockuser.cpp:29 msgid "List blocked users" msgstr "" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "" #: blockuser.cpp:76 msgid "Access denied" msgstr "" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "" #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "" #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "" #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "" znc-1.7.5/modules/po/disconkick.id_ID.po0000644000175000017500000000115313542151610020256 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/disconkick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" znc-1.7.5/modules/po/kickrejoin.ru_RU.po0000644000175000017500000000301713542151610020352 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/kickrejoin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: kickrejoin.cpp:56 msgid "" msgstr "<Ñекунды>" #: kickrejoin.cpp:56 msgid "Set the rejoin delay" msgstr "" #: kickrejoin.cpp:58 msgid "Show the rejoin delay" msgstr "" #: kickrejoin.cpp:77 msgid "Illegal argument, must be a positive number or 0" msgstr "" #: kickrejoin.cpp:90 msgid "Negative delays don't make any sense!" msgstr "" #: kickrejoin.cpp:98 msgid "Rejoin delay set to 1 second" msgid_plural "Rejoin delay set to {1} seconds" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: kickrejoin.cpp:101 msgid "Rejoin delay disabled" msgstr "" #: kickrejoin.cpp:106 msgid "Rejoin delay is set to 1 second" msgid_plural "Rejoin delay is set to {1} seconds" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: kickrejoin.cpp:109 msgid "Rejoin delay is disabled" msgstr "" #: kickrejoin.cpp:131 msgid "You might enter the number of seconds to wait before rejoining." msgstr "" #: kickrejoin.cpp:134 msgid "Autorejoins on kick" msgstr "" znc-1.7.5/modules/po/shell.fr_FR.po0000644000175000017500000000124413542151610017273 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/shell.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "" #: shell.cpp:169 msgid "Gives shell access" msgstr "" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "" znc-1.7.5/modules/po/flooddetach.it_IT.po0000644000175000017500000000524013542151610020452 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/flooddetach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "Mostra i limiti correnti" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "[]" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "Mostra o imposta il numero di secondi nell'intervallo di tempo" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "Mostra o imposta il numero di linee nell'intervallo di tempo" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "" "Mostra o imposta se essere notificato sullo sgancio (detach) e il ri-" "aggancio (attaching)" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "Il flood su {1} è finito, ri-aggancio..." #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "" "Canale{1} è stato \"invaso da messaggi\" (flooded), sei stato sganciato " "(detached)" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "1 linea" msgstr[1] "{1} linee" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "ogni secondo" msgstr[1] "ogni {1} secondi" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "Il limite corrente è {1} {2}" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "Il limite dei secondi è {1}" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "Imposta il limite in secondi a {1}" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "Il limite delle linee è {1}" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "Imposta il limite delle linee a {1}" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "I messaggi del modulo sono disabilitati" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "I messaggi del modulo sono abilitati" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" "Questo modulo utente richiede fino a due argomenti. Gli argomenti sono il " "numero di messaggi e dei secondi." #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "" "Sgancia (detach) dai canali quando vengono c'è un flood (invasione di " "messaggi)" znc-1.7.5/modules/po/autovoice.fr_FR.po0000644000175000017500000000606413542151610020167 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/autovoice.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: autovoice.cpp:120 msgid "List all users" msgstr "Lister tous les utilisateurs" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr " [channel]..." #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "Ajoute des salons à un utilisateur" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "Retire des salons d'un utilisateur" #: autovoice.cpp:128 msgid " [channels]" msgstr " [channels]" #: autovoice.cpp:129 msgid "Adds a user" msgstr "Ajoute un utilisateur" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "Supprime un utilisateur" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "Utilisation : AddUser [channels]" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "Utilisation : DelUser " #: autovoice.cpp:238 msgid "There are no users defined" msgstr "Il n'y a pas d'utilisateurs définis" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "Utilisateur" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "Masque réseau" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "Salons" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "Utilisation : AddChans [channel]..." #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "Utilisateur inconnu" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "Salon(s) ajouté(s) à l'utilisateur {1}" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "Usage : DelChans [channel]..." #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "Salons(s) supprimés de l'utilisateur {1}" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "Utilisateur {1} supprimé" #: autovoice.cpp:341 msgid "That user already exists" msgstr "Cet utilisateur existe déjà" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "Utilisateur {1} ajouté avec le masque {2}" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" "Chaque argument est soit un salon pour lequel vous voulez donnez la parole " "automatiquement (qui peut inclure des astérisques) soit, s'il commence " "par !, est une exclusion de la parole automatique." #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "Donne la parole automatiquement aux gens bien" znc-1.7.5/modules/po/chansaver.fr_FR.po0000644000175000017500000000075413542151610020143 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/chansaver.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "" znc-1.7.5/modules/po/identfile.de_DE.po0000644000175000017500000000412313542151610020070 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/identfile.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: identfile.cpp:30 msgid "Show file name" msgstr "Zeige Dateinamen" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "Setze Dateinamen" #: identfile.cpp:34 msgid "Show file format" msgstr "Zeige Dateiformat" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "Setzt das Dateiformat" #: identfile.cpp:38 msgid "Show current state" msgstr "Zeige aktuellen Zustand" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "Datei ist gesetzt auf: {1}" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "Datei wurde gesetzt auf: {1}" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "Format wurde gesetzt auf: {1}" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "Format würde expandiert zu: {1}" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "Format ist gesetzt auf: {1}" #: identfile.cpp:78 msgid "identfile is free" msgstr "Ident-Datei ist frei" #: identfile.cpp:86 msgid "Access denied" msgstr "Zugriff verweigert" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" "Breche Verbindung ab, ein anderer Benutzer oder ein anderes Netzwerk " "verbindet sich aktuell und verwendet die Ident-Spoof-Datei" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "[{1}] konnte nicht geschrieben werden, versuche erneut..." #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "" "Schreibe den Ident eines Benutzers in eine Datei wenn er versucht sich zu " "verbinden." znc-1.7.5/modules/po/chansaver.pot0000644000175000017500000000027113542151610017324 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "" znc-1.7.5/modules/po/lastseen.de_DE.po0000644000175000017500000000322513542151610017745 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/lastseen.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "Benutzer" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "Zuletzt gesehen" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "Info" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "Aktion" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "Bearbeiten" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "Löschen" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "Zeit der letzten Anmeldung:" #: lastseen.cpp:53 msgid "Access denied" msgstr "Zugriff verweigert" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "Benutzer" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "Zuletzt gesehen" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "nie" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "" "Zeigt eine Liste von Benutzern und wann sie sich zuletzt angemeldet haben an" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "Sammelt Daten darüber, wann ein Benutzer sich zuletzt angemeldet hat." znc-1.7.5/modules/po/simple_away.fr_FR.po0000644000175000017500000000374213542151610020503 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/simple_away.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: simple_away.cpp:56 msgid "[]" msgstr "" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "" #: simple_away.cpp:136 msgid "Away reason set" msgstr "" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" znc-1.7.5/modules/po/autovoice.de_DE.po0000644000175000017500000000574513542151610020136 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/autovoice.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: autovoice.cpp:120 msgid "List all users" msgstr "Zeige alle Benutzer an" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr " [Kanal] ..." #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "Fügt Kanäle zu Benutzern hinzu" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "Entfernt Kanäle von Benutzern" #: autovoice.cpp:128 msgid " [channels]" msgstr " [Kanäle]" #: autovoice.cpp:129 msgid "Adds a user" msgstr "Fügt einen Benutzer hinzu" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "Entfernt einen Benutzer" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "Verwendung: AddUser [Kanäle]" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "Verwendung: DelUser " #: autovoice.cpp:238 msgid "There are no users defined" msgstr "Es sind keine Benutzer definiert" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "Benutzer" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "Hostmaske" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "Kanäle" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "Verwendung: AddChans [Kanal] ..." #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "Kein solcher Benutzer" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "Kanal/Kanäle zu Benutzer {1} hinzugefügt" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "Verwendung: DelChans [Kanal] ..." #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "Kanal/Kanäle von Benutzer {1} entfernt" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "Benutzer {1} entfernt" #: autovoice.cpp:341 msgid "That user already exists" msgstr "Dieser Benutzer ist bereits vorhanden" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "Benutzer {1} mit Hostmaske {2} hinzugefügt" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" "Jedes Argument ist entweder ein Kanel in dem autovoice aktiviert sein soll " "(wobei Wildcards erlaubt sind) oder, falls es mit einem ! beginnt, eine " "Ausnahme für autovoice." #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "Gebe automatisch Voice an die guten Leute" znc-1.7.5/modules/po/raw.pot0000644000175000017500000000024013542151610016137 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "" znc-1.7.5/modules/po/admindebug.it_IT.po0000644000175000017500000000276313542151610020304 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/admindebug.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "Abilita la modalità di Debug" #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "Disabilita la modalità di Debug" #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "Mostra lo stato della modalità di Debug" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "Accesso negato!" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" "Fallito. Deve essere avviato con un TTY. (lo ZNC è avviato con --foreground?)" #: admindebug.cpp:66 msgid "Already enabled." msgstr "Già abilitato." #: admindebug.cpp:68 msgid "Already disabled." msgstr "Già disabilitato." #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "La modalità di debugging è on." #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "La modalità di debugging è off." #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "Logging a: stdout." #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "Abilita la modalità debug dinamicamente." znc-1.7.5/modules/po/chansaver.nl_NL.po0000644000175000017500000000106213542151610020140 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/chansaver.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "Houd de configuratie up-to-date wanneer gebruiks binnenkomen/verlaten." znc-1.7.5/modules/po/dcc.nl_NL.po0000644000175000017500000001362513542151610016727 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/dcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: dcc.cpp:88 msgid " " msgstr " " #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "Stuur een bestand van ZNC naar iemand" #: dcc.cpp:91 msgid "" msgstr "" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "Stuur een bestand van ZNC naar je client" #: dcc.cpp:94 msgid "List current transfers" msgstr "Laat huidige overdrachten zien" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "Je moet een beheerder zijn om de DCC module te mogen gebruiken" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "Proberen [{1}] naar [{2}] te sturen." #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "Ontvangst [{1}] van [{2}]: Bestand bestaat al." #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "Proberen te verbinden naar [{1} {2}] om [{3}] te downloaden van [{4}]." #: dcc.cpp:179 msgid "Usage: Send " msgstr "Gebruik: Send " #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "Ongeldig pad." #: dcc.cpp:199 msgid "Usage: Get " msgstr "Gebruik: Get " #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "Type" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "Status" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "Snelheid" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "Naam" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "IP-adres" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "Bestand" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "Versturen" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "Ontvangen" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "Wachten" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "{1} KiB/s" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "Je hebt geen actieve DCC overdrachten." #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "Proberen te hervatten van positie {1} van bestand [{2}] voor [{3}]" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "Kon bestand [{1}] voor [{2}] niet hervatten: verstuurd niks." #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "Slecht DCC bestand: {1}" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "Versturen [{1}] naar [{2}]: Bestand niet open!" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "Ontvangen [{1}] van [{2}]: Bestand niet open!" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "Versturen [{1}] naar [{2}]: verbinding geweigerd." #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "Ontvangen [{1}] van [{2}]: verbinding geweigerd." #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "Versturen [{1}] naar [{2}]: Time-out." #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "Ontvangen [{1}] van [{2}]: Time-out." #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "Versturen [{1}] naar [{2}]: Socket fout {3}: {4}" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "Ontvangen [{1}] van [{2}]: Socket fout {3}: {4}" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "Versturen [{1}] naar [{2}]: Overdracht gestart." #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "Ontvangen [{1}] van [{2}]: Overdracht gestart." #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "Versturen [{1}] naar [{2}]: Te veel data!" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "Ontvangen [{1}] van [{2}]: Te veel data!" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "Versturen [{1}] naar [{2}] afgerond met {3} KiB/s" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "Ontvangen [{1}] van [{2}] afgerond met {3} KiB/s" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "Versturen [{1}] naar [{2}]: Bestand te vroeg afgesloten." #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "Ontvangst [{1}] van [{2}]: Bestand te vroeg afgesloten." #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "Versturen [{1}] naar [{2}]: Fout bij lezen van bestand." #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "Ontvangen [{1}] van [{2}]: Fout bij lezen van bestand." #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "Versturen [{1}] naar [{2}]: Kan bestand niet openen." #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "Ontvangen [{1}] van [{2}]: Kan bestand niet openen." #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "Ontvangen [{1}] van [{2}]: Kan bestand niet openen." #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "Versturen [{1}] naar [{2}]: Geen bestand." #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "Versturen [{1}] naar [{2}]: Kan bestand niet openen." #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "Versturen [{1}] naar [{2}]: Bestand te groot (>4 GiB)." #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "Deze module stelt je in staat bestanden van en naar ZNC te sturen" znc-1.7.5/modules/po/admindebug.nl_NL.po0000644000175000017500000000260613542151610020272 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/admindebug.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "Debug-modus inschakelen" #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "Debug-modus uitschakelen" #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "Laat de status van de debug-modus zien" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "Toegang geweigerd!" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" #: admindebug.cpp:66 msgid "Already enabled." msgstr "Al ingeschakeld." #: admindebug.cpp:68 msgid "Already disabled." msgstr "Al uitgeschakeld." #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "Debugging modus is aan." #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "Debugging modus is uit." #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "Logboek bijhouden naar: stdout." #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "Debug-modus dynamisch inschakelen." znc-1.7.5/modules/po/certauth.it_IT.po0000644000175000017500000000533713542151610020024 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/certauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "Aggiungi una chiave" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "Chiave:" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "Aggiungi chiave" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "Non hai chiavi." #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "Chiave" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "elimina" #: certauth.cpp:31 msgid "[pubkey]" msgstr "[chiave pubblica]" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" "Aggiunge una chiave pubblica. Se non viene fornita alcuna chiave verrà usata " "la chiave corrente" #: certauth.cpp:35 msgid "id" msgstr "id" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "Cancella una chiave usando il suo numero in lista" #: certauth.cpp:37 msgid "List your public keys" msgstr "Elenco delle tue chiavi pubbliche" #: certauth.cpp:39 msgid "Print your current key" msgstr "Mostra la tua chiave attuale" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "Non sei connesso con una chiave pubblica valida" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "La tua chiave pubblica corrente è: {1}" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "Non hai fornito una chiave pubblica o ti sei connesso con uno." #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "Chiave '{1}' aggiunta." #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "La chiave '{1}' è già stata aggiunta." #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "Id" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "Chiave" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "Nessuna chiave impostata per il tuo utente" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "Numero non valido, selezionare \"list\"" #: certauth.cpp:215 msgid "Removed" msgstr "Rimosso" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "" "Permette agli utenti di autenticarsi tramite certificati SSL del client." znc-1.7.5/modules/po/sample.fr_FR.po0000644000175000017500000000425213542151610017447 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/sample.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: sample.cpp:31 msgid "Sample job cancelled" msgstr "" #: sample.cpp:33 msgid "Sample job destroyed" msgstr "" #: sample.cpp:50 msgid "Sample job done" msgstr "" #: sample.cpp:65 msgid "TEST!!!!" msgstr "" #: sample.cpp:74 msgid "I'm being loaded with the arguments: {1}" msgstr "" #: sample.cpp:85 msgid "I'm being unloaded!" msgstr "" #: sample.cpp:94 msgid "You got connected BoyOh." msgstr "" #: sample.cpp:98 msgid "You got disconnected BoyOh." msgstr "" #: sample.cpp:116 msgid "{1} {2} set mode on {3} {4}{5} {6}" msgstr "" #: sample.cpp:123 msgid "{1} {2} opped {3} on {4}" msgstr "" #: sample.cpp:129 msgid "{1} {2} deopped {3} on {4}" msgstr "" #: sample.cpp:135 msgid "{1} {2} voiced {3} on {4}" msgstr "" #: sample.cpp:141 msgid "{1} {2} devoiced {3} on {4}" msgstr "" #: sample.cpp:147 msgid "* {1} sets mode: {2} {3} on {4}" msgstr "" #: sample.cpp:163 msgid "{1} kicked {2} from {3} with the msg {4}" msgstr "" #: sample.cpp:169 msgid "* {1} ({2}@{3}) quits ({4}) from channel: {6}" msgid_plural "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}" msgstr[0] "" msgstr[1] "" #: sample.cpp:177 msgid "Attempting to join {1}" msgstr "" #: sample.cpp:182 msgid "* {1} ({2}@{3}) joins {4}" msgstr "" #: sample.cpp:189 msgid "* {1} ({2}@{3}) parts {4}" msgstr "" #: sample.cpp:196 msgid "{1} invited us to {2}, ignoring invites to {2}" msgstr "" #: sample.cpp:201 msgid "{1} invited us to {2}" msgstr "" #: sample.cpp:207 msgid "{1} is now known as {2}" msgstr "" #: sample.cpp:269 sample.cpp:276 msgid "{1} changes topic on {2} to {3}" msgstr "" #: sample.cpp:317 msgid "Hi, I'm your friendly sample module." msgstr "" #: sample.cpp:330 msgid "Description of module arguments goes here." msgstr "" #: sample.cpp:333 msgid "To be used as a sample for writing modules" msgstr "" znc-1.7.5/modules/po/flooddetach.pt_BR.po0000644000175000017500000000353413542151610020454 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/flooddetach.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: flooddetach.cpp:30 msgid "Show current limits" msgstr "" #: flooddetach.cpp:32 flooddetach.cpp:35 msgid "[]" msgstr "" #: flooddetach.cpp:33 msgid "Show or set number of seconds in the time interval" msgstr "" #: flooddetach.cpp:36 msgid "Show or set number of lines in the time interval" msgstr "" #: flooddetach.cpp:39 msgid "Show or set whether to notify you about detaching and attaching back" msgstr "" #: flooddetach.cpp:93 msgid "Flood in {1} is over, reattaching..." msgstr "" #: flooddetach.cpp:150 msgid "Channel {1} was flooded, you've been detached" msgstr "" #: flooddetach.cpp:187 msgid "1 line" msgid_plural "{1} lines" msgstr[0] "" msgstr[1] "" #: flooddetach.cpp:188 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" #: flooddetach.cpp:190 msgid "Current limit is {1} {2}" msgstr "" #: flooddetach.cpp:197 msgid "Seconds limit is {1}" msgstr "" #: flooddetach.cpp:202 msgid "Set seconds limit to {1}" msgstr "" #: flooddetach.cpp:211 msgid "Lines limit is {1}" msgstr "" #: flooddetach.cpp:216 msgid "Set lines limit to {1}" msgstr "" #: flooddetach.cpp:229 msgid "Module messages are disabled" msgstr "" #: flooddetach.cpp:231 msgid "Module messages are enabled" msgstr "" #: flooddetach.cpp:247 msgid "" "This user module takes up to two arguments. Arguments are numbers of " "messages and seconds." msgstr "" #: flooddetach.cpp:251 msgid "Detach channels when flooded" msgstr "" znc-1.7.5/modules/po/nickserv.es_ES.po0000644000175000017500000000404213542151610020007 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/nickserv.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: nickserv.cpp:31 msgid "Password set" msgstr "Contraseña establecida" #: nickserv.cpp:36 nickserv.cpp:46 msgid "Done" msgstr "" #: nickserv.cpp:41 msgid "NickServ name set" msgstr "Nombre de NickServ establecido" #: nickserv.cpp:60 msgid "No such editable command. See ViewCommands for list." msgstr "Comando no encontrado. Utiliza ViewCommands para ver una lista." #: nickserv.cpp:63 msgid "Ok" msgstr "OK" #: nickserv.cpp:68 msgid "password" msgstr "Contraseña" #: nickserv.cpp:68 msgid "Set your nickserv password" msgstr "Establece tu contraseña de NickServ" #: nickserv.cpp:70 msgid "Clear your nickserv password" msgstr "Borra tu contraseña de NickServ" #: nickserv.cpp:72 msgid "nickname" msgstr "Nick" #: nickserv.cpp:73 msgid "" "Set NickServ name (Useful on networks like EpiKnet, where NickServ is named " "Themis" msgstr "" "Establece el nombre de NickServ (util en redes donde NickServ se llama de " "otra manera)" #: nickserv.cpp:77 msgid "Reset NickServ name to default (NickServ)" msgstr "Restablece el nombre de NickServ al predeterminado" #: nickserv.cpp:81 msgid "Show patterns for lines, which are being sent to NickServ" msgstr "Mostrar patrones de líneas que son enviados a NickServ" #: nickserv.cpp:83 msgid "cmd new-pattern" msgstr "cmd nuevo-patrón" #: nickserv.cpp:84 msgid "Set pattern for commands" msgstr "Establece patrones para comandos" #: nickserv.cpp:146 msgid "Please enter your nickserv password." msgstr "Por favor, introduce tu contraseña de NickServ." #: nickserv.cpp:150 msgid "Auths you with NickServ (prefer SASL module instead)" msgstr "Te autentica con NickServ (es preferible usar el módulo de SASL)" znc-1.7.5/modules/po/cert.pot0000644000175000017500000000266613542151610016321 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" # this text is inserted into `click here` in the other string #: modules/po/../data/cert/tmpl/index.tmpl:5 msgid "here" msgstr "" # {1} is `here`, translateable in the other string #: modules/po/../data/cert/tmpl/index.tmpl:6 msgid "" "You already have a certificate set, use the form below to overwrite the " "current certificate. Alternatively click {1} to delete your certificate." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:8 msgid "You do not have a certificate yet." msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:14 cert.cpp:72 msgid "Certificate" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:18 msgid "PEM File:" msgstr "" #: modules/po/../data/cert/tmpl/index.tmpl:22 msgid "Update" msgstr "" #: cert.cpp:28 msgid "Pem file deleted" msgstr "" #: cert.cpp:31 msgid "The pem file doesn't exist or there was a error deleting the pem file." msgstr "" #: cert.cpp:38 msgid "You have a certificate in {1}" msgstr "" #: cert.cpp:41 msgid "" "You do not have a certificate. Please use the web interface to add a " "certificate" msgstr "" #: cert.cpp:44 msgid "Alternatively you can either place one at {1}" msgstr "" #: cert.cpp:52 msgid "Delete the current certificate" msgstr "" #: cert.cpp:54 msgid "Show the current certificate" msgstr "" #: cert.cpp:105 msgid "Use a ssl certificate to connect to a server" msgstr "" znc-1.7.5/modules/po/crypt.id_ID.po0000644000175000017500000000504213542151610017277 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/crypt.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "" #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "" #: crypt.cpp:204 msgid "List all keys" msgstr "" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "" #: crypt.cpp:213 msgid "[Prefix]" msgstr "" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "" #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "" #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "" #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "" #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "" #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "" #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "" #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "" #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "" #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "" #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "" znc-1.7.5/modules/po/imapauth.it_IT.po0000644000175000017500000000121513542151610020004 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/imapauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "[ server [+]porta [ UserFormatString ] ]" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "Permette agli utenti di autenticarsi tramite IMAP." znc-1.7.5/modules/po/listsockets.fr_FR.po0000644000175000017500000000431213542151610020532 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/listsockets.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "" #: listsockets.cpp:62 msgid "[-n]" msgstr "" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "" #: listsockets.cpp:96 msgid "List sockets" msgstr "" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "" #: listsockets.cpp:142 msgid "Listener" msgstr "" #: listsockets.cpp:144 msgid "Inbound" msgstr "" #: listsockets.cpp:147 msgid "Outbound" msgstr "" #: listsockets.cpp:149 msgid "Connecting" msgstr "" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "" #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "" znc-1.7.5/modules/po/webadmin.pt_BR.po0000644000175000017500000007675513542151610020005 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/webadmin.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:12 msgid "Channel Info" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:17 msgid "Channel Name:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:19 msgid "The channel name." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:24 msgid "Key:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:26 msgid "The password of the channel, if there is one." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:30 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:241 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:260 msgid "Buffer Size:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:32 msgid "The buffer count." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:36 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:235 msgid "Default Modes:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:38 msgid "The default modes of the channel." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:270 msgid "Flags" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:51 msgid "Save to config" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:282 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:410 msgid "Module {1}" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:75 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:290 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:419 msgid "Save and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:76 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:291 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:420 msgid "Save and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:78 msgid "Add Channel and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_chan.tmpl:79 msgid "Add Channel and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:8 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 msgid "<password>" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:11 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:12 msgid "<network>" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:14 msgid "" "To connect to this network from your IRC client, you can set the server " "password field as {1} or username field as {2}" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:24 msgid "Network Info" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:25 msgid "" "Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value " "from the user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:29 msgid "Network Name:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:31 msgid "The name of the IRC network." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:35 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:69 msgid "Nickname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:37 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:71 msgid "Your nickname on IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:40 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:74 msgid "Alt. Nickname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:42 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:76 msgid "Your secondary nickname, if the first is not available on IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:46 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:80 msgid "Ident:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:48 msgid "Your ident." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:51 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:91 msgid "Realname:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:53 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:93 msgid "Your real name." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:58 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:99 msgid "BindHost:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:65 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:112 msgid "Quit Message:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:67 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:114 msgid "You may define a Message shown, when you quit IRC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:71 msgid "Active:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:73 msgid "Connect to IRC & automatically re-connect" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:77 msgid "Trust all certs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:79 msgid "" "Disable certificate validation (takes precedence over TrustPKI). INSECURE!" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:83 msgid "Trust the PKI:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:85 msgid "" "Setting this to false will trust only certificates you added fingerprints " "for." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:89 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:96 msgid "Servers of this IRC network:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:93 msgid "One server per line, “host [[+]port] [password]â€, + means SSL" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:101 msgid "Hostname" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:102 #: modules/po/../data/webadmin/tmpl/settings.tmpl:13 msgid "Port" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:103 #: modules/po/../data/webadmin/tmpl/settings.tmpl:15 msgid "SSL" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:104 msgid "Password" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:116 msgid "SHA-256 fingerprints of trusted SSL certificates of this IRC network:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:120 msgid "" "When these certificates are encountered, checks for hostname, expiration " "date, CA are skipped" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:124 msgid "Flood protection:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:127 msgid "" "You might enable the flood protection. This prevents “excess flood†errors, " "which occur, when your IRC bot is command flooded or spammed. After changing " "this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:130 msgctxt "Flood Protection" msgid "Enabled" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:134 msgid "Flood protection rate:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:137 msgid "" "The number of seconds per line. After changing this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:140 msgid "{1} seconds per line" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:144 msgid "Flood protection burst:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:147 msgid "" "Defines the number of lines, which can be sent immediately. After changing " "this, reconnect ZNC to server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:150 msgid "{1} lines can be sent immediately" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:154 msgid "Channel join delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:157 msgid "" "Defines the delay in seconds, until channels are joined after getting " "connected." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:160 msgid "{1} seconds" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:165 msgid "Character encoding used between ZNC and IRC server." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:166 msgid "Server encoding:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:176 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:231 msgid "Channels" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:178 msgid "" "You will be able to add + modify channels here after you created the network." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:185 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:129 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:354 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:15 #: modules/po/../data/webadmin/tmpl/settings.tmpl:72 msgid "Add" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:187 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:430 #: modules/po/../data/webadmin/tmpl/settings.tmpl:237 msgid "Save" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:188 #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:228 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:131 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:174 #: modules/po/../data/webadmin/tmpl/settings.tmpl:176 msgid "Name" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:189 msgid "CurModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:190 msgid "DefModes" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:191 msgid "BufferSize" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:192 msgid "Options" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:194 msgid "↠Add a channel (opens in same page)" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:27 msgid "Edit" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:204 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:146 #: modules/po/../data/webadmin/tmpl/settings.tmpl:53 msgid "Del" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:222 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:168 msgid "Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:229 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:175 #: modules/po/../data/webadmin/tmpl/settings.tmpl:177 msgid "Arguments" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:230 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:176 #: modules/po/../data/webadmin/tmpl/settings.tmpl:178 msgid "Description" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:231 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:177 msgid "Loaded globally" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:232 msgid "Loaded by user" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:293 msgid "Add Network and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_network.tmpl:294 msgid "Add Network and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:15 msgid "Authentication" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:19 msgid "Username:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:29 msgid "Please enter a username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:34 msgid "Password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:36 msgid "Please enter a password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:39 msgid "Confirm password:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:41 msgid "Please re-type the above password." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:44 #: modules/po/../data/webadmin/tmpl/settings.tmpl:151 msgid "Auth Only Via Module:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:46 msgid "" "Allow user authentication by external modules only, disabling built-in " "password authentication." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:50 msgid "Allowed IPs:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:54 msgid "" "Leave empty to allow connections from all IPs.
Otherwise, one entry per " "line, wildcards * and ? are available." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:62 msgid "IRC Information" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:64 msgid "" "Nick, AltNick, Ident, RealName and QuitMsg can be left empty to use default " "values." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:82 msgid "The Ident is sent to server as username." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:85 #: modules/po/../data/webadmin/tmpl/settings.tmpl:102 msgid "Status Prefix:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:87 #: modules/po/../data/webadmin/tmpl/settings.tmpl:104 msgid "The prefix for the status and module queries." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:105 msgid "DCCBindHost:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:122 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:17 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:39 msgid "Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:132 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:18 msgid "Clients" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:133 msgid "Current Server" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:134 msgid "Nick" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:136 msgid "↠Add a network (opens in same page)" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:160 msgid "" "You will be able to add + modify networks here after you have cloned the " "user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:162 msgid "" "You will be able to add + modify networks here after you have created the " "user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:178 #: modules/po/../data/webadmin/tmpl/settings.tmpl:179 msgid "Loaded by networks" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:237 msgid "" "These are the default modes ZNC will set when you join an empty channel." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:238 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:244 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:263 msgid "Empty = use standard value" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:243 msgid "" "This is the amount of lines that the playback buffer will store for channels " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:251 msgid "Queries" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:255 msgid "Max Buffers:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:257 msgid "Maximum number of query buffers. 0 is unlimited." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:262 msgid "" "This is the amount of lines that the playback buffer will store for queries " "before dropping off the oldest line. The buffers are stored in the memory by " "default." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:285 msgid "ZNC Behavior" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:286 msgid "" "Any of the following text boxes can be left empty to use their default value." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:290 msgid "Timestamp Format:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:292 msgid "" "The format for the timestamps used in buffers, for example [%H:%M:%S]. This " "setting is ignored in new IRC clients, which use server-time. If your client " "supports server-time, change timestamp format in client settings instead." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:295 msgid "Timezone:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:298 msgid "E.g. Europe/Berlin, or GMT-6" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:306 msgid "Character encoding used between IRC client and ZNC." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:307 msgid "Client encoding:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:312 msgid "Join Tries:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:314 msgid "" "This defines how many times ZNC tries to join a channel, if the first join " "failed, e.g. due to channel mode +i/+k or if you are banned." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:317 msgid "Join speed:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:319 msgid "" "How many channels are joined in one JOIN command. 0 is unlimited (default). " "Set to small positive value if you get disconnected with “Max SendQ Exceededâ€" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:322 msgid "Timeout before reconnect:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:324 msgid "" "How much time ZNC waits (in seconds) until it receives something from " "network or declares the connection timeout. This happens after attempts to " "ping the peer." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:327 msgid "Max IRC Networks Number:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:329 msgid "Maximum number of IRC networks allowed for this user." msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:332 msgid "Substitutions" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:334 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:342 msgid "CTCP Replies:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:338 msgid "One reply per line. Example: TIME Buy a watch!" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:339 #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:355 msgid "{1} are available" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:341 msgid "Empty value means this CTCP request will be ignored" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:347 msgid "Request" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:348 msgid "Response" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:373 #: modules/po/../data/webadmin/tmpl/settings.tmpl:90 msgid "Skin:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:377 msgid "- Global -" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:379 #: modules/po/../data/webadmin/tmpl/settings.tmpl:94 msgid "Default" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:383 msgid "No other skins found" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:389 msgid "Language:" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:422 msgid "Clone and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:423 msgid "Clone and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:425 msgid "Create and return" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:426 msgid "Create and continue" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:432 #: modules/po/../data/webadmin/tmpl/listusers.tmpl:28 msgid "Clone" msgstr "" #: modules/po/../data/webadmin/tmpl/add_edit_user.tmpl:434 msgid "Create" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:5 msgid "Confirm Network Deletion" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:9 msgid "Are you sure you want to delete network “{2}†of user “{1}â€?" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:14 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:14 msgid "Yes" msgstr "" #: modules/po/../data/webadmin/tmpl/del_network.tmpl:17 #: modules/po/../data/webadmin/tmpl/del_user.tmpl:17 msgid "No" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:5 msgid "Confirm User Deletion" msgstr "" #: modules/po/../data/webadmin/tmpl/del_user.tmpl:9 msgid "Are you sure you want to delete user “{1}â€?" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:6 msgid "ZNC is compiled without encodings support. {1} is required for it." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:11 msgid "Legacy mode is disabled by modpython." msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:18 msgid "Don't ensure any encoding at all (legacy mode, not recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:22 msgid "Try to parse as UTF-8 and as {1}, send as UTF-8 (recommended)" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:26 msgid "Try to parse as UTF-8 and as {1}, send as {1}" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:30 msgid "Parse and send as {1} only" msgstr "" #: modules/po/../data/webadmin/tmpl/encoding_settings.tmpl:36 msgid "E.g. UTF-8, or ISO-8859-15" msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:5 msgid "Welcome to the ZNC webadmin module." msgstr "" #: modules/po/../data/webadmin/tmpl/index.tmpl:6 msgid "" "All changes you make will be in effect immediately after you submitted them." msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:16 msgid "Username" msgstr "" #: modules/po/../data/webadmin/tmpl/listusers.tmpl:29 #: modules/po/../data/webadmin/tmpl/settings.tmpl:21 msgid "Delete" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:6 msgid "Listen Port(s)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:14 msgid "BindHost" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:16 msgid "IPv4" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:17 msgid "IPv6" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:18 msgid "IRC" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:19 msgid "HTTP" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:20 msgid "URIPrefix" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "" "To delete port which you use to access webadmin itself, either connect to " "webadmin via another port, or do it in IRC (/znc DelPort)" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:56 msgid "Current" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:86 msgid "Settings" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:105 msgid "Default for new users only." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:110 msgid "Maximum Buffer Size:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:112 msgid "Sets the global Max Buffer Size a user can have." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:117 msgid "Connect Delay:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:119 msgid "" "The time between connection attempts to IRC servers, in seconds. This " "affects the connection between ZNC and the IRC server; not the connection " "between your IRC client and ZNC." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:124 msgid "Server Throttle:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:126 msgid "" "The minimal time between two connect attempts to the same hostname, in " "seconds. Some servers refuse your connection if you reconnect too fast." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:131 msgid "Anonymous Connection Limit per IP:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:133 msgid "Limits the number of unidentified connections per IP." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:138 msgid "Protect Web Sessions:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:140 msgid "Disallow IP changing during each web session" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:145 msgid "Hide ZNC Version:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:147 msgid "Hide version number from non-ZNC users" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:153 msgid "Allow user authentication by external modules only" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:158 msgid "MOTD:" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:162 msgid "“Message of the Dayâ€, sent to all ZNC users on connect." msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:170 msgid "Global Modules" msgstr "" #: modules/po/../data/webadmin/tmpl/settings.tmpl:180 msgid "Loaded by users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:7 msgid "Information" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:13 msgid "Uptime" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:18 msgid "Total Users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:22 msgid "Total Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:26 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:43 msgid "Attached Networks" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:30 msgid "Total Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:34 msgid "Total IRC Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:47 msgid "Client Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:51 msgid "IRC Connections" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:63 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:72 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:89 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:117 msgid "Total" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:70 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:115 msgctxt "Traffic" msgid "In" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:71 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:116 msgctxt "Traffic" msgid "Out" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:77 #: modules/po/../data/webadmin/tmpl/traffic.tmpl:104 msgid "Users" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:106 msgid "Traffic" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:113 msgid "User" msgstr "" #: modules/po/../data/webadmin/tmpl/traffic.tmpl:114 msgid "Network" msgstr "" #: webadmin.cpp:91 webadmin.cpp:1872 msgid "Global Settings" msgstr "" #: webadmin.cpp:93 msgid "Your Settings" msgstr "" #: webadmin.cpp:94 webadmin.cpp:1684 msgid "Traffic Info" msgstr "" #: webadmin.cpp:97 webadmin.cpp:1663 msgid "Manage Users" msgstr "" #: webadmin.cpp:188 msgid "Invalid Submission [Username is required]" msgstr "" #: webadmin.cpp:201 msgid "Invalid Submission [Passwords do not match]" msgstr "" #: webadmin.cpp:323 msgid "Timeout can't be less than 30 seconds!" msgstr "" #: webadmin.cpp:407 webadmin.cpp:435 webadmin.cpp:1182 webadmin.cpp:2057 msgid "Unable to load module [{1}]: {2}" msgstr "" #: webadmin.cpp:412 webadmin.cpp:440 msgid "Unable to load module [{1}] with arguments [{2}]" msgstr "" #: webadmin.cpp:521 webadmin.cpp:625 webadmin.cpp:650 webadmin.cpp:672 #: webadmin.cpp:706 webadmin.cpp:1249 msgid "No such user" msgstr "" #: webadmin.cpp:534 webadmin.cpp:566 webadmin.cpp:595 webadmin.cpp:611 msgid "No such user or network" msgstr "" #: webadmin.cpp:576 msgid "No such channel" msgstr "" #: webadmin.cpp:642 msgid "Please don't delete yourself, suicide is not the answer!" msgstr "" #: webadmin.cpp:715 webadmin.cpp:972 webadmin.cpp:1314 msgid "Edit User [{1}]" msgstr "" #: webadmin.cpp:719 webadmin.cpp:906 msgid "Edit Network [{1}]" msgstr "" #: webadmin.cpp:729 msgid "Edit Channel [{1}] of Network [{2}] of User [{3}]" msgstr "" #: webadmin.cpp:736 msgid "Edit Channel [{1}]" msgstr "" #: webadmin.cpp:744 msgid "Add Channel to Network [{1}] of User [{2}]" msgstr "" #: webadmin.cpp:749 msgid "Add Channel" msgstr "" #: webadmin.cpp:756 webadmin.cpp:1510 msgid "Auto Clear Chan Buffer" msgstr "" #: webadmin.cpp:758 msgid "Automatically Clear Channel Buffer After Playback" msgstr "" #: webadmin.cpp:766 msgid "Detached" msgstr "" #: webadmin.cpp:773 msgid "Enabled" msgstr "" #: webadmin.cpp:797 msgid "Channel name is a required argument" msgstr "" #: webadmin.cpp:806 msgid "Channel [{1}] already exists" msgstr "" #: webadmin.cpp:813 msgid "Could not add channel [{1}]" msgstr "" #: webadmin.cpp:861 msgid "Channel was added/modified, but config file was not written" msgstr "" #: webadmin.cpp:888 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks from Your Settings." msgstr "" #: webadmin.cpp:903 msgid "Edit Network [{1}] of User [{2}]" msgstr "" #: webadmin.cpp:910 msgid "Add Network for User [{1}]" msgstr "" #: webadmin.cpp:911 msgid "Add Network" msgstr "" #: webadmin.cpp:1073 msgid "Network name is a required argument" msgstr "" #: webadmin.cpp:1189 webadmin.cpp:2064 msgid "Unable to reload module [{1}]: {2}" msgstr "" #: webadmin.cpp:1226 msgid "Network was added/modified, but config file was not written" msgstr "" #: webadmin.cpp:1255 msgid "That network doesn't exist for this user" msgstr "" #: webadmin.cpp:1272 msgid "Network was deleted, but config file was not written" msgstr "" #: webadmin.cpp:1286 msgid "That channel doesn't exist for this network" msgstr "" #: webadmin.cpp:1295 msgid "Channel was deleted, but config file was not written" msgstr "" #: webadmin.cpp:1323 msgid "Clone User [{1}]" msgstr "" #: webadmin.cpp:1512 msgid "" "Automatically Clear Channel Buffer After Playback (the default value for new " "channels)" msgstr "" #: webadmin.cpp:1522 msgid "Multi Clients" msgstr "" #: webadmin.cpp:1529 msgid "Append Timestamps" msgstr "" #: webadmin.cpp:1536 msgid "Prepend Timestamps" msgstr "" #: webadmin.cpp:1544 msgid "Deny LoadMod" msgstr "" #: webadmin.cpp:1551 msgid "Admin" msgstr "" #: webadmin.cpp:1561 msgid "Deny SetBindHost" msgstr "" #: webadmin.cpp:1569 msgid "Auto Clear Query Buffer" msgstr "" #: webadmin.cpp:1571 msgid "Automatically Clear Query Buffer After Playback" msgstr "" #: webadmin.cpp:1595 msgid "Invalid Submission: User {1} already exists" msgstr "" #: webadmin.cpp:1617 webadmin.cpp:1628 msgid "Invalid submission: {1}" msgstr "" #: webadmin.cpp:1623 msgid "User was added, but config file was not written" msgstr "" #: webadmin.cpp:1634 msgid "User was edited, but config file was not written" msgstr "" #: webadmin.cpp:1792 msgid "Choose either IPv4 or IPv6 or both." msgstr "" #: webadmin.cpp:1809 msgid "Choose either IRC or HTTP or both." msgstr "" #: webadmin.cpp:1822 webadmin.cpp:1858 msgid "Port was changed, but config file was not written" msgstr "" #: webadmin.cpp:1848 msgid "Invalid request." msgstr "" #: webadmin.cpp:1862 msgid "The specified listener was not found." msgstr "" #: webadmin.cpp:2093 msgid "Settings were changed, but config file was not written" msgstr "" znc-1.7.5/modules/po/autovoice.pt_BR.po0000644000175000017500000000422213542151610020171 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/autovoice.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: autovoice.cpp:120 msgid "List all users" msgstr "" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr "" #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "" #: autovoice.cpp:128 msgid " [channels]" msgstr "" #: autovoice.cpp:129 msgid "Adds a user" msgstr "" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "" #: autovoice.cpp:238 msgid "There are no users defined" msgstr "" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "" #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "" #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "" #: autovoice.cpp:341 msgid "That user already exists" msgstr "" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "" znc-1.7.5/modules/po/adminlog.ru_RU.po0000644000175000017500000000275213542151610020021 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/adminlog.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "" #: adminlog.cpp:31 msgid " [path]" msgstr "" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "" #: adminlog.cpp:142 msgid "Access denied" msgstr "" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "" #: adminlog.cpp:170 msgid "Unknown target" msgstr "" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "" znc-1.7.5/modules/po/shell.bg_BG.po0000644000175000017500000000125013542151610017232 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/shell.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "" #: shell.cpp:169 msgid "Gives shell access" msgstr "" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "" znc-1.7.5/modules/po/sasl.ru_RU.po0000644000175000017500000000700013542151610017160 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/sasl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" #: sasl.cpp:62 msgid "search" msgstr "" #: sasl.cpp:62 msgid "Generate this output" msgstr "" #: sasl.cpp:64 msgid "[ []]" msgstr "" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "" #: sasl.cpp:72 msgid "[yes|no]" msgstr "" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "" #: sasl.cpp:114 msgid "Password was supplied" msgstr "" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "" #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "" #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "" #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "" #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "" znc-1.7.5/modules/po/clearbufferonmsg.pot0000644000175000017500000000033013542151610020672 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: clearbufferonmsg.cpp:160 msgid "Clears all channel and query buffers whenever the user does something" msgstr "" znc-1.7.5/modules/po/missingmotd.pot0000644000175000017500000000026113542151610017706 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: missingmotd.cpp:36 msgid "Sends 422 to clients when they login" msgstr "" znc-1.7.5/modules/po/cyrusauth.de_DE.po0000644000175000017500000000510313542151610020153 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/cyrusauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "Zeige aktuelle Einstellungen an" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "yes|clone |no" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" "Lege ZNC-Benutzer bei erster erfolgreicher Anmeldung an, optional von einer " "Vorlage" #: cyrusauth.cpp:56 msgid "Access denied" msgstr "Zugriff verweigert" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "Ignoriere ungültige SASL pwcheck-Methode: {1}" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "Ungültige SASL pwcheck-Methode ignorriert" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "Benötig eine pwcheck-Methode als Argument (saslauthd, auxprop)" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "SASL Konnte Nicht Initialisiert Werden - Stoppe Start" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "Wir werden keine Benutzer bei ihrer ersten Anmeldung anlegen" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" "Wir werden Benutzer bei ihrer ersten Anmeldung anlegen, wobei Benutzer [{1}] " "als Vorlage verwendet wird" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "Wir werden Benutzer bei ihrer ersten Anmeldung anlegen" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "" "Verwendung: CreateUsers yes, CreateUser no, oder CreateUser clone " "" #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" "Dieses globale Module nimmt bis zu zwei Argumente - die " "Authentifizierungsmethoden - auxprop und saslauthd" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" "Erlaube es Benutzern sich über die SASL Passwordüberprüfungsmethode zu " "authentifizieren" znc-1.7.5/modules/po/cyrusauth.pt_BR.po0000644000175000017500000000333713542151610020230 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/cyrusauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: cyrusauth.cpp:42 msgid "Shows current settings" msgstr "" #: cyrusauth.cpp:44 msgid "yes|clone |no" msgstr "" #: cyrusauth.cpp:45 msgid "" "Create ZNC users upon first successful login, optionally from a template" msgstr "" #: cyrusauth.cpp:56 msgid "Access denied" msgstr "" #: cyrusauth.cpp:70 msgid "Ignoring invalid SASL pwcheck method: {1}" msgstr "" #: cyrusauth.cpp:71 msgid "Ignored invalid SASL pwcheck method" msgstr "" #: cyrusauth.cpp:79 msgid "Need a pwcheck method as argument (saslauthd, auxprop)" msgstr "" #: cyrusauth.cpp:84 msgid "SASL Could Not Be Initialized - Halting Startup" msgstr "" #: cyrusauth.cpp:171 cyrusauth.cpp:186 msgid "We will not create users on their first login" msgstr "" #: cyrusauth.cpp:174 cyrusauth.cpp:195 msgid "" "We will create users on their first login, using user [{1}] as a template" msgstr "" #: cyrusauth.cpp:177 cyrusauth.cpp:190 msgid "We will create users on their first login" msgstr "" #: cyrusauth.cpp:199 msgid "Usage: CreateUsers yes, CreateUsers no, or CreateUsers clone " msgstr "" #: cyrusauth.cpp:232 msgid "" "This global module takes up to two arguments - the methods of authentication " "- auxprop and saslauthd" msgstr "" #: cyrusauth.cpp:238 msgid "Allow users to authenticate via SASL password verification method" msgstr "" znc-1.7.5/modules/po/chansaver.pt_BR.po0000644000175000017500000000077713542151610020160 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/chansaver.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: chansaver.cpp:91 msgid "Keeps config up-to-date when user joins/parts." msgstr "" znc-1.7.5/modules/po/identfile.ru_RU.po0000644000175000017500000000330713542151610020167 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/identfile.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: identfile.cpp:30 msgid "Show file name" msgstr "" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "" #: identfile.cpp:34 msgid "Show file format" msgstr "" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "" #: identfile.cpp:38 msgid "Show current state" msgstr "" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "" #: identfile.cpp:78 msgid "identfile is free" msgstr "" #: identfile.cpp:86 msgid "Access denied" msgstr "" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "" #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "" znc-1.7.5/modules/po/modpython.bg_BG.po0000644000175000017500000000074613542151610020155 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/modpython.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/modperl.ru_RU.po0000644000175000017500000000130713542151610017664 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/modperl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "Загружает perl-Ñкрипты как модуль ZNC" znc-1.7.5/modules/po/simple_away.pot0000644000175000017500000000325513542151610017671 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: simple_away.cpp:56 msgid "[]" msgstr "" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "" #: simple_away.cpp:136 msgid "Away reason set" msgstr "" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" znc-1.7.5/modules/po/stickychan.id_ID.po0000644000175000017500000000364413542151610020304 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/stickychan.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "" #: stickychan.cpp:30 msgid "<#channel>" msgstr "" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "" #: stickychan.cpp:101 msgid " -- End of List" msgstr "" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "" #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "" #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" znc-1.7.5/modules/po/identfile.pt_BR.po0000644000175000017500000000305513542151610020141 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/identfile.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: identfile.cpp:30 msgid "Show file name" msgstr "" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "" #: identfile.cpp:34 msgid "Show file format" msgstr "" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "" #: identfile.cpp:38 msgid "Show current state" msgstr "" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "" #: identfile.cpp:78 msgid "identfile is free" msgstr "" #: identfile.cpp:86 msgid "Access denied" msgstr "" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "" #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "" znc-1.7.5/modules/po/log.fr_FR.po0000644000175000017500000000501013542151610016740 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/log.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: log.cpp:59 msgid "" msgstr "" #: log.cpp:60 msgid "Set logging rules, use !#chan or !query to negate and * " msgstr "" #: log.cpp:62 msgid "Clear all logging rules" msgstr "" #: log.cpp:64 msgid "List all logging rules" msgstr "" #: log.cpp:67 msgid " true|false" msgstr "" #: log.cpp:68 msgid "Set one of the following options: joins, quits, nickchanges" msgstr "" #: log.cpp:71 msgid "Show current settings set by Set command" msgstr "" #: log.cpp:143 msgid "Usage: SetRules " msgstr "" #: log.cpp:144 msgid "Wildcards are allowed" msgstr "" #: log.cpp:156 log.cpp:178 msgid "No logging rules. Everything is logged." msgstr "" #: log.cpp:161 msgid "1 rule removed: {2}" msgid_plural "{1} rules removed: {2}" msgstr[0] "" msgstr[1] "" #: log.cpp:168 log.cpp:173 msgctxt "listrules" msgid "Rule" msgstr "" #: log.cpp:169 log.cpp:174 msgctxt "listrules" msgid "Logging enabled" msgstr "" #: log.cpp:189 msgid "" "Usage: Set true|false, where is one of: joins, quits, nickchanges" msgstr "" #: log.cpp:196 msgid "Will log joins" msgstr "" #: log.cpp:196 msgid "Will not log joins" msgstr "" #: log.cpp:197 msgid "Will log quits" msgstr "" #: log.cpp:197 msgid "Will not log quits" msgstr "" #: log.cpp:199 msgid "Will log nick changes" msgstr "" #: log.cpp:199 msgid "Will not log nick changes" msgstr "" #: log.cpp:203 msgid "Unknown variable. Known variables: joins, quits, nickchanges" msgstr "" #: log.cpp:211 msgid "Logging joins" msgstr "" #: log.cpp:211 msgid "Not logging joins" msgstr "" #: log.cpp:212 msgid "Logging quits" msgstr "" #: log.cpp:212 msgid "Not logging quits" msgstr "" #: log.cpp:213 msgid "Logging nick changes" msgstr "" #: log.cpp:214 msgid "Not logging nick changes" msgstr "" #: log.cpp:351 msgid "" "Invalid args [{1}]. Only one log path allowed. Check that there are no " "spaces in the path." msgstr "" #: log.cpp:401 msgid "Invalid log path [{1}]" msgstr "" #: log.cpp:404 msgid "Logging to [{1}]. Using timestamp format '{2}'" msgstr "" #: log.cpp:559 msgid "[-sanitize] Optional path where to store logs." msgstr "" #: log.cpp:563 msgid "Writes IRC logs." msgstr "" znc-1.7.5/modules/po/buffextras.it_IT.po0000644000175000017500000000225713542151610020354 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/buffextras.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: buffextras.cpp:45 msgid "Server" msgstr "Server" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "{1} imposta i mode: {2} {3}" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "{1} kicked {2} per questo motivo: {3}" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "{1} lascia: {2}" #: buffextras.cpp:73 msgid "{1} joined" msgstr "{1} è entrato" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "{1} esce da: {2}" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "{1} è ora conosciuto come {2}" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "{1} ha cambiato il topic in: {2}" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "Aggiunge joins, parts ecc. al buffer del playback" znc-1.7.5/modules/po/listsockets.pot0000644000175000017500000000362513542151610017727 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "" #: listsockets.cpp:62 msgid "[-n]" msgstr "" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "" #: listsockets.cpp:96 msgid "List sockets" msgstr "" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "" #: listsockets.cpp:142 msgid "Listener" msgstr "" #: listsockets.cpp:144 msgid "Inbound" msgstr "" #: listsockets.cpp:147 msgid "Outbound" msgstr "" #: listsockets.cpp:149 msgid "Connecting" msgstr "" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "" #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "" znc-1.7.5/modules/po/adminlog.it_IT.po0000644000175000017500000000351713542151610017775 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/adminlog.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "Mostra il percorso in cui vengono salvati i logging" #: adminlog.cpp:31 msgid " [path]" msgstr " [percorso]" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "Imposta il percorso in cui vengono salvati i logging" #: adminlog.cpp:142 msgid "Access denied" msgstr "Accesso negato" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "Adesso logging su file" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "Ora logging solo su syslog" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "Adesso logging su syslog e file" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "Utilizzo: Target [path]" #: adminlog.cpp:170 msgid "Unknown target" msgstr "Target sconosciuto. Puoi scegliere fra: file|syslog|both" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "Il logging è abilitato per i file" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "Il logging è abilitato per il syslog" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "Il logging è abilitato per entrambi, file e syslog" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "I file di Log verranno scritti in {1}" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "Logga gli eventi della ZNC su file e/o syslog." znc-1.7.5/modules/po/samplewebapi.pt_BR.po0000644000175000017500000000075513542151610020653 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/samplewebapi.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "" znc-1.7.5/modules/po/blockuser.ru_RU.po0000644000175000017500000000374113542151610020217 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/blockuser.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "" #: blockuser.cpp:29 msgid "List blocked users" msgstr "" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "" #: blockuser.cpp:76 msgid "Access denied" msgstr "" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "" #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "" #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "" #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "" znc-1.7.5/modules/po/keepnick.fr_FR.po0000644000175000017500000000217613542151610017762 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/keepnick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: keepnick.cpp:39 msgid "Try to get your primary nick" msgstr "" #: keepnick.cpp:42 keepnick.cpp:196 msgid "No longer trying to get your primary nick" msgstr "" #: keepnick.cpp:44 msgid "Show the current state" msgstr "" #: keepnick.cpp:158 msgid "ZNC is already trying to get this nickname" msgstr "" #: keepnick.cpp:173 msgid "Unable to obtain nick {1}: {2}, {3}" msgstr "" #: keepnick.cpp:181 msgid "Unable to obtain nick {1}" msgstr "" #: keepnick.cpp:191 msgid "Trying to get your primary nick" msgstr "" #: keepnick.cpp:201 msgid "Currently trying to get your primary nick" msgstr "" #: keepnick.cpp:203 msgid "Currently disabled, try 'enable'" msgstr "" #: keepnick.cpp:224 msgid "Keeps trying for your primary nick" msgstr "" znc-1.7.5/modules/po/blockuser.de_DE.po0000644000175000017500000000467613542151610020133 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/blockuser.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/blockuser/tmpl/blockuser_WebadminUser.tmpl:9 msgid "Account is blocked" msgstr "Konto ist gesperrt" #: blockuser.cpp:23 msgid "Your account has been disabled. Contact your administrator." msgstr "Dein Konto wurde deaktiviert. Kontaktiere deinen Administrator." #: blockuser.cpp:29 msgid "List blocked users" msgstr "Liste gesperrter Benutzer" #: blockuser.cpp:31 blockuser.cpp:33 msgid "" msgstr "" #: blockuser.cpp:31 msgid "Block a user" msgstr "Sperre einen Nutzer" #: blockuser.cpp:33 msgid "Unblock a user" msgstr "Entsperre einen Benutzer" #: blockuser.cpp:55 msgid "Could not block {1}" msgstr "Konnte {1} nicht sperren" #: blockuser.cpp:76 msgid "Access denied" msgstr "Zugriff verweigert" #: blockuser.cpp:85 msgid "No users are blocked" msgstr "Keine Benutzer sind gesperrt" #: blockuser.cpp:88 msgid "Blocked users:" msgstr "Gesperrte Benutzer:" #: blockuser.cpp:100 msgid "Usage: Block " msgstr "Verwendung: Block " #: blockuser.cpp:105 blockuser.cpp:147 msgid "You can't block yourself" msgstr "Du kannst dich nicht selbst blockieren" #: blockuser.cpp:110 blockuser.cpp:152 msgid "Blocked {1}" msgstr "{1} gesperrt" #: blockuser.cpp:112 msgid "Could not block {1} (misspelled?)" msgstr "Konnte {1} nicht blockieren (falsch geschrieben?)" #: blockuser.cpp:120 msgid "Usage: Unblock " msgstr "Verwendung: Unblock " #: blockuser.cpp:125 blockuser.cpp:161 msgid "Unblocked {1}" msgstr "{1} entsperrt" #: blockuser.cpp:127 msgid "This user is not blocked" msgstr "Dieser Benutzer ist nicht blockiert" #: blockuser.cpp:155 msgid "Couldn't block {1}" msgstr "Konnte {1} nicht sperren" #: blockuser.cpp:164 msgid "User {1} is not blocked" msgstr "Benutzer {1} ist nicht blockiert" #: blockuser.cpp:216 msgid "Enter one or more user names. Separate them by spaces." msgstr "Einen oder mehrere Benutzernamen durch Leerzeichen getrennt eingeben." #: blockuser.cpp:219 msgid "Block certain users from logging in." msgstr "Blockiere bestimmter Benutzer, so dass sie sich nicht anmelden können." znc-1.7.5/modules/po/savebuff.id_ID.po0000644000175000017500000000250013542151610017733 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/savebuff.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "" znc-1.7.5/modules/po/dcc.bg_BG.po0000644000175000017500000001007713542151610016663 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/dcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: dcc.cpp:88 msgid " " msgstr "" #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "" #: dcc.cpp:91 msgid "" msgstr "" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "" #: dcc.cpp:94 msgid "List current transfers" msgstr "" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "" #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "" #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "" #: dcc.cpp:179 msgid "Usage: Send " msgstr "" #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "" #: dcc.cpp:199 msgid "Usage: Get " msgstr "" #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "" #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "" #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "" #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "" #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "" #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "" #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "" #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "" #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "" #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "" #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "" #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "" #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "" #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "" #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "" #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "" #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "" znc-1.7.5/modules/po/perleval.pot0000644000175000017500000000053613542151610017170 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: perleval.pm:23 msgid "Evaluates perl code" msgstr "" #: perleval.pm:33 msgid "Only admin can load this module" msgstr "" #: perleval.pm:44 #, perl-format msgid "Error: %s" msgstr "" #: perleval.pm:46 #, perl-format msgid "Result: %s" msgstr "" znc-1.7.5/modules/po/perform.pot0000644000175000017500000000327713542151610017035 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "" #: perform.cpp:24 msgid "Usage: add " msgstr "" #: perform.cpp:29 msgid "Added!" msgstr "" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "" #: perform.cpp:41 msgid "Command Erased." msgstr "" #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "" #: perform.cpp:73 msgid "perform commands sent" msgstr "" #: perform.cpp:86 msgid "Commands Swapped." msgstr "" #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "" #: perform.cpp:100 msgid "List the perform commands" msgstr "" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "" #: perform.cpp:105 msgid " " msgstr "" #: perform.cpp:106 msgid "Swap two perform commands" msgstr "" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "" znc-1.7.5/modules/po/modpython.es_ES.po0000644000175000017500000000102313542151610020200 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/modpython.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "Carga scripts de python como módulos de ZNC" znc-1.7.5/modules/po/autoreply.nl_NL.po0000644000175000017500000000233013542151610020211 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/autoreply.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "Stelt een nieuw antwoord in" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "Laat het huidige antwoord zien" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "Huidige antwoord is: {1} ({2})" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "Nieuw antwoord is ingesteld op: {1} ({2})" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" "Je kan een automatisch antwoord instellen die gebruikt wordt als je niet " "verbonden bent met ZNC." #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "Antwoord op privé berichten wanneer je afwezig bent" znc-1.7.5/modules/po/perform.nl_NL.po0000644000175000017500000000520513542151610017643 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/perform.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "Uitvoeren" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "Voer commando's uit:" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "" "Commando's verstuurd naar de IRC server bij het verbinden, één per regel." #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "Opslaan" #: perform.cpp:24 msgid "Usage: add " msgstr "Gebruik: add " #: perform.cpp:29 msgid "Added!" msgstr "Toegevoegd!" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "Ongeldig # aangevraagd" #: perform.cpp:41 msgid "Command Erased." msgstr "Commando verwijderd." #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "Id" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "Uitvoeren" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "Uitgebreid" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "Geen commando's in je uitvoerlijst." #: perform.cpp:73 msgid "perform commands sent" msgstr "Uitvoer commando's gestuurd" #: perform.cpp:86 msgid "Commands Swapped." msgstr "Commando's omgewisseld." #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "" "Voegt commando's toe om uit te voeren wanneer er verbinding gemaakt is met " "de server" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "Verwijder een uitvoercommando" #: perform.cpp:100 msgid "List the perform commands" msgstr "Laat de uitvoercommando's zien" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "Stuur de uitvoercommando's nu naar de server" #: perform.cpp:105 msgid " " msgstr " " #: perform.cpp:106 msgid "Swap two perform commands" msgstr "Wissel twee uitvoercommando's" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "" "Houd een lijst bij van commando's die naar de IRC server verstuurd worden " "zodra ZNC hier naar verbind." znc-1.7.5/modules/po/autovoice.bg_BG.po0000644000175000017500000000420313542151610020122 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/autovoice.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: autovoice.cpp:120 msgid "List all users" msgstr "" #: autovoice.cpp:122 autovoice.cpp:125 msgid " [channel] ..." msgstr "" #: autovoice.cpp:123 msgid "Adds channels to a user" msgstr "" #: autovoice.cpp:126 msgid "Removes channels from a user" msgstr "" #: autovoice.cpp:128 msgid " [channels]" msgstr "" #: autovoice.cpp:129 msgid "Adds a user" msgstr "" #: autovoice.cpp:131 msgid "" msgstr "" #: autovoice.cpp:131 msgid "Removes a user" msgstr "" #: autovoice.cpp:215 msgid "Usage: AddUser [channels]" msgstr "" #: autovoice.cpp:229 msgid "Usage: DelUser " msgstr "" #: autovoice.cpp:238 msgid "There are no users defined" msgstr "" #: autovoice.cpp:244 autovoice.cpp:250 msgid "User" msgstr "" #: autovoice.cpp:245 autovoice.cpp:251 msgid "Hostmask" msgstr "" #: autovoice.cpp:246 autovoice.cpp:252 msgid "Channels" msgstr "" #: autovoice.cpp:263 msgid "Usage: AddChans [channel] ..." msgstr "" #: autovoice.cpp:270 autovoice.cpp:292 autovoice.cpp:329 msgid "No such user" msgstr "" #: autovoice.cpp:275 msgid "Channel(s) added to user {1}" msgstr "" #: autovoice.cpp:285 msgid "Usage: DelChans [channel] ..." msgstr "" #: autovoice.cpp:298 msgid "Channel(s) Removed from user {1}" msgstr "" #: autovoice.cpp:335 msgid "User {1} removed" msgstr "" #: autovoice.cpp:341 msgid "That user already exists" msgstr "" #: autovoice.cpp:347 msgid "User {1} added with hostmask {2}" msgstr "" #: autovoice.cpp:360 msgid "" "Each argument is either a channel you want autovoice for (which can include " "wildcards) or, if it starts with !, it is an exception for autovoice." msgstr "" #: autovoice.cpp:365 msgid "Auto voice the good people" msgstr "" znc-1.7.5/modules/po/simple_away.id_ID.po0000644000175000017500000000430713542151610020453 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/simple_away.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: simple_away.cpp:56 msgid "[]" msgstr "[]" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" "Mencetak atau mengatur alasan away (%awaytime% diganti dengan waktu yang " "anda tentukan, mendukung substitusi menggunakan ExpandString)" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "Mencetak waktu saat ini untuk menunggu sebelum membuat anda pergi" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "" #: simple_away.cpp:136 msgid "Away reason set" msgstr "Alasan away disetel" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "Alasan away: {1}" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" znc-1.7.5/modules/po/perform.de_DE.po0000644000175000017500000000376113542151610017606 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/perform.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/perform/tmpl/index.tmpl:7 perform.cpp:143 msgid "Perform" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:11 msgid "Perform commands:" msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:15 msgid "Commands sent to the IRC server on connect, one per line." msgstr "" #: modules/po/../data/perform/tmpl/index.tmpl:18 msgid "Save" msgstr "" #: perform.cpp:24 msgid "Usage: add " msgstr "" #: perform.cpp:29 msgid "Added!" msgstr "" #: perform.cpp:37 perform.cpp:82 msgid "Illegal # Requested" msgstr "" #: perform.cpp:41 msgid "Command Erased." msgstr "" #: perform.cpp:50 perform.cpp:56 msgctxt "list" msgid "Id" msgstr "" #: perform.cpp:51 perform.cpp:57 msgctxt "list" msgid "Perform" msgstr "" #: perform.cpp:52 perform.cpp:62 msgctxt "list" msgid "Expanded" msgstr "" #: perform.cpp:67 msgid "No commands in your perform list." msgstr "" #: perform.cpp:73 msgid "perform commands sent" msgstr "" #: perform.cpp:86 msgid "Commands Swapped." msgstr "" #: perform.cpp:95 msgid "" msgstr "" #: perform.cpp:96 msgid "Adds perform command to be sent to the server on connect" msgstr "" #: perform.cpp:98 msgid "" msgstr "" #: perform.cpp:98 msgid "Delete a perform command" msgstr "" #: perform.cpp:100 msgid "List the perform commands" msgstr "" #: perform.cpp:103 msgid "Send the perform commands to the server now" msgstr "" #: perform.cpp:105 msgid " " msgstr "" #: perform.cpp:106 msgid "Swap two perform commands" msgstr "" #: perform.cpp:192 msgid "Keeps a list of commands to be executed when ZNC connects to IRC." msgstr "" znc-1.7.5/modules/po/identfile.nl_NL.po0000644000175000017500000000424013542151610020132 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/identfile.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: identfile.cpp:30 msgid "Show file name" msgstr "Laat bestandsnaam zien" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "Stel bestandsnaam in" #: identfile.cpp:34 msgid "Show file format" msgstr "Laat bestandsindeling zien" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "Stel bestandsindeling in" #: identfile.cpp:38 msgid "Show current state" msgstr "Laat huidige status zien" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "Bestand is ingesteld naar: {1}" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "Bestand is ingesteld naar: {1}" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "Bestandsindeling is ingesteld op: {1}" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "Bestandsindeling zou uitgebreid worden naar: {1}" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "Bestandsindeling is ingesteld op: {1}" #: identfile.cpp:78 msgid "identfile is free" msgstr "identiteitbestand is vrij" #: identfile.cpp:86 msgid "Access denied" msgstr "Toegang geweigerd" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" "Verbinding afbreken, een andere gebruiker of netwerk is momenteel aan het " "verbinden en gebruikt het identiteitsbestand" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "Kon niet schrijven naar [{1}], opnieuw aan het proberen..." #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "" "Schrijf de identiteit van een gebruiker naar een bestand wanneer zij " "proberen te verbinden." znc-1.7.5/modules/po/crypt.it_IT.po0000644000175000017500000000730213542151610017340 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/crypt.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "<#canale|Nick>" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "Rimuove una chiave per un nick o canale" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "<#canale|Nick> " #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "Imposta una chiave per un nick o canale" #: crypt.cpp:204 msgid "List all keys" msgstr "Mostra tutte le chiavi" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "Avvia uno scambio di chiave DH1080 con il nick" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "Mostra il prefisso del nick" #: crypt.cpp:213 msgid "[Prefix]" msgstr "[Prefisso]" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "Imposta il prefisso del nick, senza argomenti viene disabilitato." #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "Ricevuta la chiave pubblica DH1080 da {1}, ora invio la mia..." #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "La chiave per {1} è stata impostata con successo." #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "Errore in {1} con {2}: {3}" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "nessuna chiave segreta calcolata" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "Target [{1}] eliminato" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "Target [{1}] non trovato" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "Utilizzo: DelKey <#canale|Nick>" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "Imposta la chiave di crittografia per [{1}] a [{2}]" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "Utilizzo: SetKey <#canale|Nick> " #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "Inviata la mia chiave pubblica DH1080 a {1}, attendo risposta ..." #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "Errore del generatore dalle nostre chiavi, non ho inviato nulla." #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "Utilizzo: KeyX " #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "Prefisso del nick disabilitato." #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "Prefisso del nick: {1}" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" "Non puoi usare :, come prefisso del nick - nemmeno se seguito anche da altri " "simboli." #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" "Sovrapposizione con il Prefisso di Status ({1}), questo prefisso del nick " "non sarà usato!" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "Disabilitare il prefisso del nick." #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "Prefisso del nick impostato a {1}" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "Target" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "Chiave" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "Non hai chiavi di crittografica impostate." #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "Crittografia per canale/messaggi privati" znc-1.7.5/modules/po/crypt.de_DE.po0000644000175000017500000000504513542151610017272 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/crypt.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: crypt.cpp:198 msgid "<#chan|Nick>" msgstr "" #: crypt.cpp:199 msgid "Remove a key for nick or channel" msgstr "" #: crypt.cpp:201 msgid "<#chan|Nick> " msgstr "" #: crypt.cpp:202 msgid "Set a key for nick or channel" msgstr "" #: crypt.cpp:204 msgid "List all keys" msgstr "" #: crypt.cpp:206 msgid "" msgstr "" #: crypt.cpp:207 msgid "Start a DH1080 key exchange with nick" msgstr "" #: crypt.cpp:210 msgid "Get the nick prefix" msgstr "" #: crypt.cpp:213 msgid "[Prefix]" msgstr "" #: crypt.cpp:214 msgid "Set the nick prefix, with no argument it's disabled." msgstr "" #: crypt.cpp:270 msgid "Received DH1080 public key from {1}, sending mine..." msgstr "" #: crypt.cpp:275 crypt.cpp:296 msgid "Key for {1} successfully set." msgstr "" #: crypt.cpp:278 crypt.cpp:299 msgid "Error in {1} with {2}: {3}" msgstr "" #: crypt.cpp:280 crypt.cpp:301 msgid "no secret key computed" msgstr "" #: crypt.cpp:395 msgid "Target [{1}] deleted" msgstr "" #: crypt.cpp:397 msgid "Target [{1}] not found" msgstr "" #: crypt.cpp:400 msgid "Usage DelKey <#chan|Nick>" msgstr "" #: crypt.cpp:415 msgid "Set encryption key for [{1}] to [{2}]" msgstr "" #: crypt.cpp:417 msgid "Usage: SetKey <#chan|Nick> " msgstr "" #: crypt.cpp:428 msgid "Sent my DH1080 public key to {1}, waiting for reply ..." msgstr "" #: crypt.cpp:430 msgid "Error generating our keys, nothing sent." msgstr "" #: crypt.cpp:433 msgid "Usage: KeyX " msgstr "" #: crypt.cpp:440 msgid "Nick Prefix disabled." msgstr "" #: crypt.cpp:442 msgid "Nick Prefix: {1}" msgstr "" #: crypt.cpp:451 msgid "You cannot use :, even followed by other symbols, as Nick Prefix." msgstr "" #: crypt.cpp:460 msgid "Overlap with Status Prefix ({1}), this Nick Prefix will not be used!" msgstr "" #: crypt.cpp:465 msgid "Disabling Nick Prefix." msgstr "" #: crypt.cpp:467 msgid "Setting Nick Prefix to {1}" msgstr "" #: crypt.cpp:474 crypt.cpp:480 msgctxt "listkeys" msgid "Target" msgstr "" #: crypt.cpp:475 crypt.cpp:481 msgctxt "listkeys" msgid "Key" msgstr "" #: crypt.cpp:485 msgid "You have no encryption keys set." msgstr "" #: crypt.cpp:507 msgid "Encryption for channel/private messages" msgstr "" znc-1.7.5/modules/po/identfile.bg_BG.po0000644000175000017500000000303613542151610020072 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/identfile.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: identfile.cpp:30 msgid "Show file name" msgstr "" #: identfile.cpp:32 msgid "" msgstr "" #: identfile.cpp:32 msgid "Set file name" msgstr "" #: identfile.cpp:34 msgid "Show file format" msgstr "" #: identfile.cpp:36 msgid "" msgstr "" #: identfile.cpp:36 msgid "Set file format" msgstr "" #: identfile.cpp:38 msgid "Show current state" msgstr "" #: identfile.cpp:48 msgid "File is set to: {1}" msgstr "" #: identfile.cpp:53 msgid "File has been set to: {1}" msgstr "" #: identfile.cpp:58 msgid "Format has been set to: {1}" msgstr "" #: identfile.cpp:59 identfile.cpp:65 msgid "Format would be expanded to: {1}" msgstr "" #: identfile.cpp:64 msgid "Format is set to: {1}" msgstr "" #: identfile.cpp:78 msgid "identfile is free" msgstr "" #: identfile.cpp:86 msgid "Access denied" msgstr "" #: identfile.cpp:181 msgid "" "Aborting connection, another user or network is currently connecting and " "using the ident spoof file" msgstr "" #: identfile.cpp:189 msgid "[{1}] could not be written, retrying..." msgstr "" #: identfile.cpp:223 msgid "Write the ident of a user to a file when they are trying to connect." msgstr "" znc-1.7.5/modules/po/simple_away.pt_BR.po0000644000175000017500000000376513542151610020520 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/simple_away.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: simple_away.cpp:56 msgid "[]" msgstr "" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "" #: simple_away.cpp:136 msgid "Away reason set" msgstr "" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "" msgstr[1] "" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" znc-1.7.5/modules/po/listsockets.es_ES.po0000644000175000017500000000475413542151610020544 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/listsockets.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "Nombre" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "Creado" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "Estado" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "SSL" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "Local" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "Remoto" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "Data In" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "Data Out" #: listsockets.cpp:62 msgid "[-n]" msgstr "[-n]" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "Muestra una lista de sockets activos. Añade -n para mostrar IPs" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "Debes ser admin para usar este módulo" #: listsockets.cpp:96 msgid "List sockets" msgstr "Mostrar sockets" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "Sí" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "No" #: listsockets.cpp:142 msgid "Listener" msgstr "En escucha" #: listsockets.cpp:144 msgid "Inbound" msgstr "Entrantes" #: listsockets.cpp:147 msgid "Outbound" msgstr "Salientes" #: listsockets.cpp:149 msgid "Connecting" msgstr "Conectando" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "Desconocido" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "No tienes sockets abiertos." #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "Entrada" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "Salida" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "Mostrar sockets activos" znc-1.7.5/modules/po/disconkick.de_DE.po0000644000175000017500000000135413542151610020251 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/disconkick.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: disconkick.cpp:32 msgid "You have been disconnected from the IRC server" msgstr "Du wurdest vom IRC-Server getrennt" #: disconkick.cpp:45 msgid "" "Kicks the client from all channels when the connection to the IRC server is " "lost" msgstr "" "Kickt den Klienten von allen Kanälen when die Verbindung zum IRC-Server " "verloren geht" znc-1.7.5/modules/po/bouncedcc.es_ES.po0000644000175000017500000000642513542151610020117 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/bouncedcc.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: bouncedcc.cpp:101 bouncedcc.cpp:119 bouncedcc.cpp:121 msgctxt "list" msgid "Type" msgstr "Tipo" #: bouncedcc.cpp:102 bouncedcc.cpp:132 msgctxt "list" msgid "State" msgstr "Estado" #: bouncedcc.cpp:103 msgctxt "list" msgid "Speed" msgstr "Velocidad" #: bouncedcc.cpp:104 bouncedcc.cpp:115 msgctxt "list" msgid "Nick" msgstr "Apodo" #: bouncedcc.cpp:105 bouncedcc.cpp:116 msgctxt "list" msgid "IP" msgstr "IP" #: bouncedcc.cpp:106 bouncedcc.cpp:122 msgctxt "list" msgid "File" msgstr "Archivo" #: bouncedcc.cpp:119 msgctxt "list" msgid "Chat" msgstr "Chat" #: bouncedcc.cpp:121 msgctxt "list" msgid "Xfer" msgstr "Xfer" #: bouncedcc.cpp:125 msgid "Waiting" msgstr "Esperando" #: bouncedcc.cpp:127 msgid "Halfway" msgstr "En camino" #: bouncedcc.cpp:129 msgid "Connected" msgstr "Conectado" #: bouncedcc.cpp:137 msgid "You have no active DCCs." msgstr "No tienes ningún DCC activo." #: bouncedcc.cpp:148 msgid "Use client IP: {1}" msgstr "Usa IP cliente: {1}" #: bouncedcc.cpp:153 msgid "List all active DCCs" msgstr "Muestra todos los DCC activos" #: bouncedcc.cpp:156 msgid "Change the option to use IP of client" msgstr "Cambia la opción para usar la IP del cliente" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Chat" msgstr "Chat" #: bouncedcc.cpp:383 bouncedcc.cpp:412 bouncedcc.cpp:436 bouncedcc.cpp:451 msgctxt "type" msgid "Xfer" msgstr "Xfer" #: bouncedcc.cpp:385 msgid "DCC {1} Bounce ({2}): Too long line received" msgstr "DCC {1} Bounce ({2}): línea demasiado larga recibida" #: bouncedcc.cpp:418 msgid "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}" msgstr "DCC {1} Bounce ({2}): tiempo de espera agotado al conectar a {3} {4}" #: bouncedcc.cpp:422 msgid "DCC {1} Bounce ({2}): Timeout while connecting." msgstr "DCC {1} Bounce ({2}): tiempo de espera agotado conectando." #: bouncedcc.cpp:427 msgid "" "DCC {1} Bounce ({2}): Timeout while waiting for incoming connection on {3} " "{4}" msgstr "" "DCC {1} Bounce ({2}): tiempo de espera agotado esperando una conexión en {3} " "{4}" #: bouncedcc.cpp:440 msgid "DCC {1} Bounce ({2}): Connection refused while connecting to {3} {4}" msgstr "" "DCC {1} Bounce ({2}): conexión rechazada mientras se conectaba a {3} {4}" #: bouncedcc.cpp:444 msgid "DCC {1} Bounce ({2}): Connection refused while connecting." msgstr "DCC {1} Bounce ({2}): conexión rechazada mientras se conectaba." #: bouncedcc.cpp:457 bouncedcc.cpp:465 msgid "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}" msgstr "DCC {1} Bounce ({2}): error de socket en {3} {4}: {5}" #: bouncedcc.cpp:460 msgid "DCC {1} Bounce ({2}): Socket error: {3}" msgstr "DCC {1} Bounce ({2}): error de socket: {3}" #: bouncedcc.cpp:547 msgid "" "Bounces DCC transfers through ZNC instead of sending them directly to the " "user. " msgstr "" "Puentea transferencias DCC a través de ZNC en vez de enviarlas directamente " "al usuario." znc-1.7.5/modules/po/pyeval.bg_BG.po0000644000175000017500000000104713542151610017427 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/pyeval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "" #: pyeval.py:82 msgid "Evaluates python code" msgstr "" znc-1.7.5/modules/po/buffextras.es_ES.po0000644000175000017500000000220613542151610020334 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/buffextras.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: buffextras.cpp:45 msgid "Server" msgstr "Servidor" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "{1} cambia modo: {2} {3}" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "{1} ha expulsado a {2} por: {3}" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "{1} cierra: {2}" #: buffextras.cpp:73 msgid "{1} joined" msgstr "{1} entra" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "{1} sale: {2}" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "{1} es ahora {2}" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "{1} ha cambiado el topic a: {2}" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "Añade joins, parts, etc. al búfer" znc-1.7.5/modules/po/ctcpflood.bg_BG.po0000644000175000017500000000274513542151610020112 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/ctcpflood.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: ctcpflood.cpp:25 ctcpflood.cpp:27 msgid "" msgstr "" #: ctcpflood.cpp:25 msgid "Set seconds limit" msgstr "" #: ctcpflood.cpp:27 msgid "Set lines limit" msgstr "" #: ctcpflood.cpp:29 msgid "Show the current limits" msgstr "" #: ctcpflood.cpp:76 msgid "Limit reached by {1}, blocking all CTCP" msgstr "" #: ctcpflood.cpp:98 msgid "Usage: Secs " msgstr "" #: ctcpflood.cpp:113 msgid "Usage: Lines " msgstr "" #: ctcpflood.cpp:125 msgid "1 CTCP message" msgid_plural "{1} CTCP messages" msgstr[0] "" msgstr[1] "" #: ctcpflood.cpp:127 msgid "every second" msgid_plural "every {1} seconds" msgstr[0] "" msgstr[1] "" #: ctcpflood.cpp:129 msgid "Current limit is {1} {2}" msgstr "" #: ctcpflood.cpp:145 msgid "" "This user module takes none to two arguments. The first argument is the " "number of lines after which the flood-protection is triggered. The second " "argument is the time (sec) to in which the number of lines is reached. The " "default setting is 4 CTCPs in 2 seconds" msgstr "" #: ctcpflood.cpp:151 msgid "Don't forward CTCP floods to clients" msgstr "" znc-1.7.5/modules/po/buffextras.bg_BG.po0000644000175000017500000000171713542151610020304 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/buffextras.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: buffextras.cpp:45 msgid "Server" msgstr "" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "" #: buffextras.cpp:73 msgid "{1} joined" msgstr "" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "" znc-1.7.5/modules/po/controlpanel.de_DE.po0000644000175000017500000005427613542151610020643 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/controlpanel.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: controlpanel.cpp:51 controlpanel.cpp:63 msgctxt "helptable" msgid "Type" msgstr "Typ" #: controlpanel.cpp:52 controlpanel.cpp:65 msgctxt "helptable" msgid "Variables" msgstr "Variablen" #: controlpanel.cpp:77 msgid "String" msgstr "Zeichenkette" #: controlpanel.cpp:78 msgid "Boolean (true/false)" msgstr "Boolean (wahr/falsch)" #: controlpanel.cpp:79 msgid "Integer" msgstr "Ganzzahl" #: controlpanel.cpp:80 msgid "Number" msgstr "Nummer" #: controlpanel.cpp:123 msgid "The following variables are available when using the Set/Get commands:" msgstr "Die folgenden Variablen stehen für die Set/Get-Befehle zur Verfügung:" #: controlpanel.cpp:146 msgid "" "The following variables are available when using the SetNetwork/GetNetwork " "commands:" msgstr "" "Die folgenden Variablen stehen für die SetNetwork/GetNetwork-Befehle zur " "Verfügung:" #: controlpanel.cpp:159 msgid "" "The following variables are available when using the SetChan/GetChan " "commands:" msgstr "" "Die folgenden Variablen stehen für die SetChan/GetChan-Befehle zur Verfügung:" #: controlpanel.cpp:165 msgid "" "You can use $user as the user name and $network as the network name for " "modifying your own user and network." msgstr "" "Um deinen eigenen User und dein eigenes Netzwerk zu bearbeiten, können $user " "und $network verwendet werden." #: controlpanel.cpp:174 controlpanel.cpp:961 controlpanel.cpp:998 msgid "Error: User [{1}] does not exist!" msgstr "Fehler: Benutzer [{1}] existiert nicht!" #: controlpanel.cpp:179 msgid "Error: You need to have admin rights to modify other users!" msgstr "Fehler: Administratorrechte benötigt um andere Benutzer zu bearbeiten!" #: controlpanel.cpp:189 msgid "Error: You cannot use $network to modify other users!" msgstr "" "Fehler: $network kann nicht verwendet werden um andere Benutzer zu " "bearbeiten!" #: controlpanel.cpp:197 msgid "Error: User {1} does not have a network named [{2}]." msgstr "Fehler: Benutzer {1} hat kein Netzwerk namens [{2}]." #: controlpanel.cpp:209 msgid "Usage: Get [username]" msgstr "Verwendung: Get [Benutzername]" #: controlpanel.cpp:299 controlpanel.cpp:502 controlpanel.cpp:577 #: controlpanel.cpp:653 controlpanel.cpp:788 controlpanel.cpp:873 msgid "Error: Unknown variable" msgstr "Fehler: Unbekannte Variable" #: controlpanel.cpp:308 msgid "Usage: Set " msgstr "Verwendung: Set " #: controlpanel.cpp:330 controlpanel.cpp:618 msgid "This bind host is already set!" msgstr "Dieser Bind Host ist bereits gesetzt!" #: controlpanel.cpp:337 controlpanel.cpp:349 controlpanel.cpp:357 #: controlpanel.cpp:420 controlpanel.cpp:439 controlpanel.cpp:455 #: controlpanel.cpp:465 controlpanel.cpp:625 msgid "Access denied!" msgstr "Zugriff verweigert!" #: controlpanel.cpp:371 controlpanel.cpp:380 controlpanel.cpp:837 msgid "Setting failed, limit for buffer size is {1}" msgstr "Setzen fehlgeschlagen, da das Limit für die Puffergröße {1} ist" #: controlpanel.cpp:400 msgid "Password has been changed!" msgstr "Das Passwort wurde geändert!" #: controlpanel.cpp:408 msgid "Timeout can't be less than 30 seconds!" msgstr "Timeout kann nicht weniger als 30 Sekunden sein!" #: controlpanel.cpp:472 msgid "That would be a bad idea!" msgstr "Das wäre eine schlechte Idee!" #: controlpanel.cpp:490 msgid "Supported languages: {1}" msgstr "Unterstützte Sprachen: {1}" #: controlpanel.cpp:514 msgid "Usage: GetNetwork [username] [network]" msgstr "Verwendung: GetNetwork [Benutzername] [Netzwerk]" #: controlpanel.cpp:533 msgid "Error: A network must be specified to get another users settings." msgstr "" "Fehler: Ein Netzwerk muss angegeben werden um Einstellungen eines anderen " "Nutzers zu bekommen." #: controlpanel.cpp:539 msgid "You are not currently attached to a network." msgstr "Du bist aktuell nicht mit einem Netzwerk verbunden." #: controlpanel.cpp:545 msgid "Error: Invalid network." msgstr "Fehler: Ungültiges Netzwerk." #: controlpanel.cpp:589 msgid "Usage: SetNetwork " msgstr "Verwendung: SetNetwork " #: controlpanel.cpp:663 msgid "Usage: AddChan " msgstr "Verwendung: AddChan " #: controlpanel.cpp:676 msgid "Error: User {1} already has a channel named {2}." msgstr "Fehler: Benutzer {1} hat bereits einen Kanal namens {2}." #: controlpanel.cpp:683 msgid "Channel {1} for user {2} added to network {3}." msgstr "Kanal {1} für User {2} zum Netzwerk {3} hinzugefügt." #: controlpanel.cpp:687 msgid "" "Could not add channel {1} for user {2} to network {3}, does it already exist?" msgstr "" "Konnte Kanal {1} nicht für Benutzer {2} zum Netzwerk {3} hinzufügen; " "existiert er bereits?" #: controlpanel.cpp:697 msgid "Usage: DelChan " msgstr "Verwendung: DelChan " #: controlpanel.cpp:712 msgid "Error: User {1} does not have any channel matching [{2}] in network {3}" msgstr "" "Fehler: Benutzer {1} hat keinen Kanal in Netzwerk {3}, der auf [{2}] passt" #: controlpanel.cpp:725 msgid "Channel {1} is deleted from network {2} of user {3}" msgid_plural "Channels {1} are deleted from network {2} of user {3}" msgstr[0] "Kanal {1} wurde von Netzwerk {2} von Nutzer {3} entfernt" msgstr[1] "Kanäle {1} wurden von Netzwerk {2} von Nutzer {3} entfernt" #: controlpanel.cpp:740 msgid "Usage: GetChan " msgstr "Verwendung: GetChan " #: controlpanel.cpp:754 controlpanel.cpp:818 msgid "Error: No channels matching [{1}] found." msgstr "Fehler: Keine auf [{1}] passende Kanäle gefunden." #: controlpanel.cpp:803 msgid "Usage: SetChan " msgstr "" "Verwendung: SetChan " #: controlpanel.cpp:884 controlpanel.cpp:894 msgctxt "listusers" msgid "Username" msgstr "Benutzername" #: controlpanel.cpp:885 controlpanel.cpp:895 msgctxt "listusers" msgid "Realname" msgstr "Realname" #: controlpanel.cpp:886 controlpanel.cpp:898 controlpanel.cpp:900 msgctxt "listusers" msgid "IsAdmin" msgstr "IstAdmin" #: controlpanel.cpp:887 controlpanel.cpp:901 msgctxt "listusers" msgid "Nick" msgstr "Nick" #: controlpanel.cpp:888 controlpanel.cpp:902 msgctxt "listusers" msgid "AltNick" msgstr "AltNick" #: controlpanel.cpp:889 controlpanel.cpp:903 msgctxt "listusers" msgid "Ident" msgstr "Ident" #: controlpanel.cpp:890 controlpanel.cpp:904 msgctxt "listusers" msgid "BindHost" msgstr "BindHost" #: controlpanel.cpp:898 controlpanel.cpp:1138 msgid "No" msgstr "Nein" #: controlpanel.cpp:900 controlpanel.cpp:1130 msgid "Yes" msgstr "Ja" #: controlpanel.cpp:914 controlpanel.cpp:983 msgid "Error: You need to have admin rights to add new users!" msgstr "Fehler: Administratorrechte benötigt um neue Benutzer hinzuzufügen!" #: controlpanel.cpp:920 msgid "Usage: AddUser " msgstr "Verwendung: AddUser " #: controlpanel.cpp:925 msgid "Error: User {1} already exists!" msgstr "Fehler: Benutzer {1} existiert bereits!" #: controlpanel.cpp:937 controlpanel.cpp:1012 msgid "Error: User not added: {1}" msgstr "Fehler: Benutzer nicht hinzugefügt: {1}" #: controlpanel.cpp:941 controlpanel.cpp:1016 msgid "User {1} added!" msgstr "Benutzer {1} hinzugefügt!" #: controlpanel.cpp:948 msgid "Error: You need to have admin rights to delete users!" msgstr "Fehler: Administratorrechte benötigt um Benutzer zu löschen!" #: controlpanel.cpp:954 msgid "Usage: DelUser " msgstr "Verwendung: DelUser " #: controlpanel.cpp:966 msgid "Error: You can't delete yourself!" msgstr "Fehler: Du kannst dich nicht selbst löschen!" #: controlpanel.cpp:972 msgid "Error: Internal error!" msgstr "Fehler: Interner Fehler!" #: controlpanel.cpp:976 msgid "User {1} deleted!" msgstr "Benutzer {1} gelöscht!" #: controlpanel.cpp:991 msgid "Usage: CloneUser " msgstr "Verwendung: CloneUser " #: controlpanel.cpp:1006 msgid "Error: Cloning failed: {1}" msgstr "Fehler: Klonen fehlgeschlagen: {1}" #: controlpanel.cpp:1035 msgid "Usage: AddNetwork [user] network" msgstr "Verwendung: AddNetwork [Benutzer] Netzwerk" #: controlpanel.cpp:1041 msgid "" "Network number limit reached. Ask an admin to increase the limit for you, or " "delete unneeded networks using /znc DelNetwork " msgstr "" "Netzwerk-Anzahl-Limit erreicht. Frag einen Administrator den Grenzwert für " "dich zu erhöhen, oder löschen nicht benötigte Netzwerke mit /znc DelNetwork " "" #: controlpanel.cpp:1049 msgid "Error: User {1} already has a network with the name {2}" msgstr "Fehler: Benutzer {1} hat schon ein Netzwerk namens {2}" #: controlpanel.cpp:1056 msgid "Network {1} added to user {2}." msgstr "Netzwerk {1} zu Benutzer {2} hinzugefügt." #: controlpanel.cpp:1060 msgid "Error: Network [{1}] could not be added for user {2}: {3}" msgstr "" "Fehler: Netzwerk [{1}] konnte nicht zu Benutzer {2} hinzugefügt werden: {3}" #: controlpanel.cpp:1080 msgid "Usage: DelNetwork [user] network" msgstr "Verwendung: DelNetwork [Benutzer] Netzwerk" #: controlpanel.cpp:1091 msgid "The currently active network can be deleted via {1}status" msgstr "Das derzeit aktive Netzwerk can mit {1}status gelöscht werden" #: controlpanel.cpp:1097 msgid "Network {1} deleted for user {2}." msgstr "Netzwerk {1} von Benutzer {2} gelöscht." #: controlpanel.cpp:1101 msgid "Error: Network {1} could not be deleted for user {2}." msgstr "Fehler: Netzwerk {1} von Benutzer {2} konnte nicht gelöscht werden." #: controlpanel.cpp:1120 controlpanel.cpp:1128 msgctxt "listnetworks" msgid "Network" msgstr "Netzwerk" #: controlpanel.cpp:1121 controlpanel.cpp:1130 controlpanel.cpp:1138 msgctxt "listnetworks" msgid "OnIRC" msgstr "OnIRC" #: controlpanel.cpp:1122 controlpanel.cpp:1131 msgctxt "listnetworks" msgid "IRC Server" msgstr "IRC-Server" #: controlpanel.cpp:1123 controlpanel.cpp:1133 msgctxt "listnetworks" msgid "IRC User" msgstr "IRC-Benutzer" #: controlpanel.cpp:1124 controlpanel.cpp:1135 msgctxt "listnetworks" msgid "Channels" msgstr "Kanäle" #: controlpanel.cpp:1143 msgid "No networks" msgstr "Keine Netzwerke" #: controlpanel.cpp:1154 msgid "Usage: AddServer [[+]port] [password]" msgstr "" "Verwendung: AddServer [[+]Port] [Passwort]" #: controlpanel.cpp:1168 msgid "Added IRC Server {1} to network {2} for user {3}." msgstr "IRC-Server {1} zu Netzwerk {2} von Benutzer {3} hinzugefügt." #: controlpanel.cpp:1172 msgid "Error: Could not add IRC server {1} to network {2} for user {3}." msgstr "" "Fehler: Konnte IRC-Server {1} nicht zu Netzwerk {2} von Benutzer {3} " "hinzufügen." #: controlpanel.cpp:1185 msgid "Usage: DelServer [[+]port] [password]" msgstr "" "Verwendung: DelServer [[+]Port] [Passwort]" #: controlpanel.cpp:1200 msgid "Deleted IRC Server {1} from network {2} for user {3}." msgstr "IRC-Server {1} von Netzwerk {2} von User {3} gelöscht." #: controlpanel.cpp:1204 msgid "Error: Could not delete IRC server {1} from network {2} for user {3}." msgstr "" "Fehler: Konnte IRC-Server {1} von Netzwerk {2} von User {3} nicht löschen." #: controlpanel.cpp:1214 msgid "Usage: Reconnect " msgstr "Verwendung: Reconnect " #: controlpanel.cpp:1241 msgid "Queued network {1} of user {2} for a reconnect." msgstr "Netzwerk {1} von Benutzer {2} für eine Neu-Verbindung eingereiht." #: controlpanel.cpp:1250 msgid "Usage: Disconnect " msgstr "Verwendung: Disconnect " #: controlpanel.cpp:1265 msgid "Closed IRC connection for network {1} of user {2}." msgstr "IRC-Verbindung von Netzwerk {1} von Benutzer {2} geschlossen." #: controlpanel.cpp:1280 controlpanel.cpp:1284 msgctxt "listctcp" msgid "Request" msgstr "Anfrage" #: controlpanel.cpp:1281 controlpanel.cpp:1285 msgctxt "listctcp" msgid "Reply" msgstr "Antwort" #: controlpanel.cpp:1289 msgid "No CTCP replies for user {1} are configured" msgstr "Keine CTCP-Antworten für Benutzer {1} konfiguriert" #: controlpanel.cpp:1292 msgid "CTCP replies for user {1}:" msgstr "CTCP-Antworten für Benutzer {1}:" #: controlpanel.cpp:1308 msgid "Usage: AddCTCP [user] [request] [reply]" msgstr "Verwendung: AddCTCP [Benutzer] [Anfrage] [Antwort]" #: controlpanel.cpp:1310 msgid "" "This will cause ZNC to reply to the CTCP instead of forwarding it to clients." msgstr "" "Hierdurch wird ZNC den CTCP beantworten anstelle ihn zum Client " "weiterzuleiten." #: controlpanel.cpp:1313 msgid "An empty reply will cause the CTCP request to be blocked." msgstr "Eine leere Antwort blockiert die CTCP-Anfrage." #: controlpanel.cpp:1322 msgid "CTCP requests {1} to user {2} will now be blocked." msgstr "CTCP-Anfragen {1} an Benutzer {2} werden nun blockiert." #: controlpanel.cpp:1326 msgid "CTCP requests {1} to user {2} will now get reply: {3}" msgstr "CTCP-Anfragen {1} an Benutzer {2} werden nun beantwortet mit: {3}" #: controlpanel.cpp:1343 msgid "Usage: DelCTCP [user] [request]" msgstr "Verwendung: DelCTCP [Benutzer] [Anfrage]" #: controlpanel.cpp:1349 msgid "CTCP requests {1} to user {2} will now be sent to IRC clients" msgstr "CTCP-Anfragen {1} an Benutzer {2} werden nun an IRC-Clients gesendet" #: controlpanel.cpp:1353 msgid "" "CTCP requests {1} to user {2} will be sent to IRC clients (nothing has " "changed)" msgstr "" "CTCP-Anfragen {1} an Benutzer {2} werden an IRC-Clients gesendet (nichts hat " "sich geändert)" #: controlpanel.cpp:1363 controlpanel.cpp:1437 msgid "Loading modules has been disabled." msgstr "Das Laden von Modulen wurde deaktiviert." #: controlpanel.cpp:1372 msgid "Error: Unable to load module {1}: {2}" msgstr "Fehler: Konnte Modul {1} nicht laden: {2}" #: controlpanel.cpp:1375 msgid "Loaded module {1}" msgstr "Modul {1} geladen" #: controlpanel.cpp:1380 msgid "Error: Unable to reload module {1}: {2}" msgstr "Fehler: Konnte Modul {1} nicht neu laden: {2}" #: controlpanel.cpp:1383 msgid "Reloaded module {1}" msgstr "Module {1} neu geladen" #: controlpanel.cpp:1387 msgid "Error: Unable to load module {1} because it is already loaded" msgstr "Fehler: Modul {1} kann nicht geladen werden, da es bereits geladen ist" #: controlpanel.cpp:1398 msgid "Usage: LoadModule [args]" msgstr "Verwendung: LoadModule [Argumente]" #: controlpanel.cpp:1417 msgid "Usage: LoadNetModule [args]" msgstr "" "Verwendung: LoadNetModule [Argumente]" #: controlpanel.cpp:1442 msgid "Please use /znc unloadmod {1}" msgstr "Bitte verwende /znc unloadmod {1}" #: controlpanel.cpp:1448 msgid "Error: Unable to unload module {1}: {2}" msgstr "Fehler: Konnte Modul {1} nicht entladen: {2}" #: controlpanel.cpp:1451 msgid "Unloaded module {1}" msgstr "Modul {1} entladen" #: controlpanel.cpp:1460 msgid "Usage: UnloadModule " msgstr "Verwendung: UnloadModule " #: controlpanel.cpp:1477 msgid "Usage: UnloadNetModule " msgstr "Verwendung: UnloadNetModule " #: controlpanel.cpp:1494 controlpanel.cpp:1499 msgctxt "listmodules" msgid "Name" msgstr "Name" #: controlpanel.cpp:1495 controlpanel.cpp:1500 msgctxt "listmodules" msgid "Arguments" msgstr "Argumente" #: controlpanel.cpp:1519 msgid "User {1} has no modules loaded." msgstr "Benutzer {1} hat keine Module geladen." #: controlpanel.cpp:1523 msgid "Modules loaded for user {1}:" msgstr "Für Benutzer {1} geladene Module:" #: controlpanel.cpp:1543 msgid "Network {1} of user {2} has no modules loaded." msgstr "Netzwerk {1} des Benutzers {2} hat keine Module geladen." #: controlpanel.cpp:1548 msgid "Modules loaded for network {1} of user {2}:" msgstr "Für Netzwerk {1} von Benutzer {2} geladene Module:" #: controlpanel.cpp:1555 msgid "[command] [variable]" msgstr "[Kommando] [Variable]" #: controlpanel.cpp:1556 msgid "Prints help for matching commands and variables" msgstr "Gibt die Hilfe für passende Kommandos und Variablen aus" #: controlpanel.cpp:1559 msgid " [username]" msgstr " [Benutzername]" #: controlpanel.cpp:1560 msgid "Prints the variable's value for the given or current user" msgstr "" "Gibt den Wert der Variable für den gegebenen oder aktuellen Benutzer aus" #: controlpanel.cpp:1562 msgid " " msgstr " " #: controlpanel.cpp:1563 msgid "Sets the variable's value for the given user" msgstr "Setzt den Wert der Variable für den gegebenen oder aktuellen Benutzer" #: controlpanel.cpp:1565 msgid " [username] [network]" msgstr " [Benutzername] [Netzwerk]" #: controlpanel.cpp:1566 msgid "Prints the variable's value for the given network" msgstr "Gibt den Wert der Variable für das gegebene Netzwerk aus" #: controlpanel.cpp:1568 msgid " " msgstr " " #: controlpanel.cpp:1569 msgid "Sets the variable's value for the given network" msgstr "Setzt den Wert der Variable für das gegebene Netzwerk" #: controlpanel.cpp:1571 msgid " [username] " msgstr " [Benutzername] " #: controlpanel.cpp:1572 msgid "Prints the variable's value for the given channel" msgstr "Gibt den Wert der Variable für den gegebenen Kanal aus" #: controlpanel.cpp:1575 msgid " " msgstr " " #: controlpanel.cpp:1576 msgid "Sets the variable's value for the given channel" msgstr "Setzt den Wert der Variable für den gegebenen Kanal" #: controlpanel.cpp:1578 controlpanel.cpp:1581 msgid " " msgstr " " #: controlpanel.cpp:1579 msgid "Adds a new channel" msgstr "Fügt einen neuen Kanal hinzu" #: controlpanel.cpp:1582 msgid "Deletes a channel" msgstr "Löscht einen Kanal" #: controlpanel.cpp:1584 msgid "Lists users" msgstr "Listet Benutzer auf" #: controlpanel.cpp:1586 msgid " " msgstr " " #: controlpanel.cpp:1587 msgid "Adds a new user" msgstr "Fügt einen neuen Benutzer hinzu" #: controlpanel.cpp:1589 controlpanel.cpp:1612 controlpanel.cpp:1626 msgid "" msgstr "" #: controlpanel.cpp:1589 msgid "Deletes a user" msgstr "Löscht einen Benutzer" #: controlpanel.cpp:1591 msgid " " msgstr " " #: controlpanel.cpp:1592 msgid "Clones a user" msgstr "Klont einen Benutzer" #: controlpanel.cpp:1594 controlpanel.cpp:1597 msgid " " msgstr " " #: controlpanel.cpp:1595 msgid "Adds a new IRC server for the given or current user" msgstr "" "Fügt einen neuen IRC-Server zum gegebenen oder aktuellen Benutzer hinzu" #: controlpanel.cpp:1598 msgid "Deletes an IRC server from the given or current user" msgstr "Löscht einen IRC-Server vom gegebenen oder aktuellen Benutzer" #: controlpanel.cpp:1600 controlpanel.cpp:1603 controlpanel.cpp:1623 msgid " " msgstr " " #: controlpanel.cpp:1601 msgid "Cycles the user's IRC server connection" msgstr "Erneuert die IRC-Verbindung des Benutzers" #: controlpanel.cpp:1604 msgid "Disconnects the user from their IRC server" msgstr "Trennt den Benutzer von ihrem IRC-Server" #: controlpanel.cpp:1606 msgid " [args]" msgstr " [Argumente]" #: controlpanel.cpp:1607 msgid "Loads a Module for a user" msgstr "Lädt ein Modul für einen Benutzer" #: controlpanel.cpp:1609 msgid " " msgstr " " #: controlpanel.cpp:1610 msgid "Removes a Module of a user" msgstr "Entfernt ein Modul von einem Benutzer" #: controlpanel.cpp:1613 msgid "Get the list of modules for a user" msgstr "Zeigt eine Liste der Module eines Benutzers" #: controlpanel.cpp:1616 msgid " [args]" msgstr " [args]" #: controlpanel.cpp:1617 msgid "Loads a Module for a network" msgstr "Lädt ein Modul für ein Netzwerk" #: controlpanel.cpp:1620 msgid " " msgstr " " #: controlpanel.cpp:1621 msgid "Removes a Module of a network" msgstr "Entfernt ein Modul von einem Netzwerk" #: controlpanel.cpp:1624 msgid "Get the list of modules for a network" msgstr "Zeigt eine Liste der Module eines Netzwerks" #: controlpanel.cpp:1627 msgid "List the configured CTCP replies" msgstr "Liste die konfigurierten CTCP-Antworten auf" #: controlpanel.cpp:1629 msgid " [reply]" msgstr " [Antwort]" #: controlpanel.cpp:1630 msgid "Configure a new CTCP reply" msgstr "Konfiguriere eine neue CTCP-Antwort" #: controlpanel.cpp:1632 msgid " " msgstr " " #: controlpanel.cpp:1633 msgid "Remove a CTCP reply" msgstr "Entfernt eine CTCP-Antwort" #: controlpanel.cpp:1637 controlpanel.cpp:1640 msgid "[username] " msgstr "[Benutzername] " #: controlpanel.cpp:1638 msgid "Add a network for a user" msgstr "Füge ein Netzwerk für einen Benutzer hinzu" #: controlpanel.cpp:1641 msgid "Delete a network for a user" msgstr "Lösche ein Netzwerk für einen Benutzer" #: controlpanel.cpp:1643 msgid "[username]" msgstr "[Benutzername]" #: controlpanel.cpp:1644 msgid "List all networks for a user" msgstr "Listet alle Netzwerke für einen Benutzer auf" #: controlpanel.cpp:1657 msgid "" "Dynamic configuration through IRC. Allows editing only yourself if you're " "not ZNC admin." msgstr "" "Dynamische Konfiguration durch IRC. Erlaubt es nur dich selbst zu bearbeiten " "falls du kein ZNC-Administrator bist." znc-1.7.5/modules/po/modperl.id_ID.po0000644000175000017500000000073213542151610017601 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/modperl.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modperl.cpp:382 msgid "Loads perl scripts as ZNC modules" msgstr "" znc-1.7.5/modules/po/buffextras.id_ID.po0000644000175000017500000000171113542151610020306 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/buffextras.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: buffextras.cpp:45 msgid "Server" msgstr "" #: buffextras.cpp:47 msgid "{1} set mode: {2} {3}" msgstr "" #: buffextras.cpp:55 msgid "{1} kicked {2} with reason: {3}" msgstr "" #: buffextras.cpp:64 msgid "{1} quit: {2}" msgstr "" #: buffextras.cpp:73 msgid "{1} joined" msgstr "" #: buffextras.cpp:81 msgid "{1} parted: {2}" msgstr "" #: buffextras.cpp:90 msgid "{1} is now known as {2}" msgstr "" #: buffextras.cpp:100 msgid "{1} changed the topic to: {2}" msgstr "" #: buffextras.cpp:115 msgid "Adds joins, parts etc. to the playback buffer" msgstr "" znc-1.7.5/modules/po/stripcontrols.de_DE.po0000644000175000017500000000114013542151610021046 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/stripcontrols.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: stripcontrols.cpp:63 msgid "" "Strips control codes (Colors, Bold, ..) from channel and private messages." msgstr "" "Entfernt Steuercodes (Farben, Fett,...) von Kanal- und Query-Nachrichten." znc-1.7.5/modules/po/dcc.pot0000644000175000017500000000741613542151610016113 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: dcc.cpp:88 msgid " " msgstr "" #: dcc.cpp:89 msgid "Send a file from ZNC to someone" msgstr "" #: dcc.cpp:91 msgid "" msgstr "" #: dcc.cpp:92 msgid "Send a file from ZNC to your client" msgstr "" #: dcc.cpp:94 msgid "List current transfers" msgstr "" #: dcc.cpp:103 msgid "You must be admin to use the DCC module" msgstr "" #: dcc.cpp:140 msgid "Attempting to send [{1}] to [{2}]." msgstr "" #: dcc.cpp:149 dcc.cpp:554 msgid "Receiving [{1}] from [{2}]: File already exists." msgstr "" #: dcc.cpp:167 msgid "" "Attempting to connect to [{1} {2}] in order to download [{3}] from [{4}]." msgstr "" #: dcc.cpp:179 msgid "Usage: Send " msgstr "" #: dcc.cpp:186 dcc.cpp:206 msgid "Illegal path." msgstr "" #: dcc.cpp:199 msgid "Usage: Get " msgstr "" #: dcc.cpp:215 dcc.cpp:232 dcc.cpp:234 msgctxt "list" msgid "Type" msgstr "" #: dcc.cpp:216 dcc.cpp:238 dcc.cpp:241 msgctxt "list" msgid "State" msgstr "" #: dcc.cpp:217 dcc.cpp:243 msgctxt "list" msgid "Speed" msgstr "" #: dcc.cpp:218 dcc.cpp:227 msgctxt "list" msgid "Nick" msgstr "" #: dcc.cpp:219 dcc.cpp:228 msgctxt "list" msgid "IP" msgstr "" #: dcc.cpp:220 dcc.cpp:229 msgctxt "list" msgid "File" msgstr "" #: dcc.cpp:232 msgctxt "list-type" msgid "Sending" msgstr "" #: dcc.cpp:234 msgctxt "list-type" msgid "Getting" msgstr "" #: dcc.cpp:239 msgctxt "list-state" msgid "Waiting" msgstr "" #: dcc.cpp:244 msgid "{1} KiB/s" msgstr "" #: dcc.cpp:250 msgid "You have no active DCC transfers." msgstr "" #: dcc.cpp:267 msgid "Attempting to resume send from position {1} of file [{2}] for [{3}]" msgstr "" #: dcc.cpp:277 msgid "Couldn't resume file [{1}] for [{2}]: not sending anything." msgstr "" #: dcc.cpp:286 msgid "Bad DCC file: {1}" msgstr "" #: dcc.cpp:341 msgid "Sending [{1}] to [{2}]: File not open!" msgstr "" #: dcc.cpp:345 msgid "Receiving [{1}] from [{2}]: File not open!" msgstr "" #: dcc.cpp:385 msgid "Sending [{1}] to [{2}]: Connection refused." msgstr "" #: dcc.cpp:389 msgid "Receiving [{1}] from [{2}]: Connection refused." msgstr "" #: dcc.cpp:397 msgid "Sending [{1}] to [{2}]: Timeout." msgstr "" #: dcc.cpp:401 msgid "Receiving [{1}] from [{2}]: Timeout." msgstr "" #: dcc.cpp:411 msgid "Sending [{1}] to [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:415 msgid "Receiving [{1}] from [{2}]: Socket error {3}: {4}" msgstr "" #: dcc.cpp:423 msgid "Sending [{1}] to [{2}]: Transfer started." msgstr "" #: dcc.cpp:427 msgid "Receiving [{1}] from [{2}]: Transfer started." msgstr "" #: dcc.cpp:446 msgid "Sending [{1}] to [{2}]: Too much data!" msgstr "" #: dcc.cpp:450 msgid "Receiving [{1}] from [{2}]: Too much data!" msgstr "" #: dcc.cpp:456 msgid "Sending [{1}] to [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:461 msgid "Receiving [{1}] from [{2}] completed at {3} KiB/s" msgstr "" #: dcc.cpp:474 msgid "Sending [{1}] to [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:478 msgid "Receiving [{1}] from [{2}]: File closed prematurely." msgstr "" #: dcc.cpp:501 msgid "Sending [{1}] to [{2}]: Error reading from file." msgstr "" #: dcc.cpp:505 msgid "Receiving [{1}] from [{2}]: Error reading from file." msgstr "" #: dcc.cpp:537 msgid "Sending [{1}] to [{2}]: Unable to open file." msgstr "" #: dcc.cpp:541 msgid "Receiving [{1}] from [{2}]: Unable to open file." msgstr "" #: dcc.cpp:563 msgid "Receiving [{1}] from [{2}]: Could not open file." msgstr "" #: dcc.cpp:572 msgid "Sending [{1}] to [{2}]: Not a file." msgstr "" #: dcc.cpp:581 msgid "Sending [{1}] to [{2}]: Could not open file." msgstr "" #: dcc.cpp:593 msgid "Sending [{1}] to [{2}]: File too large (>4 GiB)." msgstr "" #: dcc.cpp:623 msgid "This module allows you to transfer files to and from ZNC" msgstr "" znc-1.7.5/modules/po/autoreply.ru_RU.po0000644000175000017500000000214113542151610020243 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/autoreply.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: autoreply.cpp:25 msgid "" msgstr "" #: autoreply.cpp:25 msgid "Sets a new reply" msgstr "" #: autoreply.cpp:27 msgid "Displays the current query reply" msgstr "" #: autoreply.cpp:75 msgid "Current reply is: {1} ({2})" msgstr "" #: autoreply.cpp:81 msgid "New reply set to: {1} ({2})" msgstr "" #: autoreply.cpp:94 msgid "" "You might specify a reply text. It is used when automatically answering " "queries, if you are not connected to ZNC." msgstr "" #: autoreply.cpp:98 msgid "Reply to queries when you are away" msgstr "" znc-1.7.5/modules/po/adminlog.fr_FR.po0000644000175000017500000000345313542151610017762 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/adminlog.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "Afficher la cible des journaux" #: adminlog.cpp:31 msgid " [path]" msgstr " [path]" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "Configure la cible des journaux" #: adminlog.cpp:142 msgid "Access denied" msgstr "Accès refusé" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "Journalisation vers un fichier" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "Journalisation vers syslog" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "Journalisation vers syslog et un fichier" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "Utilisation: Target [path]" #: adminlog.cpp:170 msgid "Unknown target" msgstr "Cible inconnue" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "La journalisation est activée vers un fichier" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "La journalisation est activée vers syslog" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "La journalisation est activée pour syslog et un fichier" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "Le journal sera sauvegardé dans {1}" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "Journaliser les événements ZNC vers un fichier ou syslog." znc-1.7.5/modules/po/savebuff.bg_BG.po0000644000175000017500000000250613542151610017731 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/savebuff.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: savebuff.cpp:65 msgid "" msgstr "" #: savebuff.cpp:65 msgid "Sets the password" msgstr "" #: savebuff.cpp:67 msgid "" msgstr "" #: savebuff.cpp:67 msgid "Replays the buffer" msgstr "" #: savebuff.cpp:69 msgid "Saves all buffers" msgstr "" #: savebuff.cpp:221 msgid "" "Password is unset usually meaning the decryption failed. You can setpass to " "the appropriate pass and things should start working, or setpass to a new " "pass and save to reinstantiate" msgstr "" #: savebuff.cpp:232 msgid "Password set to [{1}]" msgstr "" #: savebuff.cpp:262 msgid "Replayed {1}" msgstr "" #: savebuff.cpp:341 msgid "Unable to decode Encrypted file {1}" msgstr "" #: savebuff.cpp:358 msgid "" "This user module takes up to one arguments. Either --ask-pass or the " "password itself (which may contain spaces) or nothing" msgstr "" #: savebuff.cpp:363 msgid "Stores channel and query buffers to disk, encrypted" msgstr "" znc-1.7.5/modules/po/autoattach.pot0000644000175000017500000000255613542151610017517 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: autoattach.cpp:94 msgid "Added to list" msgstr "" #: autoattach.cpp:96 msgid "{1} is already added" msgstr "" #: autoattach.cpp:100 msgid "Usage: Add [!]<#chan> " msgstr "" #: autoattach.cpp:101 msgid "Wildcards are allowed" msgstr "" #: autoattach.cpp:113 msgid "Removed {1} from list" msgstr "" #: autoattach.cpp:115 msgid "Usage: Del [!]<#chan> " msgstr "" #: autoattach.cpp:121 autoattach.cpp:129 msgid "Neg" msgstr "" #: autoattach.cpp:122 autoattach.cpp:130 msgid "Chan" msgstr "" #: autoattach.cpp:123 autoattach.cpp:131 msgid "Search" msgstr "" #: autoattach.cpp:124 autoattach.cpp:132 msgid "Host" msgstr "" #: autoattach.cpp:138 msgid "You have no entries." msgstr "" #: autoattach.cpp:146 autoattach.cpp:149 msgid "[!]<#chan> " msgstr "" #: autoattach.cpp:147 msgid "Add an entry, use !#chan to negate and * for wildcards" msgstr "" #: autoattach.cpp:150 msgid "Remove an entry, needs to be an exact match" msgstr "" #: autoattach.cpp:152 msgid "List all entries" msgstr "" #: autoattach.cpp:171 msgid "Unable to add [{1}]" msgstr "" #: autoattach.cpp:283 msgid "List of channel masks and channel masks with ! before them." msgstr "" #: autoattach.cpp:286 msgid "Reattaches you to channels on activity." msgstr "" znc-1.7.5/modules/po/certauth.es_ES.po0000644000175000017500000000522013542151610020001 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/certauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: modules/po/../data/certauth/tmpl/index.tmpl:7 msgid "Add a key" msgstr "Añadir una clave" #: modules/po/../data/certauth/tmpl/index.tmpl:11 msgid "Key:" msgstr "Clave:" #: modules/po/../data/certauth/tmpl/index.tmpl:15 msgid "Add Key" msgstr "Añadir clave" #: modules/po/../data/certauth/tmpl/index.tmpl:23 msgid "You have no keys." msgstr "No tienes claves." #: modules/po/../data/certauth/tmpl/index.tmpl:30 msgctxt "web" msgid "Key" msgstr "Clave" #: modules/po/../data/certauth/tmpl/index.tmpl:36 msgid "del" msgstr "borrar" #: certauth.cpp:31 msgid "[pubkey]" msgstr "[pubkey]" #: certauth.cpp:32 msgid "Add a public key. If key is not provided will use the current key" msgstr "" "Añadir una clave pública. Si no se proporciona una clave se usará la actual" #: certauth.cpp:35 msgid "id" msgstr "id" #: certauth.cpp:35 msgid "Delete a key by its number in List" msgstr "Borrar una clave por su número en la lista" #: certauth.cpp:37 msgid "List your public keys" msgstr "Muestra tus claves públicas" #: certauth.cpp:39 msgid "Print your current key" msgstr "Muestra tu claves actual" #: certauth.cpp:142 msgid "You are not connected with any valid public key" msgstr "No estás conectado con ninguna clave pública válida" #: certauth.cpp:144 msgid "Your current public key is: {1}" msgstr "Tu clave pública actual es: {1}" #: certauth.cpp:157 msgid "You did not supply a public key or connect with one." msgstr "No has proporcionado una clave pública." #: certauth.cpp:160 msgid "Key '{1}' added." msgstr "Clave '{1}' añadida." #: certauth.cpp:162 msgid "The key '{1}' is already added." msgstr "La clave '{1}' ya está añadida." #: certauth.cpp:170 certauth.cpp:182 msgctxt "list" msgid "Id" msgstr "Id" #: certauth.cpp:171 certauth.cpp:183 msgctxt "list" msgid "Key" msgstr "Clave" #: certauth.cpp:175 certauth.cpp:189 certauth.cpp:198 msgid "No keys set for your user" msgstr "No hay claves configuradas para tu usuario" #: certauth.cpp:203 msgid "Invalid #, check \"list\"" msgstr "Código # inválido, comprueba la lista con \"list\"" #: certauth.cpp:215 msgid "Removed" msgstr "Eliminado" #: certauth.cpp:290 msgid "Allows users to authenticate via SSL client certificates." msgstr "Permite a los usuarios autenticarse vía certificados SSL." znc-1.7.5/modules/po/modpython.nl_NL.po0000644000175000017500000000100513542151610020204 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/modpython.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modpython.cpp:512 msgid "Loads python scripts as ZNC modules" msgstr "Laad python scripts als ZNC modulen" znc-1.7.5/modules/po/shell.it_IT.po0000644000175000017500000000154213542151610017306 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/shell.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: shell.cpp:37 msgid "Failed to execute: {1}" msgstr "Impossibile eseguire: {1}" #: shell.cpp:75 msgid "You must be admin to use the shell module" msgstr "Devi essere amministratore per usare il modulo shell" #: shell.cpp:169 msgid "Gives shell access" msgstr "Fornisce accesso alla shell" #: shell.cpp:172 msgid "Gives shell access. Only ZNC admins can use it." msgstr "" "Fornisce accesso alla shell. Solo gli amministratori dello ZNC possono " "usarlo." znc-1.7.5/modules/po/modules_online.de_DE.po0000644000175000017500000000076013542151610021144 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/modules_online.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "" znc-1.7.5/modules/po/autoop.ru_RU.po0000644000175000017500000000655713542151610017545 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/autoop.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: autoop.cpp:154 msgid "List all users" msgstr "" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr "" #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr "" #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr "" #: autoop.cpp:170 msgid "Adds a user" msgstr "" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "" #: autoop.cpp:300 msgid "There are no users defined" msgstr "" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "" #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "" #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "" #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "" #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "" #: autoop.cpp:478 msgid "User {1} removed" msgstr "" #: autoop.cpp:484 msgid "That user already exists" msgstr "" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "" #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "" #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "" #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "" #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "" #: autoop.cpp:644 msgid "Auto op the good people" msgstr "" znc-1.7.5/modules/po/imapauth.pt_BR.po0000644000175000017500000000110413542151610017777 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: pt-BR\n" "X-Crowdin-File: /1.7.x/modules/po/imapauth.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" #: imapauth.cpp:168 msgid "[ server [+]port [ UserFormatString ] ]" msgstr "" #: imapauth.cpp:171 msgid "Allow users to authenticate via IMAP." msgstr "" znc-1.7.5/modules/po/raw.bg_BG.po0000644000175000017500000000072113542151610016716 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/raw.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: raw.cpp:43 msgid "View all of the raw traffic" msgstr "" znc-1.7.5/modules/po/sasl.pot0000644000175000017500000000604513542151610016321 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: modules/po/../data/sasl/tmpl/index.tmpl:7 sasl.cpp:290 msgid "SASL" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:22 msgid "Options" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:25 msgid "Connect only if SASL authentication succeeds." msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:27 msgid "Require authentication" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:35 msgid "Mechanisms" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:42 msgid "Name" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:43 sasl.cpp:89 sasl.cpp:94 msgid "Description" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:57 msgid "Selected mechanisms and their order:" msgstr "" #: modules/po/../data/sasl/tmpl/index.tmpl:74 msgid "Save" msgstr "" #: sasl.cpp:54 msgid "TLS certificate, for use with the *cert module" msgstr "" #: sasl.cpp:56 msgid "" "Plain text negotiation, this should work always if the network supports SASL" msgstr "" #: sasl.cpp:62 msgid "search" msgstr "" #: sasl.cpp:62 msgid "Generate this output" msgstr "" #: sasl.cpp:64 msgid "[ []]" msgstr "" #: sasl.cpp:65 msgid "" "Set username and password for the mechanisms that need them. Password is " "optional. Without parameters, returns information about current settings." msgstr "" #: sasl.cpp:69 msgid "[mechanism[ ...]]" msgstr "" #: sasl.cpp:70 msgid "Set the mechanisms to be attempted (in order)" msgstr "" #: sasl.cpp:72 msgid "[yes|no]" msgstr "" #: sasl.cpp:73 msgid "Don't connect unless SASL authentication succeeds" msgstr "" #: sasl.cpp:88 sasl.cpp:93 msgid "Mechanism" msgstr "" #: sasl.cpp:97 msgid "The following mechanisms are available:" msgstr "" #: sasl.cpp:107 msgid "Username is currently not set" msgstr "" #: sasl.cpp:109 msgid "Username is currently set to '{1}'" msgstr "" #: sasl.cpp:112 msgid "Password was not supplied" msgstr "" #: sasl.cpp:114 msgid "Password was supplied" msgstr "" #: sasl.cpp:122 msgid "Username has been set to [{1}]" msgstr "" #: sasl.cpp:123 msgid "Password has been set to [{1}]" msgstr "" #: sasl.cpp:143 msgid "Current mechanisms set: {1}" msgstr "" #: sasl.cpp:152 msgid "We require SASL negotiation to connect" msgstr "" #: sasl.cpp:154 msgid "We will connect even if SASL fails" msgstr "" #: sasl.cpp:191 msgid "Disabling network, we require authentication." msgstr "" #: sasl.cpp:192 msgid "Use 'RequireAuth no' to disable." msgstr "" #: sasl.cpp:245 msgid "{1} mechanism succeeded." msgstr "" #: sasl.cpp:257 msgid "{1} mechanism failed." msgstr "" #: sasl.cpp:335 msgid "" "Adds support for sasl authentication capability to authenticate to an IRC " "server" msgstr "" znc-1.7.5/modules/po/admindebug.ru_RU.po0000644000175000017500000000247413542151610020327 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/admindebug.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: admindebug.cpp:30 msgid "Enable Debug Mode" msgstr "" #: admindebug.cpp:32 msgid "Disable Debug Mode" msgstr "" #: admindebug.cpp:34 msgid "Show the Debug Mode status" msgstr "" #: admindebug.cpp:40 admindebug.cpp:49 msgid "Access denied!" msgstr "" #: admindebug.cpp:58 msgid "" "Failure. We need to be running with a TTY. (is ZNC running with --" "foreground?)" msgstr "" #: admindebug.cpp:66 msgid "Already enabled." msgstr "" #: admindebug.cpp:68 msgid "Already disabled." msgstr "" #: admindebug.cpp:92 msgid "Debugging mode is on." msgstr "" #: admindebug.cpp:94 msgid "Debugging mode is off." msgstr "" #: admindebug.cpp:96 msgid "Logging to: stdout." msgstr "" #: admindebug.cpp:105 msgid "Enable Debug mode dynamically." msgstr "" znc-1.7.5/modules/po/stickychan.de_DE.po0000644000175000017500000000364713542151610020277 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/stickychan.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "" #: stickychan.cpp:30 msgid "<#channel>" msgstr "" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "" #: stickychan.cpp:101 msgid " -- End of List" msgstr "" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "" #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "" #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" znc-1.7.5/modules/po/clientnotify.bg_BG.po0000644000175000017500000000325413542151610020640 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: bg\n" "X-Crowdin-File: /1.7.x/modules/po/clientnotify.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" #: clientnotify.cpp:47 msgid "" msgstr "" #: clientnotify.cpp:48 msgid "Sets the notify method" msgstr "" #: clientnotify.cpp:50 clientnotify.cpp:54 msgid "" msgstr "" #: clientnotify.cpp:51 msgid "Turns notifications for unseen IP addresses on or off" msgstr "" #: clientnotify.cpp:55 msgid "Turns notifications for clients disconnecting on or off" msgstr "" #: clientnotify.cpp:57 msgid "Shows the current settings" msgstr "" #: clientnotify.cpp:81 clientnotify.cpp:95 msgid "" msgid_plural "" "Another client authenticated as your user. Use the 'ListClients' command to " "see all {1} clients." msgstr[0] "" msgstr[1] "" #: clientnotify.cpp:108 msgid "Usage: Method " msgstr "" #: clientnotify.cpp:114 clientnotify.cpp:127 clientnotify.cpp:140 msgid "Saved." msgstr "" #: clientnotify.cpp:121 msgid "Usage: NewOnly " msgstr "" #: clientnotify.cpp:134 msgid "Usage: OnDisconnect " msgstr "" #: clientnotify.cpp:145 msgid "" "Current settings: Method: {1}, for unseen IP addresses only: {2}, notify on " "disconnecting clients: {3}" msgstr "" #: clientnotify.cpp:157 msgid "" "Notifies you when another IRC client logs into or out of your account. " "Configurable." msgstr "" znc-1.7.5/modules/po/fail2ban.fr_FR.po0000644000175000017500000000430613542151610017644 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/fail2ban.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: fail2ban.cpp:25 msgid "[minutes]" msgstr "" #: fail2ban.cpp:26 msgid "The number of minutes IPs are blocked after a failed login." msgstr "" #: fail2ban.cpp:28 msgid "[count]" msgstr "" #: fail2ban.cpp:29 msgid "The number of allowed failed login attempts." msgstr "" #: fail2ban.cpp:31 fail2ban.cpp:33 msgid "" msgstr "" #: fail2ban.cpp:31 msgid "Ban the specified hosts." msgstr "" #: fail2ban.cpp:33 msgid "Unban the specified hosts." msgstr "" #: fail2ban.cpp:35 msgid "List banned hosts." msgstr "" #: fail2ban.cpp:55 msgid "" "Invalid argument, must be the number of minutes IPs are blocked after a " "failed login and can be followed by number of allowed failed login attempts" msgstr "" #: fail2ban.cpp:77 fail2ban.cpp:100 fail2ban.cpp:123 fail2ban.cpp:146 #: fail2ban.cpp:172 msgid "Access denied" msgstr "" #: fail2ban.cpp:86 msgid "Usage: Timeout [minutes]" msgstr "" #: fail2ban.cpp:91 fail2ban.cpp:94 msgid "Timeout: {1} min" msgstr "" #: fail2ban.cpp:109 msgid "Usage: Attempts [count]" msgstr "" #: fail2ban.cpp:114 fail2ban.cpp:117 msgid "Attempts: {1}" msgstr "" #: fail2ban.cpp:130 msgid "Usage: Ban " msgstr "" #: fail2ban.cpp:140 msgid "Banned: {1}" msgstr "" #: fail2ban.cpp:153 msgid "Usage: Unban " msgstr "" #: fail2ban.cpp:163 msgid "Unbanned: {1}" msgstr "" #: fail2ban.cpp:165 msgid "Ignored: {1}" msgstr "" #: fail2ban.cpp:177 fail2ban.cpp:182 msgctxt "list" msgid "Host" msgstr "" #: fail2ban.cpp:178 fail2ban.cpp:183 msgctxt "list" msgid "Attempts" msgstr "" #: fail2ban.cpp:187 msgctxt "list" msgid "No bans" msgstr "" #: fail2ban.cpp:244 msgid "" "You might enter the time in minutes for the IP banning and the number of " "failed logins before any action is taken." msgstr "" #: fail2ban.cpp:249 msgid "Block IPs for some time after a failed login." msgstr "" znc-1.7.5/modules/po/watch.ru_RU.po0000644000175000017500000001117013542151610017327 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/watch.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: watch.cpp:334 msgid "All entries cleared." msgstr "" #: watch.cpp:344 msgid "Buffer count is set to {1}" msgstr "" #: watch.cpp:348 msgid "Unknown command: {1}" msgstr "" #: watch.cpp:397 msgid "Disabled all entries." msgstr "" #: watch.cpp:398 msgid "Enabled all entries." msgstr "" #: watch.cpp:405 watch.cpp:437 watch.cpp:470 watch.cpp:570 watch.cpp:585 msgid "Invalid Id" msgstr "" #: watch.cpp:414 msgid "Id {1} disabled" msgstr "" #: watch.cpp:416 msgid "Id {1} enabled" msgstr "" #: watch.cpp:428 msgid "Set DetachedClientOnly for all entries to Yes" msgstr "" #: watch.cpp:430 msgid "Set DetachedClientOnly for all entries to No" msgstr "" #: watch.cpp:446 watch.cpp:479 msgid "Id {1} set to Yes" msgstr "" #: watch.cpp:448 watch.cpp:481 msgid "Id {1} set to No" msgstr "" #: watch.cpp:461 msgid "Set DetachedChannelOnly for all entries to Yes" msgstr "" #: watch.cpp:463 msgid "Set DetachedChannelOnly for all entries to No" msgstr "" #: watch.cpp:487 watch.cpp:503 msgid "Id" msgstr "" #: watch.cpp:488 watch.cpp:504 msgid "HostMask" msgstr "" #: watch.cpp:489 watch.cpp:505 msgid "Target" msgstr "" #: watch.cpp:490 watch.cpp:506 msgid "Pattern" msgstr "" #: watch.cpp:491 watch.cpp:507 msgid "Sources" msgstr "" #: watch.cpp:492 watch.cpp:508 watch.cpp:509 msgid "Off" msgstr "" #: watch.cpp:493 watch.cpp:511 msgid "DetachedClientOnly" msgstr "" #: watch.cpp:494 watch.cpp:514 msgid "DetachedChannelOnly" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "Yes" msgstr "" #: watch.cpp:512 watch.cpp:515 msgid "No" msgstr "" #: watch.cpp:521 watch.cpp:527 msgid "You have no entries." msgstr "" #: watch.cpp:578 msgid "Sources set for Id {1}." msgstr "" #: watch.cpp:593 msgid "Id {1} removed." msgstr "" #: watch.cpp:600 watch.cpp:604 watch.cpp:609 watch.cpp:614 watch.cpp:620 #: watch.cpp:625 watch.cpp:629 watch.cpp:633 watch.cpp:638 watch.cpp:645 #: watch.cpp:652 watch.cpp:658 watch.cpp:664 msgid "Command" msgstr "" #: watch.cpp:601 watch.cpp:605 watch.cpp:610 watch.cpp:616 watch.cpp:621 #: watch.cpp:626 watch.cpp:630 watch.cpp:634 watch.cpp:641 watch.cpp:648 #: watch.cpp:654 watch.cpp:660 watch.cpp:665 msgid "Description" msgstr "" #: watch.cpp:604 msgid "Add [Target] [Pattern]" msgstr "" #: watch.cpp:606 msgid "Used to add an entry to watch for." msgstr "" #: watch.cpp:609 msgid "List" msgstr "" #: watch.cpp:611 msgid "List all entries being watched." msgstr "" #: watch.cpp:614 msgid "Dump" msgstr "" #: watch.cpp:617 msgid "Dump a list of all current entries to be used later." msgstr "" #: watch.cpp:620 msgid "Del " msgstr "" #: watch.cpp:622 msgid "Deletes Id from the list of watched entries." msgstr "" #: watch.cpp:625 msgid "Clear" msgstr "" #: watch.cpp:626 msgid "Delete all entries." msgstr "" #: watch.cpp:629 msgid "Enable " msgstr "" #: watch.cpp:630 msgid "Enable a disabled entry." msgstr "" #: watch.cpp:633 msgid "Disable " msgstr "" #: watch.cpp:635 msgid "Disable (but don't delete) an entry." msgstr "" #: watch.cpp:639 msgid "SetDetachedClientOnly " msgstr "" #: watch.cpp:642 msgid "Enable or disable detached client only for an entry." msgstr "" #: watch.cpp:646 msgid "SetDetachedChannelOnly " msgstr "" #: watch.cpp:649 msgid "Enable or disable detached channel only for an entry." msgstr "" #: watch.cpp:652 msgid "Buffer [Count]" msgstr "" #: watch.cpp:655 msgid "Show/Set the amount of buffered lines while detached." msgstr "" #: watch.cpp:659 msgid "SetSources [#chan priv #foo* !#bar]" msgstr "" #: watch.cpp:661 msgid "Set the source channels that you care about." msgstr "" #: watch.cpp:664 msgid "Help" msgstr "" #: watch.cpp:665 msgid "This help." msgstr "" #: watch.cpp:681 msgid "Entry for {1} already exists." msgstr "" #: watch.cpp:689 msgid "Adding entry: {1} watching for [{2}] -> {3}" msgstr "" #: watch.cpp:695 msgid "Watch: Not enough arguments. Try Help" msgstr "" #: watch.cpp:764 msgid "WARNING: malformed entry found while loading" msgstr "" #: watch.cpp:778 msgid "Copy activity from a specific user into a separate window" msgstr "" znc-1.7.5/modules/po/awaystore.es_ES.po0000644000175000017500000000611613542151610020205 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/awaystore.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: awaystore.cpp:67 msgid "You have been marked as away" msgstr "Has sido marcado como ausente" #: awaystore.cpp:78 awaystore.cpp:385 awaystore.cpp:388 msgid "Welcome back!" msgstr "¡Bienvenido de vuelta!" #: awaystore.cpp:100 msgid "Deleted {1} messages" msgstr "Borrado(s) {1} mensaje(s)" #: awaystore.cpp:104 msgid "USAGE: delete " msgstr "Uso: Delete " #: awaystore.cpp:109 msgid "Illegal message # requested" msgstr "Mensaje solicitado # incorrecto" #: awaystore.cpp:113 msgid "Message erased" msgstr "Mensaje borrado" #: awaystore.cpp:122 msgid "Messages saved to disk" msgstr "Mensajes guardados a disco" #: awaystore.cpp:124 msgid "There are no messages to save" msgstr "No hay mensajes a guardar" #: awaystore.cpp:135 msgid "Password updated to [{1}]" msgstr "Contraseña actualizada a [{1}]" #: awaystore.cpp:147 msgid "Corrupt message! [{1}]" msgstr "Mensaje corrupto [{1}]" #: awaystore.cpp:159 msgid "Corrupt time stamp! [{1}]" msgstr "Marca de tiempo corrupta [{1}]" #: awaystore.cpp:178 msgid "#--- End of messages" msgstr "#--- Fin de mensajes" #: awaystore.cpp:183 msgid "Timer set to 300 seconds" msgstr "Temporizador configurado a 300 segundos" #: awaystore.cpp:188 awaystore.cpp:197 msgid "Timer disabled" msgstr "Temporizador desactivado" #: awaystore.cpp:199 msgid "Timer set to {1} seconds" msgstr "Temporizador configurado a {1} segundos" #: awaystore.cpp:203 msgid "Current timer setting: {1} seconds" msgstr "Temporizador configurado a: {1} segundos" #: awaystore.cpp:278 msgid "This module needs as an argument a keyphrase used for encryption" msgstr "" "Este módulo requiere como argumento una frase de paso utilizada en el cifrado" #: awaystore.cpp:285 msgid "" "Failed to decrypt your saved messages - Did you give the right encryption " "key as an argument to this module?" msgstr "" "Fallo al descifrar los mensajes guardados. ¿Has proporcionado la clave de " "cifrado correcta como argumento de este módulo?" #: awaystore.cpp:386 awaystore.cpp:389 msgid "You have {1} messages!" msgstr "¡Tienes {1} mensaje(s)!" #: awaystore.cpp:456 msgid "Unable to find buffer" msgstr "No se ha podido encontrar el búfer" #: awaystore.cpp:469 msgid "Unable to decode encrypted messages" msgstr "No se han podido descifrar los mensajes" #: awaystore.cpp:516 msgid "" "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, 600 by " "default." msgstr "" "[ -notimer | -timer N ] [-chans] c0ntr4s3ñ4 . N es el número de segundos, " "600 por defecto." #: awaystore.cpp:521 msgid "" "Adds auto-away with logging, useful when you use ZNC from different locations" msgstr "" "Te pone ausente con registro de mensajes, útil cuando usas ZNC desde varios " "lugares" znc-1.7.5/modules/po/modules_online.id_ID.po0000644000175000017500000000075513542151610021160 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/modules_online.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules_online.cpp:117 msgid "Makes ZNC's *modules to be \"online\"." msgstr "" znc-1.7.5/modules/po/stickychan.nl_NL.po0000644000175000017500000000502413542151610020330 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: nl\n" "X-Crowdin-File: /1.7.x/modules/po/stickychan.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Dutch\n" "Language: nl_NL\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "Naam" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "Vasthoudend" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "Opslaan" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "Kanaal is vasthoudend" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "<#kanaal> [sleutel]" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "Houd een kanaal vast" #: stickychan.cpp:30 msgid "<#channel>" msgstr "<#kanaal>" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "Houd een kanaal niet meer vast" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "Laat vastgehouden kanalen zien" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "Gebruik: Stick <#kanaal> [sleutel]" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "Vastgezet {1}" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "Gebruik: Unstick <#kanaal>" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "Losgemaakt {1}" #: stickychan.cpp:101 msgid " -- End of List" msgstr " -- Einde van lijst" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "Kon {1} niet toetreden (Mist de # voor het kanaal?)" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "Vastgehouden kanalen" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "Wijzigingen zijn opgeslagen!" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "Kanalen zijn vastgehouden!" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "Kanalen zijn losgelaten!" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "" "Kanaal {1} kon niet toegetreden worden, het is een onjuiste naam voor een " "kanaal. Laat deze los." #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "Lijst van kanalen, gescheiden met comma." #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" "Vastgehouden kanalen zonder configuratie, houd je daar heel stevig vast" znc-1.7.5/modules/po/autoop.es_ES.po0000644000175000017500000001105113542151610017470 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/autoop.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: autoop.cpp:154 msgid "List all users" msgstr "Muestra todos los usuarios" #: autoop.cpp:156 autoop.cpp:159 msgid " [channel] ..." msgstr " [canal] ..." #: autoop.cpp:157 msgid "Adds channels to a user" msgstr "Añade canales a un usuario" #: autoop.cpp:160 msgid "Removes channels from a user" msgstr "Borra canales de un usuario" #: autoop.cpp:162 autoop.cpp:165 msgid " ,[mask] ..." msgstr " ,[máscara] ..." #: autoop.cpp:163 msgid "Adds masks to a user" msgstr "Añade máscaras a un usuario" #: autoop.cpp:166 msgid "Removes masks from a user" msgstr "Borra máscaras de un usuario" #: autoop.cpp:169 msgid " [,...] [channels]" msgstr " [,...] [canales]" #: autoop.cpp:170 msgid "Adds a user" msgstr "Añade un usuario" #: autoop.cpp:172 msgid "" msgstr "" #: autoop.cpp:172 msgid "Removes a user" msgstr "Borra un usuario" #: autoop.cpp:275 msgid "Usage: AddUser [,...] [channels]" msgstr "Uso: AddUser [,...] [canales]" #: autoop.cpp:291 msgid "Usage: DelUser " msgstr "Uso: DelUser " #: autoop.cpp:300 msgid "There are no users defined" msgstr "No hay usuarios definidos" #: autoop.cpp:306 autoop.cpp:317 autoop.cpp:321 autoop.cpp:323 msgid "User" msgstr "Usuario" #: autoop.cpp:307 autoop.cpp:325 msgid "Hostmasks" msgstr "Máscaras" #: autoop.cpp:308 autoop.cpp:318 msgid "Key" msgstr "Clave" #: autoop.cpp:309 autoop.cpp:319 msgid "Channels" msgstr "Canales" #: autoop.cpp:337 msgid "Usage: AddChans [channel] ..." msgstr "Uso: AddChans [canal]" #: autoop.cpp:344 autoop.cpp:365 autoop.cpp:387 autoop.cpp:408 autoop.cpp:472 msgid "No such user" msgstr "No existe el usuario" #: autoop.cpp:349 msgid "Channel(s) added to user {1}" msgstr "Canal(es) añadido(s) al usuario {1}" #: autoop.cpp:358 msgid "Usage: DelChans [channel] ..." msgstr "Uso: DelChans [canal] ..." #: autoop.cpp:371 msgid "Channel(s) Removed from user {1}" msgstr "Canal(es) borrado(s) del usuario {1}" #: autoop.cpp:380 msgid "Usage: AddMasks ,[mask] ..." msgstr "Uso: AddMasks ,[máscara] ..." #: autoop.cpp:392 msgid "Hostmasks(s) added to user {1}" msgstr "Máscara(s) añadida(s) al usuario {1}" #: autoop.cpp:401 msgid "Usage: DelMasks ,[mask] ..." msgstr "Uso: DelMasks ,[máscara] ..." #: autoop.cpp:413 msgid "Removed user {1} with key {2} and channels {3}" msgstr "Borrado usuario {1} con clave {2} y canales {3}" #: autoop.cpp:419 msgid "Hostmasks(s) Removed from user {1}" msgstr "Máscara(s) borrada(s) del usuario {1}" #: autoop.cpp:478 msgid "User {1} removed" msgstr "Usuario {1} eliminado" #: autoop.cpp:484 msgid "That user already exists" msgstr "Ese usuario ya existe" #: autoop.cpp:490 msgid "User {1} added with hostmask(s) {2}" msgstr "Usuario {1} añadido con la(s) máscara(s) {2}" #: autoop.cpp:532 msgid "" "[{1}] sent us a challenge but they are not opped in any defined channels." msgstr "[{1}] nos ha enviado un reto pero no tiene op en ningún canal." #: autoop.cpp:536 msgid "[{1}] sent us a challenge but they do not match a defined user." msgstr "[{1}] nos ha enviado un reto pero no coincide con ningún usuario." #: autoop.cpp:544 msgid "WARNING! [{1}] sent an invalid challenge." msgstr "¡ATENCIÓN! [{1}] ha enviado un reto no válido." #: autoop.cpp:560 msgid "[{1}] sent an unchallenged response. This could be due to lag." msgstr "[{1}] ha enviado una respuesta sin reto. Esto podría deberse a lag." #: autoop.cpp:577 msgid "" "WARNING! [{1}] sent a bad response. Please verify that you have their " "correct password." msgstr "" "¡ATENCIÓN! [{1}] ha enviado un respuesta incorrecta. Por favor, verifica que " "tienes su contraseña correcta." #: autoop.cpp:586 msgid "WARNING! [{1}] sent a response but did not match any defined users." msgstr "¡ATENCIÓN! [{1}] ha respondido pero no coincide con ningún usuario" #: autoop.cpp:644 msgid "Auto op the good people" msgstr "AutoOp a gente conocida" znc-1.7.5/modules/po/simple_away.ru_RU.po0000644000175000017500000000430313542151610020533 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/simple_away.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: simple_away.cpp:56 msgid "[]" msgstr "" #: simple_away.cpp:57 #, c-format msgid "" "Prints or sets the away reason (%awaytime% is replaced with the time you " "were set away, supports substitutions using ExpandString)" msgstr "" #: simple_away.cpp:63 msgid "Prints the current time to wait before setting you away" msgstr "" #: simple_away.cpp:65 msgid "" msgstr "" #: simple_away.cpp:66 msgid "Sets the time to wait before setting you away" msgstr "" #: simple_away.cpp:69 msgid "Disables the wait time before setting you away" msgstr "" #: simple_away.cpp:73 msgid "Get or set the minimum number of clients before going away" msgstr "" #: simple_away.cpp:136 msgid "Away reason set" msgstr "" #: simple_away.cpp:138 msgid "Away reason: {1}" msgstr "" #: simple_away.cpp:139 msgid "Current away reason would be: {1}" msgstr "" #: simple_away.cpp:144 msgid "Current timer setting: 1 second" msgid_plural "Current timer setting: {1} seconds" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: simple_away.cpp:153 simple_away.cpp:161 msgid "Timer disabled" msgstr "" #: simple_away.cpp:155 msgid "Timer set to 1 second" msgid_plural "Timer set to: {1} seconds" msgstr[0] "" msgstr[1] "" msgstr[2] "" msgstr[3] "" #: simple_away.cpp:166 msgid "Current MinClients setting: {1}" msgstr "" #: simple_away.cpp:169 msgid "MinClients set to {1}" msgstr "" #: simple_away.cpp:248 msgid "" "You might enter up to 3 arguments, like -notimer awaymessage or -timer 5 " "awaymessage." msgstr "" #: simple_away.cpp:253 msgid "" "This module will automatically set you away on IRC while you are " "disconnected from the bouncer." msgstr "" znc-1.7.5/modules/po/samplewebapi.it_IT.po0000644000175000017500000000077213542151610020654 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: it\n" "X-Crowdin-File: /1.7.x/modules/po/samplewebapi.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Italian\n" "Language: it_IT\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "Modulo campione delle Web API." znc-1.7.5/modules/po/stickychan.fr_FR.po0000644000175000017500000000364613542151610020334 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/stickychan.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/stickychan/tmpl/index.tmpl:9 msgid "Name" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:10 msgid "Sticky" msgstr "" #: modules/po/../data/stickychan/tmpl/index.tmpl:25 msgid "Save" msgstr "" #: modules/po/../data/stickychan/tmpl/stickychan_WebadminChan.tmpl:8 msgid "Channel is sticky" msgstr "" #: stickychan.cpp:28 msgid "<#channel> [key]" msgstr "" #: stickychan.cpp:28 msgid "Sticks a channel" msgstr "" #: stickychan.cpp:30 msgid "<#channel>" msgstr "" #: stickychan.cpp:30 msgid "Unsticks a channel" msgstr "" #: stickychan.cpp:32 msgid "Lists sticky channels" msgstr "" #: stickychan.cpp:75 msgid "Usage: Stick <#channel> [key]" msgstr "" #: stickychan.cpp:79 msgid "Stuck {1}" msgstr "" #: stickychan.cpp:85 msgid "Usage: Unstick <#channel>" msgstr "" #: stickychan.cpp:89 msgid "Unstuck {1}" msgstr "" #: stickychan.cpp:101 msgid " -- End of List" msgstr "" #: stickychan.cpp:115 msgid "Could not join {1} (# prefix missing?)" msgstr "" #: stickychan.cpp:128 msgid "Sticky Channels" msgstr "" #: stickychan.cpp:160 msgid "Changes have been saved!" msgstr "" #: stickychan.cpp:185 msgid "Channel became sticky!" msgstr "" #: stickychan.cpp:189 msgid "Channel stopped being sticky!" msgstr "" #: stickychan.cpp:209 msgid "" "Channel {1} cannot be joined, it is an illegal channel name. Unsticking." msgstr "" #: stickychan.cpp:246 msgid "List of channels, separated by comma." msgstr "" #: stickychan.cpp:251 msgid "configless sticky chans, keeps you there very stickily even" msgstr "" znc-1.7.5/modules/po/listsockets.ru_RU.po0000644000175000017500000000601213542151610020567 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/listsockets.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: modules/po/../data/listsockets/tmpl/index.tmpl:7 listsockets.cpp:214 #: listsockets.cpp:230 msgid "Name" msgstr "ИмÑ" #: modules/po/../data/listsockets/tmpl/index.tmpl:8 listsockets.cpp:215 #: listsockets.cpp:231 msgid "Created" msgstr "Создан" #: modules/po/../data/listsockets/tmpl/index.tmpl:9 listsockets.cpp:216 #: listsockets.cpp:232 msgid "State" msgstr "СоÑтоÑние" #: modules/po/../data/listsockets/tmpl/index.tmpl:10 listsockets.cpp:218 #: listsockets.cpp:235 msgid "SSL" msgstr "SSL" #: modules/po/../data/listsockets/tmpl/index.tmpl:11 listsockets.cpp:220 #: listsockets.cpp:240 msgid "Local" msgstr "Локальное" #: modules/po/../data/listsockets/tmpl/index.tmpl:12 listsockets.cpp:221 #: listsockets.cpp:242 msgid "Remote" msgstr "Удалённое" #: modules/po/../data/listsockets/tmpl/index.tmpl:13 msgid "Data In" msgstr "ВходÑщий трафик" #: modules/po/../data/listsockets/tmpl/index.tmpl:14 msgid "Data Out" msgstr "ИÑходÑщий трафик" #: listsockets.cpp:62 msgid "[-n]" msgstr "[-n]" #: listsockets.cpp:62 msgid "Shows the list of active sockets. Pass -n to show IP addresses" msgstr "Показать ÑпиÑок активных Ñокетов. Укажите -n Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ð° IP-адреÑов" #: listsockets.cpp:70 msgid "You must be admin to use this module" msgstr "Ð’Ñ‹ должны быть админиÑтратором Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтого модулÑ" #: listsockets.cpp:96 msgid "List sockets" msgstr "СпиÑок Ñокетов" #: listsockets.cpp:116 listsockets.cpp:236 msgctxt "ssl" msgid "Yes" msgstr "Да" #: listsockets.cpp:116 listsockets.cpp:237 msgctxt "ssl" msgid "No" msgstr "Ðет" #: listsockets.cpp:142 msgid "Listener" msgstr "Слушатель" #: listsockets.cpp:144 msgid "Inbound" msgstr "ВходÑщие" #: listsockets.cpp:147 msgid "Outbound" msgstr "ИÑходÑщие" #: listsockets.cpp:149 msgid "Connecting" msgstr "Подключение…" #: listsockets.cpp:152 msgid "UNKNOWN" msgstr "ÐЕИЗВЕСТÐО" #: listsockets.cpp:207 msgid "You have no open sockets." msgstr "У Ð²Ð°Ñ Ð½ÐµÑ‚ открытых Ñокетов." #: listsockets.cpp:222 listsockets.cpp:244 msgid "In" msgstr "ВходÑщие данные" #: listsockets.cpp:223 listsockets.cpp:246 msgid "Out" msgstr "ИÑходÑщие данные" #: listsockets.cpp:262 msgid "Lists active sockets" msgstr "СпиÑок активных Ñокетов" znc-1.7.5/modules/po/q.id_ID.po0000644000175000017500000001303113542151610016373 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/q.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" #: q.cpp:111 msgid "The following commands are available:" msgstr "" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "" #: q.cpp:116 msgid "Auth [ ]" msgstr "" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "" #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" #: q.cpp:128 msgid "Prints the current status of the module." msgstr "" #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "" #: q.cpp:135 msgid "Set " msgstr "" #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" #: q.cpp:146 msgid "The following settings are available:" msgstr "" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "" #: q.cpp:154 msgid "Your Q username." msgstr "" #: q.cpp:158 msgid "Your Q password." msgstr "" #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "" #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "" #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "" #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "" #: q.cpp:200 msgid "Syntax: Set " msgstr "" #: q.cpp:203 msgid "Username set" msgstr "" #: q.cpp:206 msgid "Password set" msgstr "" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "" #: q.cpp:212 msgid "UseChallenge set" msgstr "" #: q.cpp:215 msgid "RequestPerms set" msgstr "" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "" #: q.cpp:253 msgid "Connected: yes" msgstr "" #: q.cpp:254 msgid "Connected: no" msgstr "" #: q.cpp:255 msgid "Cloacked: yes" msgstr "" #: q.cpp:255 msgid "Cloacked: no" msgstr "" #: q.cpp:256 msgid "Authenticated: yes" msgstr "" #: q.cpp:257 msgid "Authenticated: no" msgstr "" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "" #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "" #: q.cpp:280 msgid "Update requested." msgstr "" #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "" #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "" #: q.cpp:408 msgid "Changes have been saved!" msgstr "" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "" #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "" #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "" #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "" #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "" znc-1.7.5/modules/po/adminlog.id_ID.po0000644000175000017500000000332213542151610017727 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: id\n" "X-Crowdin-File: /1.7.x/modules/po/adminlog.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Indonesian\n" "Language: id_ID\n" #: adminlog.cpp:29 msgid "Show the logging target" msgstr "Tampilkan target log" #: adminlog.cpp:31 msgid " [path]" msgstr " [path]" #: adminlog.cpp:32 msgid "Set the logging target" msgstr "Atur target log" #: adminlog.cpp:142 msgid "Access denied" msgstr "Akses ditolak" #: adminlog.cpp:156 msgid "Now logging to file" msgstr "Sekarang log dicatat ke file" #: adminlog.cpp:160 msgid "Now only logging to syslog" msgstr "Sekarang hanya mencatat log ke syslog" #: adminlog.cpp:164 msgid "Now logging to syslog and file" msgstr "Sekarang mencatat log ke systlog dan file" #: adminlog.cpp:168 msgid "Usage: Target [path]" msgstr "Gunakan: Target [path]" #: adminlog.cpp:170 msgid "Unknown target" msgstr "Target tidak diketahui" #: adminlog.cpp:192 msgid "Logging is enabled for file" msgstr "Log diaktifkan untuk file" #: adminlog.cpp:195 msgid "Logging is enabled for syslog" msgstr "Log diaktifkan untuk syslog" #: adminlog.cpp:198 msgid "Logging is enabled for both, file and syslog" msgstr "Log diaktifkan untuk both, file dan syslog" #: adminlog.cpp:204 msgid "Log file will be written to {1}" msgstr "Log akan di tulis ke {1}" #: adminlog.cpp:222 msgid "Log ZNC events to file and/or syslog." msgstr "Catat log kejadian ZNC ke file dan/atau syslog." znc-1.7.5/modules/po/lastseen.fr_FR.po0000644000175000017500000000260513542151610020004 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: fr\n" "X-Crowdin-File: /1.7.x/modules/po/lastseen.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: French\n" "Language: fr_FR\n" #: modules/po/../data/lastseen/tmpl/index.tmpl:8 msgid "User" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:9 lastseen.cpp:98 msgid "Last Seen" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:10 msgid "Info" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:11 msgid "Action" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:21 msgid "Edit" msgstr "" #: modules/po/../data/lastseen/tmpl/index.tmpl:22 msgid "Delete" msgstr "" #: modules/po/../data/lastseen/tmpl/lastseen_WebadminUser.tmpl:6 msgid "Last login time:" msgstr "" #: lastseen.cpp:53 msgid "Access denied" msgstr "" #: lastseen.cpp:61 lastseen.cpp:66 msgctxt "show" msgid "User" msgstr "" #: lastseen.cpp:62 lastseen.cpp:67 msgctxt "show" msgid "Last Seen" msgstr "" #: lastseen.cpp:68 lastseen.cpp:124 msgid "never" msgstr "" #: lastseen.cpp:78 msgid "Shows list of users and when they last logged in" msgstr "" #: lastseen.cpp:153 msgid "Collects data about when a user last logged in." msgstr "" znc-1.7.5/modules/po/q.de_DE.po0000644000175000017500000001323013542151610016364 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: de\n" "X-Crowdin-File: /1.7.x/modules/po/q.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: German\n" "Language: de_DE\n" #: modules/po/../data/q/tmpl/index.tmpl:11 msgid "Username:" msgstr "Benutzername:" #: modules/po/../data/q/tmpl/index.tmpl:13 msgid "Please enter a username." msgstr "Bitte gib einen Benutzernamen ein." #: modules/po/../data/q/tmpl/index.tmpl:16 msgid "Password:" msgstr "Passwort:" #: modules/po/../data/q/tmpl/index.tmpl:18 msgid "Please enter a password." msgstr "Bitte geben Sie ein Passwort ein." #: modules/po/../data/q/tmpl/index.tmpl:26 msgid "Options" msgstr "Optionen" #: modules/po/../data/q/tmpl/index.tmpl:42 msgid "Save" msgstr "Speichern" #: q.cpp:74 msgid "" "Notice: Your host will be cloaked the next time you reconnect to IRC. If you " "want to cloak your host now, /msg *q Cloak. You can set your preference " "with /msg *q Set UseCloakedHost true/false." msgstr "" #: q.cpp:111 msgid "The following commands are available:" msgstr "" #: q.cpp:113 q.cpp:116 q.cpp:121 q.cpp:126 q.cpp:130 q.cpp:135 q.cpp:140 msgid "Command" msgstr "Befehl" #: q.cpp:114 q.cpp:117 q.cpp:123 q.cpp:127 q.cpp:132 q.cpp:136 q.cpp:141 #: q.cpp:150 q.cpp:154 q.cpp:158 q.cpp:162 q.cpp:168 q.cpp:174 q.cpp:180 #: q.cpp:186 msgid "Description" msgstr "Beschreibung" #: q.cpp:116 msgid "Auth [ ]" msgstr "" #: q.cpp:118 msgid "Tries to authenticate you with Q. Both parameters are optional." msgstr "" #: q.cpp:124 msgid "Tries to set usermode +x to hide your real hostname." msgstr "" #: q.cpp:128 msgid "Prints the current status of the module." msgstr "" #: q.cpp:133 msgid "Re-requests the current user information from Q." msgstr "" #: q.cpp:135 msgid "Set " msgstr "" #: q.cpp:137 msgid "Changes the value of the given setting. See the list of settings below." msgstr "" #: q.cpp:142 msgid "Prints out the current configuration. See the list of settings below." msgstr "" #: q.cpp:146 msgid "The following settings are available:" msgstr "" #: q.cpp:148 q.cpp:152 q.cpp:156 q.cpp:160 q.cpp:166 q.cpp:172 q.cpp:178 #: q.cpp:183 q.cpp:227 q.cpp:230 q.cpp:233 q.cpp:236 q.cpp:239 q.cpp:242 #: q.cpp:245 q.cpp:248 msgid "Setting" msgstr "" #: q.cpp:149 q.cpp:153 q.cpp:157 q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 #: q.cpp:184 msgid "Type" msgstr "" #: q.cpp:153 q.cpp:157 msgid "String" msgstr "" #: q.cpp:154 msgid "Your Q username." msgstr "" #: q.cpp:158 msgid "Your Q password." msgstr "" #: q.cpp:161 q.cpp:167 q.cpp:173 q.cpp:179 q.cpp:184 msgid "Boolean" msgstr "" #: q.cpp:163 q.cpp:373 msgid "Whether to cloak your hostname (+x) automatically on connect." msgstr "" #: q.cpp:169 q.cpp:381 msgid "" "Whether to use the CHALLENGEAUTH mechanism to avoid sending passwords in " "cleartext." msgstr "" #: q.cpp:175 q.cpp:389 msgid "Whether to request voice/op from Q on join/devoice/deop." msgstr "" #: q.cpp:181 q.cpp:395 msgid "Whether to join channels when Q invites you." msgstr "" #: q.cpp:187 q.cpp:402 msgid "Whether to delay joining channels until after you are cloaked." msgstr "" #: q.cpp:192 msgid "This module takes 2 optional parameters: " msgstr "" #: q.cpp:194 msgid "Module settings are stored between restarts." msgstr "" #: q.cpp:200 msgid "Syntax: Set " msgstr "" #: q.cpp:203 msgid "Username set" msgstr "" #: q.cpp:206 msgid "Password set" msgstr "" #: q.cpp:209 msgid "UseCloakedHost set" msgstr "" #: q.cpp:212 msgid "UseChallenge set" msgstr "" #: q.cpp:215 msgid "RequestPerms set" msgstr "" #: q.cpp:218 msgid "JoinOnInvite set" msgstr "" #: q.cpp:221 msgid "JoinAfterCloaked set" msgstr "" #: q.cpp:223 msgid "Unknown setting: {1}" msgstr "" #: q.cpp:228 q.cpp:231 q.cpp:234 q.cpp:237 q.cpp:240 q.cpp:243 q.cpp:246 #: q.cpp:249 msgid "Value" msgstr "" #: q.cpp:253 msgid "Connected: yes" msgstr "" #: q.cpp:254 msgid "Connected: no" msgstr "" #: q.cpp:255 msgid "Cloacked: yes" msgstr "" #: q.cpp:255 msgid "Cloacked: no" msgstr "" #: q.cpp:256 msgid "Authenticated: yes" msgstr "" #: q.cpp:257 msgid "Authenticated: no" msgstr "" #: q.cpp:262 msgid "Error: You are not connected to IRC." msgstr "" #: q.cpp:270 msgid "Error: You are already cloaked!" msgstr "" #: q.cpp:276 msgid "Error: You are already authed!" msgstr "" #: q.cpp:280 msgid "Update requested." msgstr "" #: q.cpp:283 msgid "Unknown command. Try 'help'." msgstr "" #: q.cpp:293 msgid "Cloak successful: Your hostname is now cloaked." msgstr "" #: q.cpp:408 msgid "Changes have been saved!" msgstr "" #: q.cpp:435 msgid "Cloak: Trying to cloak your hostname, setting +x..." msgstr "" #: q.cpp:452 msgid "" "You have to set a username and password to use this module! See 'help' for " "details." msgstr "" #: q.cpp:458 msgid "Auth: Requesting CHALLENGE..." msgstr "" #: q.cpp:462 msgid "Auth: Sending AUTH request..." msgstr "" #: q.cpp:479 msgid "Auth: Received challenge, sending CHALLENGEAUTH request..." msgstr "" #: q.cpp:521 msgid "Authentication failed: {1}" msgstr "" #: q.cpp:525 msgid "Authentication successful: {1}" msgstr "" #: q.cpp:539 msgid "" "Auth failed: Q does not support HMAC-SHA-256 for CHALLENGEAUTH, falling back " "to standard AUTH." msgstr "" #: q.cpp:566 msgid "RequestPerms: Requesting op on {1}" msgstr "" #: q.cpp:579 msgid "RequestPerms: Requesting voice on {1}" msgstr "" #: q.cpp:686 msgid "Please provide your username and password for Q." msgstr "" #: q.cpp:689 msgid "Auths you with QuakeNet's Q bot." msgstr "" znc-1.7.5/modules/po/samplewebapi.es_ES.po0000644000175000017500000000077213542151610020642 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: es-ES\n" "X-Crowdin-File: /1.7.x/modules/po/samplewebapi.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Spanish\n" "Language: es_ES\n" #: samplewebapi.cpp:59 msgid "Sample Web API module." msgstr "Muestra de módulo web API." znc-1.7.5/modules/po/pyeval.ru_RU.po0000644000175000017500000000132013542151610017515 0ustar somebodysomebodymsgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 " "&& n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 " "&& n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: znc-bouncer\n" "X-Crowdin-Language: ru\n" "X-Crowdin-File: /1.7.x/modules/po/pyeval.pot\n" "Project-Id-Version: znc-bouncer\n" "Last-Translator: Various people\n" "Language-Team: Russian\n" "Language: ru_RU\n" #: pyeval.py:49 msgid "You must have admin privileges to load this module." msgstr "" #: pyeval.py:82 msgid "Evaluates python code" msgstr "" znc-1.7.5/modules/lastseen.cpp0000644000175000017500000001116413542151610016535 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include using std::map; using std::pair; using std::multimap; class CLastSeenMod : public CModule { private: time_t GetTime(const CUser* pUser) { return GetNV(pUser->GetUserName()).ToULong(); } void SetTime(const CUser* pUser) { SetNV(pUser->GetUserName(), CString(time(nullptr))); } const CString FormatLastSeen(const CUser* pUser, const CString& sDefault = "") { time_t last = GetTime(pUser); if (last < 1) { return sDefault; } else { char buf[1024]; strftime(buf, sizeof(buf) - 1, "%c", localtime(&last)); return buf; } } typedef multimap MTimeMulti; typedef map MUsers; // Shows all users as well as the time they were last seen online void ShowCommand(const CString& sLine) { if (!GetUser()->IsAdmin()) { PutModule(t_s("Access denied")); return; } const MUsers& mUsers = CZNC::Get().GetUserMap(); MUsers::const_iterator it; CTable Table; Table.AddColumn(t_s("User", "show")); Table.AddColumn(t_s("Last Seen", "show")); for (it = mUsers.begin(); it != mUsers.end(); ++it) { Table.AddRow(); Table.SetCell(t_s("User", "show"), it->first); Table.SetCell(t_s("Last Seen", "show"), FormatLastSeen(it->second, t_s("never"))); } PutModule(Table); } public: MODCONSTRUCTOR(CLastSeenMod) { AddHelpCommand(); AddCommand("Show", "", t_d("Shows list of users and when they last logged in"), [=](const CString& sLine) { ShowCommand(sLine); }); } ~CLastSeenMod() override {} // Event stuff: void OnClientLogin() override { SetTime(GetUser()); } void OnClientDisconnect() override { SetTime(GetUser()); } EModRet OnDeleteUser(CUser& User) override { DelNV(User.GetUserName()); return CONTINUE; } // Web stuff: bool WebRequiresAdmin() override { return true; } CString GetWebMenuTitle() override { return t_s("Last Seen"); } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "index") { CModules& GModules = CZNC::Get().GetModules(); Tmpl["WebAdminLoaded"] = CString(GModules.FindModule("webadmin") != nullptr); MTimeMulti mmSorted; const MUsers& mUsers = CZNC::Get().GetUserMap(); for (MUsers::const_iterator uit = mUsers.begin(); uit != mUsers.end(); ++uit) { mmSorted.insert( pair(GetTime(uit->second), uit->second)); } for (MTimeMulti::const_iterator it = mmSorted.begin(); it != mmSorted.end(); ++it) { CUser* pUser = it->second; CTemplate& Row = Tmpl.AddRow("UserLoop"); Row["Username"] = pUser->GetUserName(); Row["IsSelf"] = CString(pUser == WebSock.GetSession()->GetUser()); Row["LastSeen"] = FormatLastSeen(pUser, t_s("never")); } return true; } return false; } bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "webadmin/user" && WebSock.GetSession()->IsAdmin()) { CUser* pUser = CZNC::Get().FindUser(Tmpl["Username"]); if (pUser) { Tmpl["LastSeen"] = FormatLastSeen(pUser); } return true; } return false; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("lastseen"); } GLOBALMODULEDEFS(CLastSeenMod, t_s("Collects data about when a user last logged in.")) znc-1.7.5/modules/flooddetach.cpp0000644000175000017500000002030313542151610017166 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include using std::map; class CFloodDetachMod : public CModule { public: MODCONSTRUCTOR(CFloodDetachMod) { m_iThresholdSecs = 0; m_iThresholdMsgs = 0; AddHelpCommand(); AddCommand("Show", "", t_d("Show current limits"), [=](const CString& sLine) { ShowCommand(sLine); }); AddCommand("Secs", t_d("[]"), t_d("Show or set number of seconds in the time interval"), [=](const CString& sLine) { SecsCommand(sLine); }); AddCommand("Lines", t_d("[]"), t_d("Show or set number of lines in the time interval"), [=](const CString& sLine) { LinesCommand(sLine); }); AddCommand("Silent", "[yes|no]", t_d("Show or set whether to notify you about detaching and " "attaching back"), [=](const CString& sLine) { SilentCommand(sLine); }); } ~CFloodDetachMod() override {} void Save() { // We save the settings twice because the module arguments can // be more easily edited via webadmin, while the SetNV() stuff // survives e.g. /msg *status reloadmod ctcpflood. SetNV("secs", CString(m_iThresholdSecs)); SetNV("msgs", CString(m_iThresholdMsgs)); SetArgs(CString(m_iThresholdMsgs) + " " + CString(m_iThresholdSecs)); } bool OnLoad(const CString& sArgs, CString& sMessage) override { m_iThresholdMsgs = sArgs.Token(0).ToUInt(); m_iThresholdSecs = sArgs.Token(1).ToUInt(); if (m_iThresholdMsgs == 0 || m_iThresholdSecs == 0) { m_iThresholdMsgs = GetNV("msgs").ToUInt(); m_iThresholdSecs = GetNV("secs").ToUInt(); } if (m_iThresholdSecs == 0) m_iThresholdSecs = 2; if (m_iThresholdMsgs == 0) m_iThresholdMsgs = 5; Save(); return true; } void OnIRCDisconnected() override { m_chans.clear(); } void Cleanup() { Limits::iterator it; time_t now = time(nullptr); for (it = m_chans.begin(); it != m_chans.end(); ++it) { // The timeout for this channel did not expire yet? if (it->second.first + (time_t)m_iThresholdSecs >= now) continue; CChan* pChan = GetNetwork()->FindChan(it->first); if (it->second.second >= m_iThresholdMsgs && pChan && pChan->IsDetached()) { // The channel is detached and it is over the // messages limit. Since we only track those // limits for non-detached channels or for // channels which we detached, this means that // we detached because of a flood. if (!GetNV("silent").ToBool()) { PutModule(t_f("Flood in {1} is over, reattaching...")( pChan->GetName())); } // No buffer playback, makes sense, doesn't it? pChan->ClearBuffer(); pChan->AttachUser(); } Limits::iterator it2 = it++; m_chans.erase(it2); // Without this Bad Things (tm) could happen if (it == m_chans.end()) break; } } void Message(CChan& Channel) { Limits::iterator it; time_t now = time(nullptr); // First: Clean up old entries and reattach where necessary Cleanup(); it = m_chans.find(Channel.GetName()); if (it == m_chans.end()) { // We don't track detached channels if (Channel.IsDetached()) return; // This is the first message for this channel, start a // new timeout. std::pair tmp(now, 1); m_chans[Channel.GetName()] = tmp; return; } // No need to check it->second.first (expiry time), since // Cleanup() would have removed it if it was expired. if (it->second.second >= m_iThresholdMsgs) { // The channel already hit the limit and we detached the // user, but it is still being flooded, reset the timeout it->second.first = now; it->second.second++; return; } it->second.second++; if (it->second.second < m_iThresholdMsgs) return; // The channel hit the limit, reset the timeout so that we keep // it detached for longer. it->second.first = now; Channel.DetachUser(); if (!GetNV("silent").ToBool()) { PutModule(t_f("Channel {1} was flooded, you've been detached")( Channel.GetName())); } } EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override { Message(Channel); return CONTINUE; } // This also catches OnChanAction() EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) override { Message(Channel); return CONTINUE; } EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) override { Message(Channel); return CONTINUE; } EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) override { Message(Channel); return CONTINUE; } void OnNick(const CNick& Nick, const CString& sNewNick, const std::vector& vChans) override { for (CChan* pChan : vChans) { Message(*pChan); } } void ShowCommand(const CString& sLine) { CString sLines = t_p("1 line", "{1} lines", m_iThresholdMsgs)(m_iThresholdMsgs); CString sSeconds = t_p("every second", "every {1} seconds", m_iThresholdSecs)(m_iThresholdSecs); PutModule(t_f("Current limit is {1} {2}")(sLines, sSeconds)); } void SecsCommand(const CString& sLine) { const CString sArg = sLine.Token(1, true); if (sArg.empty()) { PutModule(t_f("Seconds limit is {1}")(m_iThresholdSecs)); } else { m_iThresholdSecs = sArg.ToUInt(); if (m_iThresholdSecs == 0) m_iThresholdSecs = 1; PutModule(t_f("Set seconds limit to {1}")(m_iThresholdSecs)); Save(); } } void LinesCommand(const CString& sLine) { const CString sArg = sLine.Token(1, true); if (sArg.empty()) { PutModule(t_f("Lines limit is {1}")(m_iThresholdMsgs)); } else { m_iThresholdMsgs = sArg.ToUInt(); if (m_iThresholdMsgs == 0) m_iThresholdMsgs = 2; PutModule(t_f("Set lines limit to {1}")(m_iThresholdMsgs)); Save(); } } void SilentCommand(const CString& sLine) { const CString sArg = sLine.Token(1, true); if (!sArg.empty()) { SetNV("silent", CString(sArg.ToBool())); } if (GetNV("silent").ToBool()) { PutModule(t_s("Module messages are disabled")); } else { PutModule(t_s("Module messages are enabled")); } } private: typedef map> Limits; Limits m_chans; unsigned int m_iThresholdSecs; unsigned int m_iThresholdMsgs; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("flooddetach"); Info.SetHasArgs(true); Info.SetArgsHelpText( Info.t_s("This user module takes up to two arguments. Arguments are " "numbers of messages and seconds.")); } USERMODULEDEFS(CFloodDetachMod, t_s("Detach channels when flooded")) znc-1.7.5/modules/shell.cpp0000644000175000017500000001203713542151610016026 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include using std::vector; // Forward Declaration class CShellMod; class CShellSock : public CExecSock { public: CShellSock(CShellMod* pShellMod, CClient* pClient, const CString& sExec) : CExecSock() { EnableReadLine(); m_pParent = pShellMod; m_pClient = pClient; if (Execute(sExec) == -1) { auto e = errno; ReadLine(t_f("Failed to execute: {1}")(strerror(e))); return; } // Get rid of that write fd, we aren't going to use it // (And clients expecting input will fail this way). close(GetWSock()); SetWSock(open("/dev/null", O_WRONLY)); } // These next two function's bodies are at the bottom of the file since they // reference CShellMod void ReadLine(const CString& sData) override; void Disconnected() override; bool IsOfClient(CClient* pClient) const { return pClient == m_pClient; } bool IsOfModule(CShellMod* pParent) const { return pParent == m_pParent; } CShellMod* m_pParent; private: CClient* m_pClient; }; class CShellMod : public CModule { public: MODCONSTRUCTOR(CShellMod) { m_sPath = CZNC::Get().GetHomePath(); } ~CShellMod() override { vector vSocks = GetManager()->FindSocksByName("SHELL"); for (unsigned int a = 0; a < vSocks.size(); a++) { GetManager()->DelSockByAddr(vSocks[a]); } } bool OnLoad(const CString& sArgs, CString& sMessage) override { #ifndef MOD_SHELL_ALLOW_EVERYONE if (!GetUser()->IsAdmin()) { sMessage = t_s("You must be admin to use the shell module"); return false; } #endif return true; } void OnModCommand(const CString& sLine) override { CString sCommand = sLine.Token(0); if (sCommand.Equals("cd")) { CString sArg = sLine.Token(1, true); CString sPath = CDir::ChangeDir( m_sPath, (sArg.empty() ? CString(CZNC::Get().GetHomePath()) : sArg), CZNC::Get().GetHomePath()); CFile Dir(sPath); if (Dir.IsDir()) { m_sPath = sPath; } else if (Dir.Exists()) { PutShell("cd: not a directory [" + sPath + "]"); } else { PutShell("cd: no such directory [" + sPath + "]"); } PutShell("znc$"); } else { RunCommand(sLine); } } void PutShell(const CString& sMsg) { CString sPath = m_sPath.Replace_n(" ", "_"); CString sSource = ":" + GetModNick() + "!shell@" + sPath; CString sLine = sSource + " PRIVMSG " + GetClient()->GetNick() + " :" + sMsg; GetClient()->PutClient(sLine); } void RunCommand(const CString& sCommand) { GetManager()->AddSock( new CShellSock(this, GetClient(), "cd " + m_sPath + " && " + sCommand), "SHELL"); } void OnClientDisconnect() override { std::vector vDeadCommands; for (Csock* pSock : *GetManager()) { if (CShellSock* pSSock = dynamic_cast(pSock)) { if (pSSock->IsOfModule(this) && pSSock->IsOfClient(GetClient())) { vDeadCommands.push_back(pSock); } } } for (Csock* pSock : vDeadCommands) { GetManager()->DelSockByAddr(pSock); } } private: CString m_sPath; }; void CShellSock::ReadLine(const CString& sData) { CString sLine = sData; sLine.TrimRight("\r\n"); sLine.Replace("\t", " "); m_pParent->SetClient(m_pClient); m_pParent->PutShell(sLine); m_pParent->SetClient(nullptr); } void CShellSock::Disconnected() { // If there is some incomplete line in the buffer, read it // (e.g. echo echo -n "hi" triggered this) CString& sBuffer = GetInternalReadBuffer(); if (!sBuffer.empty()) ReadLine(sBuffer); m_pParent->SetClient(m_pClient); m_pParent->PutShell("znc$"); m_pParent->SetClient(nullptr); } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("shell"); } #ifdef MOD_SHELL_ALLOW_EVERYONE USERMODULEDEFS(CShellMod, t_s("Gives shell access")) #else USERMODULEDEFS(CShellMod, t_s("Gives shell access. Only ZNC admins can use it.")) #endif znc-1.7.5/modules/autoreply.cpp0000644000175000017500000000601513542151610016742 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * Copyright (C) 2008 Michael "Svedrin" Ziegler diese-addy@funzt-halt.net * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include class CAutoReplyMod : public CModule { public: MODCONSTRUCTOR(CAutoReplyMod) { AddHelpCommand(); AddCommand("Set", t_d(""), t_d("Sets a new reply"), [=](const CString& sLine) { OnSetCommand(sLine); }); AddCommand("Show", "", t_d("Displays the current query reply"), [=](const CString& sLine) { OnShowCommand(sLine); }); m_Messaged.SetTTL(1000 * 120); } ~CAutoReplyMod() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { if (!sArgs.empty()) { SetReply(sArgs); } return true; } void SetReply(const CString& sReply) { SetNV("Reply", sReply); } CString GetReply() { CString sReply = GetNV("Reply"); if (sReply.empty()) { sReply = "%nick% is currently away, try again later"; SetReply(sReply); } return ExpandString(sReply); } void Handle(const CString& sNick) { CIRCSock* pIRCSock = GetNetwork()->GetIRCSock(); if (!pIRCSock) // WTF? return; if (sNick == pIRCSock->GetNick()) return; if (m_Messaged.HasItem(sNick)) return; if (GetNetwork()->IsUserAttached()) return; m_Messaged.AddItem(sNick); PutIRC("NOTICE " + sNick + " :" + GetReply()); } EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override { Handle(Nick.GetNick()); return CONTINUE; } void OnShowCommand(const CString& sCommand) { CString sReply = GetReply(); PutModule(t_f("Current reply is: {1} ({2})")(GetNV("Reply"), sReply)); } void OnSetCommand(const CString& sCommand) { SetReply(sCommand.Token(1, true)); PutModule( t_f("New reply set to: {1} ({2})")(GetNV("Reply"), GetReply())); } private: TCacheMap m_Messaged; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("autoreply"); Info.AddType(CModInfo::NetworkModule); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s( "You might specify a reply text. It is used when automatically " "answering queries, if you are not connected to ZNC.")); } USERMODULEDEFS(CAutoReplyMod, t_s("Reply to queries when you are away")) znc-1.7.5/modules/sample.cpp0000644000175000017500000002576113542151610016210 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include using std::vector; #ifdef HAVE_PTHREAD class CSampleJob : public CModuleJob { public: CSampleJob(CModule* pModule) : CModuleJob(pModule, "sample", "Message the user after a delay") {} ~CSampleJob() override { if (wasCancelled()) { GetModule()->PutModule(GetModule()->t_s("Sample job cancelled")); } else { GetModule()->PutModule(GetModule()->t_s("Sample job destroyed")); } } void runThread() override { // Cannot safely use GetModule() in here, because this runs in its // own thread and such an access would require synchronisation // between this thread and the main thread! for (int i = 0; i < 10; i++) { // Regularly check if we were cancelled if (wasCancelled()) return; sleep(1); } } void runMain() override { GetModule()->PutModule(GetModule()->t_s("Sample job done")); } }; #endif class CSampleTimer : public CTimer { public: CSampleTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {} ~CSampleTimer() override {} private: protected: void RunJob() override { GetModule()->PutModule(GetModule()->t_s("TEST!!!!")); } }; class CSampleMod : public CModule { public: MODCONSTRUCTOR(CSampleMod) {} bool OnLoad(const CString& sArgs, CString& sMessage) override { PutModule(t_f("I'm being loaded with the arguments: {1}")(sArgs)); // AddTimer(new CSampleTimer(this, 300, 0, "Sample", "Sample timer for sample // things.")); // AddTimer(new CSampleTimer(this, 5, 20, "Another", "Another sample timer.")); // AddTimer(new CSampleTimer(this, 25000, 5, "Third", "A third sample timer.")); #ifdef HAVE_PTHREAD AddJob(new CSampleJob(this)); #endif return true; } ~CSampleMod() override { PutModule(t_s("I'm being unloaded!")); } bool OnBoot() override { // This is called when the app starts up (only modules that are loaded // in the config will get this event) return true; } void OnIRCConnected() override { PutModule(t_s("You got connected BoyOh.")); } void OnIRCDisconnected() override { PutModule(t_s("You got disconnected BoyOh.")); } EModRet OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) override { sRealName += " - ZNC"; return CONTINUE; } EModRet OnBroadcast(CString& sMessage) override { PutModule("------ [" + sMessage + "]"); sMessage = "======== [" + sMessage + "] ========"; return CONTINUE; } void OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) override { PutModule(t_f("{1} {2} set mode on {3} {4}{5} {6}")( bNoChange, OpNick.GetNick(), Channel.GetName(), bAdded ? '+' : '-', uMode, Nick.GetNick())); } void OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override { PutModule(t_f("{1} {2} opped {3} on {4}")( bNoChange, OpNick.GetNick(), Nick.GetNick(), Channel.GetName())); } void OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override { PutModule(t_f("{1} {2} deopped {3} on {4}")( bNoChange, OpNick.GetNick(), Nick.GetNick(), Channel.GetName())); } void OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override { PutModule(t_f("{1} {2} voiced {3} on {4}")( bNoChange, OpNick.GetNick(), Nick.GetNick(), Channel.GetName())); } void OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) override { PutModule(t_f("{1} {2} devoiced {3} on {4}")( bNoChange, OpNick.GetNick(), Nick.GetNick(), Channel.GetName())); } void OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) override { PutModule(t_f("* {1} sets mode: {2} {3} on {4}")( OpNick.GetNick(), sModes, sArgs, Channel.GetName())); } EModRet OnRaw(CString& sLine) override { // PutModule(t_f("OnRaw(): {1}")(sLine)); return CONTINUE; } EModRet OnUserRaw(CString& sLine) override { // PutModule(t_f("OnUserRaw(): {1}")(sLine)); return CONTINUE; } void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) override { PutModule(t_f("{1} kicked {2} from {3} with the msg {4}")( OpNick.GetNick(), sKickedNick, Channel.GetName(), sMessage)); } void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) override { PutModule(t_p("* {1} ({2}@{3}) quits ({4}) from channel: {6}", "* {1} ({2}@{3}) quits ({4}) from {5} channels: {6}", vChans.size())( Nick.GetNick(), Nick.GetIdent(), Nick.GetHost(), sMessage, vChans.size(), CString(", ").Join(vChans.begin(), vChans.end()))); } EModRet OnTimerAutoJoin(CChan& Channel) override { PutModule(t_f("Attempting to join {1}")(Channel.GetName())); return CONTINUE; } void OnJoin(const CNick& Nick, CChan& Channel) override { PutModule(t_f("* {1} ({2}@{3}) joins {4}")( Nick.GetNick(), Nick.GetIdent(), Nick.GetHost(), Channel.GetName())); } void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) override { PutModule(t_f("* {1} ({2}@{3}) parts {4}")( Nick.GetNick(), Nick.GetIdent(), Nick.GetHost(), Channel.GetName())); } EModRet OnInvite(const CNick& Nick, const CString& sChan) override { if (sChan.Equals("#test")) { PutModule(t_f("{1} invited us to {2}, ignoring invites to {2}")( Nick.GetNick(), sChan)); return HALT; } PutModule(t_f("{1} invited us to {2}")(Nick.GetNick(), sChan)); return CONTINUE; } void OnNick(const CNick& OldNick, const CString& sNewNick, const vector& vChans) override { PutModule(t_f("{1} is now known as {2}")(OldNick.GetNick(), sNewNick)); } EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage) override { PutModule("[" + sTarget + "] userctcpreply [" + sMessage + "]"); sMessage = "\037" + sMessage + "\037"; return CONTINUE; } EModRet OnCTCPReply(CNick& Nick, CString& sMessage) override { PutModule("[" + Nick.GetNick() + "] ctcpreply [" + sMessage + "]"); return CONTINUE; } EModRet OnUserCTCP(CString& sTarget, CString& sMessage) override { PutModule("[" + sTarget + "] userctcp [" + sMessage + "]"); return CONTINUE; } EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override { PutModule("[" + Nick.GetNick() + "] privctcp [" + sMessage + "]"); sMessage = "\002" + sMessage + "\002"; return CONTINUE; } EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) override { PutModule("[" + Nick.GetNick() + "] chanctcp [" + sMessage + "] to [" + Channel.GetName() + "]"); sMessage = "\00311,5 " + sMessage + " \003"; return CONTINUE; } EModRet OnUserNotice(CString& sTarget, CString& sMessage) override { PutModule("[" + sTarget + "] usernotice [" + sMessage + "]"); sMessage = "\037" + sMessage + "\037"; return CONTINUE; } EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override { PutModule("[" + Nick.GetNick() + "] privnotice [" + sMessage + "]"); sMessage = "\002" + sMessage + "\002"; return CONTINUE; } EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) override { PutModule("[" + Nick.GetNick() + "] channotice [" + sMessage + "] to [" + Channel.GetName() + "]"); sMessage = "\00311,5 " + sMessage + " \003"; return CONTINUE; } EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) override { PutModule(t_f("{1} changes topic on {2} to {3}")( Nick.GetNick(), Channel.GetName(), sTopic)); return CONTINUE; } EModRet OnUserTopic(CString& sTarget, CString& sTopic) override { PutModule(t_f("{1} changes topic on {2} to {3}")(GetClient()->GetNick(), sTarget, sTopic)); return CONTINUE; } // Appends "Sample:" to an outgoing message and colors it red. EModRet OnUserMsg(CString& sTarget, CString& sMessage) override { PutModule("[" + sTarget + "] usermsg [" + sMessage + "]"); sMessage = "Sample: \0034" + sMessage + "\003"; return CONTINUE; } // Bolds an incoming message. EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override { PutModule("[" + Nick.GetNick() + "] privmsg [" + sMessage + "]"); sMessage = "\002" + sMessage + "\002"; return CONTINUE; } EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override { if (sMessage == "!ping") { PutIRC("PRIVMSG " + Channel.GetName() + " :PONG?"); } sMessage = "x " + sMessage + " x"; PutModule(sMessage); return CONTINUE; } void OnModCommand(const CString& sCommand) override { if (sCommand.Equals("TIMERS")) { ListTimers(); } } EModRet OnStatusCommand(CString& sCommand) override { if (sCommand.Equals("SAMPLE")) { PutModule(t_s("Hi, I'm your friendly sample module.")); return HALT; } return CONTINUE; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("sample"); Info.SetHasArgs(true); Info.SetArgsHelpText( Info.t_s("Description of module arguments goes here.")); } MODULEDEFS(CSampleMod, t_s("To be used as a sample for writing modules")) znc-1.7.5/modules/modtcl/0000755000175000017500000000000013542151610015472 5ustar somebodysomebodyznc-1.7.5/modules/modtcl/Makefile.inc0000644000175000017500000000060313542151610017701 0ustar somebodysomebodyifeq "$(TCL_FLAGS)" "" FILES := $(shell echo $(FILES) | sed -e "s:modtcl::") else TCLHOOK := modtcl_install endif modtclCXXFLAGS := $(TCL_FLAGS) modtclLDFLAGS := $(TCL_FLAGS) .PHONY: modtcl_install install: $(TCLHOOK) modtcl_install: mkdir -p $(DESTDIR)$(DATADIR)/modtcl/ $(INSTALL_DATA) $(srcdir)/modtcl/modtcl.tcl $(srcdir)/modtcl/binds.tcl $(DESTDIR)$(DATADIR)/modtcl/ znc-1.7.5/modules/modtcl/CMakeLists.txt0000644000175000017500000000147313542151610020237 0ustar somebodysomebody# # Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set(modinclude_modtcl PRIVATE ${TCL_INCLUDE_PATH} PARENT_SCOPE) set(modlink_modtcl PRIVATE ${TCL_LIBRARY} PARENT_SCOPE) install(FILES "modtcl.tcl" "binds.tcl" DESTINATION "${CMAKE_INSTALL_DATADIR}/znc/modtcl") znc-1.7.5/modules/modtcl/modtcl.tcl0000644000175000017500000001121113542151610017454 0ustar somebodysomebody# Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # TCL master file for ZNC modtcl # # Usage: LoadModule = modtcl /path/to/this/file # # rehash simply reloads this file and shows info for any errors set ::MasterFile [info script] proc rehash {} { if {[catch {source $::MasterFile}]} { PutModule "Error rehashing tcl master file: $::errorInfo" } } proc bgerror {message} { PutModule "Background error: $::errorInfo" } # set basic eggdrop style variables set ::botnet-nick ZNC_[GetUsername] set ::botnick [GetCurNick] set ::server [GetServer] set ::server-online [expr [GetServerOnline] / 1000] # add some eggdrop style procs proc putlog message {PutModule $message} proc puthelp {text {option ""}} { if {[regexp -nocase {^(?:privmsg|notice) (\S+) :(.*)} $text . target line]} { if {$target == "*modtcl"} {PutModule $line; return} if {$target == "*status"} {PutStatus $line; return} if {[string index $target 0] != "#" || [botonchan $target]} {PutUser ":$::botnick![getchanhost $::botnick] $text"} } PutIRC $text } proc putserv {text {option ""}} {puthelp $text} proc putquick {text {option ""}} {puthelp $text} proc stripcodes {flags args} {return [regsub -all {\xF|\x2|\x16|\x1F|\x7|\x3([0-9]{1,2})?(,[0-9]{1,2})?} [join $args] {}]} proc unixtime {} {return [clock seconds]} proc duration {s} { set ret "" foreach {n m} "year 31536000 week 604800 day 86400 hour 3600 minute 60 second 1" { if {$s >= $m} { set tmp [expr $s / $m] if {$tmp == 1} {set i ""} else {set i "s"} set ret $ret[format "%lu %s%s " $tmp $n $i] incr s -[expr $tmp * $m] } } return $ret } proc encrypt {key string} {return [bencrypt $key $string]} proc decrypt {key string} {return [bdecrypt $key $string]} proc channels {} {return [GetChans]} proc chanlist {channel {flags ""}} { set ret "" foreach u [GetChannelUsers [string trim $channel "{}"]] {lappend ret [lindex $u 0]} return $ret } proc getchanmode channel {return [GetChannelModes [string trim $channel "{}"]]} proc getchanhost {nick {channel ""}} { # TODO: to have full info here we need to use /who #chan when we join if {$channel == ""} {set channel [join [channels]]} foreach c $channel { foreach u [GetChannelUsers $c] { if {[string match $nick [lindex $u 0]]} { return "[lindex $u 1]@[lindex $u 2]" } } } return "" } proc onchan {nick chan} {return [expr [lsearch -exact [string tolower [chanlist $chan]] [string tolower $nick]] != -1]} proc botonchan channel {return [onchan $::botnick $channel]} proc isop {nick {channel ""}} {return [PermCheck $nick "@" $channel]} proc isvoice {nick {channel ""}} {return [PermCheck $nick "+" $channel]} proc botisop {{channel ""}} {return [isop $::botnick $channel]} proc botisvoice {{channel ""}} {return [isvoice $::botnick $channel]} proc PermCheck {nick perm channel} { if {$channel == ""} {set channel [channels]} if {[ModuleLoaded crypt]} {regsub {^\244} $nick {} nick} foreach c $channel { foreach u [GetChannelUsers $c] { if {[string match -nocase $nick [lindex $u 0]] && [string match *$perm* [lindex $u 3]]} { return 1 } } } return 0 } proc ModuleLoaded modname { foreach {mod args glob} [join [GetModules]] { if {[string match -nocase $modname $mod]} {return 1} } return 0 } # rewrite all timers to use the after command proc utimer {seconds tcl-command} {after [expr $seconds * 1000] ${tcl-command}} proc timer {minutes tcl-command} {after [expr $minutes * 60 * 1000] ${tcl-command}} proc utimers {} {set t {}; foreach a [after info] {lappend t "0 [lindex [after info $a] 0] $a"}; return $t} proc timers {} {set t {}; foreach a [after info] {lappend t "0 [lindex [after info $a] 0] $a"}; return $t} proc killtimer id {return [after cancel $id]} proc killutimer id {return [after cancel $id]} # pseudo procs to satisfy script loading, no functionality proc setudef {type name} {return} proc modules {} {return "encryption"} proc channel {command {options ""}} {return ""} proc queuesize {{queue ""}} {return 0} proc matchattr {handle flags {channel ""}} {return 0} # load other script files source [file dirname $::MasterFile]/binds.tcl PutModule "Successfully loaded modtcl with master file: [info script]" znc-1.7.5/modules/modtcl/binds.tcl0000644000175000017500000001164513542151610017304 0ustar somebodysomebody# Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Binds module to process incoming messages with ZNC modtcl # # Supported bind types: bot, dcc, evnt, kick, msg, msgm, nick, pub, pubm, time # evnt: prerehash,rehash,init-server,disconnect-server # namespace eval Binds { # vars if {![info exists Binds::List]} { variable List [list] } # procs proc Add {type flags cmd {procname ""}} { if {![regexp {^(bot|dcc|evnt|kick|msg|msgm|nick|pub|pubm|time)$} $type]} { PutModule "Tcl error: Bind type: $type not supported" return } # ToDo: Flags check from user info (IsAdmin, etc) # ToDo: bind hit counter if {[lsearch $Binds::List "$type $flags [list $cmd] 0 [list $procname]"] == -1} { lappend Binds::List "$type $flags [list $cmd] 0 [list $procname]" } return $cmd } proc Del {type flags cmd procname} { if {[set match [lsearch [binds] "$type $flags $cmd 0 $procname"]] != -1 || [set match [lsearch [binds] "$type $flags {${cmd}} 0 $procname"]] != -1} { set Binds::List [lreplace $Binds::List $match $match] return $cmd } else { error "Tcl error: no such binding" } } proc ProcessPubm {nick user handle channel text} { # Loop bind list and execute foreach n [binds pub] { if {[string match [lindex $n 2] [lindex [split $text] 0]]} { [lindex $n 4] $nick $user $handle $channel [lrange [join $text] 1 end] } } foreach {type flags mask hits proc} [join [binds pubm]] { regsub {^%} $mask {*} mask if {[ModuleLoaded crypt]} {regsub {^\244} $nick {} nick} if {[string match -nocase $mask "$channel $text"]} { $proc $nick $user $handle $channel $text } } } proc ProcessMsgm {nick user handle text} { # Loop bind list and execute foreach n [binds msg] { if {[string match [lindex $n 2] [lindex [split $text] 0]]} { [lindex $n 4] $nick $user $handle [lrange [join $text] 1 end] } } foreach {type flags mask hits proc} [join [binds msgm]] { regsub {^%} $mask {*} mask if {[ModuleLoaded crypt]} {regsub {^\244} $nick {} nick} if {[string match -nocase $mask "$text"]} { $proc $nick $user $handle $text } } } proc ProcessTime {} { if {[clock format [clock seconds] -format "%S"] != 0} {return} set time [clock format [clock seconds] -format "%M %H %d %m %Y"] foreach {mi ho da mo ye} $time {} # Loop bind list and execute foreach n [binds time] { if {[string match [lindex $n 2] $time]} { [lindex $n 4] $mi $ho $da $mo $ye } } } proc ProcessEvnt {event} { foreach n [binds evnt] { if {[string match [lindex $n 2] $event]} { [lindex $n 4] $event } } switch $event { init-server { set ::botnick [GetCurNick] set ::server [GetServer] set ::server-online [expr [GetServerOnline] / 1000] } disconnect-server { set ::botnick "" set ::server "" set ::server-online 0 } } } proc ProcessBot {from-bot cmd text} { foreach n [binds bot] { if {[string match [lindex $n 2] $cmd]} { [lindex $n 4] ${from-bot} $cmd $text } } } proc ProcessNick {nick user handle channel newnick} { if {$nick == $::botnick} {set ::botnick $newnick} foreach n [binds nick] { if {[string match [lindex $n 2] $newnick]} { [lindex $n 4] $nick $user $handle $channel $newnick } } } proc ProcessKick {nick user handle channel target reason} { foreach n [binds kick] { if {[string match [lindex $n 2 0] $channel]} { if {[llength [lindex $n 2]] <= 1 || [string match [lindex $n 2 1] $target]} { if {[llength [lindex $n 2]] <= 2 || [string match [lindex $n 2 2] $reason]} { [lindex $n 4] $nick $user $handle $channel $target $reason } } } } } proc ProcessDcc {handle idx text} { set match 0 foreach n [binds dcc] { if {[string match -nocase [lindex $n 2] [string range [lindex $text 0] 1 end]]} { [lindex $n 4] $handle $idx [lrange $text 1 end] set match 1 } } if {!$match} { PutModule "Error, dcc trigger '[string range [lindex $text 0] 1 end]' doesn't exist" } } } # Provide aliases according to eggdrop specs proc ::bind {type flags cmd procname} {Binds::Add $type $flags $cmd $procname} proc ::unbind {type flags cmd procname} {Binds::Del $type $flags $cmd $procname} proc ::binds {{type ""}} {if {$type != ""} {set type "$type "};return [lsearch -all -inline $Binds::List "$type*"]} proc ::bindlist {{type ""}} {foreach bind $Binds::List {PutModule "$bind"}} PutModule "modtcl script loaded: Binds v0.2" znc-1.7.5/modules/listsockets.cpp0000644000175000017500000002036113542151610017265 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include class CSocketSorter { public: CSocketSorter(Csock* p) { m_pSock = p; } bool operator<(const CSocketSorter& other) const { // The 'biggest' item is displayed first. // return false: this is first // return true: other is first // Listeners go to the top if (m_pSock->GetType() != other.m_pSock->GetType()) { if (m_pSock->GetType() == Csock::LISTENER) return false; if (other.m_pSock->GetType() == Csock::LISTENER) return true; } const CString& sMyName = m_pSock->GetSockName(); const CString& sMyName2 = sMyName.Token(1, true, "::"); bool bMyEmpty = sMyName2.empty(); const CString& sHisName = other.GetSock()->GetSockName(); const CString& sHisName2 = sHisName.Token(1, true, "::"); bool bHisEmpty = sHisName2.empty(); // Then sort by first token after "::" if (bMyEmpty && !bHisEmpty) return false; if (bHisEmpty && !bMyEmpty) return true; if (!bMyEmpty && !bHisEmpty) { int c = sMyName2.StrCmp(sHisName2); if (c < 0) return false; if (c > 0) return true; } // and finally sort by the whole socket name return sMyName.StrCmp(sHisName) > 0; } Csock* GetSock() const { return m_pSock; } private: Csock* m_pSock; }; class CListSockets : public CModule { public: MODCONSTRUCTOR(CListSockets) { AddHelpCommand(); AddCommand("List", t_d("[-n]"), t_d("Shows the list of active sockets. " "Pass -n to show IP addresses"), [=](const CString& sLine) { OnListCommand(sLine); }); } bool OnLoad(const CString& sArgs, CString& sMessage) override { #ifndef MOD_LISTSOCKETS_ALLOW_EVERYONE if (!GetUser()->IsAdmin()) { sMessage = t_s("You must be admin to use this module"); return false; } #endif return true; } std::priority_queue GetSockets() { CSockManager& m = CZNC::Get().GetManager(); std::priority_queue ret; for (unsigned int a = 0; a < m.size(); a++) { Csock* pSock = m[a]; // These sockets went through SwapSockByAddr. That means // another socket took over the connection from this // socket. So ignore this to avoid listing the // connection twice. if (pSock->GetCloseType() == Csock::CLT_DEREFERENCE) continue; ret.push(pSock); } return ret; } bool WebRequiresAdmin() override { return true; } CString GetWebMenuTitle() override { return t_s("List sockets"); } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "index") { if (CZNC::Get().GetManager().empty()) { return false; } std::priority_queue socks = GetSockets(); while (!socks.empty()) { Csock* pSocket = socks.top().GetSock(); socks.pop(); CTemplate& Row = Tmpl.AddRow("SocketsLoop"); Row["Name"] = pSocket->GetSockName(); Row["Created"] = GetCreatedTime(pSocket); Row["State"] = GetSocketState(pSocket); Row["SSL"] = pSocket->GetSSL() ? t_s("Yes", "ssl") : t_s("No", "ssl"); Row["Local"] = GetLocalHost(pSocket, true); Row["Remote"] = GetRemoteHost(pSocket, true); Row["In"] = CString::ToByteStr(pSocket->GetBytesRead()); Row["Out"] = CString::ToByteStr(pSocket->GetBytesWritten()); } return true; } return false; } void OnListCommand(const CString& sLine) { CString sArg = sLine.Token(1, true); bool bShowHosts = true; if (sArg.Equals("-n")) { bShowHosts = false; } ShowSocks(bShowHosts); } CString GetSocketState(Csock* pSocket) { switch (pSocket->GetType()) { case Csock::LISTENER: return t_s("Listener"); case Csock::INBOUND: return t_s("Inbound"); case Csock::OUTBOUND: if (pSocket->IsConnected()) return t_s("Outbound"); else return t_s("Connecting"); } return t_s("UNKNOWN"); } CString GetCreatedTime(Csock* pSocket) { unsigned long long iStartTime = pSocket->GetStartTime(); timeval tv; tv.tv_sec = iStartTime / 1000; tv.tv_usec = iStartTime % 1000 * 1000; return CUtils::FormatTime(tv, "%Y-%m-%d %H:%M:%S.%f", GetUser()->GetTimezone()); } CString GetLocalHost(Csock* pSocket, bool bShowHosts) { CString sBindHost; if (bShowHosts) { sBindHost = pSocket->GetBindHost(); } if (sBindHost.empty()) { sBindHost = pSocket->GetLocalIP(); } return sBindHost + " " + CString(pSocket->GetLocalPort()); } CString GetRemoteHost(Csock* pSocket, bool bShowHosts) { CString sHost; u_short uPort; if (!bShowHosts) { sHost = pSocket->GetRemoteIP(); } // While connecting, there might be no ip available if (sHost.empty()) { sHost = pSocket->GetHostName(); } // While connecting, GetRemotePort() would return 0 if (pSocket->GetType() == Csock::OUTBOUND) { uPort = pSocket->GetPort(); } else { uPort = pSocket->GetRemotePort(); } if (uPort != 0) { return sHost + " " + CString(uPort); } return sHost; } void ShowSocks(bool bShowHosts) { if (CZNC::Get().GetManager().empty()) { PutStatus(t_s("You have no open sockets.")); return; } std::priority_queue socks = GetSockets(); CTable Table; Table.AddColumn(t_s("Name")); Table.AddColumn(t_s("Created")); Table.AddColumn(t_s("State")); #ifdef HAVE_LIBSSL Table.AddColumn(t_s("SSL")); #endif Table.AddColumn(t_s("Local")); Table.AddColumn(t_s("Remote")); Table.AddColumn(t_s("In")); Table.AddColumn(t_s("Out")); while (!socks.empty()) { Csock* pSocket = socks.top().GetSock(); socks.pop(); Table.AddRow(); Table.SetCell(t_s("Name"), pSocket->GetSockName()); Table.SetCell(t_s("Created"), GetCreatedTime(pSocket)); Table.SetCell(t_s("State"), GetSocketState(pSocket)); #ifdef HAVE_LIBSSL Table.SetCell(t_s("SSL"), pSocket->GetSSL() ? t_s("Yes", "ssl") : t_s("No", "ssl")); #endif Table.SetCell(t_s("Local"), GetLocalHost(pSocket, bShowHosts)); Table.SetCell(t_s("Remote"), GetRemoteHost(pSocket, bShowHosts)); Table.SetCell(t_s("In"), CString::ToByteStr(pSocket->GetBytesRead())); Table.SetCell(t_s("Out"), CString::ToByteStr(pSocket->GetBytesWritten())); } PutModule(Table); return; } ~CListSockets() override {} }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("listsockets"); } USERMODULEDEFS(CListSockets, t_s("Lists active sockets")) znc-1.7.5/modules/webadmin.cpp0000644000175000017500000023472713542151610016521 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include using std::stringstream; using std::make_pair; using std::set; using std::vector; using std::map; /* Stuff to be able to write this: // i will be name of local variable, see below // pUser can be nullptr if only global modules are needed FOR_EACH_MODULE(i, pUser) { // i is local variable of type CModules::iterator, // so *i has type CModule* } */ struct FOR_EACH_MODULE_Type { enum { AtGlobal, AtUser, AtNetwork, } where; CModules CMtemp; CModules& CMuser; CModules& CMnet; FOR_EACH_MODULE_Type(CUser* pUser) : CMuser(pUser ? pUser->GetModules() : CMtemp), CMnet(CMtemp) { where = AtGlobal; } FOR_EACH_MODULE_Type(CIRCNetwork* pNetwork) : CMuser(pNetwork ? pNetwork->GetUser()->GetModules() : CMtemp), CMnet(pNetwork ? pNetwork->GetModules() : CMtemp) { where = AtGlobal; } FOR_EACH_MODULE_Type(std::pair arg) : CMuser(arg.first ? arg.first->GetModules() : CMtemp), CMnet(arg.second ? arg.second->GetModules() : CMtemp) { where = AtGlobal; } operator bool() { return false; } }; inline bool FOR_EACH_MODULE_CanContinue(FOR_EACH_MODULE_Type& state, CModules::iterator& i) { if (state.where == FOR_EACH_MODULE_Type::AtGlobal && i == CZNC::Get().GetModules().end()) { i = state.CMuser.begin(); state.where = FOR_EACH_MODULE_Type::AtUser; } if (state.where == FOR_EACH_MODULE_Type::AtUser && i == state.CMuser.end()) { i = state.CMnet.begin(); state.where = FOR_EACH_MODULE_Type::AtNetwork; } return !(state.where == FOR_EACH_MODULE_Type::AtNetwork && i == state.CMnet.end()); } #define FOR_EACH_MODULE(I, pUserOrNetwork) \ if (FOR_EACH_MODULE_Type FOR_EACH_MODULE_Var = pUserOrNetwork) { \ } else \ for (CModules::iterator I = CZNC::Get().GetModules().begin(); \ FOR_EACH_MODULE_CanContinue(FOR_EACH_MODULE_Var, I); ++I) class CWebAdminMod : public CModule { public: MODCONSTRUCTOR(CWebAdminMod) { VPair vParams; vParams.push_back(make_pair("user", "")); AddSubPage(std::make_shared( "settings", t_d("Global Settings"), vParams, CWebSubPage::F_ADMIN)); AddSubPage(std::make_shared( "edituser", t_d("Your Settings"), vParams)); AddSubPage(std::make_shared("traffic", t_d("Traffic Info"), vParams)); AddSubPage(std::make_shared( "listusers", t_d("Manage Users"), vParams, CWebSubPage::F_ADMIN)); } ~CWebAdminMod() override {} bool OnLoad(const CString& sArgStr, CString& sMessage) override { if (sArgStr.empty() || CModInfo::GlobalModule != GetType()) return true; // We don't accept any arguments, but for backwards // compatibility we have to do some magic here. sMessage = "Arguments converted to new syntax"; bool bSSL = false; bool bIPv6 = false; bool bShareIRCPorts = true; unsigned short uPort = 8080; CString sArgs(sArgStr); CString sPort; CString sListenHost; CString sURIPrefix; while (sArgs.Left(1) == "-") { CString sOpt = sArgs.Token(0); sArgs = sArgs.Token(1, true); if (sOpt.Equals("-IPV6")) { bIPv6 = true; } else if (sOpt.Equals("-IPV4")) { bIPv6 = false; } else if (sOpt.Equals("-noircport")) { bShareIRCPorts = false; } else { // Uhm... Unknown option? Let's just ignore all // arguments, older versions would have returned // an error and denied loading return true; } } // No arguments left: Only port sharing if (sArgs.empty() && bShareIRCPorts) return true; if (sArgs.find(" ") != CString::npos) { sListenHost = sArgs.Token(0); sPort = sArgs.Token(1, true); } else { sPort = sArgs; } if (sPort.Left(1) == "+") { sPort.TrimLeft("+"); bSSL = true; } if (!sPort.empty()) { uPort = sPort.ToUShort(); } if (!bShareIRCPorts) { // Make all existing listeners IRC-only const vector& vListeners = CZNC::Get().GetListeners(); for (CListener* pListener : vListeners) { pListener->SetAcceptType(CListener::ACCEPT_IRC); } } // Now turn that into a listener instance CListener* pListener = new CListener( uPort, sListenHost, sURIPrefix, bSSL, (!bIPv6 ? ADDR_IPV4ONLY : ADDR_ALL), CListener::ACCEPT_HTTP); if (!pListener->Listen()) { sMessage = "Failed to add backwards-compatible listener"; return false; } CZNC::Get().AddListener(pListener); SetArgs(""); return true; } CUser* GetNewUser(CWebSock& WebSock, CUser* pUser) { std::shared_ptr spSession = WebSock.GetSession(); CString sUsername = WebSock.GetParam("newuser"); if (sUsername.empty()) { sUsername = WebSock.GetParam("user"); } if (sUsername.empty()) { WebSock.PrintErrorPage( t_s("Invalid Submission [Username is required]")); return nullptr; } if (pUser) { /* If we are editing a user we must not change the user name */ sUsername = pUser->GetUserName(); } CString sArg = WebSock.GetParam("password"); if (sArg != WebSock.GetParam("password2")) { WebSock.PrintErrorPage( t_s("Invalid Submission [Passwords do not match]")); return nullptr; } CUser* pNewUser = new CUser(sUsername); if (!sArg.empty()) { CString sSalt = CUtils::GetSalt(); CString sHash = CUser::SaltedHash(sArg, sSalt); pNewUser->SetPass(sHash, CUser::HASH_DEFAULT, sSalt); } sArg = WebSock.GetParam("authonlyviamodule"); if (spSession->IsAdmin()) { if (!sArg.empty()) { pNewUser->SetAuthOnlyViaModule(sArg.ToBool()); } } else if (pUser) { pNewUser->SetAuthOnlyViaModule(pUser->AuthOnlyViaModule()); } VCString vsArgs; WebSock.GetRawParam("allowedips").Split("\n", vsArgs); if (vsArgs.size()) { for (const CString& sHost : vsArgs) { pNewUser->AddAllowedHost(sHost.Trim_n()); } } else { pNewUser->AddAllowedHost("*"); } WebSock.GetRawParam("ctcpreplies").Split("\n", vsArgs); for (const CString& sReply : vsArgs) { pNewUser->AddCTCPReply(sReply.Token(0).Trim_n(), sReply.Token(1, true).Trim_n()); } sArg = WebSock.GetParam("nick"); if (!sArg.empty()) { pNewUser->SetNick(sArg); } sArg = WebSock.GetParam("altnick"); if (!sArg.empty()) { pNewUser->SetAltNick(sArg); } sArg = WebSock.GetParam("statusprefix"); if (!sArg.empty()) { pNewUser->SetStatusPrefix(sArg); } sArg = WebSock.GetParam("ident"); if (!sArg.empty()) { pNewUser->SetIdent(sArg); } sArg = WebSock.GetParam("realname"); if (!sArg.empty()) { pNewUser->SetRealName(sArg); } sArg = WebSock.GetParam("quitmsg"); if (!sArg.empty()) { pNewUser->SetQuitMsg(sArg); } sArg = WebSock.GetParam("chanmodes"); if (!sArg.empty()) { pNewUser->SetDefaultChanModes(sArg); } sArg = WebSock.GetParam("timestampformat"); if (!sArg.empty()) { pNewUser->SetTimestampFormat(sArg); } sArg = WebSock.GetParam("bindhost"); // To change BindHosts be admin or don't have DenySetBindHost if (spSession->IsAdmin() || !spSession->GetUser()->DenySetBindHost()) { CString sArg2 = WebSock.GetParam("dccbindhost"); if (!sArg.empty()) { pNewUser->SetBindHost(sArg); } if (!sArg2.empty()) { pNewUser->SetDCCBindHost(sArg2); } } else if (pUser) { pNewUser->SetBindHost(pUser->GetBindHost()); pNewUser->SetDCCBindHost(pUser->GetDCCBindHost()); } sArg = WebSock.GetParam("chanbufsize"); if (!sArg.empty()) { // First apply the old limit in case the new one is too high if (pUser) pNewUser->SetChanBufferSize(pUser->GetChanBufferSize(), true); pNewUser->SetChanBufferSize(sArg.ToUInt(), spSession->IsAdmin()); } sArg = WebSock.GetParam("querybufsize"); if (!sArg.empty()) { // First apply the old limit in case the new one is too high if (pUser) pNewUser->SetQueryBufferSize(pUser->GetQueryBufferSize(), true); pNewUser->SetQueryBufferSize(sArg.ToUInt(), spSession->IsAdmin()); } pNewUser->SetSkinName(WebSock.GetParam("skin")); pNewUser->SetAutoClearChanBuffer( WebSock.GetParam("autoclearchanbuffer").ToBool()); pNewUser->SetMultiClients(WebSock.GetParam("multiclients").ToBool()); pNewUser->SetTimestampAppend( WebSock.GetParam("appendtimestamp").ToBool()); pNewUser->SetTimestampPrepend( WebSock.GetParam("prependtimestamp").ToBool()); pNewUser->SetTimezone(WebSock.GetParam("timezone")); pNewUser->SetJoinTries(WebSock.GetParam("jointries").ToUInt()); pNewUser->SetMaxJoins(WebSock.GetParam("maxjoins").ToUInt()); pNewUser->SetAutoClearQueryBuffer( WebSock.GetParam("autoclearquerybuffer").ToBool()); pNewUser->SetMaxQueryBuffers( WebSock.GetParam("maxquerybuffers").ToUInt()); unsigned int uNoTrafficTimeout = WebSock.GetParam("notraffictimeout").ToUInt(); if (uNoTrafficTimeout < 30) { uNoTrafficTimeout = 30; WebSock.GetSession()->AddError( t_s("Timeout can't be less than 30 seconds!")); } pNewUser->SetNoTrafficTimeout(uNoTrafficTimeout); #ifdef HAVE_I18N CString sLanguage = WebSock.GetParam("language"); if (CTranslationInfo::GetTranslations().count(sLanguage) == 0) { sLanguage = ""; } pNewUser->SetLanguage(sLanguage); #endif #ifdef HAVE_ICU CString sEncodingUtf = WebSock.GetParam("encoding_utf"); if (sEncodingUtf == "legacy") { pNewUser->SetClientEncoding(""); } CString sEncoding = WebSock.GetParam("encoding"); if (sEncoding.empty()) { sEncoding = "UTF-8"; } if (sEncodingUtf == "send") { pNewUser->SetClientEncoding("^" + sEncoding); } else if (sEncodingUtf == "receive") { pNewUser->SetClientEncoding("*" + sEncoding); } else if (sEncodingUtf == "simple") { pNewUser->SetClientEncoding(sEncoding); } #endif if (spSession->IsAdmin()) { pNewUser->SetDenyLoadMod(WebSock.GetParam("denyloadmod").ToBool()); pNewUser->SetDenySetBindHost( WebSock.GetParam("denysetbindhost").ToBool()); pNewUser->SetAuthOnlyViaModule( WebSock.GetParam("authonlyviamodule").ToBool()); sArg = WebSock.GetParam("maxnetworks"); if (!sArg.empty()) pNewUser->SetMaxNetworks(sArg.ToUInt()); } else if (pUser) { pNewUser->SetDenyLoadMod(pUser->DenyLoadMod()); pNewUser->SetDenySetBindHost(pUser->DenySetBindHost()); pNewUser->SetAuthOnlyViaModule(pUser->AuthOnlyViaModule()); pNewUser->SetMaxNetworks(pUser->MaxNetworks()); } // If pUser is not nullptr, we are editing an existing user. // Users must not be able to change their own admin flag. if (pUser != CZNC::Get().FindUser(WebSock.GetUser())) { pNewUser->SetAdmin(WebSock.GetParam("isadmin").ToBool()); } else if (pUser) { pNewUser->SetAdmin(pUser->IsAdmin()); } if (spSession->IsAdmin() || (pUser && !pUser->DenyLoadMod())) { WebSock.GetParamValues("loadmod", vsArgs); // disallow unload webadmin from itself if (CModInfo::UserModule == GetType() && pUser == CZNC::Get().FindUser(WebSock.GetUser())) { bool bLoadedWebadmin = false; for (const CString& s : vsArgs) { CString sModName = s.TrimRight_n("\r"); if (sModName == GetModName()) { bLoadedWebadmin = true; break; } } if (!bLoadedWebadmin) { vsArgs.push_back(GetModName()); } } for (const CString& s : vsArgs) { CString sModRet; CString sModName = s.TrimRight_n("\r"); CString sModLoadError; if (!sModName.empty()) { CString sArgs = WebSock.GetParam("modargs_" + sModName); try { if (!pNewUser->GetModules().LoadModule( sModName, sArgs, CModInfo::UserModule, pNewUser, nullptr, sModRet)) { sModLoadError = t_f("Unable to load module [{1}]: {2}")( sModName, sModRet); } } catch (...) { sModLoadError = t_f( "Unable to load module [{1}] with arguments [{2}]")( sModName, sArgs); } if (!sModLoadError.empty()) { DEBUG(sModLoadError); spSession->AddError(sModLoadError); } } } } else if (pUser) { CModules& Modules = pUser->GetModules(); for (const CModule* pMod : Modules) { CString sModName = pMod->GetModName(); CString sArgs = pMod->GetArgs(); CString sModRet; CString sModLoadError; try { if (!pNewUser->GetModules().LoadModule( sModName, sArgs, CModInfo::UserModule, pNewUser, nullptr, sModRet)) { sModLoadError = t_f("Unable to load module [{1}]: {2}")( sModName, sModRet); } } catch (...) { sModLoadError = t_f("Unable to load module [{1}] with arguments [{2}]")( sModName, sArgs); } if (!sModLoadError.empty()) { DEBUG(sModLoadError); spSession->AddError(sModLoadError); } } } return pNewUser; } CString SafeGetUserNameParam(CWebSock& WebSock) { CString sUserName = WebSock.GetParam("user"); // check for POST param if (sUserName.empty() && !WebSock.IsPost()) { // if no POST param named user has been given and we are not // saving this form, fall back to using the GET parameter. sUserName = WebSock.GetParam("user", false); } return sUserName; } CString SafeGetNetworkParam(CWebSock& WebSock) { CString sNetwork = WebSock.GetParam("network"); // check for POST param if (sNetwork.empty() && !WebSock.IsPost()) { // if no POST param named user has been given and we are not // saving this form, fall back to using the GET parameter. sNetwork = WebSock.GetParam("network", false); } return sNetwork; } CUser* SafeGetUserFromParam(CWebSock& WebSock) { return CZNC::Get().FindUser(SafeGetUserNameParam(WebSock)); } CIRCNetwork* SafeGetNetworkFromParam(CWebSock& WebSock) { CUser* pUser = CZNC::Get().FindUser(SafeGetUserNameParam(WebSock)); CIRCNetwork* pNetwork = nullptr; if (pUser) { pNetwork = pUser->FindNetwork(SafeGetNetworkParam(WebSock)); } return pNetwork; } CString GetWebMenuTitle() override { return "webadmin"; } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { std::shared_ptr spSession = WebSock.GetSession(); if (sPageName == "settings") { // Admin Check if (!spSession->IsAdmin()) { return false; } return SettingsPage(WebSock, Tmpl); } else if (sPageName == "adduser") { // Admin Check if (!spSession->IsAdmin()) { return false; } return UserPage(WebSock, Tmpl); } else if (sPageName == "addnetwork") { CUser* pUser = SafeGetUserFromParam(WebSock); // Admin||Self Check if (!spSession->IsAdmin() && (!spSession->GetUser() || spSession->GetUser() != pUser)) { return false; } if (pUser) { return NetworkPage(WebSock, Tmpl, pUser); } WebSock.PrintErrorPage(t_s("No such user")); return true; } else if (sPageName == "editnetwork") { CIRCNetwork* pNetwork = SafeGetNetworkFromParam(WebSock); // Admin||Self Check if (!spSession->IsAdmin() && (!spSession->GetUser() || !pNetwork || spSession->GetUser() != pNetwork->GetUser())) { return false; } if (!pNetwork) { WebSock.PrintErrorPage(t_s("No such user or network")); return true; } return NetworkPage(WebSock, Tmpl, pNetwork->GetUser(), pNetwork); } else if (sPageName == "delnetwork") { CString sUser = WebSock.GetParam("user"); if (sUser.empty() && !WebSock.IsPost()) { sUser = WebSock.GetParam("user", false); } CUser* pUser = CZNC::Get().FindUser(sUser); // Admin||Self Check if (!spSession->IsAdmin() && (!spSession->GetUser() || spSession->GetUser() != pUser)) { return false; } return DelNetwork(WebSock, pUser, Tmpl); } else if (sPageName == "editchan") { CIRCNetwork* pNetwork = SafeGetNetworkFromParam(WebSock); // Admin||Self Check if (!spSession->IsAdmin() && (!spSession->GetUser() || !pNetwork || spSession->GetUser() != pNetwork->GetUser())) { return false; } if (!pNetwork) { WebSock.PrintErrorPage(t_s("No such user or network")); return true; } CString sChan = WebSock.GetParam("name"); if (sChan.empty() && !WebSock.IsPost()) { sChan = WebSock.GetParam("name", false); } CChan* pChan = pNetwork->FindChan(sChan); if (!pChan) { WebSock.PrintErrorPage(t_s("No such channel")); return true; } return ChanPage(WebSock, Tmpl, pNetwork, pChan); } else if (sPageName == "addchan") { CIRCNetwork* pNetwork = SafeGetNetworkFromParam(WebSock); // Admin||Self Check if (!spSession->IsAdmin() && (!spSession->GetUser() || !pNetwork || spSession->GetUser() != pNetwork->GetUser())) { return false; } if (pNetwork) { return ChanPage(WebSock, Tmpl, pNetwork); } WebSock.PrintErrorPage(t_s("No such user or network")); return true; } else if (sPageName == "delchan") { CIRCNetwork* pNetwork = SafeGetNetworkFromParam(WebSock); // Admin||Self Check if (!spSession->IsAdmin() && (!spSession->GetUser() || !pNetwork || spSession->GetUser() != pNetwork->GetUser())) { return false; } if (pNetwork) { return DelChan(WebSock, pNetwork); } WebSock.PrintErrorPage(t_s("No such user or network")); return true; } else if (sPageName == "deluser") { if (!spSession->IsAdmin()) { return false; } if (!WebSock.IsPost()) { // Show the "Are you sure?" page: CString sUser = WebSock.GetParam("user", false); CUser* pUser = CZNC::Get().FindUser(sUser); if (!pUser) { WebSock.PrintErrorPage(t_s("No such user")); return true; } Tmpl.SetFile("del_user.tmpl"); Tmpl["Username"] = sUser; return true; } // The "Are you sure?" page has been submitted with "Yes", // so we actually delete the user now: CString sUser = WebSock.GetParam("user"); CUser* pUser = CZNC::Get().FindUser(sUser); if (pUser && pUser == spSession->GetUser()) { WebSock.PrintErrorPage( t_s("Please don't delete yourself, suicide is not the " "answer!")); return true; } else if (CZNC::Get().DeleteUser(sUser)) { WebSock.Redirect(GetWebPath() + "listusers"); return true; } WebSock.PrintErrorPage(t_s("No such user")); return true; } else if (sPageName == "edituser") { CString sUserName = SafeGetUserNameParam(WebSock); CUser* pUser = CZNC::Get().FindUser(sUserName); if (!pUser) { if (sUserName.empty()) { pUser = spSession->GetUser(); } // else: the "no such user" message will be printed. } // Admin||Self Check if (!spSession->IsAdmin() && (!spSession->GetUser() || spSession->GetUser() != pUser)) { return false; } if (pUser) { return UserPage(WebSock, Tmpl, pUser); } WebSock.PrintErrorPage(t_s("No such user")); return true; } else if (sPageName == "listusers" && spSession->IsAdmin()) { return ListUsersPage(WebSock, Tmpl); } else if (sPageName == "traffic") { return TrafficPage(WebSock, Tmpl); } else if (sPageName == "index") { return true; } else if (sPageName == "add_listener") { // Admin Check if (!spSession->IsAdmin()) { return false; } return AddListener(WebSock, Tmpl); } else if (sPageName == "del_listener") { // Admin Check if (!spSession->IsAdmin()) { return false; } return DelListener(WebSock, Tmpl); } return false; } bool ChanPage(CWebSock& WebSock, CTemplate& Tmpl, CIRCNetwork* pNetwork, CChan* pChan = nullptr) { std::shared_ptr spSession = WebSock.GetSession(); Tmpl.SetFile("add_edit_chan.tmpl"); CUser* pUser = pNetwork->GetUser(); if (!pUser) { WebSock.PrintErrorPage(t_s("No such user")); return true; } if (!WebSock.GetParam("submitted").ToUInt()) { Tmpl["User"] = pUser->GetUserName(); Tmpl["Network"] = pNetwork->GetName(); CTemplate& breadUser = Tmpl.AddRow("BreadCrumbs"); breadUser["Text"] = t_f("Edit User [{1}]")(pUser->GetUserName()); breadUser["URL"] = GetWebPath() + "edituser?user=" + pUser->GetUserName(); CTemplate& breadNet = Tmpl.AddRow("BreadCrumbs"); breadNet["Text"] = t_f("Edit Network [{1}]")(pNetwork->GetName()); breadNet["URL"] = GetWebPath() + "editnetwork?user=" + pUser->GetUserName() + "&network=" + pNetwork->GetName(); CTemplate& breadChan = Tmpl.AddRow("BreadCrumbs"); if (pChan) { Tmpl["Action"] = "editchan"; Tmpl["Edit"] = "true"; Tmpl["Title"] = t_f("Edit Channel [{1}] of Network [{2}] of User [{3}]")( pChan->GetName(), pNetwork->GetName(), pUser->GetUserName()); Tmpl["ChanName"] = pChan->GetName(); Tmpl["BufferSize"] = CString(pChan->GetBufferCount()); Tmpl["DefModes"] = pChan->GetDefaultModes(); Tmpl["Key"] = pChan->GetKey(); breadChan["Text"] = t_f("Edit Channel [{1}]")(pChan->GetName()); if (pChan->InConfig()) { Tmpl["InConfig"] = "true"; } } else { Tmpl["Action"] = "addchan"; Tmpl["Title"] = t_f("Add Channel to Network [{1}] of User [{2}]")( pNetwork->GetName(), pUser->GetUserName()); Tmpl["BufferSize"] = CString(pUser->GetBufferCount()); Tmpl["DefModes"] = CString(pUser->GetDefaultChanModes()); Tmpl["InConfig"] = "true"; breadChan["Text"] = t_s("Add Channel"); } // o1 used to be AutoCycle which was removed CTemplate& o2 = Tmpl.AddRow("OptionLoop"); o2["Name"] = "autoclearchanbuffer"; o2["DisplayName"] = t_s("Auto Clear Chan Buffer"); o2["Tooltip"] = t_s("Automatically Clear Channel Buffer After Playback"); if ((pChan && pChan->AutoClearChanBuffer()) || (!pChan && pUser->AutoClearChanBuffer())) { o2["Checked"] = "true"; } CTemplate& o3 = Tmpl.AddRow("OptionLoop"); o3["Name"] = "detached"; o3["DisplayName"] = t_s("Detached"); if (pChan && pChan->IsDetached()) { o3["Checked"] = "true"; } CTemplate& o4 = Tmpl.AddRow("OptionLoop"); o4["Name"] = "enabled"; o4["DisplayName"] = t_s("Enabled"); if (pChan && !pChan->IsDisabled()) { o4["Checked"] = "true"; } FOR_EACH_MODULE(i, pNetwork) { CTemplate& mod = Tmpl.AddRow("EmbeddedModuleLoop"); mod.insert(Tmpl.begin(), Tmpl.end()); mod["WebadminAction"] = "display"; if ((*i)->OnEmbeddedWebRequest(WebSock, "webadmin/channel", mod)) { mod["Embed"] = WebSock.FindTmpl(*i, "WebadminChan.tmpl"); mod["ModName"] = (*i)->GetModName(); } } return true; } CString sChanName = WebSock.GetParam("name").Trim_n(); if (!pChan) { if (sChanName.empty()) { WebSock.PrintErrorPage( t_s("Channel name is a required argument")); return true; } // This could change the channel name and e.g. add a "#" prefix pChan = new CChan(sChanName, pNetwork, true); if (pNetwork->FindChan(pChan->GetName())) { WebSock.PrintErrorPage( t_f("Channel [{1}] already exists")(pChan->GetName())); delete pChan; return true; } if (!pNetwork->AddChan(pChan)) { WebSock.PrintErrorPage( t_f("Could not add channel [{1}]")(sChanName)); return true; } } if (WebSock.GetParam("buffersize").empty()) { pChan->ResetBufferCount(); } else { unsigned int uBufferSize = WebSock.GetParam("buffersize").ToUInt(); if (pChan->GetBufferCount() != uBufferSize) { pChan->SetBufferCount(uBufferSize, spSession->IsAdmin()); } } pChan->SetDefaultModes(WebSock.GetParam("defmodes")); pChan->SetInConfig(WebSock.GetParam("save").ToBool()); bool bAutoClearChanBuffer = WebSock.GetParam("autoclearchanbuffer").ToBool(); if (pChan->AutoClearChanBuffer() != bAutoClearChanBuffer) { pChan->SetAutoClearChanBuffer( WebSock.GetParam("autoclearchanbuffer").ToBool()); } pChan->SetKey(WebSock.GetParam("key")); bool bDetached = WebSock.GetParam("detached").ToBool(); if (pChan->IsDetached() != bDetached) { if (bDetached) { pChan->DetachUser(); } else { pChan->AttachUser(); } } bool bEnabled = WebSock.GetParam("enabled").ToBool(); if (bEnabled) pChan->Enable(); else pChan->Disable(); CTemplate TmplMod; TmplMod["User"] = pUser->GetUserName(); TmplMod["ChanName"] = pChan->GetName(); TmplMod["WebadminAction"] = "change"; FOR_EACH_MODULE(it, pNetwork) { (*it)->OnEmbeddedWebRequest(WebSock, "webadmin/channel", TmplMod); } if (!CZNC::Get().WriteConfig()) { WebSock.PrintErrorPage(t_s( "Channel was added/modified, but config file was not written")); return true; } if (WebSock.HasParam("submit_return")) { WebSock.Redirect(GetWebPath() + "editnetwork?user=" + pUser->GetUserName().Escape_n(CString::EURL) + "&network=" + pNetwork->GetName().Escape_n(CString::EURL)); } else { WebSock.Redirect( GetWebPath() + "editchan?user=" + pUser->GetUserName().Escape_n(CString::EURL) + "&network=" + pNetwork->GetName().Escape_n(CString::EURL) + "&name=" + pChan->GetName().Escape_n(CString::EURL)); } return true; } bool NetworkPage(CWebSock& WebSock, CTemplate& Tmpl, CUser* pUser, CIRCNetwork* pNetwork = nullptr) { std::shared_ptr spSession = WebSock.GetSession(); Tmpl.SetFile("add_edit_network.tmpl"); if (!pNetwork && !spSession->IsAdmin() && !pUser->HasSpaceForNewNetwork()) { WebSock.PrintErrorPage(t_s( "Network number limit reached. Ask an admin to increase the " "limit for you, or delete unneeded networks from Your " "Settings.")); return true; } if (!WebSock.GetParam("submitted").ToUInt()) { Tmpl["Username"] = pUser->GetUserName(); CTemplate& breadNet = Tmpl.AddRow("BreadCrumbs"); CIRCNetwork EmptyNetwork(pUser, ""); CIRCNetwork* pRealNetwork = pNetwork; if (pNetwork) { Tmpl["Action"] = "editnetwork"; Tmpl["Edit"] = "true"; Tmpl["Title"] = t_f("Edit Network [{1}] of User [{2}]")( pNetwork->GetName(), pUser->GetUserName()); breadNet["Text"] = t_f("Edit Network [{1}]")(pNetwork->GetName()); } else { Tmpl["Action"] = "addnetwork"; Tmpl["Title"] = t_f("Add Network for User [{1}]")(pUser->GetUserName()); breadNet["Text"] = t_s("Add Network"); pNetwork = &EmptyNetwork; } set ssNetworkMods; CZNC::Get().GetModules().GetAvailableMods(ssNetworkMods, CModInfo::NetworkModule); set ssDefaultMods; CZNC::Get().GetModules().GetDefaultMods(ssDefaultMods, CModInfo::NetworkModule); for (const CModInfo& Info : ssNetworkMods) { CTemplate& l = Tmpl.AddRow("ModuleLoop"); l["Name"] = Info.GetName(); l["Description"] = Info.GetDescription(); l["Wiki"] = Info.GetWikiPage(); l["HasArgs"] = CString(Info.GetHasArgs()); l["ArgsHelpText"] = Info.GetArgsHelpText(); if (pRealNetwork) { CModule* pModule = pNetwork->GetModules().FindModule(Info.GetName()); if (pModule) { l["Checked"] = "true"; l["Args"] = pModule->GetArgs(); } } else { for (const CModInfo& DInfo : ssDefaultMods) { if (Info.GetName() == DInfo.GetName()) { l["Checked"] = "true"; } } } // Check if module is loaded globally l["CanBeLoadedGlobally"] = CString(Info.SupportsType(CModInfo::GlobalModule)); l["LoadedGlobally"] = CString(CZNC::Get().GetModules().FindModule( Info.GetName()) != nullptr); // Check if module is loaded by user l["CanBeLoadedByUser"] = CString(Info.SupportsType(CModInfo::UserModule)); l["LoadedByUser"] = CString( pUser->GetModules().FindModule(Info.GetName()) != nullptr); if (!spSession->IsAdmin() && pUser->DenyLoadMod()) { l["Disabled"] = "true"; } } // To change BindHosts be admin or don't have DenySetBindHost if (spSession->IsAdmin() || !spSession->GetUser()->DenySetBindHost()) { Tmpl["BindHostEdit"] = "true"; Tmpl["BindHost"] = pNetwork->GetBindHost(); } CTemplate& breadUser = Tmpl.AddRow("BreadCrumbs"); breadUser["Text"] = t_f("Edit User [{1}]")(pUser->GetUserName()); breadUser["URL"] = GetWebPath() + "edituser?user=" + pUser->GetUserName(); Tmpl["Name"] = pNetwork->GetName(); Tmpl["Nick"] = pNetwork->GetNick(); Tmpl["AltNick"] = pNetwork->GetAltNick(); Tmpl["Ident"] = pNetwork->GetIdent(); Tmpl["RealName"] = pNetwork->GetRealName(); Tmpl["QuitMsg"] = pNetwork->GetQuitMsg(); Tmpl["FloodProtection"] = CString(CIRCSock::IsFloodProtected(pNetwork->GetFloodRate())); Tmpl["FloodRate"] = CString(pNetwork->GetFloodRate()); Tmpl["FloodBurst"] = CString(pNetwork->GetFloodBurst()); Tmpl["JoinDelay"] = CString(pNetwork->GetJoinDelay()); Tmpl["IRCConnectEnabled"] = CString(pNetwork->GetIRCConnectEnabled()); Tmpl["TrustAllCerts"] = CString(pNetwork->GetTrustAllCerts()); Tmpl["TrustPKI"] = CString(pNetwork->GetTrustPKI()); const vector& vServers = pNetwork->GetServers(); for (const CServer* pServer : vServers) { CTemplate& l = Tmpl.AddRow("ServerLoop"); l["Server"] = pServer->GetString(); } const vector& Channels = pNetwork->GetChans(); for (const CChan* pChan : Channels) { CTemplate& l = Tmpl.AddRow("ChannelLoop"); l["Network"] = pNetwork->GetName(); l["Username"] = pUser->GetUserName(); l["Name"] = pChan->GetName(); l["Perms"] = pChan->GetPermStr(); l["CurModes"] = pChan->GetModeString(); l["DefModes"] = pChan->GetDefaultModes(); if (pChan->HasBufferCountSet()) { l["BufferSize"] = CString(pChan->GetBufferCount()); } else { l["BufferSize"] = CString(pChan->GetBufferCount()) + " (default)"; } l["Options"] = pChan->GetOptions(); if (pChan->InConfig()) { l["InConfig"] = "true"; } } for (const CString& sFP : pNetwork->GetTrustedFingerprints()) { CTemplate& l = Tmpl.AddRow("TrustedFingerprints"); l["FP"] = sFP; } FOR_EACH_MODULE(i, make_pair(pUser, pNetwork)) { CTemplate& mod = Tmpl.AddRow("EmbeddedModuleLoop"); mod.insert(Tmpl.begin(), Tmpl.end()); mod["WebadminAction"] = "display"; if ((*i)->OnEmbeddedWebRequest(WebSock, "webadmin/network", mod)) { mod["Embed"] = WebSock.FindTmpl(*i, "WebadminNetwork.tmpl"); mod["ModName"] = (*i)->GetModName(); } } #ifdef HAVE_ICU for (const CString& sEncoding : CUtils::GetEncodings()) { CTemplate& l = Tmpl.AddRow("EncodingLoop"); l["Encoding"] = sEncoding; } const CString sEncoding = pRealNetwork ? pNetwork->GetEncoding() : "^UTF-8"; if (sEncoding.empty()) { Tmpl["EncodingUtf"] = "legacy"; } else if (sEncoding[0] == '*') { Tmpl["EncodingUtf"] = "receive"; Tmpl["Encoding"] = sEncoding.substr(1); } else if (sEncoding[0] == '^') { Tmpl["EncodingUtf"] = "send"; Tmpl["Encoding"] = sEncoding.substr(1); } else { Tmpl["EncodingUtf"] = "simple"; Tmpl["Encoding"] = sEncoding; } Tmpl["LegacyEncodingDisabled"] = CString(CZNC::Get().IsForcingEncoding()); #else Tmpl["LegacyEncodingDisabled"] = "true"; Tmpl["EncodingDisabled"] = "true"; Tmpl["EncodingUtf"] = "legacy"; #endif return true; } CString sName = WebSock.GetParam("name").Trim_n(); if (sName.empty()) { WebSock.PrintErrorPage(t_s("Network name is a required argument")); return true; } if (!pNetwork || pNetwork->GetName() != sName) { CString sNetworkAddError; CIRCNetwork* pOldNetwork = pNetwork; pNetwork = pUser->AddNetwork(sName, sNetworkAddError); if (!pNetwork) { WebSock.PrintErrorPage(sNetworkAddError); return true; } if (pOldNetwork) { for (CModule* pModule : pOldNetwork->GetModules()) { CString sPath = pUser->GetUserPath() + "/networks/" + sName + "/moddata/" + pModule->GetModName(); pModule->MoveRegistry(sPath); } pNetwork->Clone(*pOldNetwork, false); pUser->DeleteNetwork(pOldNetwork->GetName()); } } CString sArg; pNetwork->SetNick(WebSock.GetParam("nick")); pNetwork->SetAltNick(WebSock.GetParam("altnick")); pNetwork->SetIdent(WebSock.GetParam("ident")); pNetwork->SetRealName(WebSock.GetParam("realname")); pNetwork->SetQuitMsg(WebSock.GetParam("quitmsg")); pNetwork->SetIRCConnectEnabled(WebSock.GetParam("doconnect").ToBool()); pNetwork->SetTrustAllCerts(WebSock.GetParam("trustallcerts").ToBool()); pNetwork->SetTrustPKI(WebSock.GetParam("trustpki").ToBool()); sArg = WebSock.GetParam("bindhost"); // To change BindHosts be admin or don't have DenySetBindHost if (spSession->IsAdmin() || !spSession->GetUser()->DenySetBindHost()) { pNetwork->SetBindHost(WebSock.GetParam("bindhost")); } if (WebSock.GetParam("floodprotection").ToBool()) { pNetwork->SetFloodRate(WebSock.GetParam("floodrate").ToDouble()); pNetwork->SetFloodBurst(WebSock.GetParam("floodburst").ToUShort()); } else { pNetwork->SetFloodRate(-1); } pNetwork->SetJoinDelay(WebSock.GetParam("joindelay").ToUShort()); #ifdef HAVE_ICU CString sEncodingUtf = WebSock.GetParam("encoding_utf"); if (sEncodingUtf == "legacy") { pNetwork->SetEncoding(""); } CString sEncoding = WebSock.GetParam("encoding"); if (sEncoding.empty()) { sEncoding = "UTF-8"; } if (sEncodingUtf == "send") { pNetwork->SetEncoding("^" + sEncoding); } else if (sEncodingUtf == "receive") { pNetwork->SetEncoding("*" + sEncoding); } else if (sEncodingUtf == "simple") { pNetwork->SetEncoding(sEncoding); } #endif VCString vsArgs; pNetwork->DelServers(); WebSock.GetRawParam("servers").Split("\n", vsArgs); for (const CString& sServer : vsArgs) { pNetwork->AddServer(sServer.Trim_n()); } WebSock.GetRawParam("fingerprints").Split("\n", vsArgs); pNetwork->ClearTrustedFingerprints(); for (const CString& sFP : vsArgs) { pNetwork->AddTrustedFingerprint(sFP); } WebSock.GetParamValues("channel", vsArgs); for (const CString& sChan : vsArgs) { CChan* pChan = pNetwork->FindChan(sChan.TrimRight_n("\r")); if (pChan) { pChan->SetInConfig(WebSock.GetParam("save_" + sChan).ToBool()); } } set ssArgs; WebSock.GetParamValues("loadmod", ssArgs); if (spSession->IsAdmin() || !pUser->DenyLoadMod()) { for (const CString& s : ssArgs) { CString sModRet; CString sModName = s.TrimRight_n("\r"); CString sModLoadError; if (!sModName.empty()) { CString sArgs = WebSock.GetParam("modargs_" + sModName); CModule* pMod = pNetwork->GetModules().FindModule(sModName); if (!pMod) { if (!pNetwork->GetModules().LoadModule( sModName, sArgs, CModInfo::NetworkModule, pUser, pNetwork, sModRet)) { sModLoadError = t_f("Unable to load module [{1}]: {2}")( sModName, sModRet); } } else if (pMod->GetArgs() != sArgs) { if (!pNetwork->GetModules().ReloadModule( sModName, sArgs, pUser, pNetwork, sModRet)) { sModLoadError = t_f("Unable to reload module [{1}]: {2}")( sModName, sModRet); } } if (!sModLoadError.empty()) { DEBUG(sModLoadError); WebSock.GetSession()->AddError(sModLoadError); } } } } const CModules& vCurMods = pNetwork->GetModules(); set ssUnloadMods; for (const CModule* pCurMod : vCurMods) { if (ssArgs.find(pCurMod->GetModName()) == ssArgs.end() && pCurMod->GetModName() != GetModName()) { ssUnloadMods.insert(pCurMod->GetModName()); } } for (const CString& sMod : ssUnloadMods) { pNetwork->GetModules().UnloadModule(sMod); } CTemplate TmplMod; TmplMod["Username"] = pUser->GetUserName(); TmplMod["Name"] = pNetwork->GetName(); TmplMod["WebadminAction"] = "change"; FOR_EACH_MODULE(it, make_pair(pUser, pNetwork)) { (*it)->OnEmbeddedWebRequest(WebSock, "webadmin/network", TmplMod); } if (!CZNC::Get().WriteConfig()) { WebSock.PrintErrorPage(t_s( "Network was added/modified, but config file was not written")); return true; } if (WebSock.HasParam("submit_return")) { WebSock.Redirect(GetWebPath() + "edituser?user=" + pUser->GetUserName().Escape_n(CString::EURL)); } else { WebSock.Redirect(GetWebPath() + "editnetwork?user=" + pUser->GetUserName().Escape_n(CString::EURL) + "&network=" + pNetwork->GetName().Escape_n(CString::EURL)); } return true; } bool DelNetwork(CWebSock& WebSock, CUser* pUser, CTemplate& Tmpl) { CString sNetwork = WebSock.GetParam("name"); if (sNetwork.empty() && !WebSock.IsPost()) { sNetwork = WebSock.GetParam("name", false); } if (!pUser) { WebSock.PrintErrorPage(t_s("No such user")); return true; } if (sNetwork.empty()) { WebSock.PrintErrorPage( t_s("That network doesn't exist for this user")); return true; } if (!WebSock.IsPost()) { // Show the "Are you sure?" page: Tmpl.SetFile("del_network.tmpl"); Tmpl["Username"] = pUser->GetUserName(); Tmpl["Network"] = sNetwork; return true; } pUser->DeleteNetwork(sNetwork); if (!CZNC::Get().WriteConfig()) { WebSock.PrintErrorPage( t_s("Network was deleted, but config file was not written")); return true; } WebSock.Redirect(GetWebPath() + "edituser?user=" + pUser->GetUserName().Escape_n(CString::EURL)); return false; } bool DelChan(CWebSock& WebSock, CIRCNetwork* pNetwork) { CString sChan = WebSock.GetParam("name", false); if (sChan.empty()) { WebSock.PrintErrorPage( t_s("That channel doesn't exist for this network")); return true; } pNetwork->DelChan(sChan); pNetwork->PutIRC("PART " + sChan); if (!CZNC::Get().WriteConfig()) { WebSock.PrintErrorPage( t_s("Channel was deleted, but config file was not written")); return true; } WebSock.Redirect( GetWebPath() + "editnetwork?user=" + pNetwork->GetUser()->GetUserName().Escape_n(CString::EURL) + "&network=" + pNetwork->GetName().Escape_n(CString::EURL)); return false; } bool UserPage(CWebSock& WebSock, CTemplate& Tmpl, CUser* pUser = nullptr) { std::shared_ptr spSession = WebSock.GetSession(); Tmpl.SetFile("add_edit_user.tmpl"); if (!WebSock.GetParam("submitted").ToUInt()) { CUser EmptyUser(""); CUser* pRealUser = pUser; if (pUser) { Tmpl["Title"] = t_f("Edit User [{1}]")(pUser->GetUserName()); Tmpl["Edit"] = "true"; } else { CString sUsername = WebSock.GetParam("clone", false); pUser = CZNC::Get().FindUser(sUsername); pRealUser = pUser; if (pUser) { Tmpl["Title"] = t_f("Clone User [{1}]")(pUser->GetUserName()); Tmpl["Clone"] = "true"; Tmpl["CloneUsername"] = pUser->GetUserName(); } else { pUser = &EmptyUser; Tmpl["Title"] = "Add User"; } } Tmpl["ImAdmin"] = CString(spSession->IsAdmin()); Tmpl["Username"] = pUser->GetUserName(); Tmpl["AuthOnlyViaModule"] = CString(pUser->AuthOnlyViaModule()); Tmpl["Nick"] = pUser->GetNick(); Tmpl["AltNick"] = pUser->GetAltNick(); Tmpl["StatusPrefix"] = pUser->GetStatusPrefix(); Tmpl["Ident"] = pUser->GetIdent(); Tmpl["RealName"] = pUser->GetRealName(); Tmpl["QuitMsg"] = pUser->GetQuitMsg(); Tmpl["DefaultChanModes"] = pUser->GetDefaultChanModes(); Tmpl["ChanBufferSize"] = CString(pUser->GetChanBufferSize()); Tmpl["QueryBufferSize"] = CString(pUser->GetQueryBufferSize()); Tmpl["TimestampFormat"] = pUser->GetTimestampFormat(); Tmpl["Timezone"] = pUser->GetTimezone(); Tmpl["JoinTries"] = CString(pUser->JoinTries()); Tmpl["NoTrafficTimeout"] = CString(pUser->GetNoTrafficTimeout()); Tmpl["MaxNetworks"] = CString(pUser->MaxNetworks()); Tmpl["MaxJoins"] = CString(pUser->MaxJoins()); Tmpl["MaxQueryBuffers"] = CString(pUser->MaxQueryBuffers()); Tmpl["Language"] = pUser->GetLanguage(); const set& ssAllowedHosts = pUser->GetAllowedHosts(); for (const CString& sHost : ssAllowedHosts) { CTemplate& l = Tmpl.AddRow("AllowedHostLoop"); l["Host"] = sHost; } const vector& vNetworks = pUser->GetNetworks(); for (const CIRCNetwork* pNetwork : vNetworks) { CTemplate& l = Tmpl.AddRow("NetworkLoop"); l["Name"] = pNetwork->GetName(); l["Username"] = pUser->GetUserName(); l["Clients"] = CString(pNetwork->GetClients().size()); l["IRCNick"] = pNetwork->GetIRCNick().GetNick(); CServer* pServer = pNetwork->GetCurrentServer(); if (pServer) { l["Server"] = pServer->GetName() + ":" + (pServer->IsSSL() ? "+" : "") + CString(pServer->GetPort()); } } const MCString& msCTCPReplies = pUser->GetCTCPReplies(); for (const auto& it : msCTCPReplies) { CTemplate& l = Tmpl.AddRow("CTCPLoop"); l["CTCP"] = it.first + " " + it.second; } SCString ssTimezones = CUtils::GetTimezones(); for (const CString& sTZ : ssTimezones) { CTemplate& l = Tmpl.AddRow("TZLoop"); l["TZ"] = sTZ; } #ifdef HAVE_I18N Tmpl["HaveI18N"] = "true"; // TODO maybe stop hardcoding English here CTemplate& l_en = Tmpl.AddRow("LanguageLoop"); l_en["Code"] = ""; l_en["Name"] = "English"; for (const auto& it : CTranslationInfo::GetTranslations()) { CTemplate& lang = Tmpl.AddRow("LanguageLoop"); lang["Code"] = it.first; lang["Name"] = it.second.sSelfName; } #else Tmpl["HaveI18N"] = "false"; #endif #ifdef HAVE_ICU for (const CString& sEncoding : CUtils::GetEncodings()) { CTemplate& l = Tmpl.AddRow("EncodingLoop"); l["Encoding"] = sEncoding; } const CString sEncoding = pRealUser ? pUser->GetClientEncoding() : "^UTF-8"; if (sEncoding.empty()) { Tmpl["EncodingUtf"] = "legacy"; } else if (sEncoding[0] == '*') { Tmpl["EncodingUtf"] = "receive"; Tmpl["Encoding"] = sEncoding.substr(1); } else if (sEncoding[0] == '^') { Tmpl["EncodingUtf"] = "send"; Tmpl["Encoding"] = sEncoding.substr(1); } else { Tmpl["EncodingUtf"] = "simple"; Tmpl["Encoding"] = sEncoding; } Tmpl["LegacyEncodingDisabled"] = CString(CZNC::Get().IsForcingEncoding()); #else Tmpl["LegacyEncodingDisabled"] = "true"; Tmpl["EncodingDisabled"] = "true"; Tmpl["EncodingUtf"] = "legacy"; #endif // To change BindHosts be admin or don't have DenySetBindHost if (spSession->IsAdmin() || !spSession->GetUser()->DenySetBindHost()) { Tmpl["BindHostEdit"] = "true"; Tmpl["BindHost"] = pUser->GetBindHost(); Tmpl["DCCBindHost"] = pUser->GetDCCBindHost(); } vector vDirs; WebSock.GetAvailSkins(vDirs); for (const CString& SubDir : vDirs) { CTemplate& l = Tmpl.AddRow("SkinLoop"); l["Name"] = SubDir; if (SubDir == pUser->GetSkinName()) { l["Checked"] = "true"; } } set ssUserMods; CZNC::Get().GetModules().GetAvailableMods(ssUserMods); set ssDefaultMods; CZNC::Get().GetModules().GetDefaultMods(ssDefaultMods, CModInfo::UserModule); for (const CModInfo& Info : ssUserMods) { CTemplate& l = Tmpl.AddRow("ModuleLoop"); l["Name"] = Info.GetName(); l["Description"] = Info.GetDescription(); l["Wiki"] = Info.GetWikiPage(); l["HasArgs"] = CString(Info.GetHasArgs()); l["ArgsHelpText"] = Info.GetArgsHelpText(); CModule* pModule = nullptr; pModule = pUser->GetModules().FindModule(Info.GetName()); // Check if module is loaded by all or some networks const vector& userNetworks = pUser->GetNetworks(); unsigned int networksWithRenderedModuleCount = 0; for (const CIRCNetwork* pCurrentNetwork : userNetworks) { const CModules& networkModules = pCurrentNetwork->GetModules(); if (networkModules.FindModule(Info.GetName())) { networksWithRenderedModuleCount++; } } l["CanBeLoadedByNetwork"] = CString(Info.SupportsType(CModInfo::NetworkModule)); l["LoadedByAllNetworks"] = CString( networksWithRenderedModuleCount == userNetworks.size()); l["LoadedBySomeNetworks"] = CString(networksWithRenderedModuleCount != 0); if (pModule) { l["Checked"] = "true"; l["Args"] = pModule->GetArgs(); if (CModInfo::UserModule == GetType() && Info.GetName() == GetModName()) { l["Disabled"] = "true"; } } if (!pRealUser) { for (const CModInfo& DInfo : ssDefaultMods) { if (Info.GetName() == DInfo.GetName()) { l["Checked"] = "true"; } } } l["CanBeLoadedGlobally"] = CString(Info.SupportsType(CModInfo::GlobalModule)); // Check if module is loaded globally l["LoadedGlobally"] = CString(CZNC::Get().GetModules().FindModule( Info.GetName()) != nullptr); if (!spSession->IsAdmin() && pUser->DenyLoadMod()) { l["Disabled"] = "true"; } } CTemplate& o1 = Tmpl.AddRow("OptionLoop"); o1["Name"] = "autoclearchanbuffer"; o1["DisplayName"] = t_s("Auto Clear Chan Buffer"); o1["Tooltip"] = t_s("Automatically Clear Channel Buffer After Playback (the " "default value for new channels)"); if (pUser->AutoClearChanBuffer()) { o1["Checked"] = "true"; } /* o2 used to be auto cycle which was removed */ CTemplate& o4 = Tmpl.AddRow("OptionLoop"); o4["Name"] = "multiclients"; o4["DisplayName"] = t_s("Multi Clients"); if (pUser->MultiClients()) { o4["Checked"] = "true"; } CTemplate& o7 = Tmpl.AddRow("OptionLoop"); o7["Name"] = "appendtimestamp"; o7["DisplayName"] = t_s("Append Timestamps"); if (pUser->GetTimestampAppend()) { o7["Checked"] = "true"; } CTemplate& o8 = Tmpl.AddRow("OptionLoop"); o8["Name"] = "prependtimestamp"; o8["DisplayName"] = t_s("Prepend Timestamps"); if (pUser->GetTimestampPrepend()) { o8["Checked"] = "true"; } if (spSession->IsAdmin()) { CTemplate& o9 = Tmpl.AddRow("OptionLoop"); o9["Name"] = "denyloadmod"; o9["DisplayName"] = t_s("Deny LoadMod"); if (pUser->DenyLoadMod()) { o9["Checked"] = "true"; } CTemplate& o10 = Tmpl.AddRow("OptionLoop"); o10["Name"] = "isadmin"; o10["DisplayName"] = t_s("Admin"); if (pUser->IsAdmin()) { o10["Checked"] = "true"; } if (pUser == CZNC::Get().FindUser(WebSock.GetUser())) { o10["Disabled"] = "true"; } CTemplate& o11 = Tmpl.AddRow("OptionLoop"); o11["Name"] = "denysetbindhost"; o11["DisplayName"] = t_s("Deny SetBindHost"); if (pUser->DenySetBindHost()) { o11["Checked"] = "true"; } } CTemplate& o12 = Tmpl.AddRow("OptionLoop"); o12["Name"] = "autoclearquerybuffer"; o12["DisplayName"] = t_s("Auto Clear Query Buffer"); o12["Tooltip"] = t_s("Automatically Clear Query Buffer After Playback"); if (pUser->AutoClearQueryBuffer()) { o12["Checked"] = "true"; } FOR_EACH_MODULE(i, pUser) { CTemplate& mod = Tmpl.AddRow("EmbeddedModuleLoop"); mod.insert(Tmpl.begin(), Tmpl.end()); mod["WebadminAction"] = "display"; if ((*i)->OnEmbeddedWebRequest(WebSock, "webadmin/user", mod)) { mod["Embed"] = WebSock.FindTmpl(*i, "WebadminUser.tmpl"); mod["ModName"] = (*i)->GetModName(); } } return true; } /* If pUser is nullptr, we are adding a user, else we are editing this * one */ CString sUsername = WebSock.GetParam("user"); if (!pUser && CZNC::Get().FindUser(sUsername)) { WebSock.PrintErrorPage( t_f("Invalid Submission: User {1} already exists")(sUsername)); return true; } CUser* pNewUser = GetNewUser(WebSock, pUser); if (!pNewUser) { // GetNewUser already called WebSock.PrintErrorPage() return true; } CString sErr; CString sConfigErrorMsg; if (!pUser) { CString sClone = WebSock.GetParam("clone"); if (CUser* pCloneUser = CZNC::Get().FindUser(sClone)) { pNewUser->CloneNetworks(*pCloneUser); } // Add User Submission if (!CZNC::Get().AddUser(pNewUser, sErr)) { delete pNewUser; WebSock.PrintErrorPage(t_f("Invalid submission: {1}")(sErr)); return true; } pUser = pNewUser; sConfigErrorMsg = t_s("User was added, but config file was not written"); } else { // Edit User Submission if (!pUser->Clone(*pNewUser, sErr, false)) { delete pNewUser; WebSock.PrintErrorPage(t_f("Invalid submission: {1}")(sErr)); return true; } delete pNewUser; sConfigErrorMsg = t_s("User was edited, but config file was not written"); } CTemplate TmplMod; TmplMod["Username"] = sUsername; TmplMod["WebadminAction"] = "change"; FOR_EACH_MODULE(it, pUser) { (*it)->OnEmbeddedWebRequest(WebSock, "webadmin/user", TmplMod); } if (!CZNC::Get().WriteConfig()) { WebSock.PrintErrorPage(sConfigErrorMsg); return true; } if (spSession->IsAdmin() && WebSock.HasParam("submit_return")) { WebSock.Redirect(GetWebPath() + "listusers"); } else { WebSock.Redirect(GetWebPath() + "edituser?user=" + pUser->GetUserName()); } /* we don't want the template to be printed while we redirect */ return false; } bool ListUsersPage(CWebSock& WebSock, CTemplate& Tmpl) { std::shared_ptr spSession = WebSock.GetSession(); const map& msUsers = CZNC::Get().GetUserMap(); Tmpl["Title"] = t_s("Manage Users"); Tmpl["Action"] = "listusers"; for (const auto& it : msUsers) { CTemplate& l = Tmpl.AddRow("UserLoop"); CUser* pUser = it.second; l["Username"] = pUser->GetUserName(); l["Clients"] = CString(pUser->GetAllClients().size()); l["Networks"] = CString(pUser->GetNetworks().size()); if (pUser == spSession->GetUser()) { l["IsSelf"] = "true"; } } return true; } bool TrafficPage(CWebSock& WebSock, CTemplate& Tmpl) { std::shared_ptr spSession = WebSock.GetSession(); Tmpl["Title"] = t_s("Traffic Info"); Tmpl["Uptime"] = CZNC::Get().GetUptime(); const map& msUsers = CZNC::Get().GetUserMap(); Tmpl["TotalUsers"] = CString(msUsers.size()); size_t uiNetworks = 0, uiAttached = 0, uiClients = 0, uiServers = 0; for (const auto& it : msUsers) { CUser* pUser = it.second; if (!spSession->IsAdmin() && spSession->GetUser() != it.second) { continue; } vector vNetworks = pUser->GetNetworks(); for (const CIRCNetwork* pNetwork : vNetworks) { uiNetworks++; if (pNetwork->IsIRCConnected()) { uiServers++; } if (pNetwork->IsNetworkAttached()) { uiAttached++; } uiClients += pNetwork->GetClients().size(); } uiClients += pUser->GetUserClients().size(); } Tmpl["TotalNetworks"] = CString(uiNetworks); Tmpl["AttachedNetworks"] = CString(uiAttached); Tmpl["TotalCConnections"] = CString(uiClients); Tmpl["TotalIRCConnections"] = CString(uiServers); CZNC::TrafficStatsPair Users, ZNC, Total; CZNC::TrafficStatsMap traffic = CZNC::Get().GetTrafficStats(Users, ZNC, Total); for (const auto& it : traffic) { if (!spSession->IsAdmin() && !spSession->GetUser()->GetUserName().Equals(it.first)) { continue; } CTemplate& l = Tmpl.AddRow("TrafficLoop"); l["Username"] = it.first; l["In"] = CString::ToByteStr(it.second.first); l["Out"] = CString::ToByteStr(it.second.second); l["Total"] = CString::ToByteStr(it.second.first + it.second.second); CZNC::TrafficStatsPair NetworkTotal; CZNC::TrafficStatsMap NetworkTraffic = CZNC::Get().GetNetworkTrafficStats(it.first, NetworkTotal); for (const auto& it2 : NetworkTraffic) { CTemplate& l2 = Tmpl.AddRow("TrafficLoop"); l2["Network"] = it2.first; l2["In"] = CString::ToByteStr(it2.second.first); l2["Out"] = CString::ToByteStr(it2.second.second); l2["Total"] = CString::ToByteStr(it2.second.first + it2.second.second); } } Tmpl["UserIn"] = CString::ToByteStr(Users.first); Tmpl["UserOut"] = CString::ToByteStr(Users.second); Tmpl["UserTotal"] = CString::ToByteStr(Users.first + Users.second); Tmpl["ZNCIn"] = CString::ToByteStr(ZNC.first); Tmpl["ZNCOut"] = CString::ToByteStr(ZNC.second); Tmpl["ZNCTotal"] = CString::ToByteStr(ZNC.first + ZNC.second); Tmpl["AllIn"] = CString::ToByteStr(Total.first); Tmpl["AllOut"] = CString::ToByteStr(Total.second); Tmpl["AllTotal"] = CString::ToByteStr(Total.first + Total.second); return true; } bool AddListener(CWebSock& WebSock, CTemplate& Tmpl) { unsigned short uPort = WebSock.GetParam("port").ToUShort(); CString sHost = WebSock.GetParam("host"); CString sURIPrefix = WebSock.GetParam("uriprefix"); if (sHost == "*") sHost = ""; bool bSSL = WebSock.GetParam("ssl").ToBool(); bool bIPv4 = WebSock.GetParam("ipv4").ToBool(); bool bIPv6 = WebSock.GetParam("ipv6").ToBool(); bool bIRC = WebSock.GetParam("irc").ToBool(); bool bWeb = WebSock.GetParam("web").ToBool(); EAddrType eAddr = ADDR_ALL; if (bIPv4) { if (bIPv6) { eAddr = ADDR_ALL; } else { eAddr = ADDR_IPV4ONLY; } } else { if (bIPv6) { eAddr = ADDR_IPV6ONLY; } else { WebSock.GetSession()->AddError( t_s("Choose either IPv4 or IPv6 or both.")); return SettingsPage(WebSock, Tmpl); } } CListener::EAcceptType eAccept; if (bIRC) { if (bWeb) { eAccept = CListener::ACCEPT_ALL; } else { eAccept = CListener::ACCEPT_IRC; } } else { if (bWeb) { eAccept = CListener::ACCEPT_HTTP; } else { WebSock.GetSession()->AddError( t_s("Choose either IRC or HTTP or both.")); return SettingsPage(WebSock, Tmpl); } } CString sMessage; if (CZNC::Get().AddListener(uPort, sHost, sURIPrefix, bSSL, eAddr, eAccept, sMessage)) { if (!sMessage.empty()) { WebSock.GetSession()->AddSuccess(sMessage); } if (!CZNC::Get().WriteConfig()) { WebSock.GetSession()->AddError( t_s("Port was changed, but config file was not written")); } } else { WebSock.GetSession()->AddError(sMessage); } return SettingsPage(WebSock, Tmpl); } bool DelListener(CWebSock& WebSock, CTemplate& Tmpl) { unsigned short uPort = WebSock.GetParam("port").ToUShort(); CString sHost = WebSock.GetParam("host"); bool bIPv4 = WebSock.GetParam("ipv4").ToBool(); bool bIPv6 = WebSock.GetParam("ipv6").ToBool(); EAddrType eAddr = ADDR_ALL; if (bIPv4) { if (bIPv6) { eAddr = ADDR_ALL; } else { eAddr = ADDR_IPV4ONLY; } } else { if (bIPv6) { eAddr = ADDR_IPV6ONLY; } else { WebSock.GetSession()->AddError(t_s("Invalid request.")); return SettingsPage(WebSock, Tmpl); } } CListener* pListener = CZNC::Get().FindListener(uPort, sHost, eAddr); if (pListener) { CZNC::Get().DelListener(pListener); if (!CZNC::Get().WriteConfig()) { WebSock.GetSession()->AddError( t_s("Port was changed, but config file was not written")); } } else { WebSock.GetSession()->AddError( t_s("The specified listener was not found.")); } return SettingsPage(WebSock, Tmpl); } bool SettingsPage(CWebSock& WebSock, CTemplate& Tmpl) { Tmpl.SetFile("settings.tmpl"); if (!WebSock.GetParam("submitted").ToUInt()) { Tmpl["Action"] = "settings"; Tmpl["Title"] = t_s("Global Settings"); Tmpl["StatusPrefix"] = CZNC::Get().GetStatusPrefix(); Tmpl["MaxBufferSize"] = CString(CZNC::Get().GetMaxBufferSize()); Tmpl["ConnectDelay"] = CString(CZNC::Get().GetConnectDelay()); Tmpl["ServerThrottle"] = CString(CZNC::Get().GetServerThrottle()); Tmpl["AnonIPLimit"] = CString(CZNC::Get().GetAnonIPLimit()); Tmpl["ProtectWebSessions"] = CString(CZNC::Get().GetProtectWebSessions()); Tmpl["HideVersion"] = CString(CZNC::Get().GetHideVersion()); Tmpl["AuthOnlyViaModule"] = CString(CZNC::Get().GetAuthOnlyViaModule()); const VCString& vsMotd = CZNC::Get().GetMotd(); for (const CString& sMotd : vsMotd) { CTemplate& l = Tmpl.AddRow("MOTDLoop"); l["Line"] = sMotd; } const vector& vpListeners = CZNC::Get().GetListeners(); for (const CListener* pListener : vpListeners) { CTemplate& l = Tmpl.AddRow("ListenLoop"); l["Port"] = CString(pListener->GetPort()); l["BindHost"] = pListener->GetBindHost(); l["IsHTTP"] = CString(pListener->GetAcceptType() != CListener::ACCEPT_IRC); l["IsIRC"] = CString(pListener->GetAcceptType() != CListener::ACCEPT_HTTP); l["URIPrefix"] = pListener->GetURIPrefix() + "/"; // simple protection for user from shooting his own foot // TODO check also for hosts/families // such check is only here, user still can forge HTTP request to // delete web port l["SuggestDeletion"] = CString(pListener->GetPort() != WebSock.GetLocalPort()); #ifdef HAVE_LIBSSL if (pListener->IsSSL()) { l["IsSSL"] = "true"; } #endif #ifdef HAVE_IPV6 switch (pListener->GetAddrType()) { case ADDR_IPV4ONLY: l["IsIPV4"] = "true"; break; case ADDR_IPV6ONLY: l["IsIPV6"] = "true"; break; case ADDR_ALL: l["IsIPV4"] = "true"; l["IsIPV6"] = "true"; break; } #else l["IsIPV4"] = "true"; #endif } vector vDirs; WebSock.GetAvailSkins(vDirs); for (const CString& SubDir : vDirs) { CTemplate& l = Tmpl.AddRow("SkinLoop"); l["Name"] = SubDir; if (SubDir == CZNC::Get().GetSkinName()) { l["Checked"] = "true"; } } set ssGlobalMods; CZNC::Get().GetModules().GetAvailableMods(ssGlobalMods, CModInfo::GlobalModule); for (const CModInfo& Info : ssGlobalMods) { CTemplate& l = Tmpl.AddRow("ModuleLoop"); CModule* pModule = CZNC::Get().GetModules().FindModule(Info.GetName()); if (pModule) { l["Checked"] = "true"; l["Args"] = pModule->GetArgs(); if (CModInfo::GlobalModule == GetType() && Info.GetName() == GetModName()) { l["Disabled"] = "true"; } } l["Name"] = Info.GetName(); l["Description"] = Info.GetDescription(); l["Wiki"] = Info.GetWikiPage(); l["HasArgs"] = CString(Info.GetHasArgs()); l["ArgsHelpText"] = Info.GetArgsHelpText(); // Check if the module is loaded by all or some users, and/or by // all or some networks unsigned int usersWithRenderedModuleCount = 0; unsigned int networksWithRenderedModuleCount = 0; unsigned int networksCount = 0; const map& allUsers = CZNC::Get().GetUserMap(); for (const auto& it : allUsers) { const CUser* pUser = it.second; // Count users which has loaded a render module const CModules& userModules = pUser->GetModules(); if (userModules.FindModule(Info.GetName())) { usersWithRenderedModuleCount++; } // Count networks which has loaded a render module const vector& userNetworks = pUser->GetNetworks(); networksCount += userNetworks.size(); for (const CIRCNetwork* pCurrentNetwork : userNetworks) { if (pCurrentNetwork->GetModules().FindModule( Info.GetName())) { networksWithRenderedModuleCount++; } } } l["CanBeLoadedByNetwork"] = CString(Info.SupportsType(CModInfo::NetworkModule)); l["LoadedByAllNetworks"] = CString(networksWithRenderedModuleCount == networksCount); l["LoadedBySomeNetworks"] = CString(networksWithRenderedModuleCount != 0); l["CanBeLoadedByUser"] = CString(Info.SupportsType(CModInfo::UserModule)); l["LoadedByAllUsers"] = CString(usersWithRenderedModuleCount == allUsers.size()); l["LoadedBySomeUsers"] = CString(usersWithRenderedModuleCount != 0); } return true; } CString sArg; sArg = WebSock.GetParam("statusprefix"); CZNC::Get().SetStatusPrefix(sArg); sArg = WebSock.GetParam("maxbufsize"); CZNC::Get().SetMaxBufferSize(sArg.ToUInt()); sArg = WebSock.GetParam("connectdelay"); CZNC::Get().SetConnectDelay(sArg.ToUInt()); sArg = WebSock.GetParam("serverthrottle"); CZNC::Get().SetServerThrottle(sArg.ToUInt()); sArg = WebSock.GetParam("anoniplimit"); CZNC::Get().SetAnonIPLimit(sArg.ToUInt()); sArg = WebSock.GetParam("protectwebsessions"); CZNC::Get().SetProtectWebSessions(sArg.ToBool()); sArg = WebSock.GetParam("hideversion"); CZNC::Get().SetHideVersion(sArg.ToBool()); sArg = WebSock.GetParam("authonlyviamodule"); CZNC::Get().SetAuthOnlyViaModule(sArg.ToBool()); VCString vsArgs; WebSock.GetRawParam("motd").Split("\n", vsArgs); CZNC::Get().ClearMotd(); for (const CString& sMotd : vsArgs) { CZNC::Get().AddMotd(sMotd.TrimRight_n()); } CZNC::Get().SetSkinName(WebSock.GetParam("skin")); set ssArgs; WebSock.GetParamValues("loadmod", ssArgs); for (const CString& s : ssArgs) { CString sModRet; CString sModName = s.TrimRight_n("\r"); CString sModLoadError; if (!sModName.empty()) { CString sArgs = WebSock.GetParam("modargs_" + sModName); CModule* pMod = CZNC::Get().GetModules().FindModule(sModName); if (!pMod) { if (!CZNC::Get().GetModules().LoadModule( sModName, sArgs, CModInfo::GlobalModule, nullptr, nullptr, sModRet)) { sModLoadError = t_f("Unable to load module [{1}]: {2}")( sModName, sModRet); } } else if (pMod->GetArgs() != sArgs) { if (!CZNC::Get().GetModules().ReloadModule( sModName, sArgs, nullptr, nullptr, sModRet)) { sModLoadError = t_f("Unable to reload module [{1}]: {2}")(sModName, sModRet); } } if (!sModLoadError.empty()) { DEBUG(sModLoadError); WebSock.GetSession()->AddError(sModLoadError); } } } const CModules& vCurMods = CZNC::Get().GetModules(); set ssUnloadMods; for (const CModule* pCurMod : vCurMods) { if (ssArgs.find(pCurMod->GetModName()) == ssArgs.end() && (CModInfo::GlobalModule != GetType() || pCurMod->GetModName() != GetModName())) { ssUnloadMods.insert(pCurMod->GetModName()); } } for (const CString& sMod : ssUnloadMods) { CZNC::Get().GetModules().UnloadModule(sMod); } if (!CZNC::Get().WriteConfig()) { WebSock.GetSession()->AddError( t_s("Settings were changed, but config file was not written")); } WebSock.Redirect(GetWebPath() + "settings"); /* we don't want the template to be printed while we redirect */ return false; } }; template <> void TModInfo(CModInfo& Info) { Info.AddType(CModInfo::UserModule); Info.SetWikiPage("webadmin"); } GLOBALMODULEDEFS(CWebAdminMod, "Web based administration module.") znc-1.7.5/modules/modtcl.cpp0000644000175000017500000004355313542151610016210 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include using std::vector; using std::map; #define STDVAR (ClientData cd, Tcl_Interp * irp, int argc, const char* argv[]) #define BADARGS(nl, nh, example) \ do { \ if ((argc < (nl)) || (argc > (nh))) { \ Tcl_AppendResult(irp, "wrong # args: should be \"", argv[0], \ (example), "\"", nullptr); \ return TCL_ERROR; \ } \ } while (0) class CModTcl; class CModTclTimer : public CTimer { public: CModTclTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription), m_pParent(nullptr) {} ~CModTclTimer() override {} protected: void RunJob() override; CModTcl* m_pParent; }; class CModTclStartTimer : public CTimer { public: CModTclStartTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription), m_pParent(nullptr) {} ~CModTclStartTimer() override {} protected: void RunJob() override; CModTcl* m_pParent; }; class CModTcl : public CModule { public: MODCONSTRUCTOR(CModTcl) { interp = nullptr; } ~CModTcl() override { if (interp) { Tcl_DeleteInterp(interp); } } bool OnLoad(const CString& sArgs, CString& sErrorMsg) override { #ifndef MOD_MODTCL_ALLOW_EVERYONE if (!GetUser()->IsAdmin()) { sErrorMsg = "You must be admin to use the modtcl module"; return false; } #endif AddTimer( new CModTclStartTimer(this, 1, 1, "ModTclStarter", "Timer for modtcl to load the interpreter.")); return true; } void Start() { CString sMyArgs = GetArgs(); interp = Tcl_CreateInterp(); Tcl_Init(interp); Tcl_CreateCommand(interp, "Binds::ProcessPubm", tcl_Bind, this, nullptr); Tcl_CreateCommand(interp, "Binds::ProcessMsgm", tcl_Bind, this, nullptr); Tcl_CreateCommand(interp, "Binds::ProcessTime", tcl_Bind, this, nullptr); Tcl_CreateCommand(interp, "Binds::ProcessEvnt", tcl_Bind, this, nullptr); Tcl_CreateCommand(interp, "Binds::ProcessNick", tcl_Bind, this, nullptr); Tcl_CreateCommand(interp, "Binds::ProcessKick", tcl_Bind, this, nullptr); Tcl_CreateCommand(interp, "PutIRC", tcl_PutIRC, this, nullptr); Tcl_CreateCommand(interp, "PutModule", tcl_PutModule, this, nullptr); Tcl_CreateCommand(interp, "PutStatus", tcl_PutStatus, this, nullptr); Tcl_CreateCommand(interp, "PutStatusNotice", tcl_PutStatusNotice, this, nullptr); Tcl_CreateCommand(interp, "PutUser", tcl_PutUser, this, nullptr); Tcl_CreateCommand(interp, "GetCurNick", tcl_GetCurNick, this, nullptr); Tcl_CreateCommand(interp, "GetUsername", tcl_GetUsername, this, nullptr); Tcl_CreateCommand(interp, "GetRealName", tcl_GetRealName, this, nullptr); Tcl_CreateCommand(interp, "GetVHost", tcl_GetBindHost, this, nullptr); Tcl_CreateCommand(interp, "GetBindHost", tcl_GetBindHost, this, nullptr); Tcl_CreateCommand(interp, "GetChans", tcl_GetChans, this, nullptr); Tcl_CreateCommand(interp, "GetChannelUsers", tcl_GetChannelUsers, this, nullptr); Tcl_CreateCommand(interp, "GetChannelModes", tcl_GetChannelModes, this, nullptr); Tcl_CreateCommand(interp, "GetServer", tcl_GetServer, this, nullptr); Tcl_CreateCommand(interp, "GetServerOnline", tcl_GetServerOnline, this, nullptr); Tcl_CreateCommand(interp, "GetModules", tcl_GetModules, this, nullptr); Tcl_CreateCommand(interp, "GetClientCount", tcl_GetClientCount, this, nullptr); Tcl_CreateCommand(interp, "exit", tcl_exit, this, nullptr); if (!sMyArgs.empty()) { int i = Tcl_EvalFile(interp, sMyArgs.c_str()); if (i != TCL_OK) { PutModule(Tcl_GetStringResult(interp)); } } AddTimer(new CModTclTimer( this, 1, 0, "ModTclUpdate", "Timer for modtcl to process pending events and idle callbacks.")); } void OnModCommand(const CString& sCommand) override { CString sResult; VCString vsResult; CString sCmd = sCommand; if (sCmd.Token(0).CaseCmp(".tcl") == 0) sCmd = sCmd.Token(1, true); if (sCmd.Left(1).CaseCmp(".") == 0) sCmd = "Binds::ProcessDcc - - {" + sCmd + "}"; Tcl_Eval(interp, sCmd.c_str()); sResult = CString(Tcl_GetStringResult(interp)); if (!sResult.empty()) { sResult.Split("\n", vsResult); unsigned int a = 0; for (a = 0; a < vsResult.size(); a++) PutModule(vsResult[a].TrimRight_n()); } } void TclUpdate() { while (Tcl_DoOneEvent(TCL_DONT_WAIT)) { } int i = Tcl_Eval(interp, "Binds::ProcessTime"); if (i != TCL_OK) { PutModule(Tcl_GetStringResult(interp)); } } CString TclEscape(CString sLine) { sLine.Replace("\\", "\\\\"); sLine.Replace("{", "\\{"); sLine.Replace("}", "\\}"); return sLine; } void OnPreRehash() override { if (interp) Tcl_Eval(interp, "Binds::ProcessEvnt prerehash"); } void OnPostRehash() override { if (interp) { Tcl_Eval(interp, "rehash"); Tcl_Eval(interp, "Binds::ProcessEvnt rehash"); } } void OnIRCConnected() override { if (interp) Tcl_Eval(interp, "Binds::ProcessEvnt init-server"); } void OnIRCDisconnected() override { if (interp) Tcl_Eval(interp, "Binds::ProcessEvnt disconnect-server"); } EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override { CString sMes = TclEscape(sMessage); CString sNick = TclEscape(CString(Nick.GetNick())); CString sHost = TclEscape(CString(Nick.GetIdent() + "@" + Nick.GetHost())); CString sChannel = TclEscape(CString(Channel.GetName())); CString sCommand = "Binds::ProcessPubm {" + sNick + "} {" + sHost + "} - {" + sChannel + "} {" + sMes + "}"; int i = Tcl_Eval(interp, sCommand.c_str()); if (i != TCL_OK) { PutModule(Tcl_GetStringResult(interp)); } return CONTINUE; } EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override { CString sMes = TclEscape(sMessage); CString sNick = TclEscape(CString(Nick.GetNick())); CString sHost = TclEscape(CString(Nick.GetIdent() + "@" + Nick.GetHost())); CString sCommand = "Binds::ProcessMsgm {" + sNick + "} {" + sHost + "} - {" + sMes + "}"; int i = Tcl_Eval(interp, sCommand.c_str()); if (i != TCL_OK) { PutModule(Tcl_GetStringResult(interp)); } return CONTINUE; } void OnNick(const CNick& OldNick, const CString& sNewNick, const vector& vChans) override { CString sOldNick = TclEscape(CString(OldNick.GetNick())); CString sNewNickTmp = TclEscape(sNewNick); CString sHost = TclEscape(CString(OldNick.GetIdent() + "@" + OldNick.GetHost())); CString sCommand; // Nick change is triggered for each common chan so that binds can be // chan specific unsigned int nLength = vChans.size(); for (unsigned int n = 0; n < nLength; n++) { sCommand = "Binds::ProcessNick {" + sOldNick + "} {" + sHost + "} - {" + vChans[n]->GetName() + "} {" + sNewNickTmp + "}"; int i = Tcl_Eval(interp, sCommand.c_str()); if (i != TCL_OK) { PutModule(Tcl_GetStringResult(interp)); } } } void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) override { CString sOpNick = TclEscape(CString(OpNick.GetNick())); CString sNick = TclEscape(sKickedNick); CString sOpHost = TclEscape(CString(OpNick.GetIdent() + "@" + OpNick.GetHost())); CString sCommand = "Binds::ProcessKick {" + sOpNick + "} {" + sOpHost + "} - {" + Channel.GetName() + "} {" + sNick + "} {" + sMessage + "}"; int i = Tcl_Eval(interp, sCommand.c_str()); if (i != TCL_OK) { PutModule(Tcl_GetStringResult(interp)); } } private: Tcl_Interp* interp; static CString argvit(const char* argv[], unsigned int end, unsigned int begin, CString delim) { CString sRet; unsigned int i; if (begin < end) sRet = CString(argv[begin]); for (i = begin + 1; i < end; i++) { sRet = sRet + delim + CString(argv[i]); } return sRet; } // Placeholder for binds incase binds.tcl isn't used static int tcl_Bind STDVAR { return TCL_OK; } static int tcl_GetCurNick STDVAR { CModTcl* mod = static_cast(cd); Tcl_SetResult(irp, (char*)mod->GetNetwork()->GetCurNick().c_str(), TCL_VOLATILE); return TCL_OK; } static int tcl_GetUsername STDVAR { CModTcl* mod = static_cast(cd); Tcl_SetResult(irp, (char*)mod->GetUser()->GetUserName().c_str(), TCL_VOLATILE); return TCL_OK; } static int tcl_GetRealName STDVAR { CModTcl* mod = static_cast(cd); Tcl_SetResult(irp, (char*)mod->GetUser()->GetRealName().c_str(), TCL_VOLATILE); return TCL_OK; } static int tcl_GetBindHost STDVAR { CModTcl* mod = static_cast(cd); Tcl_SetResult(irp, (char*)mod->GetUser()->GetBindHost().c_str(), TCL_VOLATILE); return TCL_OK; } static int tcl_GetChans STDVAR { char* p; const char* l[1]; CModTcl* mod = static_cast(cd); BADARGS(1, 1, ""); const vector& Channels = mod->GetNetwork()->GetChans(); for (unsigned int c = 0; c < Channels.size(); c++) { CChan* pChan = Channels[c]; l[0] = pChan->GetName().c_str(); p = Tcl_Merge(1, l); Tcl_AppendElement(irp, p); Tcl_Free((char*)p); } return TCL_OK; } static int tcl_GetChannelUsers STDVAR { char* p; const char* l[4]; CModTcl* mod = static_cast(cd); BADARGS(2, 999, " channel"); CString sChannel = argvit(argv, argc, 1, " "); CChan* pChannel = mod->GetNetwork()->FindChan(sChannel); if (!pChannel) { CString sMsg = "invalid channel: " + sChannel; Tcl_SetResult(irp, (char*)sMsg.c_str(), TCL_VOLATILE); return TCL_ERROR; } const map& msNicks = pChannel->GetNicks(); for (map::const_iterator it = msNicks.begin(); it != msNicks.end(); ++it) { const CNick& Nick = it->second; l[0] = (Nick.GetNick()).c_str(); l[1] = (Nick.GetIdent()).c_str(); l[2] = (Nick.GetHost()).c_str(); l[3] = (Nick.GetPermStr()).c_str(); p = Tcl_Merge(4, l); Tcl_AppendElement(irp, p); Tcl_Free((char*)p); } return TCL_OK; } static int tcl_GetChannelModes STDVAR { CModTcl* mod = static_cast(cd); BADARGS(2, 999, " channel"); CString sChannel = argvit(argv, argc, 1, " "); CChan* pChannel = mod->GetNetwork()->FindChan(sChannel); CString sMsg; if (!pChannel) { sMsg = "invalid channel: " + sChannel; Tcl_SetResult(irp, (char*)sMsg.c_str(), TCL_VOLATILE); return TCL_ERROR; } sMsg = pChannel->GetModeString(); Tcl_SetResult(irp, (char*)sMsg.c_str(), TCL_VOLATILE); return TCL_OK; } static int tcl_GetServer STDVAR { CModTcl* mod = static_cast(cd); CServer* pServer = mod->GetNetwork()->GetCurrentServer(); CString sMsg; if (pServer) sMsg = pServer->GetName() + ":" + CString(pServer->GetPort()); Tcl_SetResult(irp, (char*)sMsg.c_str(), TCL_VOLATILE); return TCL_OK; } static int tcl_GetServerOnline STDVAR { CModTcl* mod = static_cast(cd); CIRCSock* pIRCSock = mod->GetNetwork()->GetIRCSock(); CString sMsg = "0"; if (pIRCSock) sMsg = CString(pIRCSock->GetStartTime()); Tcl_SetResult(irp, (char*)sMsg.c_str(), TCL_VOLATILE); return TCL_OK; } static int tcl_GetModules STDVAR { char* p; const char* l[3]; CModTcl* mod = static_cast(cd); BADARGS(1, 1, ""); CModules& GModules = CZNC::Get().GetModules(); CModules& Modules = mod->GetUser()->GetModules(); for (unsigned int b = 0; b < GModules.size(); b++) { l[0] = GModules[b]->GetModName().c_str(); l[1] = GModules[b]->GetArgs().c_str(); l[2] = "1"; // IsGlobal p = Tcl_Merge(3, l); Tcl_AppendElement(irp, p); Tcl_Free((char*)p); } for (unsigned int b = 0; b < Modules.size(); b++) { l[0] = Modules[b]->GetModName().c_str(); l[1] = Modules[b]->GetArgs().c_str(); l[2] = "0"; // IsGlobal p = Tcl_Merge(3, l); Tcl_AppendElement(irp, p); Tcl_Free((char*)p); } return TCL_OK; } static int tcl_GetClientCount STDVAR { CModTcl* mod = static_cast(cd); Tcl_SetResult( irp, (char*)CString(mod->GetNetwork()->GetClients().size()).c_str(), TCL_VOLATILE); return TCL_OK; } static int tcl_PutIRC STDVAR { CString sMsg; CModTcl* mod = static_cast(cd); BADARGS(2, 999, " string"); sMsg = argvit(argv, argc, 1, " "); mod->GetNetwork()->PutIRC(sMsg); return TCL_OK; } static int tcl_PutModule STDVAR { CString sMsg; VCString vsMsg; CModTcl* mod = static_cast(cd); BADARGS(2, 999, " string"); sMsg = argvit(argv, argc, 1, " "); // mod->PutModule(sMsg); sMsg.Split("\n", vsMsg); unsigned int a = 0; for (a = 0; a < vsMsg.size(); a++) mod->PutModule(vsMsg[a].TrimRight_n()); return TCL_OK; } static int tcl_PutStatus STDVAR { CString sMsg; CModTcl* mod = static_cast(cd); BADARGS(2, 999, " string"); sMsg = argvit(argv, argc, 1, " "); mod->PutStatus(sMsg); return TCL_OK; } static int tcl_PutStatusNotice STDVAR { CString sMsg; CModTcl* mod = static_cast(cd); BADARGS(2, 999, " string"); sMsg = argvit(argv, argc, 1, " "); mod->GetUser()->PutStatusNotice(sMsg); return TCL_OK; } static int tcl_PutUser STDVAR { CString sMsg; CModTcl* mod = static_cast(cd); BADARGS(2, 999, " string"); sMsg = argvit(argv, argc, 1, " "); mod->GetUser()->PutUser(sMsg); return TCL_OK; } static int tcl_exit STDVAR { CString sMsg; CModTcl* mod = static_cast(cd); BADARGS(1, 2, " ?reason?"); if (!mod->GetUser()->IsAdmin()) { sMsg = "You need to be administrator to shutdown the bnc."; Tcl_SetResult(irp, (char*)sMsg.c_str(), TCL_VOLATILE); return TCL_ERROR; } if (argc > 1) { sMsg = argvit(argv, argc, 1, " "); CZNC::Get().Broadcast(sMsg); usleep(100000); // Sleep for 10ms to attempt to allow the previous // Broadcast() to go through to all users } throw CException(CException::EX_Shutdown); return TCL_OK; } }; void CModTclTimer::RunJob() { CModTcl* p = (CModTcl*)GetModule(); if (p) p->TclUpdate(); } void CModTclStartTimer::RunJob() { CModTcl* p = (CModTcl*)GetModule(); if (p) p->Start(); } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("modtcl"); Info.SetHasArgs(true); Info.SetArgsHelpText("Absolute path to modtcl.tcl file"); } NETWORKMODULEDEFS(CModTcl, "Loads Tcl scripts as ZNC modules") znc-1.7.5/modules/missingmotd.cpp0000644000175000017500000000213513542151610017252 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include class CMissingMotd : public CModule { public: MODCONSTRUCTOR(CMissingMotd) {} void OnClientLogin() override { PutUser(":irc.znc.in 422 " + GetClient()->GetNick() + " :MOTD File is missing"); } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("missingmotd"); Info.SetHasArgs(false); } USERMODULEDEFS(CMissingMotd, t_s("Sends 422 to clients when they login")) znc-1.7.5/modules/stickychan.cpp0000644000175000017500000002130613542151610017056 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #define STICKYCHAN_TIMER_INTERVAL 60 using std::vector; class CStickyChan : public CModule { public: MODCONSTRUCTOR(CStickyChan) { AddHelpCommand(); AddCommand("Stick", t_d("<#channel> [key]"), t_d("Sticks a channel"), [=](const CString& sLine) { OnStickCommand(sLine); }); AddCommand("Unstick", t_d("<#channel>"), t_d("Unsticks a channel"), [=](const CString& sLine) { OnUnstickCommand(sLine); }); AddCommand("List", "", t_d("Lists sticky channels"), [=](const CString& sLine) { OnListCommand(sLine); }); } ~CStickyChan() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override; EModRet OnUserPart(CString& sChannel, CString& sMessage) override { if (!GetNetwork()) { return CONTINUE; } for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { if (sChannel.Equals(it->first)) { CChan* pChan = GetNetwork()->FindChan(sChannel); if (pChan) { pChan->JoinUser(); return HALT; } } } return CONTINUE; } void OnMode(const CNick& pOpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) override { if (uMode == CChan::M_Key) { if (bAdded) { // We ignore channel key "*" because of some broken nets. if (sArg != "*") { SetNV(Channel.GetName(), sArg, true); } } else { SetNV(Channel.GetName(), "", true); } } } void OnStickCommand(const CString& sCommand) { CString sChannel = sCommand.Token(1).AsLower(); if (sChannel.empty()) { PutModule(t_s("Usage: Stick <#channel> [key]")); return; } SetNV(sChannel, sCommand.Token(2), true); PutModule(t_f("Stuck {1}")(sChannel)); } void OnUnstickCommand(const CString& sCommand) { CString sChannel = sCommand.Token(1); if (sChannel.empty()) { PutModule(t_s("Usage: Unstick <#channel>")); return; } DelNV(sChannel, true); PutModule(t_f("Unstuck {1}")(sChannel)); } void OnListCommand(const CString& sCommand) { int i = 1; for (MCString::iterator it = BeginNV(); it != EndNV(); ++it, i++) { if (it->second.empty()) PutModule(CString(i) + ": " + it->first); else PutModule(CString(i) + ": " + it->first + " (" + it->second + ")"); } PutModule(t_s(" -- End of List")); } void RunJob() { CIRCNetwork* pNetwork = GetNetwork(); if (!pNetwork->GetIRCSock()) return; for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { CChan* pChan = pNetwork->FindChan(it->first); if (!pChan) { pChan = new CChan(it->first, pNetwork, true); if (!it->second.empty()) pChan->SetKey(it->second); if (!pNetwork->AddChan(pChan)) { /* AddChan() deleted that channel */ PutModule(t_f("Could not join {1} (# prefix missing?)")( it->first)); continue; } } if (!pChan->IsOn() && pNetwork->IsIRCConnected()) { PutModule("Joining [" + pChan->GetName() + "]"); PutIRC("JOIN " + pChan->GetName() + (pChan->GetKey().empty() ? "" : " " + pChan->GetKey())); } } } CString GetWebMenuTitle() override { return t_s("Sticky Channels"); } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "index") { bool bSubmitted = (WebSock.GetParam("submitted").ToInt() != 0); const vector& Channels = GetNetwork()->GetChans(); for (CChan* pChan : Channels) { const CString sChan = pChan->GetName(); bool bStick = FindNV(sChan) != EndNV(); if (bSubmitted) { bool bNewStick = WebSock.GetParam("stick_" + sChan).ToBool(); if (bNewStick && !bStick) SetNV(sChan, ""); // no password support for now unless // chansaver is active too else if (!bNewStick && bStick) { MCString::iterator it = FindNV(sChan); if (it != EndNV()) DelNV(it); } bStick = bNewStick; } CTemplate& Row = Tmpl.AddRow("ChannelLoop"); Row["Name"] = sChan; Row["Sticky"] = CString(bStick); } if (bSubmitted) { WebSock.GetSession()->AddSuccess( t_s("Changes have been saved!")); } return true; } return false; } bool OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "webadmin/channel") { CString sChan = Tmpl["ChanName"]; bool bStick = FindNV(sChan) != EndNV(); if (Tmpl["WebadminAction"].Equals("display")) { Tmpl["Sticky"] = CString(bStick); } else if (WebSock.GetParam("embed_stickychan_presented") .ToBool()) { bool bNewStick = WebSock.GetParam("embed_stickychan_sticky").ToBool(); if (bNewStick && !bStick) { // no password support for now unless chansaver is active // too SetNV(sChan, ""); WebSock.GetSession()->AddSuccess( t_s("Channel became sticky!")); } else if (!bNewStick && bStick) { DelNV(sChan); WebSock.GetSession()->AddSuccess( t_s("Channel stopped being sticky!")); } } return true; } return false; } EModRet OnNumericMessage(CNumericMessage& msg) override { if (msg.GetCode() == 479) { // ERR_BADCHANNAME (juped channels or illegal channel name - ircd // hybrid) // prevent the module from getting into an infinite loop of trying // to join it. // :irc.network.net 479 mynick #channel :Illegal channel name const CString sChannel = msg.GetParam(1); for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { if (sChannel.Equals(it->first)) { PutModule( t_f("Channel {1} cannot be joined, it is an illegal " "channel name. Unsticking.")(sChannel)); OnUnstickCommand("unstick " + sChannel); return CONTINUE; } } } return CONTINUE; } }; static void RunTimer(CModule* pModule, CFPTimer* pTimer) { ((CStickyChan*)pModule)->RunJob(); } bool CStickyChan::OnLoad(const CString& sArgs, CString& sMessage) { VCString vsChans; sArgs.Split(",", vsChans, false); for (const CString& s : vsChans) { CString sChan = s.Token(0); CString sKey = s.Token(1, true); SetNV(sChan, sKey); } // Since we now have these channels added, clear the argument list SetArgs(""); AddTimer(RunTimer, "StickyChanTimer", STICKYCHAN_TIMER_INTERVAL); return (true); } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("stickychan"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s("List of channels, separated by comma.")); } NETWORKMODULEDEFS( CStickyChan, t_s("configless sticky chans, keeps you there very stickily even")) znc-1.7.5/modules/partyline.cpp0000644000175000017500000006433413542151610016735 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::set; using std::vector; using std::map; // If you change these and it breaks, you get to keep the pieces #define CHAN_PREFIX_1 "~" #define CHAN_PREFIX_1C '~' #define CHAN_PREFIX CHAN_PREFIX_1 "#" #define NICK_PREFIX CString("?") #define NICK_PREFIX_C '?' class CPartylineChannel { public: CPartylineChannel(const CString& sName) { m_sName = sName.AsLower(); } ~CPartylineChannel() {} const CString& GetTopic() const { return m_sTopic; } const CString& GetName() const { return m_sName; } const set& GetNicks() const { return m_ssNicks; } void SetTopic(const CString& s) { m_sTopic = s; } void AddNick(const CString& s) { m_ssNicks.insert(s); } void DelNick(const CString& s) { m_ssNicks.erase(s); } bool IsInChannel(const CString& s) { return m_ssNicks.find(s) != m_ssNicks.end(); } protected: CString m_sTopic; CString m_sName; set m_ssNicks; }; class CPartylineMod : public CModule { public: void ListChannelsCommand(const CString& sLine) { if (m_ssChannels.empty()) { PutModule(t_s("There are no open channels.")); return; } CTable Table; Table.AddColumn(t_s("Channel")); Table.AddColumn(t_s("Users")); for (set::const_iterator a = m_ssChannels.begin(); a != m_ssChannels.end(); ++a) { Table.AddRow(); Table.SetCell(t_s("Channel"), (*a)->GetName()); Table.SetCell(t_s("Users"), CString((*a)->GetNicks().size())); } PutModule(Table); } MODCONSTRUCTOR(CPartylineMod) { AddHelpCommand(); AddCommand("List", "", t_d("List all open channels"), [=](const CString& sLine) { ListChannelsCommand(sLine); }); } ~CPartylineMod() override { // Kick all clients who are in partyline channels for (set::iterator it = m_ssChannels.begin(); it != m_ssChannels.end(); ++it) { set ssNicks = (*it)->GetNicks(); for (set::const_iterator it2 = ssNicks.begin(); it2 != ssNicks.end(); ++it2) { CUser* pUser = CZNC::Get().FindUser(*it2); vector vClients = pUser->GetAllClients(); for (vector::const_iterator it3 = vClients.begin(); it3 != vClients.end(); ++it3) { CClient* pClient = *it3; pClient->PutClient(":*" + GetModName() + "!znc@znc.in KICK " + (*it)->GetName() + " " + pClient->GetNick() + " :" + GetModName() + " unloaded"); } } } while (!m_ssChannels.empty()) { delete *m_ssChannels.begin(); m_ssChannels.erase(m_ssChannels.begin()); } } bool OnBoot() override { // The config is now read completely, so all Users are set up Load(); return true; } bool OnLoad(const CString& sArgs, CString& sMessage) override { const map& msUsers = CZNC::Get().GetUserMap(); for (map::const_iterator it = msUsers.begin(); it != msUsers.end(); ++it) { CUser* pUser = it->second; for (CClient* pClient : pUser->GetAllClients()) { CIRCNetwork* pNetwork = pClient->GetNetwork(); if (!pNetwork || !pNetwork->IsIRCConnected() || !pNetwork->GetChanPrefixes().Contains(CHAN_PREFIX_1)) { pClient->PutClient( ":" + GetIRCServer(pNetwork) + " 005 " + pClient->GetNick() + " CHANTYPES=" + (pNetwork ? pNetwork->GetChanPrefixes() : "") + CHAN_PREFIX_1 " :are supported by this server."); } } } VCString vsChans; VCString::const_iterator it; sArgs.Split(" ", vsChans, false); for (it = vsChans.begin(); it != vsChans.end(); ++it) { if (it->Left(2) == CHAN_PREFIX) { m_ssDefaultChans.insert(it->Left(32)); } } Load(); return true; } void Load() { CString sAction, sKey; CPartylineChannel* pChannel; for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { if (it->first.find(":") != CString::npos) { sAction = it->first.Token(0, false, ":"); sKey = it->first.Token(1, true, ":"); } else { // backwards compatibility for older NV data sAction = "fixedchan"; sKey = it->first; } if (sAction == "fixedchan") { // Sorry, this was removed } if (sAction == "topic") { pChannel = FindChannel(sKey); if (pChannel && !(it->second).empty()) { PutChan(pChannel->GetNicks(), ":irc.znc.in TOPIC " + pChannel->GetName() + " :" + it->second); pChannel->SetTopic(it->second); } } } return; } void SaveTopic(CPartylineChannel* pChannel) { if (!pChannel->GetTopic().empty()) SetNV("topic:" + pChannel->GetName(), pChannel->GetTopic()); else DelNV("topic:" + pChannel->GetName()); } EModRet OnDeleteUser(CUser& User) override { // Loop through each chan for (set::iterator it = m_ssChannels.begin(); it != m_ssChannels.end();) { CPartylineChannel* pChan = *it; // RemoveUser() might delete channels, so make sure our // iterator doesn't break. ++it; RemoveUser(&User, pChan, "KICK", "User deleted", true); } return CONTINUE; } EModRet OnNumericMessage(CNumericMessage& Msg) override { if (Msg.GetCode() == 5) { for (int i = 0; i < Msg.GetParams().size(); ++i) { if (Msg.GetParams()[i].StartsWith("CHANTYPES=")) { Msg.SetParam(i, Msg.GetParam(i) + CHAN_PREFIX_1); m_spInjectedPrefixes.insert(GetNetwork()); break; } } } return CONTINUE; } void OnIRCDisconnected() override { m_spInjectedPrefixes.erase(GetNetwork()); } void OnClientLogin() override { CUser* pUser = GetUser(); CClient* pClient = GetClient(); CIRCNetwork* pNetwork = GetNetwork(); if (!pNetwork || !pNetwork->IsIRCConnected()) { pClient->PutClient(":" + GetIRCServer(pNetwork) + " 005 " + pClient->GetNick() + " CHANTYPES=" + CHAN_PREFIX_1 " :are supported by this server."); } // Make sure this user is in the default channels for (set::iterator a = m_ssDefaultChans.begin(); a != m_ssDefaultChans.end(); ++a) { CPartylineChannel* pChannel = GetChannel(*a); const CString& sNick = pUser->GetUserName(); if (pChannel->IsInChannel(sNick)) continue; CString sHost = pUser->GetBindHost(); const set& ssNicks = pChannel->GetNicks(); if (sHost.empty()) { sHost = "znc.in"; } PutChan(ssNicks, ":" + NICK_PREFIX + sNick + "!" + pUser->GetIdent() + "@" + sHost + " JOIN " + *a, false); pChannel->AddNick(sNick); } CString sNickMask = pClient->GetNickMask(); for (set::iterator it = m_ssChannels.begin(); it != m_ssChannels.end(); ++it) { const set& ssNicks = (*it)->GetNicks(); if ((*it)->IsInChannel(pUser->GetUserName())) { pClient->PutClient(":" + sNickMask + " JOIN " + (*it)->GetName()); if (!(*it)->GetTopic().empty()) { pClient->PutClient(":" + GetIRCServer(pNetwork) + " 332 " + pClient->GetNickMask() + " " + (*it)->GetName() + " :" + (*it)->GetTopic()); } SendNickList(pUser, pNetwork, ssNicks, (*it)->GetName()); PutChan(ssNicks, ":*" + GetModName() + "!znc@znc.in MODE " + (*it)->GetName() + " +" + CString(pUser->IsAdmin() ? "o" : "v") + " " + NICK_PREFIX + pUser->GetUserName(), false); } } } void OnClientDisconnect() override { CUser* pUser = GetUser(); if (!pUser->IsUserAttached() && !pUser->IsBeingDeleted()) { for (set::iterator it = m_ssChannels.begin(); it != m_ssChannels.end(); ++it) { const set& ssNicks = (*it)->GetNicks(); if (ssNicks.find(pUser->GetUserName()) != ssNicks.end()) { PutChan(ssNicks, ":*" + GetModName() + "!znc@znc.in MODE " + (*it)->GetName() + " -ov " + NICK_PREFIX + pUser->GetUserName() + " " + NICK_PREFIX + pUser->GetUserName(), false); } } } } EModRet OnUserRawMessage(CMessage& Msg) override { if ((Msg.GetCommand().Equals("WHO") || Msg.GetCommand().Equals("MODE")) && Msg.GetParam(0).StartsWith(CHAN_PREFIX_1)) { return HALT; } else if (Msg.GetCommand().Equals("TOPIC") && Msg.GetParam(0).StartsWith(CHAN_PREFIX)) { const CString sChannel = Msg.As().GetTarget(); CString sTopic = Msg.As().GetText(); sTopic.TrimPrefix(":"); CUser* pUser = GetUser(); CClient* pClient = GetClient(); CPartylineChannel* pChannel = FindChannel(sChannel); if (pChannel && pChannel->IsInChannel(pUser->GetUserName())) { const set& ssNicks = pChannel->GetNicks(); if (!sTopic.empty()) { if (pUser->IsAdmin()) { PutChan(ssNicks, ":" + pClient->GetNickMask() + " TOPIC " + sChannel + " :" + sTopic); pChannel->SetTopic(sTopic); SaveTopic(pChannel); } else { pUser->PutUser(":irc.znc.in 482 " + pClient->GetNick() + " " + sChannel + " :You're not channel operator"); } } else { sTopic = pChannel->GetTopic(); if (sTopic.empty()) { pUser->PutUser(":irc.znc.in 331 " + pClient->GetNick() + " " + sChannel + " :No topic is set."); } else { pUser->PutUser(":irc.znc.in 332 " + pClient->GetNick() + " " + sChannel + " :" + sTopic); } } } else { pUser->PutUser(":irc.znc.in 442 " + pClient->GetNick() + " " + sChannel + " :You're not on that channel"); } return HALT; } return CONTINUE; } EModRet OnUserPart(CString& sChannel, CString& sMessage) override { if (sChannel.Left(1) != CHAN_PREFIX_1) { return CONTINUE; } if (sChannel.Left(2) != CHAN_PREFIX) { GetClient()->PutClient(":" + GetIRCServer(GetNetwork()) + " 401 " + GetClient()->GetNick() + " " + sChannel + " :No such channel"); return HALT; } CPartylineChannel* pChannel = FindChannel(sChannel); PartUser(GetUser(), pChannel); return HALT; } void PartUser(CUser* pUser, CPartylineChannel* pChannel, const CString& sMessage = "") { RemoveUser(pUser, pChannel, "PART", sMessage); } void RemoveUser(CUser* pUser, CPartylineChannel* pChannel, const CString& sCommand, const CString& sMessage = "", bool bNickAsTarget = false) { if (!pChannel || !pChannel->IsInChannel(pUser->GetUserName())) { return; } vector vClients = pUser->GetAllClients(); CString sCmd = " " + sCommand + " "; CString sMsg = sMessage; if (!sMsg.empty()) sMsg = " :" + sMsg; pChannel->DelNick(pUser->GetUserName()); const set& ssNicks = pChannel->GetNicks(); CString sHost = pUser->GetBindHost(); if (sHost.empty()) { sHost = "znc.in"; } if (bNickAsTarget) { for (vector::const_iterator it = vClients.begin(); it != vClients.end(); ++it) { CClient* pClient = *it; pClient->PutClient(":" + pClient->GetNickMask() + sCmd + pChannel->GetName() + " " + pClient->GetNick() + sMsg); } PutChan(ssNicks, ":" + NICK_PREFIX + pUser->GetUserName() + "!" + pUser->GetIdent() + "@" + sHost + sCmd + pChannel->GetName() + " " + NICK_PREFIX + pUser->GetUserName() + sMsg, false, true, pUser); } else { for (vector::const_iterator it = vClients.begin(); it != vClients.end(); ++it) { CClient* pClient = *it; pClient->PutClient(":" + pClient->GetNickMask() + sCmd + pChannel->GetName() + sMsg); } PutChan(ssNicks, ":" + NICK_PREFIX + pUser->GetUserName() + "!" + pUser->GetIdent() + "@" + sHost + sCmd + pChannel->GetName() + sMsg, false, true, pUser); } if (!pUser->IsBeingDeleted() && m_ssDefaultChans.find(pChannel->GetName()) != m_ssDefaultChans.end()) { JoinUser(pUser, pChannel); } if (ssNicks.empty()) { delete pChannel; m_ssChannels.erase(pChannel); } } EModRet OnUserJoin(CString& sChannel, CString& sKey) override { if (sChannel.Left(1) != CHAN_PREFIX_1) { return CONTINUE; } if (sChannel.Left(2) != CHAN_PREFIX) { GetClient()->PutClient(":" + GetIRCServer(GetNetwork()) + " 403 " + GetClient()->GetNick() + " " + sChannel + " :Channels look like " CHAN_PREFIX "znc"); return HALT; } sChannel = sChannel.Left(32); CPartylineChannel* pChannel = GetChannel(sChannel); JoinUser(GetUser(), pChannel); return HALT; } void JoinUser(CUser* pUser, CPartylineChannel* pChannel) { if (pChannel && !pChannel->IsInChannel(pUser->GetUserName())) { vector vClients = pUser->GetAllClients(); const set& ssNicks = pChannel->GetNicks(); const CString& sNick = pUser->GetUserName(); pChannel->AddNick(sNick); CString sHost = pUser->GetBindHost(); if (sHost.empty()) { sHost = "znc.in"; } for (vector::const_iterator it = vClients.begin(); it != vClients.end(); ++it) { CClient* pClient = *it; pClient->PutClient(":" + pClient->GetNickMask() + " JOIN " + pChannel->GetName()); } PutChan(ssNicks, ":" + NICK_PREFIX + sNick + "!" + pUser->GetIdent() + "@" + sHost + " JOIN " + pChannel->GetName(), false, true, pUser); if (!pChannel->GetTopic().empty()) { for (vector::const_iterator it = vClients.begin(); it != vClients.end(); ++it) { CClient* pClient = *it; pClient->PutClient( ":" + GetIRCServer(pClient->GetNetwork()) + " 332 " + pClient->GetNickMask() + " " + pChannel->GetName() + " :" + pChannel->GetTopic()); } } SendNickList(pUser, nullptr, ssNicks, pChannel->GetName()); /* Tell the other clients we have op or voice, the current user's * clients already know from NAMES list */ if (pUser->IsAdmin()) { PutChan(ssNicks, ":*" + GetModName() + "!znc@znc.in MODE " + pChannel->GetName() + " +o " + NICK_PREFIX + pUser->GetUserName(), false, false, pUser); } PutChan(ssNicks, ":*" + GetModName() + "!znc@znc.in MODE " + pChannel->GetName() + " +v " + NICK_PREFIX + pUser->GetUserName(), false, false, pUser); } } EModRet HandleMessage(const CString& sCmd, const CString& sTarget, const CString& sMessage) { if (sTarget.empty()) { return CONTINUE; } char cPrefix = sTarget[0]; if (cPrefix != CHAN_PREFIX_1C && cPrefix != NICK_PREFIX_C) { return CONTINUE; } CUser* pUser = GetUser(); CClient* pClient = GetClient(); CIRCNetwork* pNetwork = GetNetwork(); CString sHost = pUser->GetBindHost(); if (sHost.empty()) { sHost = "znc.in"; } if (cPrefix == CHAN_PREFIX_1C) { if (FindChannel(sTarget) == nullptr) { pClient->PutClient(":" + GetIRCServer(pNetwork) + " 401 " + pClient->GetNick() + " " + sTarget + " :No such channel"); return HALT; } PutChan(sTarget, ":" + NICK_PREFIX + pUser->GetUserName() + "!" + pUser->GetIdent() + "@" + sHost + " " + sCmd + " " + sTarget + " :" + sMessage, true, false); } else { CString sNick = sTarget.LeftChomp_n(1); CUser* pTargetUser = CZNC::Get().FindUser(sNick); if (pTargetUser) { vector vClients = pTargetUser->GetAllClients(); if (vClients.empty()) { pClient->PutClient(":" + GetIRCServer(pNetwork) + " 401 " + pClient->GetNick() + " " + sTarget + " :User is not attached: " + sNick + ""); return HALT; } for (vector::const_iterator it = vClients.begin(); it != vClients.end(); ++it) { CClient* pTarget = *it; pTarget->PutClient( ":" + NICK_PREFIX + pUser->GetUserName() + "!" + pUser->GetIdent() + "@" + sHost + " " + sCmd + " " + pTarget->GetNick() + " :" + sMessage); } } else { pClient->PutClient(":" + GetIRCServer(pNetwork) + " 401 " + pClient->GetNick() + " " + sTarget + " :No such znc user: " + sNick + ""); } } return HALT; } EModRet OnUserMsg(CString& sTarget, CString& sMessage) override { return HandleMessage("PRIVMSG", sTarget, sMessage); } EModRet OnUserNotice(CString& sTarget, CString& sMessage) override { return HandleMessage("NOTICE", sTarget, sMessage); } EModRet OnUserCTCP(CString& sTarget, CString& sMessage) override { return HandleMessage("PRIVMSG", sTarget, "\001" + sMessage + "\001"); } EModRet OnUserCTCPReply(CString& sTarget, CString& sMessage) override { return HandleMessage("NOTICE", sTarget, "\001" + sMessage + "\001"); } const CString GetIRCServer(CIRCNetwork* pNetwork) { if (!pNetwork) { return "irc.znc.in"; } const CString& sServer = pNetwork->GetIRCServer(); if (!sServer.empty()) return sServer; return "irc.znc.in"; } bool PutChan(const CString& sChan, const CString& sLine, bool bIncludeCurUser = true, bool bIncludeClient = true, CUser* pUser = nullptr, CClient* pClient = nullptr) { CPartylineChannel* pChannel = FindChannel(sChan); if (pChannel != nullptr) { PutChan(pChannel->GetNicks(), sLine, bIncludeCurUser, bIncludeClient, pUser, pClient); return true; } return false; } void PutChan(const set& ssNicks, const CString& sLine, bool bIncludeCurUser = true, bool bIncludeClient = true, CUser* pUser = nullptr, CClient* pClient = nullptr) { const map& msUsers = CZNC::Get().GetUserMap(); if (!pUser) pUser = GetUser(); if (!pClient) pClient = GetClient(); for (map::const_iterator it = msUsers.begin(); it != msUsers.end(); ++it) { if (ssNicks.find(it->first) != ssNicks.end()) { if (it->second == pUser) { if (bIncludeCurUser) { it->second->PutAllUser( sLine, nullptr, (bIncludeClient ? nullptr : pClient)); } } else { it->second->PutAllUser(sLine); } } } } void PutUserIRCNick(CUser* pUser, const CString& sPre, const CString& sPost) { const vector& vClients = pUser->GetAllClients(); vector::const_iterator it; for (it = vClients.begin(); it != vClients.end(); ++it) { (*it)->PutClient(sPre + (*it)->GetNick() + sPost); } } void SendNickList(CUser* pUser, CIRCNetwork* pNetwork, const set& ssNicks, const CString& sChan) { CString sNickList; for (set::const_iterator it = ssNicks.begin(); it != ssNicks.end(); ++it) { CUser* pChanUser = CZNC::Get().FindUser(*it); if (pChanUser == pUser) { continue; } if (pChanUser && pChanUser->IsUserAttached()) { sNickList += (pChanUser->IsAdmin()) ? "@" : "+"; } sNickList += NICK_PREFIX + (*it) + " "; if (sNickList.size() >= 500) { PutUserIRCNick(pUser, ":" + GetIRCServer(pNetwork) + " 353 ", " @ " + sChan + " :" + sNickList); sNickList.clear(); } } if (sNickList.size()) { PutUserIRCNick(pUser, ":" + GetIRCServer(pNetwork) + " 353 ", " @ " + sChan + " :" + sNickList); } vector vClients = pUser->GetAllClients(); for (vector::const_iterator it = vClients.begin(); it != vClients.end(); ++it) { CClient* pClient = *it; pClient->PutClient(":" + GetIRCServer(pNetwork) + " 353 " + pClient->GetNick() + " @ " + sChan + " :" + ((pUser->IsAdmin()) ? "@" : "+") + pClient->GetNick()); } PutUserIRCNick(pUser, ":" + GetIRCServer(pNetwork) + " 366 ", " " + sChan + " :End of /NAMES list."); } CPartylineChannel* FindChannel(const CString& sChan) { CString sChannel = sChan.AsLower(); for (set::iterator it = m_ssChannels.begin(); it != m_ssChannels.end(); ++it) { if ((*it)->GetName().AsLower() == sChannel) return *it; } return nullptr; } CPartylineChannel* GetChannel(const CString& sChannel) { CPartylineChannel* pChannel = FindChannel(sChannel); if (!pChannel) { pChannel = new CPartylineChannel(sChannel.AsLower()); m_ssChannels.insert(pChannel); } return pChannel; } private: set m_ssChannels; set m_spInjectedPrefixes; set m_ssDefaultChans; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("partyline"); Info.SetHasArgs(true); Info.SetArgsHelpText( Info.t_s("You may enter a list of channels the user joins, when " "entering the internal partyline.")); } GLOBALMODULEDEFS( CPartylineMod, t_s("Internal channels and queries for users connected to ZNC")) znc-1.7.5/modules/awaystore.cpp0000644000175000017500000004101013542151610016726 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * Author: imaginos * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Quiet Away and message logger * * I originally wrote this module for when I had multiple clients connected to *ZNC. I would leave work and forget to close my client, arriving at home * and re-attaching there someone may have messaged me in commute and I wouldn't *know it until I would arrive back at work the next day. I wrote it such that * my xchat client would monitor desktop activity and ping the module to let it *know I was active. Within a few minutes of inactivity the pinging stops and * the away module sets the user as away and logging commences. */ #define REQUIRESSL #include #include #include #include #include #include using std::vector; using std::map; #define CRYPT_VERIFICATION_TOKEN "::__:AWAY:__::" class CAway; class CAwayJob : public CTimer { public: CAwayJob(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {} ~CAwayJob() override {} protected: void RunJob() override; }; class CAway : public CModule { void AwayCommand(const CString& sCommand) { CString sReason; timeval curtime; gettimeofday(&curtime, nullptr); if (sCommand.Token(1) != "-quiet") { sReason = CUtils::FormatTime(curtime, sCommand.Token(1, true), GetUser()->GetTimezone()); PutModNotice(t_s("You have been marked as away")); } else { sReason = CUtils::FormatTime(curtime, sCommand.Token(2, true), GetUser()->GetTimezone()); } Away(false, sReason); } void BackCommand(const CString& sCommand) { if ((m_vMessages.empty()) && (sCommand.Token(1) != "-quiet")) PutModNotice(t_s("Welcome back!")); Ping(); Back(); } void MessagesCommand(const CString& sCommand) { for (u_int a = 0; a < m_vMessages.size(); a++) PutModule(m_vMessages[a]); } void ReplayCommand(const CString& sCommand) { CString nick = GetClient()->GetNick(); for (u_int a = 0; a < m_vMessages.size(); a++) { CString sWhom = m_vMessages[a].Token(1, false, ":"); CString sMessage = m_vMessages[a].Token(2, true, ":"); PutUser(":" + sWhom + " PRIVMSG " + nick + " :" + sMessage); } } void DeleteCommand(const CString& sCommand) { CString sWhich = sCommand.Token(1); if (sWhich == "all") { PutModNotice(t_f("Deleted {1} messages")(m_vMessages.size())); for (u_int a = 0; a < m_vMessages.size(); a++) m_vMessages.erase(m_vMessages.begin() + a--); } else if (sWhich.empty()) { PutModNotice(t_s("USAGE: delete ")); return; } else { u_int iNum = sWhich.ToUInt(); if (iNum >= m_vMessages.size()) { PutModNotice(t_s("Illegal message # requested")); return; } else { m_vMessages.erase(m_vMessages.begin() + iNum); PutModNotice(t_s("Message erased")); } SaveBufferToDisk(); } } void SaveCommand(const CString& sCommand) { if (m_saveMessages) { SaveBufferToDisk(); PutModNotice(t_s("Messages saved to disk")); } else { PutModNotice(t_s("There are no messages to save")); } } void PingCommand(const CString& sCommand) { Ping(); if (m_bIsAway) Back(); } void PassCommand(const CString& sCommand) { m_sPassword = sCommand.Token(1); PutModNotice(t_f("Password updated to [{1}]")(m_sPassword)); } void ShowCommand(const CString& sCommand) { map> msvOutput; for (u_int a = 0; a < m_vMessages.size(); a++) { CString sTime = m_vMessages[a].Token(0, false); CString sWhom = m_vMessages[a].Token(1, false); CString sMessage = m_vMessages[a].Token(2, true); if ((sTime.empty()) || (sWhom.empty()) || (sMessage.empty())) { // illegal format PutModule(t_f("Corrupt message! [{1}]")(m_vMessages[a])); m_vMessages.erase(m_vMessages.begin() + a--); continue; } time_t iTime = sTime.ToULong(); char szFormat[64]; struct tm t; localtime_r(&iTime, &t); size_t iCount = strftime(szFormat, 64, "%F %T", &t); if (iCount <= 0) { PutModule(t_f("Corrupt time stamp! [{1}]")(m_vMessages[a])); m_vMessages.erase(m_vMessages.begin() + a--); continue; } CString sTmp = " " + CString(a) + ") ["; sTmp.append(szFormat, iCount); sTmp += "] "; sTmp += sMessage; msvOutput[sWhom].push_back(sTmp); } for (map>::iterator it = msvOutput.begin(); it != msvOutput.end(); ++it) { PutModule(it->first); for (u_int a = 0; a < it->second.size(); a++) PutModule(it->second[a]); } PutModule(t_s("#--- End of messages")); } void EnableTimerCommand(const CString& sCommand) { SetAwayTime(300); PutModule(t_s("Timer set to 300 seconds")); } void DisableTimerCommand(const CString& sCommand) { SetAwayTime(0); PutModule(t_s("Timer disabled")); } void SetTimerCommand(const CString& sCommand) { int iSetting = sCommand.Token(1).ToInt(); SetAwayTime(iSetting); if (iSetting == 0) PutModule(t_s("Timer disabled")); else PutModule(t_f("Timer set to {1} seconds")(iSetting)); } void TimerCommand(const CString& sCommand) { PutModule(t_f("Current timer setting: {1} seconds")(GetAwayTime())); } public: MODCONSTRUCTOR(CAway) { Ping(); m_bIsAway = false; m_bBootError = false; m_saveMessages = true; m_chanMessages = false; SetAwayTime(300); AddTimer( new CAwayJob(this, 60, 0, "AwayJob", "Checks for idle and saves messages every 1 minute")); AddHelpCommand(); AddCommand("Away", static_cast(&CAway::AwayCommand), "[-quiet]"); AddCommand("Back", static_cast(&CAway::BackCommand), "[-quiet]"); AddCommand("Messages", static_cast(&CAway::BackCommand)); AddCommand("Delete", static_cast(&CAway::DeleteCommand), "delete "); AddCommand("Save", static_cast(&CAway::SaveCommand)); AddCommand("Ping", static_cast(&CAway::PingCommand)); AddCommand("Pass", static_cast(&CAway::PassCommand)); AddCommand("Show", static_cast(&CAway::ShowCommand)); AddCommand("Replay", static_cast(&CAway::ReplayCommand)); AddCommand("EnableTimer", static_cast( &CAway::EnableTimerCommand)); AddCommand("DisableTimer", static_cast( &CAway::DisableTimerCommand)); AddCommand("SetTimer", static_cast( &CAway::SetTimerCommand), ""); AddCommand("Timer", static_cast(&CAway::TimerCommand)); } ~CAway() override { if (!m_bBootError) SaveBufferToDisk(); } bool OnLoad(const CString& sArgs, CString& sMessage) override { CString sMyArgs = sArgs; size_t uIndex = 0; if (sMyArgs.Token(0) == "-nostore") { uIndex++; m_saveMessages = false; } if (sMyArgs.Token(uIndex) == "-chans") { uIndex++; m_chanMessages = true; } if (sMyArgs.Token(uIndex) == "-notimer") { SetAwayTime(0); sMyArgs = sMyArgs.Token(uIndex + 1, true); } else if (sMyArgs.Token(uIndex) == "-timer") { SetAwayTime(sMyArgs.Token(uIndex + 1).ToInt()); sMyArgs = sMyArgs.Token(uIndex + 2, true); } if (m_saveMessages) { if (!sMyArgs.empty()) { m_sPassword = CBlowfish::MD5(sMyArgs); } else { sMessage = t_s("This module needs as an argument a keyphrase used for " "encryption"); return false; } if (!BootStrap()) { sMessage = t_s( "Failed to decrypt your saved messages - " "Did you give the right encryption key as an argument to " "this module?"); m_bBootError = true; return false; } } return true; } void OnIRCConnected() override { if (m_bIsAway) { Away(true); // reset away if we are reconnected } else { // ircd seems to remember your away if you killed the client and // came back Back(); } } bool BootStrap() { CString sFile; if (DecryptMessages(sFile)) { VCString vsLines; VCString::iterator it; sFile.Split("\n", vsLines); for (it = vsLines.begin(); it != vsLines.end(); ++it) { CString sLine(*it); sLine.Trim(); AddMessage(sLine); } } else { m_sPassword = ""; CUtils::PrintError("[" + GetModName() + ".so] Failed to Decrypt Messages"); return (false); } return (true); } void SaveBufferToDisk() { if (!m_sPassword.empty()) { CString sFile = CRYPT_VERIFICATION_TOKEN; for (u_int b = 0; b < m_vMessages.size(); b++) sFile += m_vMessages[b] + "\n"; CBlowfish c(m_sPassword, BF_ENCRYPT); sFile = c.Crypt(sFile); CString sPath = GetPath(); if (!sPath.empty()) { CFile File(sPath); if (File.Open(O_WRONLY | O_CREAT | O_TRUNC, 0600)) { File.Chmod(0600); File.Write(sFile); } File.Close(); } } } void OnClientLogin() override { Back(true); } void OnClientDisconnect() override { Away(); } CString GetPath() { CString sBuffer = GetUser()->GetUserName(); CString sRet = GetSavePath(); sRet += "/.znc-away-" + CBlowfish::MD5(sBuffer, true); return (sRet); } void Away(bool bForce = false, const CString& sReason = "") { if ((!m_bIsAway) || (bForce)) { if (!bForce) m_sReason = sReason; else if (!sReason.empty()) m_sReason = sReason; time_t iTime = time(nullptr); char* pTime = ctime(&iTime); CString sTime; if (pTime) { sTime = pTime; sTime.Trim(); } if (m_sReason.empty()) m_sReason = "Auto Away at " + sTime; PutIRC("AWAY :" + m_sReason); m_bIsAway = true; } } void Back(bool bUsePrivMessage = false) { PutIRC("away"); m_bIsAway = false; if (!m_vMessages.empty()) { if (bUsePrivMessage) { PutModule(t_s("Welcome back!")); PutModule(t_f("You have {1} messages!")(m_vMessages.size())); } else { PutModNotice(t_s("Welcome back!")); PutModNotice(t_f("You have {1} messages!")(m_vMessages.size())); } } m_sReason = ""; } EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override { if (m_bIsAway) AddMessage(time(nullptr), Nick, sMessage); return (CONTINUE); } EModRet OnChanMsg(CNick& nick, CChan& channel, CString& sMessage) override { if (m_bIsAway && m_chanMessages && sMessage.AsLower().find(m_pNetwork->GetCurNick().AsLower()) != CString::npos) { AddMessage(time(nullptr), nick, channel.GetName() + " " + sMessage); } return (CONTINUE); } EModRet OnPrivAction(CNick& Nick, CString& sMessage) override { if (m_bIsAway) { AddMessage(time(nullptr), Nick, "* " + sMessage); } return (CONTINUE); } EModRet OnUserNotice(CString& sTarget, CString& sMessage) override { Ping(); if (m_bIsAway) Back(); return (CONTINUE); } EModRet OnUserMsg(CString& sTarget, CString& sMessage) override { Ping(); if (m_bIsAway) Back(); return (CONTINUE); } EModRet OnUserAction(CString& sTarget, CString& sMessage) override { Ping(); if (m_bIsAway) Back(); return (CONTINUE); } time_t GetTimeStamp() const { return (m_iLastSentData); } void Ping() { m_iLastSentData = time(nullptr); } time_t GetAwayTime() { return m_iAutoAway; } void SetAwayTime(time_t u) { m_iAutoAway = u; } bool IsAway() { return (m_bIsAway); } private: CString m_sPassword; bool m_bBootError; bool DecryptMessages(CString& sBuffer) { CString sMessages = GetPath(); CString sFile; sBuffer = ""; CFile File(sMessages); if (sMessages.empty() || !File.Open() || !File.ReadFile(sFile)) { PutModule(t_s("Unable to find buffer")); return (true); // gonna be successful here } File.Close(); if (!sFile.empty()) { CBlowfish c(m_sPassword, BF_DECRYPT); sBuffer = c.Crypt(sFile); if (sBuffer.Left(strlen(CRYPT_VERIFICATION_TOKEN)) != CRYPT_VERIFICATION_TOKEN) { // failed to decode :( PutModule(t_s("Unable to decode encrypted messages")); return (false); } sBuffer.erase(0, strlen(CRYPT_VERIFICATION_TOKEN)); } return (true); } void AddMessage(time_t iTime, const CNick& Nick, const CString& sMessage) { if (Nick.GetNick() == GetNetwork()->GetIRCNick().GetNick()) return; // ignore messages from self AddMessage(CString(iTime) + " " + Nick.GetNickMask() + " " + sMessage); } void AddMessage(const CString& sText) { if (m_saveMessages) { m_vMessages.push_back(sText); } } time_t m_iLastSentData; bool m_bIsAway; time_t m_iAutoAway; vector m_vMessages; CString m_sReason; bool m_saveMessages; bool m_chanMessages; }; void CAwayJob::RunJob() { CAway* p = (CAway*)GetModule(); p->SaveBufferToDisk(); if (!p->IsAway()) { time_t iNow = time(nullptr); if ((iNow - p->GetTimeStamp()) > p->GetAwayTime() && p->GetAwayTime() != 0) p->Away(); } } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("awaystore"); Info.SetHasArgs(true); Info.SetArgsHelpText(Info.t_s( "[ -notimer | -timer N ] [-chans] passw0rd . N is number of seconds, " "600 by default.")); } NETWORKMODULEDEFS( CAway, t_s("Adds auto-away with logging, useful when you use ZNC from " "different locations")) znc-1.7.5/modules/simple_away.cpp0000644000175000017500000002030013542151610017221 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #define SIMPLE_AWAY_DEFAULT_REASON "Auto away at %awaytime%" #define SIMPLE_AWAY_DEFAULT_TIME 60 class CSimpleAway; class CSimpleAwayJob : public CTimer { public: CSimpleAwayJob(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {} ~CSimpleAwayJob() override {} protected: void RunJob() override; }; class CSimpleAway : public CModule { private: CString m_sReason; unsigned int m_iAwayWait; unsigned int m_iMinClients; bool m_bClientSetAway; bool m_bWeSetAway; public: MODCONSTRUCTOR(CSimpleAway) { m_sReason = SIMPLE_AWAY_DEFAULT_REASON; m_iAwayWait = SIMPLE_AWAY_DEFAULT_TIME; m_iMinClients = 1; m_bClientSetAway = false; m_bWeSetAway = false; AddHelpCommand(); AddCommand("Reason", t_d("[]"), t_d("Prints or sets the away reason (%awaytime% is replaced " "with the time you were set away, supports " "substitutions using ExpandString)"), [=](const CString& sLine) { OnReasonCommand(sLine); }); AddCommand( "Timer", "", t_d("Prints the current time to wait before setting you away"), [=](const CString& sLine) { OnTimerCommand(sLine); }); AddCommand("SetTimer", t_d(""), t_d("Sets the time to wait before setting you away"), [=](const CString& sLine) { OnSetTimerCommand(sLine); }); AddCommand("DisableTimer", "", t_d("Disables the wait time before setting you away"), [=](const CString& sLine) { OnDisableTimerCommand(sLine); }); AddCommand( "MinClients", "", t_d("Get or set the minimum number of clients before going away"), [=](const CString& sLine) { OnMinClientsCommand(sLine); }); } ~CSimpleAway() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { CString sReasonArg; // Load AwayWait CString sFirstArg = sArgs.Token(0); if (sFirstArg.Equals("-notimer")) { SetAwayWait(0); sReasonArg = sArgs.Token(1, true); } else if (sFirstArg.Equals("-timer")) { SetAwayWait(sArgs.Token(1).ToUInt()); sReasonArg = sArgs.Token(2, true); } else { CString sAwayWait = GetNV("awaywait"); if (!sAwayWait.empty()) SetAwayWait(sAwayWait.ToUInt(), false); sReasonArg = sArgs; } // Load Reason if (!sReasonArg.empty()) { SetReason(sReasonArg); } else { CString sSavedReason = GetNV("reason"); if (!sSavedReason.empty()) SetReason(sSavedReason, false); } // MinClients CString sMinClients = GetNV("minclients"); if (!sMinClients.empty()) SetMinClients(sMinClients.ToUInt(), false); // Set away on load, required if loaded via webadmin if (GetNetwork()->IsIRCConnected() && MinClientsConnected()) SetAway(false); return true; } void OnIRCConnected() override { if (MinClientsConnected()) SetBack(); else SetAway(false); } void OnClientLogin() override { if (MinClientsConnected()) SetBack(); } void OnClientDisconnect() override { /* There might still be other clients */ if (!MinClientsConnected()) SetAway(); } void OnReasonCommand(const CString& sLine) { CString sReason = sLine.Token(1, true); if (!sReason.empty()) { SetReason(sReason); PutModule(t_s("Away reason set")); } else { PutModule(t_f("Away reason: {1}")(m_sReason)); PutModule(t_f("Current away reason would be: {1}")(ExpandReason())); } } void OnTimerCommand(const CString& sLine) { PutModule(t_p("Current timer setting: 1 second", "Current timer setting: {1} seconds", m_iAwayWait)(m_iAwayWait)); } void OnSetTimerCommand(const CString& sLine) { SetAwayWait(sLine.Token(1).ToUInt()); if (m_iAwayWait == 0) PutModule(t_s("Timer disabled")); else PutModule(t_p("Timer set to 1 second", "Timer set to: {1} seconds", m_iAwayWait)(m_iAwayWait)); } void OnDisableTimerCommand(const CString& sLine) { SetAwayWait(0); PutModule(t_s("Timer disabled")); } void OnMinClientsCommand(const CString& sLine) { if (sLine.Token(1).empty()) { PutModule(t_f("Current MinClients setting: {1}")(m_iMinClients)); } else { SetMinClients(sLine.Token(1).ToUInt()); PutModule(t_f("MinClients set to {1}")(m_iMinClients)); } } EModRet OnUserRawMessage(CMessage& msg) override { if (!msg.GetCommand().Equals("AWAY")) return CONTINUE; // If a client set us away, we don't touch that away message m_bClientSetAway = !msg.GetParam(0).Trim_n(" ").empty(); m_bWeSetAway = false; return CONTINUE; } void SetAway(bool bTimer = true) { if (bTimer) { RemTimer("simple_away"); AddTimer(new CSimpleAwayJob(this, m_iAwayWait, 1, "simple_away", "Sets you away after detach")); } else { if (!m_bClientSetAway) { PutIRC("AWAY :" + ExpandReason()); m_bWeSetAway = true; } } } void SetBack() { RemTimer("simple_away"); if (m_bWeSetAway) { PutIRC("AWAY"); m_bWeSetAway = false; } } private: bool MinClientsConnected() { return GetNetwork()->GetClients().size() >= m_iMinClients; } CString ExpandReason() { CString sReason = m_sReason; if (sReason.empty()) sReason = SIMPLE_AWAY_DEFAULT_REASON; time_t iTime = time(nullptr); CString sTime = CUtils::CTime(iTime, GetUser()->GetTimezone()); sReason.Replace("%awaytime%", sTime); sReason = ExpandString(sReason); sReason.Replace("%s", sTime); // Backwards compatibility with previous // syntax, where %s was substituted with // sTime. ZNC <= 1.6.x return sReason; } /* Settings */ void SetReason(CString& sReason, bool bSave = true) { if (bSave) SetNV("reason", sReason); m_sReason = sReason; } void SetAwayWait(unsigned int iAwayWait, bool bSave = true) { if (bSave) SetNV("awaywait", CString(iAwayWait)); m_iAwayWait = iAwayWait; } void SetMinClients(unsigned int iMinClients, bool bSave = true) { if (bSave) SetNV("minclients", CString(iMinClients)); m_iMinClients = iMinClients; } }; void CSimpleAwayJob::RunJob() { ((CSimpleAway*)GetModule())->SetAway(false); } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("simple_away"); Info.SetHasArgs(true); Info.SetArgsHelpText( Info.t_s("You might enter up to 3 arguments, like -notimer awaymessage " "or -timer 5 awaymessage.")); } NETWORKMODULEDEFS(CSimpleAway, t_s("This module will automatically set you away on IRC " "while you are disconnected from the bouncer.")) znc-1.7.5/modules/modules_online.cpp0000644000175000017500000000742313542151610017736 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include class CFOModule : public CModule { public: MODCONSTRUCTOR(CFOModule) {} ~CFOModule() override {} bool IsOnlineModNick(const CString& sNick) { const CString& sPrefix = GetUser()->GetStatusPrefix(); if (!sNick.StartsWith(sPrefix)) return false; CString sModNick = sNick.substr(sPrefix.length()); if (sModNick.Equals("status") || GetNetwork()->GetModules().FindModule(sModNick) || GetUser()->GetModules().FindModule(sModNick) || CZNC::Get().GetModules().FindModule(sModNick)) return true; return false; } EModRet OnUserRaw(CString& sLine) override { // Handle ISON if (sLine.Token(0).Equals("ison")) { VCString vsNicks; // Get the list of nicks which are being asked for sLine.Token(1, true).TrimLeft_n(":").Split(" ", vsNicks, false); CString sBNCNicks; for (const CString& sNick : vsNicks) { if (IsOnlineModNick(sNick)) { sBNCNicks += " " + sNick; } } // Remove the leading space sBNCNicks.LeftChomp(); if (!GetNetwork()->GetIRCSock()) { // if we are not connected to any IRC server, send // an empty or module-nick filled response. PutUser(":irc.znc.in 303 " + GetClient()->GetNick() + " :" + sBNCNicks); } else { // We let the server handle this request and then act on // the 303 response from the IRC server. m_ISONRequests.push_back(sBNCNicks); } } // Handle WHOIS if (sLine.Token(0).Equals("whois")) { CString sNick = sLine.Token(1); if (IsOnlineModNick(sNick)) { CIRCNetwork* pNetwork = GetNetwork(); PutUser(":znc.in 311 " + pNetwork->GetCurNick() + " " + sNick + " znc znc.in * :" + sNick); PutUser(":znc.in 312 " + pNetwork->GetCurNick() + " " + sNick + " *.znc.in :Bouncer"); PutUser(":znc.in 318 " + pNetwork->GetCurNick() + " " + sNick + " :End of /WHOIS list."); return HALT; } } return CONTINUE; } EModRet OnRaw(CString& sLine) override { // Handle 303 reply if m_Requests is not empty if (sLine.Token(1) == "303" && !m_ISONRequests.empty()) { VCString::iterator it = m_ISONRequests.begin(); sLine.Trim(); // Only append a space if this isn't an empty reply if (sLine.Right(1) != ":") { sLine += " "; } // add BNC nicks to the reply sLine += *it; m_ISONRequests.erase(it); } return CONTINUE; } private: VCString m_ISONRequests; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("modules_online"); } NETWORKMODULEDEFS(CFOModule, t_s("Makes ZNC's *modules to be \"online\".")) znc-1.7.5/modules/disconkick.cpp0000644000175000017500000000304213542151610017034 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include class CKickClientOnIRCDisconnect : public CModule { public: MODCONSTRUCTOR(CKickClientOnIRCDisconnect) {} void OnIRCDisconnected() override { CString sPrefix = GetUser()->GetStatusPrefix(); for (CChan* pChan : GetNetwork()->GetChans()) { if (pChan->IsOn()) { PutUser(":" + sPrefix + "disconkick!znc@znc.in KICK " + pChan->GetName() + " " + GetNetwork()->GetIRCNick().GetNick() + " :" + t_s("You have been disconnected from the IRC server")); } } } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("disconkick"); } USERMODULEDEFS( CKickClientOnIRCDisconnect, t_s("Kicks the client from all channels when the connection to the " "IRC server is lost")) znc-1.7.5/modules/bouncedcc.cpp0000644000175000017500000005100213542151610016637 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using std::set; class CBounceDCCMod; class CDCCBounce : public CSocket { public: CDCCBounce(CBounceDCCMod* pMod, unsigned long uLongIP, unsigned short uPort, const CString& sFileName, const CString& sRemoteNick, const CString& sRemoteIP, bool bIsChat = false); CDCCBounce(CBounceDCCMod* pMod, const CString& sHostname, unsigned short uPort, const CString& sRemoteNick, const CString& sRemoteIP, const CString& sFileName, int iTimeout = 60, bool bIsChat = false); ~CDCCBounce() override; static unsigned short DCCRequest(const CString& sNick, unsigned long uLongIP, unsigned short uPort, const CString& sFileName, bool bIsChat, CBounceDCCMod* pMod, const CString& sRemoteIP); void ReadLine(const CString& sData) override; void ReadData(const char* data, size_t len) override; void ReadPaused() override; void Timeout() override; void ConnectionRefused() override; void ReachedMaxBuffer() override; void SockError(int iErrno, const CString& sDescription) override; void Connected() override; void Disconnected() override; Csock* GetSockObj(const CString& sHost, unsigned short uPort) override; void Shutdown(); void PutServ(const CString& sLine); void PutPeer(const CString& sLine); bool IsPeerConnected() { return (m_pPeer) ? m_pPeer->IsConnected() : false; } // Setters void SetPeer(CDCCBounce* p) { m_pPeer = p; } void SetRemoteIP(const CString& s) { m_sRemoteIP = s; } void SetRemoteNick(const CString& s) { m_sRemoteNick = s; } void SetRemote(bool b) { m_bIsRemote = b; } // !Setters // Getters unsigned short GetUserPort() const { return m_uRemotePort; } const CString& GetRemoteAddr() const { return m_sRemoteIP; } const CString& GetRemoteNick() const { return m_sRemoteNick; } const CString& GetFileName() const { return m_sFileName; } CDCCBounce* GetPeer() const { return m_pPeer; } bool IsRemote() { return m_bIsRemote; } bool IsChat() { return m_bIsChat; } // !Getters private: protected: CString m_sRemoteNick; CString m_sRemoteIP; CString m_sConnectIP; CString m_sLocalIP; CString m_sFileName; CBounceDCCMod* m_pModule; CDCCBounce* m_pPeer; unsigned short m_uRemotePort; bool m_bIsChat; bool m_bIsRemote; static const unsigned int m_uiMaxDCCBuffer; static const unsigned int m_uiMinDCCBuffer; }; // If we buffer more than this in memory, we will throttle the receiving side const unsigned int CDCCBounce::m_uiMaxDCCBuffer = 10 * 1024; // If less than this is in the buffer, the receiving side continues const unsigned int CDCCBounce::m_uiMinDCCBuffer = 2 * 1024; class CBounceDCCMod : public CModule { public: void ListDCCsCommand(const CString& sLine) { CTable Table; Table.AddColumn(t_s("Type", "list")); Table.AddColumn(t_s("State", "list")); Table.AddColumn(t_s("Speed", "list")); Table.AddColumn(t_s("Nick", "list")); Table.AddColumn(t_s("IP", "list")); Table.AddColumn(t_s("File", "list")); set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CDCCBounce* pSock = (CDCCBounce*)*it; CString sSockName = pSock->GetSockName(); if (!(pSock->IsRemote())) { Table.AddRow(); Table.SetCell(t_s("Nick", "list"), pSock->GetRemoteNick()); Table.SetCell(t_s("IP", "list"), pSock->GetRemoteAddr()); if (pSock->IsChat()) { Table.SetCell(t_s("Type", "list"), t_s("Chat", "list")); } else { Table.SetCell(t_s("Type", "list"), t_s("Xfer", "list")); Table.SetCell(t_s("File", "list"), pSock->GetFileName()); } CString sState = t_s("Waiting"); if ((pSock->IsConnected()) || (pSock->IsPeerConnected())) { sState = t_s("Halfway"); if ((pSock->IsConnected()) && (pSock->IsPeerConnected())) { sState = t_s("Connected"); } } Table.SetCell(t_s("State", "list"), sState); } } if (PutModule(Table) == 0) { PutModule(t_s("You have no active DCCs.")); } } void UseClientIPCommand(const CString& sLine) { CString sValue = sLine.Token(1, true); if (!sValue.empty()) { SetNV("UseClientIP", sValue); } PutModule(t_f("Use client IP: {1}")(GetNV("UseClientIP").ToBool())); } MODCONSTRUCTOR(CBounceDCCMod) { AddHelpCommand(); AddCommand("ListDCCs", "", t_d("List all active DCCs"), [this](const CString& sLine) { ListDCCsCommand(sLine); }); AddCommand("UseClientIP", "", t_d("Change the option to use IP of client"), [this](const CString& sLine) { UseClientIPCommand(sLine); }); } ~CBounceDCCMod() override {} CString GetLocalDCCIP() { return GetUser()->GetLocalDCCIP(); } bool UseClientIP() { return GetNV("UseClientIP").ToBool(); } EModRet OnUserCTCP(CString& sTarget, CString& sMessage) override { if (sMessage.StartsWith("DCC ")) { CString sType = sMessage.Token(1, false, " ", false, "\"", "\"", true); CString sFile = sMessage.Token(2, false, " ", false, "\"", "\"", false); unsigned long uLongIP = sMessage.Token(3, false, " ", false, "\"", "\"", true).ToULong(); unsigned short uPort = sMessage.Token(4, false, " ", false, "\"", "\"", true).ToUShort(); unsigned long uFileSize = sMessage.Token(5, false, " ", false, "\"", "\"", true).ToULong(); CString sIP = GetLocalDCCIP(); if (!UseClientIP()) { uLongIP = CUtils::GetLongIP(GetClient()->GetRemoteIP()); } if (sType.Equals("CHAT")) { unsigned short uBNCPort = CDCCBounce::DCCRequest( sTarget, uLongIP, uPort, "", true, this, ""); if (uBNCPort) { PutIRC("PRIVMSG " + sTarget + " :\001DCC CHAT chat " + CString(CUtils::GetLongIP(sIP)) + " " + CString(uBNCPort) + "\001"); } } else if (sType.Equals("SEND")) { // DCC SEND readme.txt 403120438 5550 1104 unsigned short uBNCPort = CDCCBounce::DCCRequest( sTarget, uLongIP, uPort, sFile, false, this, ""); if (uBNCPort) { PutIRC("PRIVMSG " + sTarget + " :\001DCC SEND " + sFile + " " + CString(CUtils::GetLongIP(sIP)) + " " + CString(uBNCPort) + " " + CString(uFileSize) + "\001"); } } else if (sType.Equals("RESUME")) { // PRIVMSG user :DCC RESUME "znc.o" 58810 151552 unsigned short uResumePort = sMessage.Token(3).ToUShort(); set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CDCCBounce* pSock = (CDCCBounce*)*it; if (pSock->GetLocalPort() == uResumePort) { PutIRC("PRIVMSG " + sTarget + " :\001DCC " + sType + " " + sFile + " " + CString(pSock->GetUserPort()) + " " + sMessage.Token(4) + "\001"); } } } else if (sType.Equals("ACCEPT")) { // Need to lookup the connection by port, filter the port, and // forward to the user set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CDCCBounce* pSock = (CDCCBounce*)*it; if (pSock->GetUserPort() == sMessage.Token(3).ToUShort()) { PutIRC("PRIVMSG " + sTarget + " :\001DCC " + sType + " " + sFile + " " + CString(pSock->GetLocalPort()) + " " + sMessage.Token(4) + "\001"); } } } return HALTCORE; } return CONTINUE; } EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override { CIRCNetwork* pNetwork = GetNetwork(); if (sMessage.StartsWith("DCC ") && pNetwork->IsUserAttached()) { // DCC CHAT chat 2453612361 44592 CString sType = sMessage.Token(1, false, " ", false, "\"", "\"", true); CString sFile = sMessage.Token(2, false, " ", false, "\"", "\"", false); unsigned long uLongIP = sMessage.Token(3, false, " ", false, "\"", "\"", true).ToULong(); unsigned short uPort = sMessage.Token(4, false, " ", false, "\"", "\"", true).ToUShort(); unsigned long uFileSize = sMessage.Token(5, false, " ", false, "\"", "\"", true).ToULong(); if (sType.Equals("CHAT")) { CNick FromNick(Nick.GetNickMask()); unsigned short uBNCPort = CDCCBounce::DCCRequest( FromNick.GetNick(), uLongIP, uPort, "", true, this, CUtils::GetIP(uLongIP)); if (uBNCPort) { CString sIP = GetLocalDCCIP(); PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + pNetwork->GetCurNick() + " :\001DCC CHAT chat " + CString(CUtils::GetLongIP(sIP)) + " " + CString(uBNCPort) + "\001"); } } else if (sType.Equals("SEND")) { // DCC SEND readme.txt 403120438 5550 1104 unsigned short uBNCPort = CDCCBounce::DCCRequest( Nick.GetNick(), uLongIP, uPort, sFile, false, this, CUtils::GetIP(uLongIP)); if (uBNCPort) { CString sIP = GetLocalDCCIP(); PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + pNetwork->GetCurNick() + " :\001DCC SEND " + sFile + " " + CString(CUtils::GetLongIP(sIP)) + " " + CString(uBNCPort) + " " + CString(uFileSize) + "\001"); } } else if (sType.Equals("RESUME")) { // Need to lookup the connection by port, filter the port, and // forward to the user unsigned short uResumePort = sMessage.Token(3).ToUShort(); set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CDCCBounce* pSock = (CDCCBounce*)*it; if (pSock->GetLocalPort() == uResumePort) { PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + pNetwork->GetCurNick() + " :\001DCC " + sType + " " + sFile + " " + CString(pSock->GetUserPort()) + " " + sMessage.Token(4) + "\001"); } } } else if (sType.Equals("ACCEPT")) { // Need to lookup the connection by port, filter the port, and // forward to the user set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CDCCBounce* pSock = (CDCCBounce*)*it; if (pSock->GetUserPort() == sMessage.Token(3).ToUShort()) { PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + pNetwork->GetCurNick() + " :\001DCC " + sType + " " + sFile + " " + CString(pSock->GetLocalPort()) + " " + sMessage.Token(4) + "\001"); } } } return HALTCORE; } return CONTINUE; } }; CDCCBounce::CDCCBounce(CBounceDCCMod* pMod, unsigned long uLongIP, unsigned short uPort, const CString& sFileName, const CString& sRemoteNick, const CString& sRemoteIP, bool bIsChat) : CSocket(pMod) { m_uRemotePort = uPort; m_sConnectIP = CUtils::GetIP(uLongIP); m_sRemoteIP = sRemoteIP; m_sFileName = sFileName; m_sRemoteNick = sRemoteNick; m_pModule = pMod; m_bIsChat = bIsChat; m_sLocalIP = pMod->GetLocalDCCIP(); m_pPeer = nullptr; m_bIsRemote = false; if (bIsChat) { EnableReadLine(); } else { DisableReadLine(); } } CDCCBounce::CDCCBounce(CBounceDCCMod* pMod, const CString& sHostname, unsigned short uPort, const CString& sRemoteNick, const CString& sRemoteIP, const CString& sFileName, int iTimeout, bool bIsChat) : CSocket(pMod, sHostname, uPort, iTimeout) { m_uRemotePort = 0; m_bIsChat = bIsChat; m_pModule = pMod; m_pPeer = nullptr; m_sRemoteNick = sRemoteNick; m_sFileName = sFileName; m_sRemoteIP = sRemoteIP; m_bIsRemote = false; SetMaxBufferThreshold(10240); if (bIsChat) { EnableReadLine(); } else { DisableReadLine(); } } CDCCBounce::~CDCCBounce() { if (m_pPeer) { m_pPeer->Shutdown(); m_pPeer = nullptr; } } void CDCCBounce::ReadLine(const CString& sData) { CString sLine = sData.TrimRight_n("\r\n"); DEBUG(GetSockName() << " <- [" << sLine << "]"); PutPeer(sLine); } void CDCCBounce::ReachedMaxBuffer() { DEBUG(GetSockName() << " == ReachedMaxBuffer()"); CString sType = m_bIsChat ? t_s("Chat", "type") : t_s("Xfer", "type"); m_pModule->PutModule(t_f("DCC {1} Bounce ({2}): Too long line received")( sType, m_sRemoteNick)); Close(); } void CDCCBounce::ReadData(const char* data, size_t len) { if (m_pPeer) { m_pPeer->Write(data, len); size_t BufLen = m_pPeer->GetInternalWriteBuffer().length(); if (BufLen >= m_uiMaxDCCBuffer) { DEBUG(GetSockName() << " The send buffer is over the " "limit (" << BufLen << "), throttling"); PauseRead(); } } } void CDCCBounce::ReadPaused() { if (!m_pPeer || m_pPeer->GetInternalWriteBuffer().length() <= m_uiMinDCCBuffer) UnPauseRead(); } void CDCCBounce::Timeout() { DEBUG(GetSockName() << " == Timeout()"); CString sType = m_bIsChat ? t_s("Chat", "type") : t_s("Xfer", "type"); if (IsRemote()) { CString sHost = Csock::GetHostName(); if (!sHost.empty()) { m_pModule->PutModule(t_f( "DCC {1} Bounce ({2}): Timeout while connecting to {3} {4}")( sType, m_sRemoteNick, sHost, Csock::GetPort())); } else { m_pModule->PutModule( t_f("DCC {1} Bounce ({2}): Timeout while connecting.")( sType, m_sRemoteNick)); } } else { m_pModule->PutModule(t_f( "DCC {1} Bounce ({2}): Timeout while waiting for incoming " "connection on {3} {4}")(sType, m_sRemoteNick, Csock::GetLocalIP(), Csock::GetLocalPort())); } } void CDCCBounce::ConnectionRefused() { DEBUG(GetSockName() << " == ConnectionRefused()"); CString sType = m_bIsChat ? t_s("Chat", "type") : t_s("Xfer", "type"); CString sHost = Csock::GetHostName(); if (!sHost.empty()) { m_pModule->PutModule( t_f("DCC {1} Bounce ({2}): Connection refused while connecting to " "{3} {4}")(sType, m_sRemoteNick, sHost, Csock::GetPort())); } else { m_pModule->PutModule( t_f("DCC {1} Bounce ({2}): Connection refused while connecting.")( sType, m_sRemoteNick)); } } void CDCCBounce::SockError(int iErrno, const CString& sDescription) { DEBUG(GetSockName() << " == SockError(" << iErrno << ")"); CString sType = m_bIsChat ? t_s("Chat", "type") : t_s("Xfer", "type"); if (IsRemote()) { CString sHost = Csock::GetHostName(); if (!sHost.empty()) { m_pModule->PutModule(t_f( "DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}")( sType, m_sRemoteNick, sHost, Csock::GetPort(), sDescription)); } else { m_pModule->PutModule(t_f("DCC {1} Bounce ({2}): Socket error: {3}")( sType, m_sRemoteNick, sDescription)); } } else { m_pModule->PutModule( t_f("DCC {1} Bounce ({2}): Socket error on {3} {4}: {5}")( sType, m_sRemoteNick, Csock::GetLocalIP(), Csock::GetLocalPort(), sDescription)); } } void CDCCBounce::Connected() { SetTimeout(0); DEBUG(GetSockName() << " == Connected()"); } void CDCCBounce::Disconnected() { DEBUG(GetSockName() << " == Disconnected()"); } void CDCCBounce::Shutdown() { m_pPeer = nullptr; DEBUG(GetSockName() << " == Close(); because my peer told me to"); Close(); } Csock* CDCCBounce::GetSockObj(const CString& sHost, unsigned short uPort) { Close(); if (m_sRemoteIP.empty()) { m_sRemoteIP = sHost; } CDCCBounce* pSock = new CDCCBounce(m_pModule, sHost, uPort, m_sRemoteNick, m_sRemoteIP, m_sFileName, m_bIsChat); CDCCBounce* pRemoteSock = new CDCCBounce(m_pModule, sHost, uPort, m_sRemoteNick, m_sRemoteIP, m_sFileName, m_bIsChat); pSock->SetPeer(pRemoteSock); pRemoteSock->SetPeer(pSock); pRemoteSock->SetRemote(true); pSock->SetRemote(false); CZNC::Get().GetManager().Connect( m_sConnectIP, m_uRemotePort, "DCC::" + CString((m_bIsChat) ? "Chat" : "XFER") + "::Remote::" + m_sRemoteNick, 60, false, m_sLocalIP, pRemoteSock); pSock->SetSockName(GetSockName()); return pSock; } void CDCCBounce::PutServ(const CString& sLine) { DEBUG(GetSockName() << " -> [" << sLine << "]"); Write(sLine + "\r\n"); } void CDCCBounce::PutPeer(const CString& sLine) { if (m_pPeer) { m_pPeer->PutServ(sLine); } else { PutServ("*** Not connected yet ***"); } } unsigned short CDCCBounce::DCCRequest(const CString& sNick, unsigned long uLongIP, unsigned short uPort, const CString& sFileName, bool bIsChat, CBounceDCCMod* pMod, const CString& sRemoteIP) { CDCCBounce* pDCCBounce = new CDCCBounce(pMod, uLongIP, uPort, sFileName, sNick, sRemoteIP, bIsChat); unsigned short uListenPort = CZNC::Get().GetManager().ListenRand( "DCC::" + CString((bIsChat) ? "Chat" : "Xfer") + "::Local::" + sNick, pMod->GetLocalDCCIP(), false, SOMAXCONN, pDCCBounce, 120); return uListenPort; } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("bouncedcc"); } USERMODULEDEFS(CBounceDCCMod, t_s("Bounces DCC transfers through ZNC instead of sending them " "directly to the user. ")) znc-1.7.5/modules/route_replies.cpp0000644000175000017500000003551613542151610017607 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include struct reply { const char* szReply; bool bLastResponse; }; // TODO this list is far from complete, no errors are handled static const struct { const char* szRequest; struct reply vReplies[19]; } vRouteReplies[] = { {"WHO", {{"402", true}, /* rfc1459 ERR_NOSUCHSERVER */ {"352", false}, /* rfc1459 RPL_WHOREPLY */ {"315", true}, /* rfc1459 RPL_ENDOFWHO */ {"354", false}, // e.g. Quaknet uses this for WHO #chan %n {"403", true}, // No such chan {nullptr, true}}}, {"LIST", {{"402", true}, /* rfc1459 ERR_NOSUCHSERVER */ {"321", false}, /* rfc1459 RPL_LISTSTART */ {"322", false}, /* rfc1459 RPL_LIST */ {"323", true}, /* rfc1459 RPL_LISTEND */ {nullptr, true}}}, {"NAMES", { {"353", false}, /* rfc1459 RPL_NAMREPLY */ {"366", true}, /* rfc1459 RPL_ENDOFNAMES */ // No such nick/channel {"401", true}, {nullptr, true}, }}, {"LUSERS", {{"251", false}, /* rfc1459 RPL_LUSERCLIENT */ {"252", false}, /* rfc1459 RPL_LUSEROP */ {"253", false}, /* rfc1459 RPL_LUSERUNKNOWN */ {"254", false}, /* rfc1459 RPL_LUSERCHANNELS */ {"255", false}, /* rfc1459 RPL_LUSERME */ {"265", false}, {"266", true}, // We don't handle 250 here since some IRCds don't sent it //{"250", true}, {nullptr, true}}}, {"WHOIS", {{"311", false}, /* rfc1459 RPL_WHOISUSER */ {"312", false}, /* rfc1459 RPL_WHOISSERVER */ {"313", false}, /* rfc1459 RPL_WHOISOPERATOR */ {"317", false}, /* rfc1459 RPL_WHOISIDLE */ {"319", false}, /* rfc1459 RPL_WHOISCHANNELS */ {"301", false}, /* rfc1459 RPL_AWAY */ {"276", false}, /* oftc-hybrid RPL_WHOISCERTFP */ {"330", false}, /* ratbox RPL_WHOISLOGGEDIN aka ircu RPL_WHOISACCOUNT */ {"338", false}, /* RPL_WHOISACTUALLY -- "actually using host" */ {"378", false}, /* RPL_WHOISHOST -- real address of vhosts */ {"671", false}, /* RPL_WHOISSECURE */ {"307", false}, /* RPL_WHOISREGNICK */ {"379", false}, /* RPL_WHOISMODES */ {"760", false}, /* ircv3.2 RPL_WHOISKEYVALUE */ {"318", true}, /* rfc1459 RPL_ENDOFWHOIS */ {"401", true}, /* rfc1459 ERR_NOSUCHNICK */ {"402", true}, /* rfc1459 ERR_NOSUCHSERVER */ {"431", true}, /* rfc1459 ERR_NONICKNAMEGIVEN */ {nullptr, true}}}, {"PING", {{"PONG", true}, {"402", true}, /* rfc1459 ERR_NOSUCHSERVER */ {"409", true}, /* rfc1459 ERR_NOORIGIN */ {nullptr, true}}}, {"USERHOST", {{"302", true}, {"461", true}, /* rfc1459 ERR_NEEDMOREPARAMS */ {nullptr, true}}}, {"TIME", {{"391", true}, /* rfc1459 RPL_TIME */ {"402", true}, /* rfc1459 ERR_NOSUCHSERVER */ {nullptr, true}}}, {"WHOWAS", {{"406", false}, /* rfc1459 ERR_WASNOSUCHNICK */ {"312", false}, /* rfc1459 RPL_WHOISSERVER */ {"314", false}, /* rfc1459 RPL_WHOWASUSER */ {"369", true}, /* rfc1459 RPL_ENDOFWHOWAS */ {"431", true}, /* rfc1459 ERR_NONICKNAMEGIVEN */ {nullptr, true}}}, {"ISON", {{"303", true}, /* rfc1459 RPL_ISON */ {"461", true}, /* rfc1459 ERR_NEEDMOREPARAMS */ {nullptr, true}}}, {"LINKS", {{"364", false}, /* rfc1459 RPL_LINKS */ {"365", true}, /* rfc1459 RPL_ENDOFLINKS */ {"402", true}, /* rfc1459 ERR_NOSUCHSERVER */ {nullptr, true}}}, {"MAP", {{"006", false}, // inspircd {"270", false}, // SilverLeo wants this two added {"015", false}, {"017", true}, {"007", true}, {"481", true}, /* rfc1459 ERR_NOPRIVILEGES */ {nullptr, true}}}, {"TRACE", {{"200", false}, /* rfc1459 RPL_TRACELINK */ {"201", false}, /* rfc1459 RPL_TRACECONNECTING */ {"202", false}, /* rfc1459 RPL_TRACEHANDSHAKE */ {"203", false}, /* rfc1459 RPL_TRACEUNKNOWN */ {"204", false}, /* rfc1459 RPL_TRACEOPERATOR */ {"205", false}, /* rfc1459 RPL_TRACEUSER */ {"206", false}, /* rfc1459 RPL_TRACESERVER */ {"208", false}, /* rfc1459 RPL_TRACENEWTYPE */ {"261", false}, /* rfc1459 RPL_TRACELOG */ {"262", true}, {"402", true}, /* rfc1459 ERR_NOSUCHSERVER */ {nullptr, true}}}, {"USERS", { {"265", false}, {"266", true}, {"392", false}, /* rfc1459 RPL_USERSSTART */ {"393", false}, /* rfc1459 RPL_USERS */ {"394", true}, /* rfc1459 RPL_ENDOFUSERS */ {"395", false}, /* rfc1459 RPL_NOUSERS */ {"402", true}, /* rfc1459 ERR_NOSUCHSERVER */ {"424", true}, /* rfc1459 ERR_FILEERROR */ {"446", true}, /* rfc1459 ERR_USERSDISABLED */ {nullptr, true}, }}, {"METADATA", { {"761", false}, /* ircv3.2 RPL_KEYVALUE */ {"762", true}, /* ircv3.2 RPL_METADATAEND */ {"765", true}, /* ircv3.2 ERR_TARGETINVALID */ {"766", true}, /* ircv3.2 ERR_NOMATCHINGKEYS */ {"767", true}, /* ircv3.2 ERR_KEYINVALID */ {"768", true}, /* ircv3.2 ERR_KEYNOTSET */ {"769", true}, /* ircv3.2 ERR_KEYNOPERMISSION */ {nullptr, true}, }}, // This is just a list of all possible /mode replies stuffed together. // Since there should never be more than one of these going on, this // should work fine and makes the code simpler. {"MODE", {// "You're not a channel operator" {"482", true}, // MODE I {"346", false}, {"347", true}, // MODE b {"367", false}, {"368", true}, // MODE e {"348", false}, {"349", true}, {"467", true}, /* rfc1459 ERR_KEYSET */ {"472", true}, /* rfc1459 ERR_UNKNOWNMODE */ {"501", true}, /* rfc1459 ERR_UMODEUNKNOWNFLAG */ {"502", true}, /* rfc1459 ERR_USERSDONTMATCH */ {nullptr, true}, }}, // END (last item!) {nullptr, {{nullptr, true}}}}; class CRouteTimeout : public CTimer { public: CRouteTimeout(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {} ~CRouteTimeout() override {} protected: void RunJob() override; }; struct queued_req { CMessage msg; const struct reply* reply; }; typedef std::map> requestQueue; class CRouteRepliesMod : public CModule { public: MODCONSTRUCTOR(CRouteRepliesMod) { m_pDoing = nullptr; m_pReplies = nullptr; AddHelpCommand(); AddCommand("Silent", t_d("[yes|no]"), t_d("Decides whether to show the timeout messages or not"), [=](const CString& sLine) { SilentCommand(sLine); }); } ~CRouteRepliesMod() override { requestQueue::iterator it; while (!m_vsPending.empty()) { it = m_vsPending.begin(); while (!it->second.empty()) { PutIRC(it->second[0].msg); it->second.erase(it->second.begin()); } m_vsPending.erase(it); } } void OnIRCConnected() override { m_pDoing = nullptr; m_pReplies = nullptr; m_vsPending.clear(); // No way we get a reply, so stop the timer (If it's running) RemTimer("RouteTimeout"); } void OnIRCDisconnected() override { OnIRCConnected(); // Let's keep it in one place } void OnClientDisconnect() override { requestQueue::iterator it; if (GetClient() == m_pDoing) { // The replies which aren't received yet will be // broadcasted to everyone, but at least nothing breaks RemTimer("RouteTimeout"); m_pDoing = nullptr; m_pReplies = nullptr; } it = m_vsPending.find(GetClient()); if (it != m_vsPending.end()) m_vsPending.erase(it); SendRequest(); } EModRet OnRawMessage(CMessage& msg) override { CString sCmd = msg.GetCommand().AsUpper(); size_t i = 0; if (!m_pReplies) return CONTINUE; // Is this a "not enough arguments" error? if (sCmd == "461") { // :server 461 nick WHO :Not enough parameters CString sOrigCmd = msg.GetParam(1); if (m_LastRequest.GetCommand().Equals(sOrigCmd)) { // This is the reply to the last request if (RouteReply(msg, true)) return HALTCORE; return CONTINUE; } } while (m_pReplies[i].szReply != nullptr) { if (m_pReplies[i].szReply == sCmd) { if (RouteReply(msg, m_pReplies[i].bLastResponse)) return HALTCORE; return CONTINUE; } i++; } // TODO HALTCORE is wrong, it should not be passed to // the clients, but the core itself should still handle it! return CONTINUE; } EModRet OnUserRawMessage(CMessage& Message) override { const CString& sCmd = Message.GetCommand(); if (!GetNetwork()->GetIRCSock() || !GetNetwork()->GetIRCSock()->IsConnected()) return CONTINUE; if (Message.GetType() == CMessage::Type::Mode) { // Check if this is a mode request that needs to be handled // If there are arguments to a mode change, // we must not route it. if (!Message.GetParamsColon(2).empty()) return CONTINUE; // Grab the mode change parameter CString sMode = Message.GetParam(1); // If this is a channel mode request, znc core replies to it if (sMode.empty()) return CONTINUE; // Check if this is a mode change or a specific // mode request (the later needs to be routed). sMode.TrimPrefix("+"); if (sMode.length() != 1) return CONTINUE; // Now just check if it's one of the supported modes switch (sMode[0]) { case 'I': case 'b': case 'e': break; default: return CONTINUE; } // Ok, this looks like we should route it. // Fall through to the next loop } for (size_t i = 0; vRouteReplies[i].szRequest != nullptr; i++) { if (vRouteReplies[i].szRequest == sCmd) { struct queued_req req = {Message, vRouteReplies[i].vReplies}; m_vsPending[GetClient()].push_back(req); SendRequest(); return HALTCORE; } } return CONTINUE; } void Timeout() { // The timer will be deleted after this by the event loop if (!GetNV("silent_timeouts").ToBool()) { PutModule( t_s("This module hit a timeout which is probably a " "connectivity issue.")); PutModule( t_s("However, if you can provide steps to reproduce this " "issue, please do report a bug.")); PutModule( t_f("To disable this message, do \"/msg {1} silent yes\"")( GetModNick())); PutModule(t_f("Last request: {1}")(m_LastRequest.ToString())); PutModule(t_s("Expected replies:")); for (size_t i = 0; m_pReplies[i].szReply != nullptr; i++) { if (m_pReplies[i].bLastResponse) PutModule(t_f("{1} (last)")(m_pReplies[i].szReply)); else PutModule(m_pReplies[i].szReply); } } m_pDoing = nullptr; m_pReplies = nullptr; SendRequest(); } private: bool RouteReply(const CMessage& msg, bool bFinished = false) { if (!m_pDoing) return false; // TODO: RouteReply(const CMessage& Message, bool bFinished = false) m_pDoing->PutClient(msg); if (bFinished) { // Stop the timeout RemTimer("RouteTimeout"); m_pDoing = nullptr; m_pReplies = nullptr; SendRequest(); } return true; } void SendRequest() { requestQueue::iterator it; if (m_pDoing || m_pReplies) return; if (m_vsPending.empty()) return; it = m_vsPending.begin(); if (it->second.empty()) { m_vsPending.erase(it); SendRequest(); return; } // When we are called from the timer, we need to remove it. // We can't delete it (segfault on return), thus we // just stop it. The main loop will delete it. CTimer* pTimer = FindTimer("RouteTimeout"); if (pTimer) { pTimer->Stop(); UnlinkTimer(pTimer); } AddTimer( new CRouteTimeout(this, 60, 1, "RouteTimeout", "Recover from missing / wrong server replies")); m_pDoing = it->first; m_pReplies = it->second[0].reply; m_LastRequest = it->second[0].msg; PutIRC(it->second[0].msg); it->second.erase(it->second.begin()); } void SilentCommand(const CString& sLine) { const CString sValue = sLine.Token(1); if (!sValue.empty()) { SetNV("silent_timeouts", sValue); } PutModule(GetNV("silent_timeouts").ToBool() ? t_s("Timeout messages are disabled.") : t_s("Timeout messages are enabled.")); } CClient* m_pDoing; const struct reply* m_pReplies; requestQueue m_vsPending; // This field is only used for display purpose. CMessage m_LastRequest; }; void CRouteTimeout::RunJob() { CRouteRepliesMod* pMod = (CRouteRepliesMod*)GetModule(); pMod->Timeout(); } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("route_replies"); } NETWORKMODULEDEFS(CRouteRepliesMod, t_s("Send replies (e.g. to /who) to the right client only")) znc-1.7.5/modules/notes.cpp0000644000175000017500000001602413542151610016047 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include using std::stringstream; class CNotesMod : public CModule { bool m_bShowNotesOnLogin{}; void ListCommand(const CString& sLine) { ListNotes(); } void AddNoteCommand(const CString& sLine) { CString sKey(sLine.Token(1)); CString sValue(sLine.Token(2, true)); if (!GetNV(sKey).empty()) { PutModule( t_s("That note already exists. Use MOD to " "overwrite.")); } else if (AddNote(sKey, sValue)) { PutModule(t_f("Added note {1}")(sKey)); } else { PutModule(t_f("Unable to add note {1}")(sKey)); } } void ModCommand(const CString& sLine) { CString sKey(sLine.Token(1)); CString sValue(sLine.Token(2, true)); if (AddNote(sKey, sValue)) { PutModule(t_f("Set note for {1}")(sKey)); } else { PutModule(t_f("Unable to add note {1}")(sKey)); } } void GetCommand(const CString& sLine) { CString sNote = GetNV(sLine.Token(1, true)); if (sNote.empty()) { PutModule(t_s("This note doesn't exist.")); } else { PutModule(sNote); } } void DelCommand(const CString& sLine) { CString sKey(sLine.Token(1)); if (DelNote(sKey)) { PutModule(t_f("Deleted note {1}")(sKey)); } else { PutModule(t_f("Unable to delete note {1}")(sKey)); } } public: MODCONSTRUCTOR(CNotesMod) { AddHelpCommand(); AddCommand("List", "", t_d("List notes"), [=](const CString& sLine) { ListCommand(sLine); }); AddCommand("Add", t_d(" "), t_d("Add a note"), [=](const CString& sLine) { AddNoteCommand(sLine); }); AddCommand("Del", t_d(""), t_d("Delete a note"), [=](const CString& sLine) { DelCommand(sLine); }); AddCommand("Mod", t_d(" "), t_d("Modify a note"), [=](const CString& sLine) { ModCommand(sLine); }); AddCommand("Get", t_d(""), "", [=](const CString& sLine) { GetCommand(sLine); }); } ~CNotesMod() override {} bool OnLoad(const CString& sArgs, CString& sMessage) override { m_bShowNotesOnLogin = !sArgs.Equals("-disableNotesOnLogin"); return true; } CString GetWebMenuTitle() override { return t_s("Notes"); } void OnClientLogin() override { if (m_bShowNotesOnLogin) { ListNotes(true); } } EModRet OnUserRaw(CString& sLine) override { if (sLine.Left(1) != "#") { return CONTINUE; } CString sKey; bool bOverwrite = false; if (sLine == "#?") { ListNotes(true); return HALT; } else if (sLine.Left(2) == "#-") { sKey = sLine.Token(0).LeftChomp_n(2); if (DelNote(sKey)) { PutModNotice(t_f("Deleted note {1}")(sKey)); } else { PutModNotice(t_f("Unable to delete note {1}")(sKey)); } return HALT; } else if (sLine.Left(2) == "#+") { sKey = sLine.Token(0).LeftChomp_n(2); bOverwrite = true; } else if (sLine.Left(1) == "#") { sKey = sLine.Token(0).LeftChomp_n(1); } CString sValue(sLine.Token(1, true)); if (!sKey.empty()) { if (!bOverwrite && FindNV(sKey) != EndNV()) { PutModNotice( t_s("That note already exists. Use /#+ to " "overwrite.")); } else if (AddNote(sKey, sValue)) { if (!bOverwrite) { PutModNotice(t_f("Added note {1}")(sKey)); } else { PutModNotice(t_f("Set note for {1}")(sKey)); } } else { PutModNotice(t_f("Unable to add note {1}")(sKey)); } } return HALT; } bool DelNote(const CString& sKey) { return DelNV(sKey); } bool AddNote(const CString& sKey, const CString& sNote) { if (sKey.empty()) { return false; } return SetNV(sKey, sNote); } void ListNotes(bool bNotice = false) { CClient* pClient = GetClient(); if (pClient) { CTable Table; Table.AddColumn(t_s("Key")); Table.AddColumn(t_s("Note")); for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { Table.AddRow(); Table.SetCell(t_s("Key"), it->first); Table.SetCell(t_s("Note"), it->second); } if (Table.size()) { unsigned int idx = 0; CString sLine; while (Table.GetLine(idx++, sLine)) { if (bNotice) { pClient->PutModNotice(GetModName(), sLine); } else { pClient->PutModule(GetModName(), sLine); } } } else { if (bNotice) { PutModNotice(t_s("You have no entries.")); } else { PutModule(t_s("You have no entries.")); } } } } bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) override { if (sPageName == "index") { for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) { CTemplate& Row = Tmpl.AddRow("NotesLoop"); Row["Key"] = it->first; Row["Note"] = it->second; } return true; } else if (sPageName == "delnote") { DelNote(WebSock.GetParam("key", false)); WebSock.Redirect(GetWebPath()); return true; } else if (sPageName == "addnote") { AddNote(WebSock.GetParam("key"), WebSock.GetParam("note")); WebSock.Redirect(GetWebPath()); return true; } return false; } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("notes"); Info.SetHasArgs(true); Info.SetArgsHelpText( Info.t_s("This user module takes up to one arguments. It can be " "-disableNotesOnLogin not to show notes upon client login")); } USERMODULEDEFS(CNotesMod, t_s("Keep and replay notes")) znc-1.7.5/modules/dcc.cpp0000644000175000017500000005113413542151610015451 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include using std::set; class CDCCMod; class CDCCSock : public CSocket { public: CDCCSock(CDCCMod* pMod, const CString& sRemoteNick, const CString& sLocalFile, unsigned long uFileSize = 0, CFile* pFile = nullptr); CDCCSock(CDCCMod* pMod, const CString& sRemoteNick, const CString& sRemoteIP, unsigned short uRemotePort, const CString& sLocalFile, unsigned long uFileSize); ~CDCCSock() override; void ReadData(const char* data, size_t len) override; void ConnectionRefused() override; void SockError(int iErrno, const CString& sDescription) override; void Timeout() override; void Connected() override; void Disconnected() override; void SendPacket(); Csock* GetSockObj(const CString& sHost, unsigned short uPort) override; CFile* OpenFile(bool bWrite = true); bool Seek(unsigned long int uPos); // Setters void SetRemoteIP(const CString& s) { m_sRemoteIP = s; } void SetRemoteNick(const CString& s) { m_sRemoteNick = s; } void SetFileName(const CString& s) { m_sFileName = s; } void SetFileOffset(unsigned long u) { m_uBytesSoFar = u; } // !Setters // Getters unsigned short GetUserPort() const { return m_uRemotePort; } const CString& GetRemoteNick() const { return m_sRemoteNick; } const CString& GetFileName() const { return m_sFileName; } const CString& GetLocalFile() const { return m_sLocalFile; } CFile* GetFile() { return m_pFile; } double GetProgress() const { return ((m_uFileSize) && (m_uBytesSoFar)) ? (double)(((double)m_uBytesSoFar / (double)m_uFileSize) * 100.0) : 0; } bool IsSend() const { return m_bSend; } // const CString& GetRemoteIP() const { return m_sRemoteIP; } // !Getters private: protected: CString m_sRemoteNick; CString m_sRemoteIP; CString m_sFileName; CString m_sLocalFile; CString m_sSendBuf; unsigned short m_uRemotePort; unsigned long long m_uFileSize; unsigned long long m_uBytesSoFar; bool m_bSend; bool m_bNoDelFile; CFile* m_pFile; CDCCMod* m_pModule; }; class CDCCMod : public CModule { public: MODCONSTRUCTOR(CDCCMod) { AddHelpCommand(); AddCommand("Send", t_d(" "), t_d("Send a file from ZNC to someone"), [=](const CString& sLine) { SendCommand(sLine); }); AddCommand("Get", t_d(""), t_d("Send a file from ZNC to your client"), [=](const CString& sLine) { GetCommand(sLine); }); AddCommand("ListTransfers", "", t_d("List current transfers"), [=](const CString& sLine) { ListTransfersCommand(sLine); }); } ~CDCCMod() override {} #ifndef MOD_DCC_ALLOW_EVERYONE bool OnLoad(const CString& sArgs, CString& sMessage) override { if (!GetUser()->IsAdmin()) { sMessage = t_s("You must be admin to use the DCC module"); return false; } return true; } #endif bool SendFile(const CString& sRemoteNick, const CString& sFileName) { CString sFullPath = CDir::ChangeDir(GetSavePath(), sFileName, CZNC::Get().GetHomePath()); CDCCSock* pSock = new CDCCSock(this, sRemoteNick, sFullPath); CFile* pFile = pSock->OpenFile(false); if (!pFile) { delete pSock; return false; } CString sLocalDCCIP = GetUser()->GetLocalDCCIP(); unsigned short uPort = CZNC::Get().GetManager().ListenRand( "DCC::LISTEN::" + sRemoteNick, sLocalDCCIP, false, SOMAXCONN, pSock, 120); if (GetUser()->GetNick().Equals(sRemoteNick)) { PutUser(":*dcc!znc@znc.in PRIVMSG " + sRemoteNick + " :\001DCC SEND " + pFile->GetShortName() + " " + CString(CUtils::GetLongIP(sLocalDCCIP)) + " " + CString(uPort) + " " + CString(pFile->GetSize()) + "\001"); } else { PutIRC("PRIVMSG " + sRemoteNick + " :\001DCC SEND " + pFile->GetShortName() + " " + CString(CUtils::GetLongIP(sLocalDCCIP)) + " " + CString(uPort) + " " + CString(pFile->GetSize()) + "\001"); } PutModule(t_f("Attempting to send [{1}] to [{2}].")( pFile->GetShortName(), sRemoteNick)); return true; } bool GetFile(const CString& sRemoteNick, const CString& sRemoteIP, unsigned short uRemotePort, const CString& sFileName, unsigned long uFileSize) { if (CFile::Exists(sFileName)) { PutModule(t_f("Receiving [{1}] from [{2}]: File already exists.")( sFileName, sRemoteNick)); return false; } CDCCSock* pSock = new CDCCSock(this, sRemoteNick, sRemoteIP, uRemotePort, sFileName, uFileSize); if (!pSock->OpenFile()) { delete pSock; return false; } CZNC::Get().GetManager().Connect(sRemoteIP, uRemotePort, "DCC::GET::" + sRemoteNick, 60, false, GetUser()->GetLocalDCCIP(), pSock); PutModule( t_f("Attempting to connect to [{1} {2}] in order to download [{3}] " "from [{4}].")(sRemoteIP, uRemotePort, sFileName, sRemoteNick)); return true; } void SendCommand(const CString& sLine) { CString sToNick = sLine.Token(1); CString sFile = sLine.Token(2); CString sAllowedPath = GetSavePath(); CString sAbsolutePath; if ((sToNick.empty()) || (sFile.empty())) { PutModule(t_s("Usage: Send ")); return; } sAbsolutePath = CDir::CheckPathPrefix(sAllowedPath, sFile); if (sAbsolutePath.empty()) { PutStatus(t_s("Illegal path.")); return; } SendFile(sToNick, sFile); } void GetCommand(const CString& sLine) { CString sFile = sLine.Token(1); CString sAllowedPath = GetSavePath(); CString sAbsolutePath; if (sFile.empty()) { PutModule(t_s("Usage: Get ")); return; } sAbsolutePath = CDir::CheckPathPrefix(sAllowedPath, sFile); if (sAbsolutePath.empty()) { PutModule(t_s("Illegal path.")); return; } SendFile(GetUser()->GetNick(), sFile); } void ListTransfersCommand(const CString& sLine) { CTable Table; Table.AddColumn(t_s("Type", "list")); Table.AddColumn(t_s("State", "list")); Table.AddColumn(t_s("Speed", "list")); Table.AddColumn(t_s("Nick", "list")); Table.AddColumn(t_s("IP", "list")); Table.AddColumn(t_s("File", "list")); set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CDCCSock* pSock = (CDCCSock*)*it; Table.AddRow(); Table.SetCell(t_s("Nick", "list"), pSock->GetRemoteNick()); Table.SetCell(t_s("IP", "list"), pSock->GetRemoteIP()); Table.SetCell(t_s("File", "list"), pSock->GetFileName()); if (pSock->IsSend()) { Table.SetCell(t_s("Type", "list"), t_s("Sending", "list-type")); } else { Table.SetCell(t_s("Type", "list"), t_s("Getting", "list-type")); } if (pSock->GetType() == Csock::LISTENER) { Table.SetCell(t_s("State", "list"), t_s("Waiting", "list-state")); } else { Table.SetCell(t_s("State", "list"), CString::ToPercent(pSock->GetProgress())); Table.SetCell(t_s("Speed", "list"), t_f("{1} KiB/s")(static_cast( pSock->GetAvgRead() / 1024.0))); } } if (PutModule(Table) == 0) { PutModule(t_s("You have no active DCC transfers.")); } } void OnModCTCP(const CString& sMessage) override { if (sMessage.StartsWith("DCC RESUME ")) { CString sFile = sMessage.Token(2); unsigned short uResumePort = sMessage.Token(3).ToUShort(); unsigned long uResumeSize = sMessage.Token(4).ToULong(); set::const_iterator it; for (it = BeginSockets(); it != EndSockets(); ++it) { CDCCSock* pSock = (CDCCSock*)*it; if (pSock->GetLocalPort() == uResumePort) { if (pSock->Seek(uResumeSize)) { PutModule( t_f("Attempting to resume send from position {1} " "of file [{2}] for [{3}]")( uResumeSize, pSock->GetFileName(), pSock->GetRemoteNick())); PutUser(":*dcc!znc@znc.in PRIVMSG " + GetUser()->GetNick() + " :\001DCC ACCEPT " + sFile + " " + CString(uResumePort) + " " + CString(uResumeSize) + "\001"); } else { PutModule(t_f( "Couldn't resume file [{1}] for [{2}]: not sending " "anything.")(sFile, GetUser()->GetNick())); } } } } else if (sMessage.StartsWith("DCC SEND ")) { CString sLocalFile = CDir::CheckPathPrefix(GetSavePath(), sMessage.Token(2)); if (sLocalFile.empty()) { PutModule(t_f("Bad DCC file: {1}")(sMessage.Token(2))); } unsigned long uLongIP = sMessage.Token(3).ToULong(); unsigned short uPort = sMessage.Token(4).ToUShort(); unsigned long uFileSize = sMessage.Token(5).ToULong(); GetFile(GetClient()->GetNick(), CUtils::GetIP(uLongIP), uPort, sLocalFile, uFileSize); } } }; CDCCSock::CDCCSock(CDCCMod* pMod, const CString& sRemoteNick, const CString& sLocalFile, unsigned long uFileSize, CFile* pFile) : CSocket(pMod) { m_sRemoteNick = sRemoteNick; m_uFileSize = uFileSize; m_uRemotePort = 0; m_uBytesSoFar = 0; m_pModule = pMod; m_pFile = pFile; m_sLocalFile = sLocalFile; m_bSend = true; m_bNoDelFile = false; SetMaxBufferThreshold(0); } CDCCSock::CDCCSock(CDCCMod* pMod, const CString& sRemoteNick, const CString& sRemoteIP, unsigned short uRemotePort, const CString& sLocalFile, unsigned long uFileSize) : CSocket(pMod) { m_sRemoteNick = sRemoteNick; m_sRemoteIP = sRemoteIP; m_uRemotePort = uRemotePort; m_uFileSize = uFileSize; m_uBytesSoFar = 0; m_pModule = pMod; m_pFile = nullptr; m_sLocalFile = sLocalFile; m_bSend = false; m_bNoDelFile = false; SetMaxBufferThreshold(0); } CDCCSock::~CDCCSock() { if ((m_pFile) && (!m_bNoDelFile)) { m_pFile->Close(); delete m_pFile; } } void CDCCSock::ReadData(const char* data, size_t len) { if (!m_pFile) { DEBUG("File not open! closing get."); if (m_bSend) { m_pModule->PutModule(t_f("Sending [{1}] to [{2}]: File not open!")( m_sFileName, m_sRemoteNick)); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: File not open!")( m_sFileName, m_sRemoteNick)); } Close(); return; } // DCC specs says the receiving end sends the number of bytes it // received so far as a 4 byte integer in network byte order, so we need // uint32_t to do the job portably. This also means that the maximum // file that we can transfer is 4 GiB big (see OpenFile()). if (m_bSend) { m_sSendBuf.append(data, len); while (m_sSendBuf.size() >= 4) { uint32_t iRemoteSoFar; memcpy(&iRemoteSoFar, m_sSendBuf.data(), sizeof(iRemoteSoFar)); iRemoteSoFar = ntohl(iRemoteSoFar); if ((iRemoteSoFar + 65536) >= m_uBytesSoFar) { SendPacket(); } m_sSendBuf.erase(0, 4); } } else { m_pFile->Write(data, len); m_uBytesSoFar += len; uint32_t uSoFar = htonl((uint32_t)m_uBytesSoFar); Write((char*)&uSoFar, sizeof(uSoFar)); if (m_uBytesSoFar >= m_uFileSize) { Close(); } } } void CDCCSock::ConnectionRefused() { DEBUG(GetSockName() << " == ConnectionRefused()"); if (m_bSend) { m_pModule->PutModule(t_f("Sending [{1}] to [{2}]: Connection refused.")( m_sFileName, m_sRemoteNick)); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: Connection refused.")( m_sFileName, m_sRemoteNick)); } } void CDCCSock::Timeout() { DEBUG(GetSockName() << " == Timeout()"); if (m_bSend) { m_pModule->PutModule(t_f("Sending [{1}] to [{2}]: Timeout.")( m_sFileName, m_sRemoteNick)); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: Timeout.")( m_sFileName, m_sRemoteNick)); } } void CDCCSock::SockError(int iErrno, const CString& sDescription) { DEBUG(GetSockName() << " == SockError(" << iErrno << ", " << sDescription << ")"); if (m_bSend) { m_pModule->PutModule( t_f("Sending [{1}] to [{2}]: Socket error {3}: {4}")( m_sFileName, m_sRemoteNick, iErrno, sDescription)); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: Socket error {3}: {4}")( m_sFileName, m_sRemoteNick, iErrno, sDescription)); } } void CDCCSock::Connected() { DEBUG(GetSockName() << " == Connected(" << GetRemoteIP() << ")"); if (m_bSend) { m_pModule->PutModule(t_f("Sending [{1}] to [{2}]: Transfer started.")( m_sFileName, m_sRemoteNick)); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: Transfer started.")( m_sFileName, m_sRemoteNick)); } if (m_bSend) { SendPacket(); } SetTimeout(120); } void CDCCSock::Disconnected() { const CString sStart = ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - "; DEBUG(GetSockName() << " == Disconnected()"); if (m_uBytesSoFar > m_uFileSize) { if (m_bSend) { m_pModule->PutModule(t_f("Sending [{1}] to [{2}]: Too much data!")( m_sFileName, m_sRemoteNick)); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: Too much data!")( m_sFileName, m_sRemoteNick)); } } else if (m_uBytesSoFar == m_uFileSize) { if (m_bSend) { m_pModule->PutModule( t_f("Sending [{1}] to [{2}] completed at {3} KiB/s")( m_sFileName, m_sRemoteNick, static_cast(GetAvgWrite() / 1024.0))); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}] completed at {3} KiB/s")( m_sFileName, m_sRemoteNick, static_cast(GetAvgRead() / 1024.0))); } } else { m_pModule->PutModule(sStart + "Incomplete!"); } } void CDCCSock::SendPacket() { if (!m_pFile) { if (m_bSend) { m_pModule->PutModule( t_f("Sending [{1}] to [{2}]: File closed prematurely.")( m_sFileName, m_sRemoteNick)); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: File closed prematurely.")( m_sFileName, m_sRemoteNick)); } Close(); return; } if (GetInternalWriteBuffer().size() > 1024 * 1024) { // There is still enough data to be written, don't add more // stuff to that buffer. DEBUG("SendPacket(): Skipping send, buffer still full enough [" << GetInternalWriteBuffer().size() << "][" << m_sRemoteNick << "][" << m_sFileName << "]"); return; } char szBuf[4096]; ssize_t iLen = m_pFile->Read(szBuf, 4096); if (iLen < 0) { if (m_bSend) { m_pModule->PutModule( t_f("Sending [{1}] to [{2}]: Error reading from file.")( m_sFileName, m_sRemoteNick)); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: Error reading from file.")( m_sFileName, m_sRemoteNick)); } Close(); return; } if (iLen > 0) { Write(szBuf, iLen); m_uBytesSoFar += iLen; } } Csock* CDCCSock::GetSockObj(const CString& sHost, unsigned short uPort) { Close(); CDCCSock* pSock = new CDCCSock(m_pModule, m_sRemoteNick, m_sLocalFile, m_uFileSize, m_pFile); pSock->SetSockName("DCC::SEND::" + m_sRemoteNick); pSock->SetTimeout(120); pSock->SetFileName(m_sFileName); pSock->SetFileOffset(m_uBytesSoFar); m_bNoDelFile = true; return pSock; } CFile* CDCCSock::OpenFile(bool bWrite) { if ((m_pFile) || (m_sLocalFile.empty())) { if (m_bSend) { m_pModule->PutModule( t_f("Sending [{1}] to [{2}]: Unable to open file.")( m_sFileName, m_sRemoteNick)); } else { m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: Unable to open file.")( m_sFileName, m_sRemoteNick)); } return nullptr; } m_pFile = new CFile(m_sLocalFile); if (bWrite) { if (m_pFile->Exists()) { delete m_pFile; m_pFile = nullptr; m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: File already exists.")( m_sFileName, m_sRemoteNick)); return nullptr; } if (!m_pFile->Open(O_WRONLY | O_TRUNC | O_CREAT)) { delete m_pFile; m_pFile = nullptr; m_pModule->PutModule( t_f("Receiving [{1}] from [{2}]: Could not open file.")( m_sFileName, m_sRemoteNick)); return nullptr; } } else { if (!m_pFile->IsReg()) { delete m_pFile; m_pFile = nullptr; m_pModule->PutModule( t_f("Sending [{1}] to [{2}]: Not a file.")( m_sFileName, m_sRemoteNick)); return nullptr; } if (!m_pFile->Open()) { delete m_pFile; m_pFile = nullptr; m_pModule->PutModule( t_f("Sending [{1}] to [{2}]: Could not open file.")( m_sFileName, m_sRemoteNick)); return nullptr; } // The DCC specs only allow file transfers with files smaller // than 4GiB (see ReadData()). unsigned long long uFileSize = m_pFile->GetSize(); if (uFileSize > (unsigned long long)0xffffffffULL) { delete m_pFile; m_pFile = nullptr; m_pModule->PutModule( t_f("Sending [{1}] to [{2}]: File too large (>4 GiB).")( m_sFileName, m_sRemoteNick)); return nullptr; } m_uFileSize = uFileSize; } m_sFileName = m_pFile->GetShortName(); return m_pFile; } bool CDCCSock::Seek(unsigned long int uPos) { if (m_pFile) { if (m_pFile->Seek(uPos)) { m_uBytesSoFar = uPos; return true; } } return false; } template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("dcc"); } USERMODULEDEFS(CDCCMod, t_s("This module allows you to transfer files to and from ZNC")) znc-1.7.5/modules/clearbufferonmsg.cpp0000644000175000017500000001111413542151610020236 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include using std::vector; enum { RULE_MSG, RULE_CTCP, RULE_ACTION, RULE_NOTICE, RULE_PART, RULE_TOPIC, RULE_QUIT, RULE_MAX, }; class CClearBufferOnMsgMod : public CModule { public: MODCONSTRUCTOR(CClearBufferOnMsgMod) { SetAllRules(true); // false for backward compatibility m_bRules[RULE_QUIT] = false; } void ClearAllBuffers() { CIRCNetwork* pNetwork = GetNetwork(); if (pNetwork) { const vector& vChans = pNetwork->GetChans(); for (CChan* pChan : vChans) { // Skip detached channels, they weren't read yet if (pChan->IsDetached()) continue; pChan->ClearBuffer(); // We deny AutoClearChanBuffer on all channels since this module // doesn't make any sense with it pChan->SetAutoClearChanBuffer(false); } vector VQueries = pNetwork->GetQueries(); for (CQuery* pQuery : VQueries) { pNetwork->DelQuery(pQuery->GetName()); } // We deny AutoClearQueryBuffer since this module // doesn't make any sense with it GetUser()->SetAutoClearQueryBuffer(false); } } EModRet OnUserMsg(CString& sTarget, CString& sMessage) override { if (m_bRules[RULE_MSG]) ClearAllBuffers(); return CONTINUE; } EModRet OnUserCTCP(CString& sTarget, CString& sMessage) override { if (m_bRules[RULE_CTCP]) ClearAllBuffers(); return CONTINUE; } EModRet OnUserAction(CString& sTarget, CString& sMessage) override { if (m_bRules[RULE_ACTION]) ClearAllBuffers(); return CONTINUE; } EModRet OnUserNotice(CString& sTarget, CString& sMessage) override { if (m_bRules[RULE_NOTICE]) ClearAllBuffers(); return CONTINUE; } EModRet OnUserPart(CString& sChannel, CString& sMessage) override { if (m_bRules[RULE_PART]) ClearAllBuffers(); return CONTINUE; } EModRet OnUserTopic(CString& sChannel, CString& sTopic) override { if (m_bRules[RULE_TOPIC]) ClearAllBuffers(); return CONTINUE; } EModRet OnUserQuit(CString& sMessage) override { if (m_bRules[RULE_QUIT]) ClearAllBuffers(); return CONTINUE; } void SetAllRules(bool bVal) { for (int i = 0; i < RULE_MAX; i++) m_bRules[i] = bVal; } void SetRule(const CString& sOpt, bool bVal) { static const struct { CString sName; int Index; } Names[RULE_MAX] = { {"msg", RULE_MSG}, {"ctcp", RULE_CTCP}, {"action", RULE_ACTION}, {"notice", RULE_NOTICE}, {"part", RULE_PART}, {"topic", RULE_TOPIC}, {"quit", RULE_QUIT}, }; if (sOpt.Equals("all")) { SetAllRules(bVal); } else { for (int i = 0; i < RULE_MAX; i++) { if (sOpt.Equals(Names[i].sName)) m_bRules[Names[i].Index] = bVal; } } } bool OnLoad(const CString& sArgs, CString& sMessage) override { VCString vsOpts; sArgs.Split(" ", vsOpts, false); for (CString& sOpt : vsOpts) { if (sOpt.StartsWith("!")) SetRule(sOpt.substr(1), false); else if (!sOpt.empty()) SetRule(sOpt, true); } return true; } private: bool m_bRules[RULE_MAX]; }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("clearbufferonmsg"); Info.SetHasArgs(true); Info.SetArgsHelpText("[ [!] ]"); } USERMODULEDEFS(CClearBufferOnMsgMod, t_s("Clears all channel and query buffers " "whenever the user does something")) znc-1.7.5/modules/notify_connect.cpp0000644000175000017500000000312613542151610017737 0ustar somebodysomebody/* * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include class CNotifyConnectMod : public CModule { public: MODCONSTRUCTOR(CNotifyConnectMod) {} void OnClientLogin() override { NotifyAdmins(t_s("attached")); } void OnClientDisconnect() override { NotifyAdmins(t_s("detached")); } private: void SendAdmins(const CString& msg) { CZNC::Get().Broadcast(msg, true, nullptr, GetClient()); } void NotifyAdmins(const CString& event) { CString client = GetUser()->GetUserName(); if (GetClient()->GetIdentifier() != "") { client += "@"; client += GetClient()->GetIdentifier(); } CString ip = GetClient()->GetRemoteIP(); SendAdmins(t_f("{1} {2} from {3}")(client, event, ip)); } }; template <> void TModInfo(CModInfo& Info) { Info.SetWikiPage("notify_connect"); } GLOBALMODULEDEFS( CNotifyConnectMod, t_s("Notifies all admin users when a client connects or disconnects.")) znc-1.7.5/Doxyfile0000644000175000017500000022552613542151610014262 0ustar somebodysomebody# Doxyfile 1.8.1.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = ZNC # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = trunk # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = YES # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. MARKDOWN_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = include src third_party/Csocket # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # style sheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a color wheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of # entries shown in the various tree structured indices initially; the user # can expand and collapse entries dynamically later on. Doxygen will expand # the tree to such a level that at most the specified number of entries are # visible (unless a fully collapsed tree already exceeds this amount). # So setting the number of entries 1 will produce a full collapsed tree by # default. 0 is a special value representing an infinite number of entries # and will result in a full expanded tree by default. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see #
# Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. # However, it is strongly recommended to install a local # copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = HAVE_IPV6 \ HAVE_LIBSSL \ HAVE_LSTAT \ HAVE_PTHREAD \ HAVE_THREADED_DNS \ HAVE_ICU \ _NO_CSOCKET_NS \ _MODULES # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. For each # tag file the location of the external documentation should be added. The # format of a tag file without this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths # or URLs. Note that each tag file must have a unique name (where the name does # NOT include the path). If a tag file is not located in the directory in which # doxygen is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = FreeSans # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more # manageable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = YES # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES znc-1.7.5/Makefile.in0000644000175000017500000002333013542151642014613 0ustar somebodysomebodySHELL := @SHELL@ # Support out-of-tree builds srcdir := @srcdir@ VPATH := @srcdir@ prefix := @prefix@ exec_prefix := @exec_prefix@ datarootdir := @datarootdir@ bindir := @bindir@ datadir := @datadir@ sysconfdir := @sysconfdir@ libdir := @libdir@ includedir := @includedir@ sbindir := @sbindir@ localstatedir := @localstatedir@ systemdsystemunitdir := @systemdsystemunitdir@ CXX := @CXX@ CXXFLAGS := -I$(srcdir)/include -Iinclude @CPPFLAGS@ @CXXFLAGS@ LDFLAGS := @LDFLAGS@ LIBS := @LIBS@ LIBZNC := @LIBZNC@ LIBZNCDIR:= @LIBZNCDIR@ MODDIR := @MODDIR@ DATADIR := @DATADIR@ PKGCONFIGDIR := $(libdir)/pkgconfig INSTALL := @INSTALL@ INSTALL_PROGRAM := @INSTALL_PROGRAM@ INSTALL_SCRIPT := @INSTALL_SCRIPT@ INSTALL_DATA := @INSTALL_DATA@ GIT := @GIT@ SED := @SED@ GTEST_DIR := @GTEST_DIR@ GMOCK_DIR := @GMOCK_DIR@ ifeq "$(GTEST_DIR)" "" GTEST_DIR := $(srcdir)/third_party/googletest/googletest endif ifeq "$(GMOCK_DIR)" "" GMOCK_DIR := $(srcdir)/third_party/googletest/googlemock endif qt_CFLAGS := @qt_CFLAGS@ -fPIC -std=c++11 -pthread qt_LIBS := @qt_LIBS@ -pthread # Force the simple internal regex engine to get consistent behavior on all platforms. # See https://code.google.com/p/chromium/issues/detail?id=317224 for more details. GTEST_FLAGS := -DGTEST_HAS_POSIX_RE=0 -I$(GMOCK_DIR)/include -I$(GTEST_DIR)/include # Silence warnings about overload virtual Csock::Write(), and missing field # initializers in both gtest and gmock GTEST_FLAGS += -Wno-overloaded-virtual -Wno-missing-field-initializers LIB_SRCS := ZNCString.cpp Csocket.cpp znc.cpp IRCNetwork.cpp User.cpp IRCSock.cpp \ Client.cpp Chan.cpp Nick.cpp Server.cpp Modules.cpp MD5.cpp Buffer.cpp Utils.cpp \ FileUtils.cpp HTTPSock.cpp Template.cpp ClientCommand.cpp Socket.cpp SHA256.cpp \ WebModules.cpp Listener.cpp Config.cpp ZNCDebug.cpp Threads.cpp version.cpp Query.cpp \ SSLVerifyHost.cpp Message.cpp Translation.cpp LIB_SRCS := $(addprefix src/,$(LIB_SRCS)) BIN_SRCS := src/main.cpp LIB_OBJS := $(patsubst %cpp,%o,$(LIB_SRCS)) BIN_OBJS := $(patsubst %cpp,%o,$(BIN_SRCS)) TESTS := StringTest ConfigTest UtilsTest ThreadTest NickTest ClientTest NetworkTest \ MessageTest ModulesTest IRCSockTest QueryTest BufferTest UserTest TESTS := $(addprefix test/,$(addsuffix .o,$(TESTS))) CLEAN := znc src/*.o test/*.o core core.* .version_extra .depend modules/.depend \ unittest $(LIBZNC) DISTCLEAN := Makefile config.log config.status znc-buildmod include/znc/zncconfig.h \ modules/Makefile man/Makefile znc.pc znc-uninstalled.pc test/Makefile CXXFLAGS += -D_MODDIR_=\"$(MODDIR)\" -D_DATADIR_=\"$(DATADIR)\" ifneq "$(V)" "" VERBOSE=1 endif ifeq "$(VERBOSE)" "" Q=@ E=@echo C=-s else Q= E=@\# C= endif .PHONY: all man modules clean distclean install version_extra_recompile test .SECONDARY: all: znc man modules $(LIBZNC) @echo "" @echo " ZNC was successfully compiled." @echo " Use '$(MAKE) install' to install ZNC to '$(prefix)'." ifeq "$(LIBZNC)" "" OBJS := $(BIN_OBJS) $(LIB_OBJS) znc: $(OBJS) $(E) Linking znc... $(Q)$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) else znc: $(BIN_OBJS) $(LIBZNC) $(E) Linking znc... $(Q)$(CXX) $(LDFLAGS) -o $@ $(BIN_OBJS) -L. -lznc -Wl,-rpath,$(LIBZNCDIR) $(LIBS) $(LIBZNC): $(LIB_OBJS) $(E) Linking $(LIBZNC)... $(Q)$(CXX) $(LDFLAGS) -shared -o $@ $(LIB_OBJS) $(LIBS) -Wl,--out-implib=libznc.dll.a endif unittest: $(LIB_OBJS) test/gtest-all.o test/gmock-all.o test/gmock-main.o $(TESTS) $(E) Linking unit test... $(Q)$(CXX) $(LDFLAGS) -o $@ $(LIB_OBJS) test/gtest-all.o test/gmock-all.o test/gmock-main.o $(TESTS) $(LIBS) inttest: test/Integration.o test/Int-gtest-all.o test/Int-gmock-all.o $(E) Linking integration test... $(Q)g++ -std=c++11 -o $@ test/Integration.o test/Int-gtest-all.o test/Int-gmock-all.o $(LIBS) $(qt_LIBS) man: @$(MAKE) -C man $(C) modules: $(LIBZNC) include/znc/Csocket.h @$(MAKE) -C modules $(C) clean: rm -rf $(CLEAN) @$(MAKE) -C modules clean; @$(MAKE) -C man clean distclean: clean rm -rf $(DISTCLEAN) src/%.o: src/%.cpp Makefile include/znc/Csocket.h @mkdir -p .depend src $(E) Building core object $*... $(Q)$(CXX) $(CXXFLAGS) -c -o $@ $< -MD -MF .depend/$*.dep -MT $@ test/%.o: test/%.cpp Makefile include/znc/Csocket.h @mkdir -p .depend test $(E) Building test object $*... $(Q)$(CXX) $(CXXFLAGS) $(GTEST_FLAGS) -c -o $@ $< -MD -MF .depend/$*.test.dep -MT $@ test/gtest-all.o: $(GTEST_DIR)/src/gtest-all.cc Makefile @mkdir -p .depend test $(E) Building test object gtest-all... $(Q)$(CXX) $(CXXFLAGS) $(GTEST_FLAGS) -I$(GTEST_DIR) -c -o $@ $< -MD -MF .depend/gtest-all.dep -MT $@ test/gmock-all.o: $(GMOCK_DIR)/src/gmock-all.cc Makefile @mkdir -p .depend test $(E) Building test object gmock-all... $(Q)$(CXX) $(CXXFLAGS) $(GTEST_FLAGS) -I$(GMOCK_DIR) -c -o $@ $< -MD -MF .depend/gmock-all.dep -MT $@ test/gmock-main.o: $(GMOCK_DIR)/src/gmock_main.cc Makefile @mkdir -p .depend test $(E) Building test object gmock-main... $(Q)$(CXX) $(CXXFLAGS) $(GTEST_FLAGS) -c -o $@ $< -MD -MF .depend/gmock-main.dep -MT $@ # Qt fails under TSAN, so CXXFLAGS/LDFLAGS can't be used. test/Integration.o: test/integration/autoconf-all.cpp Makefile @mkdir -p .depend test $(E) Building test object Integration... $(Q)g++ $(qt_CFLAGS) $(GTEST_FLAGS) -I$(srcdir)/test/integration/framework -c -o $@ $< -MD -MF .depend/Integration.test.dep -MT $@ '-DZNC_BIN_DIR="$(bindir)"' '-DZNC_SRC_DIR="$(realpath $(srcdir))"' test/Int-gtest-all.o: $(GTEST_DIR)/src/gtest-all.cc Makefile @mkdir -p .depend test $(E) Building test object Int-gtest-all... $(Q)g++ $(qt_CFLAGS) $(GTEST_FLAGS) -I$(GTEST_DIR) -c -o $@ $< -MD -MF .depend/Int-gtest-all.dep -MT $@ test/Int-gmock-all.o: $(GMOCK_DIR)/src/gmock-all.cc Makefile @mkdir -p .depend test $(E) Building test object Int-gmock-all... $(Q)g++ $(qt_CFLAGS) $(GTEST_FLAGS) -I$(GMOCK_DIR) -c -o $@ $< -MD -MF .depend/Int-gmock-all.dep -MT $@ test/Int-gmock-main.o: $(GMOCK_DIR)/src/gmock_main.cc Makefile @mkdir -p .depend test $(E) Building test object Int-gmock-main... $(Q)g++ $(qt_CFLAGS) $(GTEST_FLAGS) -c -o $@ $< -MD -MF .depend/Int-gmock-main.dep -MT $@ ifneq "" "" # If git commit was changed since previous build, add a phony target to dependencies, forcing version.o to be recompiled # Nightlies have pregenerated version.cpp src/version.cpp: Makefile version.sh $(shell if [ x`cat .version_extra 2> /dev/null` != x`$(srcdir)/version.sh "$(GIT)" 3>&2 2> /dev/null` ]; then echo version_extra_recompile; fi) @mkdir -p .depend src $(E) Building source file version.cpp... $(Q)WRITE_OUTPUT=yes $(srcdir)/version.sh "$(GIT)" > .version_extra 2> /dev/null CLEAN += src/version.cpp endif CLEAN += src/Csocket.cpp include/znc/Csocket.h src/Csocket.cpp: third_party/Csocket/Csocket.cc @rm -f $@ @mkdir -p src @sed -e 's:#include "Csocket.h":#include :' $^ > $@ include/znc/Csocket.h: third_party/Csocket/Csocket.h @rm -f $@ @mkdir -p include/znc @sed -e 's:#include "defines.h":#include :' $^ > $@ third_party/Csocket/Csocket.h third_party/Csocket/Csocket.cc: @echo It looks like git submodules are not initialized. Run: git submodule update --init --recursive @exit 1 znc.service: znc.service.in @sed -e "s:\@CMAKE_INSTALL_FULL_BINDIR\@:$(bindir):" $^ > $@ CLEAN += znc.service install: znc znc.service $(LIBZNC) test -d $(DESTDIR)$(bindir) || $(INSTALL) -d $(DESTDIR)$(bindir) test -d $(DESTDIR)$(includedir)/znc || $(INSTALL) -d $(DESTDIR)$(includedir)/znc test -d $(DESTDIR)$(PKGCONFIGDIR) || $(INSTALL) -d $(DESTDIR)$(PKGCONFIGDIR) test -d $(DESTDIR)$(MODDIR) || $(INSTALL) -d $(DESTDIR)$(MODDIR) test -d $(DESTDIR)$(DATADIR) || $(INSTALL) -d $(DESTDIR)$(DATADIR) cp -R $(srcdir)/webskins $(DESTDIR)$(DATADIR) find $(DESTDIR)$(DATADIR)/webskins -type d -exec chmod 0755 '{}' \; find $(DESTDIR)$(DATADIR)/webskins -type f -exec chmod 0644 '{}' \; $(INSTALL_PROGRAM) znc $(DESTDIR)$(bindir) $(INSTALL_SCRIPT) znc-buildmod $(DESTDIR)$(bindir) $(INSTALL_DATA) $(srcdir)/include/znc/*.h $(DESTDIR)$(includedir)/znc $(INSTALL_DATA) include/znc/*.h $(DESTDIR)$(includedir)/znc $(INSTALL_DATA) znc.pc $(DESTDIR)$(PKGCONFIGDIR) @$(MAKE) -C modules install DESTDIR=$(DESTDIR); if test -n "$(LIBZNC)"; then \ test -d $(DESTDIR)$(LIBZNCDIR) || $(INSTALL) -d $(DESTDIR)$(LIBZNCDIR) || exit 1 ; \ $(INSTALL_PROGRAM) $(LIBZNC) $(DESTDIR)$(LIBZNCDIR) || exit 1 ; \ $(INSTALL_PROGRAM) libznc.dll.a $(DESTDIR)$(libdir) || exit 1 ; \ fi @$(MAKE) -C man install DESTDIR=$(DESTDIR) @HAVE_SYSTEMD_TRUE@test -d $(DESTDIR)$(systemdsystemunitdir) || $(INSTALL) -d $(DESTDIR)$(systemdsystemunitdir) @HAVE_SYSTEMD_TRUE@$(INSTALL_DATA) $(srcdir)/znc.service $(DESTDIR)$(systemdsystemunitdir) @echo "" @echo "******************************************************************" @echo " ZNC was successfully installed." @echo " You can use '$(bindir)/znc --makeconf'" @echo " to generate a config file." @echo "" @echo " If you need help with using ZNC, please visit our wiki at:" @echo " https://znc.in" uninstall: rm $(DESTDIR)$(bindir)/znc rm $(DESTDIR)$(bindir)/znc-buildmod rm $(DESTDIR)$(includedir)/znc/*.h rm $(DESTDIR)$(PKGCONFIGDIR)/znc.pc rm -rf $(DESTDIR)$(DATADIR)/webskins if test -n "$(LIBZNC)"; then \ rm $(DESTDIR)$(LIBZNCDIR)/$(LIBZNC) || exit 1 ; \ rmdir $(DESTDIR)$(LIBZNCDIR) || exit 1 ; \ fi @$(MAKE) -C man uninstall DESTDIR=$(DESTDIR) @if test -n "modules"; then \ $(MAKE) -C modules uninstall DESTDIR=$(DESTDIR); \ fi rmdir $(DESTDIR)$(bindir) rmdir $(DESTDIR)$(includedir)/znc rmdir $(DESTDIR)$(PKGCONFIGDIR) @echo "Successfully uninstalled, but empty directories were left behind" test: unittest $(Q)./unittest # This test uses files at /lib/znc, which is less than ideal, especially from build scripts of distros. # That's why it's a separate make target. test2: inttest $(Q)./inttest -include $(wildcard .depend/*.dep) znc-1.7.5/translations/0000755000175000017500000000000013542151610015261 5ustar somebodysomebodyznc-1.7.5/translations/es-ES0000644000175000017500000000002213542151610016112 0ustar somebodysomebodySelfName Español znc-1.7.5/translations/bg-BG0000644000175000017500000000003413542151610016057 0ustar somebodysomebodySelfName БългарÑки znc-1.7.5/translations/fr-FR0000644000175000017500000000002313542151610016113 0ustar somebodysomebodySelfName Français znc-1.7.5/translations/de-DE0000644000175000017500000000002113542151610016053 0ustar somebodysomebodySelfName Deutsch znc-1.7.5/translations/ru-RU0000644000175000017500000000003013542151610016147 0ustar somebodysomebodySelfName РуÑÑкий znc-1.7.5/translations/it-IT0000644000175000017500000000002213542151610016124 0ustar somebodysomebodySelfName Italiano znc-1.7.5/translations/id-ID0000644000175000017500000000002413542151610016066 0ustar somebodysomebodySelfName Indonesian znc-1.7.5/translations/nl-NL0000644000175000017500000000002413542151610016120 0ustar somebodysomebodySelfName Nederlands znc-1.7.5/ChangeLog.md0000644000175000017500000027655513542151610014735 0ustar somebodysomebody# ZNC 1.7.5 (2019-09-23) * modpython: Add support for Python 3.8 * modtcl: install .tcl files when building with CMake * nickserv: report success of Clear commands * Update translations, add Italian, Bulgarian, fix name of Dutch * Update error messages to be clearer * Add a deprecation warning to ./configure to use CMake instead in addition to an already existing warning in README # ZNC 1.7.4 (2019-06-19) ## Fixes * This is a security release to fix CVE-2019-12816 (remote code execution by existing non-admin users). Thanks to Jeriko One for the bugreport. * Send "Connected!" messages to client to the correct nick. # Internal * Increase znc-buildmod timeout in the test. # ZNC 1.7.3 (2019-03-30) ## Fixes This is a security release to fix CVE-2019-9917. Thanks to LunarBNC for the bugreport. ## New Docker only: the znc image now supports --user option of docker run. # ZNC 1.7.2 (2019-01-19) ## New * Add French translation * Update translations ## Fixes * Fix compilation without deprecated APIs in OpenSSL * Distinguish Channel CTCP Requests and Replies * admindebug: Enforce need of TTY to turn on debug mode * controlpanel: Add missing return to ListNetMods * webadmin: Fix adding the last allowed network ## Internal * Add more details to DNS error logs # ZNC 1.7.1 (2018-07-17) ## Security critical fixes * CVE-2018-14055: non-admin user could gain admin privileges and shell access by injecting values into znc.conf. * CVE-2018-14056: path traversal in HTTP handler via ../ in a web skin name. ## Core * Fix znc-buildmod to not hardcode the compiler used to build ZNC anymore in CMake build * Fix language selector. Russian and German were both not selectable. * Fix build without SSL support * Fix several broken strings * Stop spamming users about debug mode. This feature was added in 1.7.0, now reverted. ## New * Add partial Spanish, Indonesian, and Dutch translations ## Modules * adminlog: Log the error message again (regression of 1.7.0) * admindebug: New module, which allows admins to turn on/off --debug in runtime * flooddetach: Fix description of commands * modperl: Fix memory leak in NV handling * modperl: Fix functions which return VCString * modpython: Fix functions which return VCString * webadmin: Fix fancy CTCP replies editor for Firefox. It was showing the plain version even when JS is enabled ## Internal * Deprecate one of the overloads of CMessage::GetParams(), rename it to CMessage::GetParamsColon() * Don't throw from destructor in the integration test * Fix a warning with integration test / gmake / znc-buildmod interaction. # ZNC 1.7.0 (2018-05-01) ## New * Add CMake build. Minimum supported CMake version is 3.1. For now ZNC can be built with either CMake or autoconf. In future autoconf is going to be removed. * Currently `znc-buildmod` requires python if CMake was used; if that's a concern for you, please open a bug. * Increase minimum GCC version from 4.7 to 4.8. Minimum Clang version stays at 3.2. * Make ZNC UI translateable to different languages (only with CMake), add partial Russian and German translations. * If you want to translate ZNC to your language, please join https://crowdin.com/project/znc-bouncer * Configs written before ZNC 0.206 can't be read anymore * Implement IRCv3.2 capabilities `away-notify`, `account-notify`, `extended-join` * Implement IRCv3.2 capabilities `echo-message`, `cap-notify` on the "client side" * Update capability names as they are named in IRCv3.2: `znc.in/server-time-iso`→`server-time`, `znc.in/batch`→`batch`. Old names will continue working for a while, then will be removed in some future version. * Make ZNC request `server-time` from server when available * Increase accepted line length from 1024 to 2048 to give some space to message tags * Separate buffer size settings for channels and queries * Support separate `SSLKeyFile` and `SSLDHParamFile` configuration in addition to existing `SSLCertFile` * Add "AuthOnlyViaModule" global/user setting * Added pyeval module * Added stripcontrols module * Add new substitutions to ExpandString: `%empty%` and `%network%`. * Stop defaulting real name to "Got ZNC?" * Make the user aware that debug mode is enabled. * Added `ClearAllBuffers` command * Don't require CSRF token for POSTs if the request uses HTTP Basic auth. * Set `HttpOnly` and `SameSite=strict` for session cookies * Add SNI SSL client support * Add support for CIDR notation in allowed hosts list and in trusted proxy list * Add network-specific config for cert validation in addition to user-supplied fingerprints: `TrustAllCerts`, defaults to false, and `TrustPKI`, defaults to true. * Add `/attach` command for symmetry with `/detach`. Unlike `/join` it allows wildcards. * Timestamp format now supports sub-second precision with `%f`. Used in awaystore, listsockets, log modules and buffer playback when client doesn't support server-time * Build on macOS using ICU, Python, and OpenSSL from Homebrew, if available * Remove `--with-openssl=/path` option from ./configure. SSL is still supported and is still configurable ## Fixes * Revert tables to how they were in ZNC 1.4 * Remove flawed Add/Del/ListBindHost(s). They didn't correctly do what they were intended for, but users often confused them with the SetBindHost option. SetBindHost still works. * Fix disconnection issues when being behind NAT by decreasing the interval how often PING is sent and making it configurable via a setting to change ping timeout time * Change default flood rates to match RFC1459, prevent excess flood problems * Match channel names and hostmasks case-insensitively in autoattach, autocycle, autoop, autovoice, log, watch modules * Fix crash in shell module which happens if client disconnects at a wrong time * Decrease CPU usage when joining channels during startup or reconnect, add config write delay setting * Always send the users name in NOTICE when logging in. * Don't try to quit multiple times * Don't send PART to client which sent QUIT * Send failed logins to NOTICE instead of PRIVMSG * Stop creating files with odd permissions on Solaris * Save channel key on JOIN even if user was not on the channel yet * Stop buffering and echoing CTCP requests and responses to other clients with self-message, except for /me * Support discovery of tcl 8.6 during `./configure` ## Modules * adminlog: * Make path configurable * alias: * Add `Dump` command to copy your config between users * awaystore: * Add `-chans` option which records channel highlights * blockmotd: * Add `GetMotd` command * clearbufferonmsg: * Add options which events trigger clearation of buffers. * controlpanel: * Add the `DelServer` command. * Add `$user` and `$network` aliases for `$me` and `$net` respectively * Allow reseting channel-specific `AutoClearChanBuffer` and `BufferSize` settings by setting them to `-` * Change type of values from "double" to "number", which is more obvious for non-programmers * crypt: * Fix build with LibreSSL * Cover notices, actions and topics * Don't use the same or overlapping NickPrefix as StatusPrefix * Add DH1080 key exchange * Add Get/SetNickPrefix commands, hide the internal keyword from ListKeys * cyrusauth: * Improve UI * fail2ban: * Make timeout and attempts configurable, add BAN, UNBAN and LIST commands * flooddetach: * Detach on nick floods * keepnick: * Improve behaviour by listening to ircd-side numeric errors * log: * Add `-timestamp` option * Add options to hide joins, quits and nick changes. * Stop forcing username and network name to be lower case in filenames * Log user quit messages * missingmotd: * Include nick in IRC numeric 422 command, reduce client confusion * modperl: * Provide `operator ""` for `ZNC::String` * Honor `PERL5LIB` env var * Fix functions like `HasPerm()` which accept `char` * When a broken module couldn't be loaded, it couldn't be loaded anymore even if it was fixed later. * Force strings to UTF-8 in modperl to fix double encoding during concatenation/interpolation. * modpython: * Require ZNC to be built with encodings support * Disable legacy encoding mode when modpython is loaded. * Support `CQuery` and `CServer` * nickserv: * Use `/nickserv identify` by default instead of `/msg nickserv`. * Support messages from X3 services * notify_connect: * Show client identification * sasl: * Add web interface * Enable all known mechanisms by default * Make the first requirement for SET actually mandatory, return information about settings if no input for SET * schat: * Require explicit path to certificate. * simple_away: * Use ExpandString for away reason, rename old `%s` to `%awaytime%` * Add `MinClients` option * stickychan: * Save registry on every stick/unstick action, auto-save if channel key changes * Stop checking so often, increase delay to once every 3 minutes * webadmin: * Make server editor and CTCP replies editor more fancy, when JS is enabled * Make tables sortable. * Allow reseting chan buffer size by entering an empty value * Show per-network traffic info * Make the traffic info page visible for non-admins, non-admins can see only their traffic ## Internal * Stop pretending that ZNC ABI is stable, when it's not. Make module version checks more strict and prevent crashes when loading a module which are built for the wrong ZNC version. * Add an integration test * Various HTML changes * Introduce a CMessage class and its subclasses * Add module callbacks which accept CMessage, deprecate old callbacks * Add `OnNumericMessage` module callback, which previously was possible only with `OnRaw`, which could give unexpected results if the message has IRCv3.2 tags. * Modernize code to use more C++11 features * Various code cleanups * Fix CSS of `_default_` skin for Fingerprints section * Add `OnUserQuitMessage()` module hook. * Add `OnPrivBufferStarting()` and `OnPrivBufferEnding()` hooks * `CString::WildCmp()`: add an optional case-sensitivity argument * Do not call `OnAddUser()` hook during ZNC startup * Allow modules to override CSRF protection. * Rehash now reloads only global settings * Remove `CAP CLEAR` * Add `CChan::GetNetwork()` * `CUser`: add API for removing and clearing allowed hosts * `CZNC`: add missing SSL-related getters and setters * Add a possibility (not an "option") to disable launch after --makeconf * Move Unix signal processing to a dedicated thread. * Add clang-format configuration, switch tabs to spaces. * `CString::StripControls()`: Strip background colors when we reset foreground * Make chan modes and permissions to be char instead of unsigned char. ## Cosmetic * Alphabetically sort the modules we compile using autoconf/Makefile * Alphabetically sort output of `znc --help` * Change output during startup to be more compact * Show new server name when reconnecting to a different server with `/znc jump` * Hide passwords in listservers output * Filter out ZNC passwords in output of `znc -D` * Switch znc.in URLs to https # ZNC 1.6.6 (2018-03-05) * Fix use-after-free in `znc --makepem`. It was broken for a long time, but started segfaulting only now. This is a useability fix, not a security fix, because self-signed (or signed by a CA) certificates can be created without using `--makepem`, and then combined into znc.pem. * Fix build on Cygwin. # ZNC 1.6.5 (2017-03-12) ## Fixes * Fixed a regression of 1.6.4 which caused a crash in modperl/modpython. * Fixed the behavior of `verbose` command in the sasl module. # ZNC 1.6.4 (2016-12-10) ## Fixes * Fixed build with OpenSSL 1.1. * Fixed build on Cygwin. * Fixed a segfault after cloning a user. The bug was introduced in ZNC 1.6.0. * Fixed a segfault when deleting a user or network which is waiting for DNS during connection. The bug was introduced in ZNC 1.0. * Fixed a segfault which could be triggered using alias module. * Fixed an error in controlpanel module when setting the bindhost of another user. * Fixed route_replies to not cause client to disconnect by timeout. * Fixed compatibility with the Gitter IRC bridge. ## Internal * Fixed `OnInvite` for modpython and modperl. * Fixed external location of GoogleTest for `make test`. # ZNC 1.6.3 (2016-02-23) ## Core * New character encoding is now applied immediately, without reconnect. * Fixed build with LibreSSL. * Fixed error 404 when accessing the web UI with the configured URI prefix, but without the `/` in the end. * `znc-buildmod` now exits with non-zero exit code when the .cpp file is not found. * Fixed `znc-buildmod` on Cygwin. * ExpandString got expanded. It now expands `%znc%` to `ZNC - http://znc.in`, honoring the global "Hide version" setting. * Default quit message is switched from `ZNC - http://znc.in` to `%znc%`, which is the same, but "automatically" changes the shown version when ZNC gets upgraded. Before, the old version was recorded in the user's quit message, and stayed the same regardless of the current version of ZNC. ## Modules * modperl: * Fixed a memory leak. * sasl: * Added an option to show which mechanisms failed or succeeded. * webadmin: * Fixed an error message on invalid user settings to say what exactly was invalid. * No more autocomplete password in user settings. It led to an error when ZNC thought the user is going to change a password, but the passwords didn't match. # ZNC 1.6.2 (2015-11-15) ## Fixes * Fixed a use-after-delete in webadmin. It was already partially fixed in ZNC 1.4; since 1.4 it has been still possible to trigger, but much harder. * Fixed a startup failure when awaynick and simple_away were both loaded, and simple_away had arguments. * Fixed a build failure when using an ancient OpenSSL version. * Fixed a build failure when using OpenSSL which was built without SSLv3 support. * Bindhost was sometimes used as ident. * `CAP :END` wasn't parsed correctly, causing timeout during login for some clients. * Fixed channel keys if client joined several channels in single command. * Fixed memory leak when reading an invalid config. ## Modules * autovoice: * Check for autovoices when we are opped. * controlpanel: * Fixed `DelCTCPReply` case-insensitivity. * dcc: * Add missing return statement. It was harmless. * modpython: * Fixed a memory leak. * modules_online: * Wrong ident was used before. * stickychan: * Fixed to unstick inaccessible channels to avoid infinite join loops. ## Internal * Fixed the nick passed to `CModule::OnChanMsg()` so it has channel permissions set. * Fixed noisy `-Winconsistent-missing-override` compilation warnings. * Initialized some fields in constructors of modules before `OnLoad()`. ## Cosmetic * Various modules had commands with empty descriptions. * perform: * Say "number" instead of "nr". * route_replies: * Make the timeout error message more clear. # ZNC 1.6.1 (2015-08-04) ## Fixes * Fixed the problem that channels were no longer removed from the config despite of chansaver being loaded. * Fixed query buffer size for users who have the default channel buffer size set to 0. * Fixed a startup failure when simple_away was loaded after awaynick. * Fixed channel matching commands, such as DETACH, to be case insensitive. * Specified the required compiler versions in the configure script. * Fixed a rare conflict of HTTP-Basic auth and cookies. * Hid local IP address from the 404 page. * Fixed a build failure for users who have `-Werror=missing-declarations` in their `CXXFLAGS`. * Fixed `CXXFLAGS=-DVERSION_EXTRA="foo"` which is used by some distros to package ZNC. * Fixed `znc-buildmod` on Cygwin. ## Modules * chansaver: * Fixed random loading behavior due to an uninitialized member variable. * modpython: * Fixed access to `CUser::GetUserClients()` and `CUser::GetAllClients()`. * sasl: * Improved help texts for the SET and REQUIREAUTH commands. * savebuff: * Fixed periodical writes on the disk when the module is loaded after startup. * webadmin: * Fixed module checkboxes not to claim that all networks/users have loaded a module when there are no networks/users. * Added an explanation that ZNC was built without ICU support, when encoding settings are disabled for that reason. * Improved the breadcrumbs. * Mentioned ExpandString in CTCP replies. * Added an explanation how to delete port which is used to access webadmin. ## Internal * Fixed `CThreadPool` destructor to handle spurious wakeups. * Fixed `make distclean` to remove `zncconfig.h`. * Improved the error message about `--datadir`. * Fixed a compilation warning when `HAVE_LIBSSL` is not defined. * Fixed 'comparision' typos in CString documentation. * Added a non-minified version of the jQuery source code to make Linux distributions (Debian) happy, even though the jQuery license does not require this. # ZNC 1.6.0 (2015-02-12) ## New * Switch versioning scheme to ... * Add settings for which SSL/TLS protocols to use (SSLProtocols), which ciphers to enable (SSLCiphers). By default TLSv1+ are enabled, SSLv2/3 are disabled. Default ciphers are what Mozilla advices: https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 * Validate SSL certificates. * Allow clients to specify an ID as part of username (user[@identifier][/network]). Currently not used, but modules can use it. * Add alias module for ZNC-side command interception and processing. * Support character encodings with separate settings for networks, and for clients. It replaces older charset module, which didn't work well with webadmin, log and other modules. * Support X-Forwarded-For HTTP header, used with new TrustedProxy setting. * Add URIPrefix option for HTTP listeners, used with reverse proxy. * Store query buffers per query the same way it's done for channels, add new option AutoClearQueryBuffer. * Add DisableChan command to *status, it was available only in webadmin before. * Allow wildcards in arguments of Help commands of *status and various modules. * Support IRCv3.2 batches, used for buffer playbacks. * Support IRCv3.2 self-message. * Remove awaynick module. It's considered bad etiquette. * Add JoinDelay setting, which allows a delay between connection to server, and joining first channel. By default it joins immediately after connect. * Make Detach, EnableChan and DisableChan commands of *status accept multiple channels. * znc-buildmod: Build output to the current working directory. * Wrap long lines in tables (e.g. in Help or ListAvailMods commands). * Support ECDHE if available in OpenSSL. * Report ZNC version more consistently, add HideVersion setting, which hides ZNC version from public. * Bump compiler requirements to support C++11. This means GCC 4.7+, Clang 3.2+, SWIG 3.0.0+. ## Fixes * Disable TLS compression. * Disallow setting ConnectDelay to zero, don't hammer server with our failed connects. * Simplify --makeconf. * Fix logic to find an available nick when connecting to server. * Fix handling of CTCP flood. * Allow network specific quit messages. * Make various text labels gender-neutral. * Fix finding SWIG 3 on FreeBSD. * Handle multi-receiver NOTICE and PRIVMSG. * Make channels follow user-level settings when appropriate. * Write disabled status to config for disabled channels. * Fix double output in messages from modules. * Fix memory leak in gzip compression in HTTP server. * Use random DNS result instead of choosing the same one every time. * Fix HTTP basic auth. * Mention network in message shown if client didn't send PASS. ## Modules * autoattach: * Make it also a network module. * autoreply: * Use NOTICE instead of PRIVMSG. * autoop: * Add support for multiple hostmasks per user. * awaystore: * Store CTCP ACTIONs too. * Reset timer and return from away when a client does a CTCP ACTION. * Allows use of strftime formatting in away messages. * bouncedcc: * Fix quotes in file names. * Fix check for "Connected" state. * buffextras: * Make it also a network module. * chansaver: * Fix saving channel keys. * Add support for loading as a global module. * controlpanel: * Add AddChan, DelChan commands, useful for admins to edit other users' channels, was available only in webadmin before. * Check if adding a new channel succeeded. * Revise Help output. * Allow wildcards for GetChan and SetChan. * flooddetach: * Show current value in Lines and Secs commands. * Add Silent [yes|no] command, similar to route_replies. * listsockets: * Show traffic stats. * log: * Use only lower case characters in log filenames. * Use directories and YYYY-MM-DD filename by default. * Add support for logging rules. E.g. /msg *log setrules #znc !#* * modperl: * Fix some int_t types. * modpython: * Fix calling overloaded methods with parameter CString&. * Support CZNC::GetUserMap(). * Set has_args and args_help_text from module. * Release python/swig ownership when adding object created in python to ZNC container. * Fix some int_t types. * Enable default arguments feature of SWIG 3.0.4. No functionality change, it just makes generated code a bit more beautiful. * nickserv: * Support tddirc.net. * Remove commands Ghost, Recover, Release, Group. The same functionality is available via new alias module. * q: * Add JoinOnInvite, JoinAfterCloaked options. * Don't cloak host on first module load if already connected to IRC. * Add web configuration. * Use HMAC-SHA-256 instead of HMAC-MD5. * route_replies: * Handle numerics 307 and 379 in /whois reply. Handle IRCv3.2 METADATA numerics. * sample: * Make it a network module, which are easier to write. * sasl: * Remove DH-BLOWFISH and DH-AES. See http://nullroute.eu.org/~grawity/irc-sasl-dh.html and http://kaniini.dereferenced.org/2014/12/26/do-not-use-DH-AES-or-DH-BLOWFISH.html for details. * savebuff: * Do not skip channels with AutoClearChanBuffer=true. * Handle empty password in SetPass the same way as during startup. * simple_away: * Apply auto-away on load if no user is connected. * stickychan: * Don't join channels when not connected. * watch: * Add support for detached-only clients, and detached-only channels. * webadmin: * Combine "List Users" and "Add User". * Module argument autocomplete="off", for nickserv module, which contains password in argument before first save. * For every module show in which other levels that module is loaded (global/user/network). * Open links to wiki pages about modules in separate window/tab. * Support renaming a network (it was already possible outside of webadmin, via /znc MoveNetwork). However, it doesn't support moving networks between users yet, for that use /znc command. * Add missing page title on Traffic page. * Improve navigation: "Save and continue". * Clarify that timestamp format is useless with server-time. ## Internal * Move Csocket to git submodule. * Unit tests, via GTest. * Allow lambdas for module command callbacks. * New modules hooks: OnSendToClient, OnSendToIRC, OnJoining, OnMode2, OnChanBufferPlayLine2, OnPrivBufferPlayLine2. * Add methods to CString: StartsWith, EndsWith, Join, Find, Contains, and Convert. * Add limited support for using threads in modules: CModuleJob class. * Inherit CClient and CIRCSock from a common class CIRCSocket. * Add CZNC::CreateInstance to make porting ZNC to MSVC a bit easier. * Add CUtils::Get/SetMessageTags(). * Add CIRCNetwork::FindChans(). * Add CChan::SendBuffer(client, buffer) overload. * Add CIRCNetwork::LoadModule() helper. * Add CClient::IsPlaybackActive(). * Web: Discard sessions in LRU order. * Introduce CaseSensitivity enum class. * Fix CNick::Parse(). * Remove redundant CWebSocket::GetModule(). * Switch from CSmartPtr to std::shared_ptr. * Fix GetClients() const correctness. * Make self-signed cert with SHA-256, provide DH parameters in --makepem. * Use override keyword. * Show username of every http request in -D output. * Split CUserTimer into CIRCNetworkPingTimer and CIRCNetworkJoinTimer. * Give a reason for disabled features during ./configure, where it makes sense. * Use make-tarball.sh for nightlies too. * Revise CChan::JoinUser() & AttachUser(). * Modules: use public API. * Modules: use AddCommand(). * Add ChangeLog.md. # ZNC 1.4 (2014-05-08) This release is done to fix a denial of service attack through webadmin. After authentication, users can crash ZNC through a use-after-delete. Additionally, a number of fixes and nice, low-risk additions from our development branch is included. In detail, these are: ## New * Reduce users' confusion during --makeconf. * Warn people that making ZNC listen on port 6667 might cause problems with some web browsers. * Always generate a SSL certificate during --makeconf. * Stop asking for a bind host / listen host in --makeconf. People who don't want wildcard binds can configure this later. * Don't create ~/.znc/modules if it doesn't exist yet. ## Fixes * Fix a use-after-delete in webadmin. CVE-2014-9403 * Honor the BindHost whitelist when configuring BindHosts in controlpanel module. * Ignore trailing whitespace in /znc jump arguments. * Change formatting of startup messages so that we never overwrite part of a message when printing the result of an action. * Fix configure on non-bash shells. * Send the correct error for invalid CAP subcommands. * Make sure znc-buildmod includes zncconfig.h at the beginning of module code. ## Modules * Make awaystore automatically call the Ping command when the Back command is used. * Add SSL information and port number to servers in network list in webadmin. * Disable password autocompletion when editing users in webadmin. * Make nickserv module work on StarChat.net and ircline.org. * Remove accidental timeout for run commands in shell module. * certauth now uses a case insensitive comparison on hexadecimal fingerprints. ### controlpanel * Correct double output. * Add support for the MaxNetworks global setting. * Add support for the BindHost per-network setting. ### modperl and modpython * Make OnAddNetwork and OnDeleteNetwork module hooks work. * Don't create .pyc files during compilation. * Fix modperl on MacOS X. Twice. * Require at least SWIG 2.0.12 on MacOS X. ## Internal * Don't redefine _FORTIFY_SOURCE if compiler already defines it. * Cache list of available timezones instead of re-reading it whenever it is needed. * Improve const-correctness. * Fix various low-priority compiler warnings. * Change in-memory storage format for ServerThrottle. * Use native API on Win32 to replace a file with another file. * Add src/version.cpp to .gitignore. # ZNC 1.2 (2013-11-04) ## New * ZNC has been relicensed to Apache 2.0 * Show password block in --makepass in new format * Return MaxJoins setting, it helps against server sending ZNC too many lines at once and disconnecting with "Max SendQ exceeded" * Make /znc detach case insensitive, allow "/detach #chan1,#chan2" syntax * No longer store 381 in the buffer ## Fixes * CModule::OnMode(): Fix a stupid NULL pointer dereference * Fix NULL pointer dereference in webadmin. * Fix a crash when you delete a user with more than one attached client * Fix a random crash with module hooks * Revert "Rewrite the JOIN channel logic, dropping MaxJoins" * Fix build on some systems * Fix build of shallow git clone * Fix build of git tags * Fix OOT builds with swig files in source dir * Don't send NAMES and TOPIC for detached channels when a client connects * Fix memory leak * Consistency between Del* and Rem* in command names * Fix changing client nick when client connects. * Timezone GMT+N is really GMT+N now. It behaved like -N before. * Escape special characters in debug output (znc --debug) * Don't disconnect networkless users without PINGing them first. * Don't lose dlerror() message. * Fix use-after-free which may happen during shutdown * Fix "Error: Success" message in SSL * Fixed double forward slashes and incorrect active module highlighting. * make clean: Only delete files that can be regenerated * Don't make backup of znc.conf readable by everyone. * makepem: create pem only rw for the user, on non-win32 * Don't ever try to overwrite /usr/bin/git * Fix user modes * Request secure cookie transmission for HTTPS * "make clean" removes .depend/ * Fix support for /msg @#chan :hi * Fix saving config on some cygwin installations * Fix error message for invalid network name ## Modules * Return old fakeonline module (accidentally removed in 1.0) as modules_online * autoattach: add string searching * autocycle: Convert to a network module * chansaver: Fix chansaver to not rewrite the config each time a user joins a channel on startup * cert: Make default type of cert mod to be network. * watch: Don't handle multiple matching patterns for each target * route_replies: Add some WHOIS numerics * block_motd: Allow block_motd to be loaded per-network and globally * notify_connect: Fixed syntax on attach/detach messages to be more consistent * cyrusauth: Fix user creation ### controlpanel * Support network module manipulation * Increases general verbosity of command results. * Fix bug for "Disconnect" help * Standardize error wordings ### webadmin * Allow loading webadmin as user module. * Show instructions on how to use networks in Add Network too * clarify that + is SSL * Show example timezone in webadmin * Enable embedding network modules. * Enable embedding modules to network pages. * Change save network to show the network and not redirect user ### sasl * Implement DH-AES encrypted password scheme. * Add missing length check * Description line for DH-BLOWFISH * Fixing unaligned accesses ### awaystore * Fix loading old configs which referred to "away" module * Fix displaying IPv6 addresses ### crypt * Add time stamp to buffered messages * Use ASCII for nick prefix and make it configurable ### nickserv * Make NickServ nickname configurable. * Add support for NickServ on wenet.ru and Azzurra * nickserv: don't confuse people so much ### log * Add -sanitize option to log module. * Convert / and \ character to - in nicks for filenames. * Create files with the same permissions as the whole log directory. ### charset * Don't try to build charset module if iconv is not found * Fix: Converted raw string include NULL character in charset module ### modperl * A bit more debug output on modperl * Fix perl modules being shown incorrectly in the webadmin ### partyline * Fix PartyLine so that forced channels may not be left at all - users will be rejoined at once. * Fix partyline rejoin on user deletion ## Internal * Require SWIG 2.0.8 for modperl/modpython (removes hacks to make older SWIG work) * Web interface now supports gzip compression * Update server-time to new specs with ISO 8601 * Add a generic threads abstraction * Add CString::StripControls to strip controls (Colors, C0) from strings * Change PutModule to handle multiple lines * Debug output: Only print queued lines if they are really just queued * Add initial unit tests, runnable by "make test" * Add nick comparison function CNick::NickEquals * Force including zncconfig.h at the beginning of every .cpp * Add OnAddNetwork, OnDeleteNetwork module hooks # ZNC 1.0 (2012-11-07) ## The Big News Multiple networks per user Think about new users as "user groups", while new networks are similar to old users. To login to ZNC, use user/network:password as password, or user/network as username. Also, you can switch between different networks on the fly using the /znc JumpNetwork command. When you first run ZNC 1.0, it will automatically convert your config and create a network called "default" for each user. Settings from each user are moved into these "default" networks. When you log into ZNC without setting a network, the "default" network will automatically be chosen for you. Users can create new networks up to an admin-configurable limit. By default, this limit is one network per user. Existing user-per-network setups can be migrated to the new multinetwork setup using the /znc MoveNetwork command. You can see a list of networks via /znc ListNetworks and /znc ListAllUserNetworks. ## Timezones Timezone can now be configured by name, e.g. "GMT-9", or "Europe/Madrid". Old TimezoneOffset setting (which was the number of hours between the server's timezone and the user's timezone) is deprecated and should not be used anymore. Its old value is lost. The reason for this change is that the old TimezoneOffset was not trivial to count and often broke during switches to/from daylight savings time. So if you previously used the TimezoneOffset option, you now have to configure your timezone again (via the webadmin or controlpanel module). ## No more ZNC-Extra Most modules from ZNC-Extra are now enabled in the usual installation. It was pointless to have them shipped in the tarball, but requiring user to add some weird flags to ./configure. Antiidle, fakeonline and motdfile modules are dropped. Away module is renamed to awaystore to better explain its meaning. ## Fixes * Don't try IPv6 servers when IPv6 isn't available. Use threads for non-blocking DNS instead of c-ares. * Fix debug output of identfile. * Don't forward WHO replies with multi-prefix to clients which don't support multi-prefix * Send nick changes to clients before we call the OnNick module hook * Don't connect to SSLed IRC servers when ZNC is compiled without SSL support * Fix check for visibility support in the compiler * Fix compilation on cygwin again, including modperl and modpython * Support parting several channels at once * Fix a crash in admin (now controlpanel) module * Fix webadmin to deny setting a bindhost that is not on the global list of allowed bindhosts. * Fix using empty value for defaults in user page in webadmin. ## Minor Stuff * Rename admin module to controlpanel to make it clearer that it's not the same as admin flag of a user. * Add protection from flood. If you send multiple lines at once, they will be slowed down, so that the server will not disconnect ZNC due to flood. It can be configured and can be completely turned off. Default settings are: 1 line per second, first 4 lines are sent at once. * Modules can support several types now: a module can be loaded as a user module, as a network module and as a global module, if the module supports these types. * Rename (non-)KeepBuffer to AutoClearChanBuffer * Process starttls numeric * Improvements to modperl, modpython, modtcl. * Add timestamps to znc --debug * Listeners editor in webadmin * Add sasl module which uses SASL to authenticate to NickServ. * Rename saslauth to cyrusauth, to make it clearer that it's not needed to do SASL authentication to NickServ. * Modules get a way to describe their arguments. * webadmin: allow editing of the bindhost without global list. * Don't send our password required notice until after CAP negotiation * Rewrite the JOIN channel logic, dropping MaxJoins * Support messages directed to specific user prefixes (like /msg @#channel Hello) * Show link to http://znc.in/ from web as a link. It was plain text before. * Webadmin: use HTML5 numeric inputs for numbers. * Add SSL/IPv6/DNS info to znc --version * Clarify that only admins can load the shell module. * cyrusauth: Allow creating new users on first login * Clear channel buffers when keep buffer is disabled if we're online * send_raw: Add a command to send a line to the current client * webadmin: Implement clone user * autoreply: Honor RFC 2812. * Add 381 to the buffer ("You are now an IRC Operator") * identfile: Pause the connection queue while we have a locked file * Add ShowBindHost command * autoop: Check for autoops when we get op status * Improvements and fixes to the partyline module * partyline Drop support for fixed channels * Check that there're modules available on startup. Check if ZNC is installed or not. * Modified description field for bouncedcc module to explain what the module actually does. * nickserv: add support for nickserv requests on wenet.ru and rusnet. * send 422 event if MOTD buffer is empty * route_replies: Handle much more replies * Clear text colors before appending timestamps to buffer lines, add space before AppendTimestamp for colorless lines. * Don't replace our motd with a different servers motd * webadmin: Add a "Disabled" checkbox for channels * Send a 464 ERR_PASSWDMISMATCH to clients that did not supply a password * Separate compilation and linking for modules. * Trim spaces from end of commands to autoattach. * nickserv: add ghost, recover and release * Warn if config was saved in a newer ZNC version. * Backup znc.conf when upgrading ZNC. ## Internal Stuff * #include instead of #include "...h" * Add string formatting function with named params. * Python, perl: support global, user, network modules. * Csock: able use non-int number of secs for timer. * CString("off").ToBool() shouldn't be true * Python: Override __eq__ to allow comparison of strings * python: Allow iterating over CModules * Add methods to CModule to get the web path * Rework modperl to better integrate with perl. * Store all 005 values in a map. * Python: Use znc.Socket if no socket class is specified in CreateSocket() * CZNC::WriteConfig(): Better --debug output * Slight refactor of CBuffer & CBufLine. * Implemented an OnInvite hook * Allow a client to become "away" * Create a connection queue * Set default TrimPrefix to ":" * Add a config writer * Wrap MODULECALL macros in a do-while * Don't require CTimer's label to be unique if its empty * Allow loading python modules with modpython (ex. modname/__init__.py) * bNoChange in On{,De}{Op,Voice} wast incorrect * Drop znc-config, change znc-buildmod so it doesn't need znc-config # ZNC 0.206 (2012-04-05) ## Fixes * Identfile: don't crash when ZNC is shutting down. * CTCPReplies setting with empty value now blocks those CTCP requests to the client. * Show more sane error messages instead of "Error: Success". * Imapauth: Follow RFC more closely. * "No" is a false value too. ## Minor stuff * Add Show command to identfile, which should help you understand what's going on, if identfile is blocking every connection attempt for some reason. * Make TLS certs valid for 10 years. * Ask for port > 1024 in --makeconf. * Reset JoinTries counter when we enable a channel. # ZNC 0.204 (2012-01-22) This release fixes CVE-2012-0033, http://www.openwall.com/lists/oss-security/2012/01/08/2 https://bugs.gentoo.org/show_bug.cgi?id=CVE-2012-0033 https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2012-0033 ## Fixes * Fix a crash in bouncedcc module with DCC RESUME. * Fix modperl compilation. * Don't use mkdir during install. * Fix compilation failures, which happened sometimes when an older ZNC was already installed. * Check for the swig2.0 binary too, instead of only swig. ## Minor stuff * Unload modules in reverse order. * Don't send server redirects (numeric 010) to clients. * Make it possible to filter the result of the help command. * Drop @DEFS@ from the build system so that we don't force HAVE_CONFIG_H upon others. * Move autocycle to extra. * Handle raw 482 in route_replies. * Improve identfile's debug messages. * Send a MODE request when JOINing. * Block raw 301 in antiidle. # ZNC 0.202 (2011-09-21) This is a bugfix-mostly release. ## Fixes * Fix a crash when a user changes the buffer size of a channel. * Fix a NULL pointer dereference in buffer-related module hooks. * Fix the autocycle module to not fight with ChanServ. * Fix the getchan command in the admin module. * Don't timeout bouncedcc connections so that idling DCC chats are possible. * Fix build error when compiling against uclibc(++). ## Minor stuff * Improve the timeout message in the route_replies module. * Add the -r parameter to the man page of ZNC. * Install .py files along with .pyc. # ZNC 0.200 (2011-08-20) ## The Big News * Move ident spoofing from ZNC core into new identfile module. * Move dcc handling from ZNC core into new modules bouncedcc and dcc. * Remove the obsolete fixfreenode module. * New module: cert * Move away into ZNC-Extra. ## Fixes * In ZNC 0.098 there was a memleak whenever someone JOINs a channel. * Compile even when OpenSSL was built with no-ssl2. * Correctly handle excessive web sessions. * Correctly save non-ASCII characters to the NV. * Fix znc-buildmod when ZNC was compiled out of tree. * Don't always use IPv6 when verifying the listener in --makeconf. ## Minor Things * Remove a pointless MODE request which ZNC sent on every JOIN. * Raise ZNC's timeouts. * Log's logging path becomes configurable. * Add a replay command to away. * Add a get command to notes. * Add -disableNotesOnLogin argument to notes. * Add hostmask handling to autoattach. * Make it possible for modules to provide additional info, e.g. providing a homepage URL. * Various improvements to modpython. * Hardcode a default entry for the CN in znc --makepem. * Work around Mac OS' and Solaris' brokenness. * Make ZNC compile without getopt_long(). This fixes compilation on e.g. Solaris 9 and hopefully Irix. * Check for errors like "no space left on disk" while writing the config file. * Improve the error handling when reading the config. * Move module data files to own directory in the source and in installation prefix. * Handle Listeners after SSLCertFile during startup. * Check for required SWIG version in ./configure. * Make it possible to use ExpandString-stuff in QuitMsg. * znc-buildmod: Print ZNC's version number. * Add config option ProtectWebSessions which makes it possible to disable the IP check for web sessions. ## Internal Stuff * Build modules with hidden symbol visibility. * Clean up includes. This might break external modules. * New CModCommand for simplifiying module commands. * Add the OnIRCConnectionError(CIRCSock *pIRCSock) module hook * Remove config-related module hooks. * Fix CString::Escape_n() * Make the CUser::IsIRCConnected method check if ZNC already successfully logged in to IRC. * and more... # ZNC 0.098 (2011-03-28) ## New stuff * Add a list of features to the output of /znc version. (cce5824) * Add modpython. (a564e2) (88c84ef) (1854e1) (9745dcb) (644632) (4c6d52c) (b7700fe) (0f2265c) * Verify during --makeconf that the specified listener works. (11ffe9d) * Add TimestampFormat and StatusPrefix settings to admin. (853ddc5) * Add DCCBindHost, channel keys and some more to webadmin. (570fab6) (eb26386) (1e0585c) * Add a web interface to listsockets. (144cdf) * Add a web interface to perform. (c8910c) (89edf703) (ba183e46) * Don't reply to CTCP floods. (142eeb) * Accept wildcards for /znc DetachChan, EnableChan, ClearBuffer and SetBuffer. (e66b24) * Added reconnect and disconnect commands to admin. (65ae83) * Moved from SourceForge to GitHub. (daa610) (ed17804) (86c0e97) (e6bff0c) (087f01) * Don't force --foreground when compiling with --enable-debug. (778449) (fbd8d6) * Add functions for managing CTCPReplies to admin. (3f0e200) * Allow omitting user names with some commands in admin. (4faad67) * Some fixed with ISpoofFile and SSLCertFile paths which use "~". (cd7822) (f69aeff) (ce10cee) ## Fixes * Send more than a single channel per JOIN command. (3327a97) (6a1d27) * Properly unload perl modules so that their code is reread on next load. (ce45917) * Make certauth remember its module list across restarts again. (451b7e32) * Ignore dereferenced sockets in listsockets. (50b57b) * Fix a cross-compilation problem in configure. (d9b4ba1) * Bind web sessions to IP addresses. (577a097) (4556cc) * Limit the number of web sessions per IP. (913a3c8) (bf6dc45) * Build on cygwin again. (37b70a) * Allow admins to ignore MaxBufferSize in webadmin. (b37e23) * Fix some compiler warning generated by clang. (c7c12f0) * Call modules for mode-changes done by not-in-channel nicks. (a53306) * Fix installation with checkinstall and the permissions of some static data. (4c7808) (3d3235) ## Minor stuff * Properly report errors in admin's addserver command. (ed924cb) * Improvements of modperl. (1baa019) (12b1cf6) (7237b9) (ece2c88) * Check for modperl that we have at least Perl 5.10. (0bc606) * Verify in configure that tcl actually works. (89bd527) * Add a warning header to znc.conf that warns about editing the file. (2472ea) (8cadb6) * Improve the ISpoof debug output. (128af8e) * Improve HTTP client-side caching for static files. (9ef41ae) (4e5f9e8) * Removed all generated/copied scripts from the repo. (fde73c60) (9574d6) (e2ce2cf) (5a6a7b) * Only allow admins to use email. (81c864) * Make clearbufferonmsg clear the buffer a little less often. (ddd302fbf) * Make the output from /znc help smaller. (0d928c) * Add a web interface to send_raw. (d8b181) (a93a586) ## Internal stuff * Some optimizations with lots of users and channels. (b359f) (5e070e) * Various changes to the Makefiles. (33e1ccc) (0ad5cf) (df3409) (e17348c) (936b43) (18234a) (0cc8beb) (d21a1be) (517307b) (40632f) (afa16df) (4be0572) (452e3f) (9fec8f) (f76f1e7) (6b396f) * Added a third argument to the OnPart module hook. (a0c0b7) (1d10335) (e4b48d5) * Added vim modelines to some files. (dc8a39) * Added an auto-generated zncconfig.h (8a1c2a4) (aeeb1eb3) (f4927709) (40a1bb) (3ecbf13) (87037f) (b6c8e1) * Update to latest Csocket. (cc552f) * Handle paths like "~/foo" in CFile. (cb2e50a) * Add some generic interface for module commands. (ebd7e53) (8e59fb9) (31bbffa) * CUser::m_sUserName was made const. (d44e590) # ZNC 0.096 (2010-11-06) ## New stuff * Added a new module: clearbufferonmsg. (r2107) (r2151) * Added an optional server name argument to /znc jump. (r2109) * Big overhaul for modperl. (r2119) (r2120) (r2122) (r2123) (r2125) (r2127) (r2133) (r2136) (r2138) (r2140) (r2142) (r2143) (r2144) (r2146) (r2147) (r2156) (r2160) * Modules can now directly influence other modules' web pages. (r2128) (r2129) (r2130) (r2131) (r2132) (r2134) (r2135) ## Fixes * The route_replies module now handles "354" who replies. (r2112) * Fixed a bogus "invalid password" error during login with some clients. (r2117) * Reject long input lines on incoming connections. (r2124) * The lastseen module should only link to webadmin if the latter is loaded. (r2126) * Fixed cases where HTTP requests were incorrectly dropped. (r2148) (r2149) * Fixed partyline to work with servers that don't send a 005 CHANTYPES. (r2162) * Fixed error message from configure if dlopen() isn't found. (r2166) ## Minor stuff * Renamed "vhost" to "bindhost" to better describe what the option does. (r2113) * Honor timezone offset in the simple_away module. (r2114) * Load global modules as soon as their config line is read. (r2118) * Use poll() instead of select() by default. (r2153) (r2165) * Ignore the channel key "*" in the chansaver module. (r2155) ## Internal stuff * Fixed some function prototypes. (r2108) * Rearranged ZNC's CAP handling to IRCds. (r2137) * Added more doxygen comments. (r2139) (r2145) (r2150) (r2152) (r2154) (r2157) * Removed some useless typedefs. (r2158) * Clean up the lastseen module. (r2163) (r2164) # ZNC 0.094 (2010-08-20) ## New stuff * Add new global setting MaxBufferSize instead of hardcoding a value. (r2020) (r2025) * Support CAP. (r2022) (r2024) (r2027) (r2041) (r2048) (r2070) (r2071) (r2097) (r2098) (r2099) (r2100) * Add new module certauth which works similar to certfp. (r2029) * route_replies now also supports routing channel ban lists, ban exemptions and invite exceptions. (r2035) * Add a -nostore flag to the away module. (r2044) * Add a new config option SSLCertFile. (r2086) (r2088) ## Fixes * Fix configure to automatically disable modperl if perl is not found. (r2017) * Include the port number in cookie names to make them unique across different znc instances on the same box. (r2030) * Make sure that we have at least c-ares 1.5.0. (r2055) * Make znc work on solaris. (r2064) (r2065) (r2067) (r2068) * Improve configure's and make's output. (r2079) (r2080) (r2094) (r2101) * Complain about truncated config files. (r2083) * Fix some std::out_of_range error triggerable by people with a valid login. (r2087) (r2093) (r2095) * Make fakeonline behave while we are not connected to an IRC server. (r2091) * Always attach to channels when joining them. (r2092) * Fix a NULL pointer dereference in route_replies. (r2102) (r2103) ## Minor stuff * Allow leading and trailing spaces in config entries. (r2010) * Various minor changes. (r2012) (r2014) (r2021) * Use pkg-config for finding openssl, if it's available. We still fall back to the old code if this fails. (r2018) * znc no longer accepts an alternative file name for znc.conf as its argument. (r2037) * Generate correct HTTP status codes in webmods and make sure this doesn't happen again. (r2039) (r2040) * Rewrite our PING/PONG handling. (r2043) * Raise the size of the query buffer to 250. (r2089) * Update to latest Csocket. (r2096) ## Internal stuff * Remove the fake module usage in WebMods. (r2011) * Remove fake modules completely. (r2012) (r2015) * Make CTable more robust. (r2031) * Move the OnKick() module call so it is issued when the nick still is visible in the channel. (r2038) * Remove CZNC::GetUser() since CZNC::FindUser() does the same. (r2046) * Minor changes to webmod skins. (r2061) (r2062) * Add new macros GLOBALMODULECALL and ALLMODULECALL. (r2074) (r2075) (r2076) * Remove a bogus CClient* argument from some module calls. (r2077) * Mark some functions as const. (r2081) (r2082) (r2084) (r2085) # ZNC 0.092 (2010-07-03) This is a bugfix-only release, mainly for fixing CVE-2010-2488. ## Fixes * ZNC wrongly counted outgoing connections towards the AnonIPLimit config option. (r2050) * The traffic stats caused a NULL pointer dereference if there were any unauthenticated connections. CVE-2010-2488 (r2051) * Csocket had a bug where a wrong error message was generated and one that caused busy loops with c-ares. (r2053) # ZNC 0.090 (2010-06-06) ## Upgrading from previous versions ## Errors during start-up The shell, email and imapauth modules have been moved from the regular module set to the "extra" set, you have to use --enable-extra with ./configure to compile them. So, to fix these errors, edit the znc.conf file in ~/.znc/configs and don't load those modules, or recompile znc with extra. ### WebMods While previously only the "webadmin" provided an HTTP server/interface, the HTTP server is now integrated into ZNC's core. This means that all modules (not only webadmin) can now provide web pages. Examples shipping with ZNC are lastseen, stickychan and notes. Old-style module arguments to webadmin will be automatically converted to the new syntax. Please note that the WebMods interface uses session cookies instead of 'Basic' HTTP authentication. All URLs to webadmin's settings pages have changed. Please adjust your scripts etc. if necessary. ### Running without installing If you want to run ZNC without doing make install, i.e. if you want to run it from the source dir, you will have to add --enable-run-from-source as an argument to ./configure. You do not have to care about this if you use a --prefix= or if you install ZNC system-wide. ### I upgraded and WebAdmin/WebMods is acting weird, Log Out does not work. Starting with 0.090, ZNC uses cookies instead of HTTP Basic authentication. If your browser is still sending the Basic credentials to ZNC, e.g. because you have saved them in a bookmark, or password manager, or simply haven't restarted your browser in a while, those will continue to work, even after you click the Log Out button. To fix this, remove any user:pass@host portions from your bookmarks, remove all entries for ZNC's web interface from your password manager, and restart your browser. ## New stuff * Webmods - Every module can now provide its own webpages. (r1784) (r1785) (r1787) (r1788) (r1789) (r1790) (r1791) (r1792) (r1793) (r1795) (r1796) (r1797) (r1800) (r1801) (r1802) (r1804) (r1805) (r1806) (r1824) (r1825) (r1826) (r1827) (r1843) (r1844) (r1868) (r1886) (r1888) (r1915) (r1916) (r1931) (r1934) (r1870) (r1871) (r1872) (r1873) (r1874) (r1875) (r1876) (r1879) (r1887) (r1891) (r1967) (r1982) (r1984) (r1996) (r1997) (r2000) (r2002) (r2003) * Webmods and thus webadmin now use cookies for managing sessions instead of HTTP authentication. (r1799) (r1819) (r1823) (r1839) (r1840) (r1857) (r1858) (r1859) (r1861) (r1862) * WebMod-enabled lastseen, stickychan modules. (r1880) (r1881) (r1889) (r1918) * Partyline now also handles notices, /me and CTCP. (r1758) * Partyline now saves channel topics across restarts. (r1898) (r1901) * Added a "number of channels" column to /znc listusers. (r1769) * Added an optional user name argument to /znc listchans. (r1770) * Support for the general CAP protocol and the multi-prefix and userhost-in-names caps on connections to the IRC server. (r1812) * ZNC can now listen on IPv4-only, IPv6-only or on both-IP sockets. Renamed "Listen" config option to "Listener". (r1816) (r1817) (r1977) * Added LoadModule, UnLoadModule, ListMods commands to the Admin module. (r1845) (r1864) * Added ability to set/get TimezoneOffset to the Admin module. (r1906) * Added "Connect to IRC + automatically re-connect" checkbox to webadmin. (r1851) * Remember "automatically connect + reconnect" flag across restarts by writing it to the config file. (r1852) * Added AddPort, DelPort, ListPorts command to *status. (r1899) (r1913) * Added optional quit message argument to disconnect command. (r1926) * Added new charset module to extra. (r1942) (r1947) (r1977) (r1985) (r1994) * Added a traffic info page to webadmin. (r1958) (r1959) ## Fixes * Don't let ZNC connect to itself. (r1760) * Added a missing error message to /znc updatemod. (r1772) * Generate cryptographically stronger certificates in --makepem. (r1774) * Autoattach now triggers on channel actions. (r1778) * --disable-tcl now really disables TCL instead of enabling it. (r1782) * User name comparison in blockuser is now case-sensitive. (r1786) * Fixed /names when route_replies is loaded. (r1811) * autoreply now ignores messages from self. (r1828) * Don't forward our own QUIT messages to clients. (r1860) * Do not create empty directories if one does ./znc --datadir=NON_EXISTING_DIR. (r1878) * Query to Raw send the command to IRC instead of to the client. (r1892) * Fixed desync in Partyline after addfixchan or delfixchan. (r1904) * Save passwords for Nickserv module as NV instead of keeping them as arguments. (r1914) * CSRF Protection. (r1932) (r1933) (r1935) (r1936) (r1938) (r1940) (r1944) * Fixed a rare configure failure with modperl. (r1946) * disconkick now only sends kicks for channels the client actually joined. (r1952) * More sanity checks while rewriting znc.conf. (r1962) * Fixed static compilation with libcrypto which needs libdl by checking for libdl earlier. (r1969) * Fixed modtcl with newer tcl versions. (r1970) * Better error message if pkg-config is not found. (r1983) * Fixed a possible race condition in autoop which could cause bogous "invalid password" messages. (r1998) ## Minor stuff * Fixed a memory leak and some coding style thanks to cppcheck. (r1761) (r1762) (r1763) (r1764) (r1776) (r1777) * Updated to latest Csocket. (r1766) (r1767) (r1814) (r1905) (r1930) * Cleanup to /znc help. (r1771) * Removed --disable-modules. Modules are now always enabled. (r1794) (r1829) * saslauth: Error out "better" on invalid module arguments. (r1809) * Changed the default ConnectDelay from 30s to 5s. (r1822) * Misc style/skin fixes to webadmin/webmods. (r1853) (r1854) (r1856) (r1883) (r1884) (r1885) (r1890) (r1900) (r1907) (r1908) (r1909) (r1911) (r1912) (r1917) (r1945) (r2005) * Do not expose ZNC's version number through the web interface unless there's an active user session. (r1877) * Updated AUTHORS file. (r1902) (r1910) (r1999) * Moved some modules into/out of extra. (r1919) (r1922) (r1923) * Added ./configure --enable-run-from-script, without it ZNC will no longer look for modules in ./modules/. (r1927) (r1928) (r2001) * Made a dedicated page to confirm user deletion in webadmin. (r1937) (r1939) (r1941) (r1943) * Use spaces for separating ip addresses from ports. (r1955) * ZNC's built-in MOTD now goes through ExpandString. (r1956) * Check for root before generating a new config file. (r1988) * Added a flag for adding irc-only / http-only ports via /znc addport. (r1990) (r1992) ## Internal stuff * Minor cleanup to various places. (r1757) (r1759) (r1846) (r1847) (r1863) (r1865) (r1920) (r1921) (r2004) * Changes in configure. (r1893) (r1894) (r1895) (r1896) (r1897) * Flakes messed with the version number. (r1768) * CString::Split() now Trim()s values before pushing them if bTrimWhiteSpace is true. (r1798) * Added new module hooks for config entries. (r1803) (r1848) (r1849) (r1850) * New module hook OnAddUser(). (r1820) (r1821) * Cleanup to ISUPPORT parser. (r1807) * Use Split() instead of Token() where possible. (r1808) * Modularize CIRCSock::ForwardRaw353(). (r1810) * Use a better seed for srand(). (r1813) * Changes to debug output. (r1815) (r1836) (r1837) (r1855) (r1882) * Support for delayed HTTP request processing. (r1830) (r1833) (r1834) (r1835) (r1838) (r1841) (r1842) * Fixed CSmartPtr's operator==. (r1818) * Better port/listener management exposed through CZNC. (r1866) (r1867) * Move CListener and CRealListener into their own files. (r1924) * Move the HTTP/IRC switching to CIncomingConnection. (r1925) * Add IsIRCAway() to CUser. (r1903) * Move some common pid file code into new InitPidFile(). (r1929) * Templates can now sort loops based on a key. (r1948) (r1949) (r1951) (r1953) (r1954) * A lot of work went into this release, we would like to thank everyone who contributed code, helped testing or provided feedback. # ZNC 0.080 (2010-02-18) ## New stuff * Update to latest Csocket. (r1682) (r1727) (r1735) (r1751) (r1752) (r1753) * Only allow admins to load modtcl unless -DMOD_MODTCL_ALLOW_EVERYONE is used. (r1684) * Include /me's in the query buffer. (r1687) * Some tweaks to savebuff to differentiate it more from buffextras. (r1691) (r1692) * send_raw can now also send to clients. (r1697) * Move the "Another client authenticated as you"-message into new module clientnotify. (r1698) * Imported block_motd module into extra. (r1700) * Imported flooddetach into extra. (r1701) (r1717) * Added new setting ServerThrottle which sets a timeout between connections to the same server. (r1702) (r1705) * Only ask for the more common modules in --makeconf. (r1706) * Use UTF-8 as default charset for webadmin. (r1716) * Revamped default webadmin skin. It's very grayish, but looks way more like 2010 than the old default skin does. (r1720) * New font style for the "ice" webadmin skin. (r1721) * Added a summary line to /znc listchans. (r1729) * The admin module can now handle more settings and got some missing permission checks added. (r1743) (r1744) (r1745) (r1746) (r1747) ## Fixes * Apply new ConnectDelay settings immediately after a rehash. (r1679) * Do a clean shutdown just before a restart. (r1681) * Fix a theoretical crash in modtcl. (r1685) * Users should use the correct save and download path after Clone(). (r1686) * Several improvements to znc-buildmod. (r1688) (r1689) (r1690) (r1695) * Fix a crash with modperl by loading modules differently. (r1714) * Fix HTTP Cache-Control headers for static files served by webadmin. (r1719) * Send the nicklist to a user who is being force-rejoined in partyline. (r1731) * Set the issuer name in CUtils::GenerateCert(). (r1732) * Fixed some inconsistency with /znc reloadmod. (r1749) * Added a work-around for SSL connections which incorrectly errored out during handshake. (r1750) ## Minor stuff * Don't try to catch SIGILL, SIGBUS or SIGSEGV, the default action will do fine. (r1680) * Added IP-address to messages from notify_connect. (r1699) * Switched to Csocket's own c-ares code. (r1704) (r1707) (r1708) (r1709) (r1710) (r1712) (r1713) * Add more doxygen comments. (r1715) (r1718) (r1737) * Removed useless "add your current ip" checkbox from webadmin's edit user page. (r1722) * Don't try to request a MOTD if there is none. (r1728) ## Internal stuff * It's 2010, where's my hoverboard? (r1693) * Got rid of Timers.h. (r1696) * Added a Clone() method to CNick. (r1711) * Call OnChanAction() after OnChanCTCP(). (r1730) * Random cleanups to CFile::Delete(). (r1694) * Other random cleanups. (r1723) (r1724) (r1725) (r1726) (r1736) * Move the implementation of CSocket to Socket.cpp/h. (r1733) # ZNC 0.078 (2009-12-18) ## New stuff * Add a DCCVHost config option which specifies the VHost (IP only!) for DCC bouncing. (r1647) * Users cloned via the admin module no longer automatically connect to IRC. (r1653) * Inform new clients about their /away status. (r1655) * The "BUG" messages from route_replies can now be turned off via /msg *route_replies silent yes. (r1660) * Rewrite znc.conf on SIGUSR1. (r1666) * ISpoofFormat now supports ExpandString. (r1670) ## Fixes * Allow specifing port and password for delserver. (r1640) * Write the config file on restart and shutdown. (r1641) * Disable c-ares if it is not found unless --enable-c-ares was used. (r1644) (r1645) * blockuser was missing an admin check. (r1648) * Sometimes, removing a server caused znc to lose track of which server it is connected to. (r1659) * Include a more portable header for uint32_t in SHA256.h. (r1665) * Fixed cases where ZNC didn't properly block PONG replies to its own PINGs. (r1668) * Fixed a possible crash if a client disconnected before an auth module was able to verify the login. (r1669) * Away allowed to accidentally execute IRC commands. (r1672) * Correctly bind to named hosts if c-ares is enabled. (r1673) * Don't accept only spaces as QuitMsg because this would cause an invalid config to be written out. (r1675) ## Minor stuff * Comment out some weird code in Client.cpp. (r1646) * Remove connect_throttle since it's obsoleted by fail2ban. (r1649) * Remove outdated sample znc.conf. (r1654) * route_replies now got a higher timeout before it generates a "BUG" message. (r1657) * Documented the signals on which znc reacts better. (r1667) ## Internal stuff * New module hook OnIRCConnecting(). (r1638) * Remove obsolete CUtils::GetHashPass(). (r1642) * A module's GetDescription() now returns a C-String. (r1661) (r1662) * When opening a module, check the version number first and don't do anything on a mismatch. (r1663) # ZNC 0.076 (2009-09-24) ## New stuff * Add a make uninstall Makefile target. (r1580) * Imported modules from znc-extra: fixfreenode, buffextras, autoreply, route_replies, adminlog. (r1591) (r1592) (r1593) (r1594) (r1595) * Imported the rest of znc-extra under modules/extra hidden behind configure's --enable-extra. (r1605) (r1606) (r1608) (r1609) (r1610) * ZNC now uses SHA-256 instead of MD5 for hashing passwords. MD5 hashes still work correctly. (r1618) ## Fixes * Don't cache duplicate raw 005 (e.g. due to /version). (r1579) * Send a MODE removing all user modes to clients when we lose the irc connection. (r1583) * Use a nickmask instead of a nick as the source for ZNC-generated MODE commands. (r1584) * Use the right error codes if startup fails. (r1585) * Fix a NULL pointer dereference in some of the ares-specific code. (r1586) * VHost and Motd input boxes in graphiX and dark-clouds in webadmin didn't insert newlines. (r1588) * Generate proper error messages when loading modules. This was broken since znc 0.070. (r1596) * Allow unloading of removed modules. This was broken since znc 0.070. (r1597) * Fix savebuff with KeepBuffer = false. (r1616) * Fix accidental low buffer size for webadmin sockets. (r1617) * AltNicks are no longer truncated to 9 characters. (r1620) * Webadmin can now successfully add new admin users and have them load the shell module. (r1625) * Webadmin no longer includes the znc version in the auth realm. (r1627) * CUser::Clone now handles modules after all other settings, making it work with shell. (r1628) * Some CSS selectors in webadmin's dark-clouds and graphiX skins were wrong. (r1631) * The help of admin was improved. (r1632) (r1633) ## Minor stuff * make distclean now also removes the pkg-config files. (r1581) * Add the autoconf check for large file support. (r1587) * Generic "not enough arguments" support for route_replies and some fix for /lusers. (r1598) (r1600) * ZNC now tries to join channels in random order. (r1601) (r1602) (r1603) * route_replies now handles "No such channel" for /names. (r1614) * Fixes a theoretical crash on shutdown. (r1624) * saslauth was moved to znc-extra. (r1626) ## Internal stuff * Now using autoconf 2.64. (r1604) * Removed unused classes CNoCopy and CSafePtr. (r1607) * Moved CZNC::FindModPath() to CModules. (r1611) * Added CModules::GetModDirs() as a central place for finding module dirs. (r1612) (r1629) * Added CModules::GetModPathInfo() which works like GetModInfo() but which takes the full path to the module. (r1613) * Updated to latest Csocket which adds openssl 1.0 compatibility and fixes some minor bug. (r1615) (r1621) * Merged the internal join and ping timers. (r1622) (r1623) # ZNC 0.074 (2009-07-23) ## Fixes * Fix a regression due to (r1569): Webadmin was broken if the skins were accessed through an absolute path (=almost always). (r1574) * Fix a possible crash if users are deleted while they have active DCC sockets. (r1575) Sorry for breaking your webadmin experience guys. :( # ZNC 0.072 (2009-07-21) All webadmin skins are broken in this release due to a bug in webadmin itself. This is fixed in the next release. High-impact security bugs There was a path traversal bug in ZNC which allowed attackers write access to any place to which ZNC has write access. The attacker only needed a user account (with BounceDCCs enabled). Details are in the commit message. (r1570) This is CVE-2009-2658. Affected versions All ZNC versions since ZNC 0.022 (Initial import in SVN) are affected. ## New stuff * /msg *status uptime is now accessible to everyone. (r1526) * ZNC can now optionally use c-ares for asynchronous DNS resolving. (r1548) (r1549) (r1550) (r1551) (r1552) (r1553) (r1556) (r1565) (r1566) * The new config option AnonIPLimit limits the number of unidentified connections per IP. (r1561) (r1563) (r1567) ## Fixes * znc --no-color --makeconf still used some color codes. (r1519) * Webadmin favicons were broken since (r1481). (r1524) * znc.pc was installed to the wrong directory in multilib systems. (r1530) * Handle flags like e.g. --allow-root for /msg *status restart. (r1531) (r1533) * Fix channel user mode tracking. (r1574) * Fix a possible crash if users are deleted while they are connecting to IRC. (r1557) * Limit HTTP POST data to 1 MiB. (r1559) * OnStatusCommand() wasn't called for commands executed via /znc. (r1562) * On systems where sizeof(off_t) is 4, all ZNC-originated DCCs failed with "File too large (>4 GiB)". (r1568) * ZNC didn't properly verify paths when checking for directory traversal attacks (Low impact). (r1569) ## Minor stuff * Minor speed optimizations. (r1527) (r1532) * stickychan now accepts a channel list as module arguments. (r1534) * Added a clear command to nickserv. (r1554) * Added an execute command to perform. (r1558) * Added a swap command to perform. (r1560) * fail2ban clears all bans on rehash. (r1564) ## Internal stuff * The API for traffic stats changed. (r1521) (r1523) * Some optimizations to CSmartPtr. (r1522) * CString now accepts an optional precision for converting floating point numbers. (r1525) * Made home dir optional in CDir::ChangeDir(). (r1536) * Stuff. (r1537) (r1550) * EMFILE in CSockets is handled by closing the socket. (r1544) * Special thanks to cnu and flakes! # ZNC 0.070 (2009-05-23) ## New stuff * Add a CloneUser command to admin. (r1477) * Make webadmin work better with browser caches in conjunction with changing skins. (r1481) (r1482) * Better error messages if binding a listening port fails. (r1483) * admin module now supports per-channel settings. (r1484) * Fix the KICK that partyline generates when a user is deleted. (r1486) * fail2ban now allows a couple of login attempts before an IP is banned. (r1489) * Fixed a crash bug in stickychan. (r1500) * Install a pkg-config .pc file. (r1503) * Auto-detect globalness in re/un/loadmod commands. (r1505) ## Fixes * Fix a bug where ZNC lost its lock on the config file. (r1457) * Limit DCC transfers to files smaller than 4 GiB. (r1461) * Make znc -D actually work. (r1466) * Make znc --datadir ./meh --makeconf work. The restart used to fail. (r1468) * Fix a crash bug if CNick::GetPermStr() was called on CNick objects from module calls. (r1491) * Some fixes for solaris. (r1496) (r1497) (r1498) * nickserv module now also works on OFTC. (r1502) * Make sure the "Invalid password" message is sent before a client socket is closed. (r1506) * Fix a bug where ZNC would reply with stale cached MODEs for a "MODE #chan" request. (r1507) ## Minor stuff * Man page updates. (r1467) * Make CFile::Close() check close()'s return values if --debug is used. (r1476) * Update to latest Csocket. (r1490) * Improve the error messages generated by /msg *status loadmod. (r1493) * Remove broken znc --encrypt-pem. (r1495) ## Internal stuff * cout and endl are included in Utils.h, not main.h. (r1449) * CFile::Get*Time() now return a time_t. (r1453) (r1479) * Switched some more CFile members to more appropriate return types. (r1454) (r1471) * CFile::Seek() now takes an off_t as its argument. (r1458) * Turn TCacheMap into more of a map. (r1487) (r1488) * Updates to latest Csocket. (r1509) * API breakage: CAuthBase now wants a Csock* instead of just the remote ip. (r1511) (r1512) * New Module hooks (r1494) * OnChanBufferStarting() * OnChanBufferPlayLine() * OnChanBufferEnding() * OnPrivBufferPlayLine() # ZNC 0.068 (2009-03-29) ## New stuff * watch now uses ExpandString on the patterns. (r1402) * A user is now always notified for failed logins to his account. This now also works with auth modules like imapauth. (r1415) (r1416) * Added /msg *status UpdateModule which reloads an user module on all users. (r1418) (r1419) * A module whose version doesn't match the current ZNC version is now marked as such in ListAvailModules and friends. (r1420) * Added a Set password command to admin. (r1423) (r1424) * ZNC no longer uses znc.conf-backup. (r1432) * Two new command line options were added to ZNC: * ZNC --foreground and znc -f stop ZNC from forking into the background. (r1441) * ZNC --debug and znc -D produce output as if ZNC was compiled with --enable-debug. (r1442) (r1443) ## Fixes * cd in shell works again. (r1401) * Make WALLOPS properly honour KeepBuffer. Before this, they were always added to the replay buffer. (r1405) * ZNC now handles raw 432 Illegal Nickname when trying to login to IRC and sends its AltNick. (r1425) * Fix a crash with recursion in module calls. (r1438) * Fixed some compiler warnings with -Wmissing-declarations. (r1439) ## Minor stuff * Allow a leading colon on client's PASS commands. (r1403) * CFile::IsDir() failed on "/". (r1404) * CZNC::AddUser() now always returns a useful error description. (r1406) * Some micro-optimizations. (r1408) (r1409) * The new default for JoinTries is 10. This should help some excess flood problems. (r1411) * All webadmin skins must now reside inside the webadmin skins dir or they are rejected. (r1412) * Watch now saves its module settings as soon as possible, to prevent data loss on unclean shutdown. (r1413) (r1414) * Regenerated configure with autoconf 2.63. (r1426) * Some dead code elimination. (r1435) * Clean up znc -n output a little. (r1437) ## Internal stuff * CString::Base64Decode() now strips newlines. (r1410) * Remove CModInfo::IsSystem() since it was almost unused and quite useless. (r1417) * Some minor changes to CSmartPtr. (r1421) (r1422) * Added CFile::Sync(), a fsync() wrapper. (r1431) # ZNC 0.066 (2009-02-24) There was a privilege escalation bug in webadmin which could allow all ZNC users to write to znc.conf. They could gain shell access through this. (r1395) (r1396) This is CVE-2009-0759. ## Affected versions This bug affects all versions of ZNC which include the webadmin module. Let's just say this affects every ZNC version, ok? ;) ## Who can use this bug? First, ZNC must have the webadmin module loaded and accessible to the outside. Now any user who already has a valid login can exploit this bug. An admin must help (unknowingly) to trigger this bug by reloading the config. ## Impact Through this bug users can write arbitrary strings to the znc.conf file. Unprivileged ZNC users can make themselves admin and load the shell module to gain shell access. Unprivileged ZNC users can temporarily overwrite any file ZNC has write access to via ISpoof. This can be used to overwrite ~/.ssh/authorized_keys and gain shell access. Unprivileged ZNC users can permanently truncate any file to which ZNC has write access via ISpoof. ZNC never saves more than 1kB for restoring the ISpoofFile. ## How can I protect myself? Upgrade to ZNC 0.066 or newer or unload webadmin. ## What happens? Webadmin doesn't properly validate user input. If you send a manipulated POST request to webadmin's edit user page which includes newlines in e.g. the QuitMessage field, this field will be written unmodified to the config. This way you can add new lines to znc.conf. The new lines will not be parsed until the next rehash or restart. This can be done with nearly all input fields in webadmin. Because every user can modify himself via webadmin, every user can exploit this bug. ## Thanks Thanks to cnu for finding and reporting this bug. ## New stuff * Added the admin module. (r1379) (r1386) * savebuff and away no longer ask for a password on startup. (r1388) * Added the fail2ban module. (r1390) ## Fixes * savebuff now also works with KeepBuffer turned off. (r1384) * webadmin did not properly escape module description which could allow XSS attacks. (r1391) * Fix some "use of uninitialized variable" warnings. (r1392) * Check the return value of strftime(). This allowed reading stack memory. (r1394) ## Minor stuff * Some dead code elimination. (r1381) * Don't have two places where the version number is defined. (r1382) ## Internal stuff * Removed some useless and unused CFile members. (r1383) * Removed the DEBUG_ONLY define. (r1385) * OnFailedLogin() is now called for all failed logins, not only failed IRC ones. This changes CAuthBase API. (r1389) # ZNC 0.064 (2009-02-16) ## New stuff * schat now prints a message if a client connects and there are still some active schats. (r1282) * awaynick: Set awaynick on connect, not after some time. (r1291) * Allow adding new servers through /msg *status addserver even if a server with the same name but e.g. a different port is already added. (r1295) (r1296) * Show the current server in /msg *status listservers with a star. (r1308) * /msg *status listmods now displays the module's arguments instead of its description. Use listavailmods for the description. (r1310) * ZNC now updates the channel buffers for detached channels and thus gives a buffer replay when you reattach. (r1325) * watch now adds timestamps to messages it adds to the playback buffers. (r1333) * ZNC should now work on cygwin out of the box (use --disable-ipv6). (r1351) * Webadmin will handle all HTTP requests on the irc ports. (r1368) (r1375) ## Fixes * Handle read errors in CFile::Copy() instead of going into an endless loop. (r1280) (r1287) * Make schat work properly again and clean it up a little. (r1281) (r1303) * Removed all calls to getcwd(). We now no longer depend on PATH_MAX. (r1286) * stickychan: Don't try to join channels if we are not connected to IRC. (r1298) * watch now saved its settings. (r1304) * Don't forward PONG replies that we requested to the user. (r1309) * awaynick evaluated the awaynick multiple times and thus didn't set the nick back. (r1313) * znc-config --version said '@VERSION@' instead of the actual version number. (r1319) * Handle JOIN redirects due to +L. (r1327) * Remove the length restrictions on webadmin's password fields which led to silent password truncation. (r1330) * Webadmin now reloads global modules if you change their arguments. (r1331) * The main binary is no longer built with position independent code. (r1338) * ZNC failed to bounce DCCs if its own ip started with a value above 127. (r1340) * Savebuff no longer reloads old channel buffers if you did /msg *status clearbuffer. (r1345) * Some work has been done to make ZNC work with mingw (It doesn't work out of the box yet). (r1339) (r1341) (r1342) (r1343) (r1344) (r1354) (r1355) (r1356) (r1358) (r1359) * modperl used huge amounts of memory after some time. This is now fixed. (r1357) * shell now generates error messages if e.g. fork() fails. (r1369) * If the allowed buffer size is lowered, the buffer is now automatically shrunk. (r1371) * webadmin now refuses to transfer files bigger than 16 MiB, because it would block ZNC. (r1374) ## Minor stuff * Only reply to /mode requests if we actually know the answer. (r1290) * Lowered some timeouts. (r1297) * Memory usage optimizations. (r1300) (r1301) (r1302) * Allow custom compiler flags in znc-buildmod via the $CXXFLAGS and $LIBS environment flags. (r1312) * Show the client's IP in debug output if no username is available yet. (r1315) * Allow /msg *status setbuffer for channels we are currently not on. (r1323) * Updated the README. (r1326) * Use @includedir@ instead of @prefix@/include in the Makefile. (r1328) * Use RTLD_NOW for loading modules instead of RTLD_LAZY which could take down the bouncer. (r1332) * Use stat() instead of lstat() if the later one isn't available. (r1339) * CExecSock now generates an error message if execvp() fails. (r1362) * Improved some error messages. (r1367) ## Internal stuff * Add traffic tracking support to CSocket. Every module that uses CSocket now automatically gets the traffic it causes tracked. (r1283) * Add VERSION_MINOR and VERSION_MAJOR defines. (r1284) (r1285) * Rework CZNC::Get*Path() a little. (r1289) (r1292) (r1299) * Remove the IPv6 stuff from CServer. It wasn't used at all. (r1294) * Make email use CSocket instead of Csock. (r1305) * Cleaned up and improved CFile::ReadLine() and CChan::AddNicks() a little. (r1306) (r1307) * Replaced most calls to strtoul() and atoi() with calls to the appropriate CString members. (r1320) * Moved the SetArgs() call before the OnLoad() call so that modules can overwrite there arguments in OnLoad(). (r1329) * Let CZNC::AddUser() check if the user name is still free. (r1346) * API stuff * Added CModule::IsGlobal(). (r1283) * Added CModule::BeginTimers(), EndTimers(), BeginSockets() and EndSockets(). (r1293) * Added CModule::ClearNV(). (r1304) * Removed ReadFile(), WriteFile(), ReadLine() (Use CFile instead), Lower(), Upper() (Use CString::AsUpper(), ::ToUpper(), ::*Lower() instead) and added CFile::ReadFile() (r1311) * Added CModules::OnUnknownUserRaw(). (r1314) * Added CUtils::SaltedHash() for computing the salted MD5 hashes ZNC uses. (r1324) * Removed CLockFile and made CFile take over its job. (r1337) (r1352) (r1353) * Change the return type to CUtils::GetPass() to CString. (r1343) * Added a DEBUG(f) define that expands to DEBUG_ONLY(cout << f << endl). (r1348) (r1349) * Removed some unused functions and definitions. (r1360) (r1361) # ZNC 0.062 (2008-12-06) ## New stuff * Add --disable-optimization to configure. (r1206) * New webadmin skin dark-clouds by bigpresh. (r1210) * Added the q module as a replacement for QAuth. (r1217) (r1218) * Added an enhanced /znc command: (r1228) * /znc jump is equal to /msg *status jump * /znc *shell pwd is equal to /msg *shell pwd * Webadmin should generate less traffic, because it now uses client-side caching for static data (images, style sheets, ...). (r1248) * Changes to the vhost interface from *status: (r1256) * New commands: AddVHost, RemVHost and ListVHosts. * SetVHost now only accepts vhosts from the ListVHosts list, if it is non-empty. * ZNC now should compile and work fine on Mac OS. (r1258) * IPv6 is now enabled by default unless you disable it with --disable-ipv6. (r1270) ## Fixes * Make keepnick usable. (r1203) (r1209) * Don't display 'Your message to .. got lost' for our own nick. (r1211) * Fix compile error with GCC 4.3.1 if ssl is disabled. Thanks to sebastinas. (r1212) * Limit the maximum buffer space each socket may use to prevent DoS attacks. (r1233) * Properly clean the cached perms when you are kicked from a channel. (r1236) * Due to changes in rev 1155-1158, modperl crashed on load on some machines. (r1237) (r1239) * Stickychan didn't work with disabled channels. (r1238) * Catch a throw UNLOAD in the OnBoot module hook. (r1249) * Webadmin now accepts symlinks in the skin dir. (r1252) * Fix for partyline if a force-joined user is deleted. (r1263) (r1264) * Revert change from (r1125) so that we compile on fbsd 4 again. (r1273) ## Minor stuff * Recompile everything if configure is run again. (r1205) * Improved the readability of ListMods und ListAvailMods. (r1216) * Accept "y" and "n" as answers to yes/no questions in --makeconf. (r1244) * --makeconf now also generates a ssl certificate if a ssl listening port is configured. (r1246) * Improved and cleaned up the simple_away module. (r1247) * The nickserv module automatically saves the password and never displays it anymore. (r1250) * Use relative instead of absolute URLs in all webadmin skins. (r1253) (r1254) * Add znc-config --cxx and use it in znc-buildmod. (r1255) * Support out-of-tree-builds. (r1257) * Make schat's showsocks command admin-only. (r1260) * Fix compilation with GCC 4.4. (r1269) * Use AC_PATH_PROG instead of which to find the perl binary. (r1274) * New AUTHORS file format. (r1275) ## Internal stuff * Removed redundant checks for NULL pointers (r1220) (r1227) * Renamed String.h and String.cpp to ZNCString. (r1202) * Print a warning in CTable if an unknown column is SetCell()'d (r1223) * Update to latest Csocket (r1225) * Remove CSocket::m_sLabel and its accessor functions. Use the socket name Csocket provides instead. (r1229) * modules Makefile: Small cleanup, one defines less and no compiler flags passed multiple times. (r1235) * Webadmin now uses CSocket instead of using Csock and keeping a list of sockets itself. (r1240) * Mark some global and static variables as const. (r1241) * Cleanup perform, no feature changes. (r1242) * Some tweaking to configure.in. Among other things, we now honour CPPFLAGS and don't check for a C compiler anymore. (r1251) * On rare occasions webadmin generated weird error messages. (r1259) * OnStatusCommand now doesn't have the const attribute on its argument. (r1262) * Some new functions: * some CString constructors (e.g. CString(true) results in "true") (r1243) (r1245) * CString::TrimPrefix() and CString::TrimSuffix() (r1224) (r1226) * CString::Equals() (r1232) (r1234) * CTable::Clear() (r1230) * CClient::PutStatus(const CTable&) (r1222) * CGlobalModule::OnClientConnect() (r1266) (r1268) * CModule::OnIRCRegistration() (r1271) * CModule::OnTimerAutoJoin() (r1272) * Renames: * CModule::OnUserAttached() is now known as CModules::OnClientLogin(). (r1266) * CModule::OnUserDetached() is now known as CModules::OnClientDisconnect(). (r1266) # ZNC 0.060 (2008-09-13) * Print a message when SIGHUP is caught. (r1197) * Moved autocycle into a module. (r1191) (r1192) * New module call OnMode(). (r1189) * Added MaxJoins and JoinTries to webadmin. (r1187) * Fix channel keyword (+k) related mess up on Quakenet (RFC, anyone?). (r1186) (r1190) * Added new module call OnUserTopicRequest(). (r1185) * Also add traffic generated by modules to the traffic stats. (r1183) * Don't use znc.com but znc.in everywhere (hostname of *status etc). (r1181) (r1195) * Close the listening port if we ran out of free FDs. (r1180) * Add a config option MaxJoins which limits the number of joins ZNC sends in one burst. (r1177) * Bug fix where WriteToDisk() didn't made sure a fail was empty. (r1176) * Add ShowMOTD and reorder the HELP output of *status. (r1175) * Add /msg *status restart . Thanks to kroimon. (r1174) * Make --makeconf more userfriendly. Thanks to kroimon. (r1173) * Don't start a new znc process after --makeconf. Thanks to kroimon. (r1171) * Add CModule::PutModule(const CTable&). (r1168) (r1169) * Unify some preprocessor macros in Modules.cpp. (r1166) * Catch a throw UNLOAD from CModule::OnLoad(). (r1164) * A couple of bugs with OnModCTCP(), OnModCommand() and OnModNotice() where fixed. (r1162) * Quicker connects and reconnects to IRC. (r1161) * Speedup the CTable class. (r1160) * Update our bundled Csocket. (r1159) * Some fixes to modperl for hppa. * Move keepnick into a module. (r1151) (r1152) (r1153) * Split up some big functions and files. (r1148) (r1149) (r1150) * modperl now fails to load if it can't find modperl.pm. (r1147) * Handle nick prefixes and such stuff from clients correctly. (r1144) (r1145) * Simplify the code connecting users a little. (r1143) * Fix partyline for users who are not connected to IRC. (r1141) * We are in a channel when we receive a join for it, not an 'end of /names'. (r1140) * Enable some more debug flags with --enable-debug. (r1138) * Don't ever throw exceptions in CModules::LoadModule(). (r1137) * Don't give any stdin to commands executed from the shell module. (r1136) * Fix some over-the-end iterator dereference on parting empty channels. (r1133) * Replace usage of getresuid() with getuid() and geteuid(). (r1132) * Use salted hashes for increased security. (r1127) (r1139) * Don't mention any libraries in znc-config. (r1126) * Don't define __GNU_LIBRARY__ for FreeBSD. (r1125) # ZNC 0.058 (2008-07-10) * Fix a crash with NAMESX-enabled IRC servers. (r1118) * Fix a privilege escalation bug in webadmin if auth modules are used. (r1113) * Remove -D_GNU_SOURCE from our CXXFLAGS. (r1110) * CUtils::GetInput() now kills the process if reading from stdin fails. (r1109) * Properly include limits.h for PATH_MAX. (r1108) * Don't allow running ZNC as root unless --allow-root is given. (r1102) * Add more possibilities for ExpandString(). (r1101) * Autoattach doesn't allow you adding an entry twice now. (r1100) * Print a warning if PATH_MAX is undefined. (r1099) * Use ExpandString() for CTCPReply. (r1096) * Add Uptime command to *status. (r1095) (r1107) * Make --makeconf clearer. (r1093) * Add man pages for znc, znc-buildmod and znc-config. (r1091) * Perl modules are no longer installed with executable bit set. (r1090) * Crypt now forwards messages to other connected clients. (r1088) * Fix a theoretical crash bug in the DNS resolving code. (r1087) * Modules now get their module name as ident, not 'znc'. (r1084) * Handle channel CTCPs the same way private CTCPs are handled. (r1082) * Webadmin: Add support for timezone offset. (r1079) * Webadmin: Remove the *.de webadmin skins. (r1078) * Webadmin: Don't reset all channel settings when a user page is saved. (r1074) * Fix a possible crash when rehashing failed to open the config file. (r1073) * The instructions at the end of makeconf showed a wrong port. (r1072) * Throttle DCC transfers to the speed of the sending side. (r1069) * De-bashify znc-buildmod. (r1068) * Time out unauthed clients after 60 secs. (r1067) * Don't fail with conspire as IRC client. (r1066) * Replace CString::Token() with a much faster version. (r1065) * DenyLoadMod users no longer can use ListAvailMods. (r1063) * Add a VERSION_EXTRA define which can be influenced via CXXFLAGS and which is appended to ZNC's version number. (r1062) # ZNC 0.056 (2008-05-24) * Rehashing also handles channel settings. (r1058) * Make znc-buildmod work with prefixes. (r1054) * Greatly speed up CUser::GetIRCSock(). Thanks to w00t. (r1053) * Don't link the ZNC binary against libsasl2. (r1050) * Make CString::RandomString() produce a more random string (this is used for autoop and increases its security). (r1047) * Remove OnRehashDone() and add OnPreRehash() and OnPostRehash(). (r1046) * Show traffic stats in a readable unit instead of lots of bytes. (r1038) * Fixed a bug were nick changes where silently dropped if we are in no channels. (r1037) * Remove the /watch command from watch. (r1035) * znc-buildmod now reports errors via exit code. (r1034) * Display a better error message if znc.conf cannot be opened. (r1033) * Print a warning from *status if some message or notice is lost because we are not connected to IRC. (r1032) * Make ./configure --bindir=DIR work. (r1031) * Always track header dependencies. This means we require a compile supporting -MMD and -MF. (r1026) * Improve some error messages if we can't connect to IRC. (r1023) * Use \n instead of \r\n for znc.conf. (r1022) * Fix some invalid replies from the shell module. (r1021) * Support chans other than #chan and &chan. (r1019) * Make chansaver add all channels to the config on load. (r1018) * Reply to PINGs if we are not connected to a server. (r1016) * Fix some bugs with Csocket, one caused segfaults when connecting to special SSL hosts. (r1015) * Use MODFLAGS instead of CXXFLAGS for modules. Do MODFLAGS=something ./configure if you want a flag that is used only by modules. (r1012) * Add OnTopic() module call. (r1011) * Don't create empty .registry files for modules. See find ~/.znc -iname ".registry" -size 0 for a list of files you can delete. (r1010) * Only allow admins to load the shell module. (r1007) * Fix CModule::DelNV()'s return value. (r1006) * Fix CUser::Clone() to handle all the settings. (r1005) * Mark all our FDs as close-on-exec. (r1004) # ZNC 0.054 (2008-04-01) * Forward /names replies for unknown channels. * Global modules can no longer hook into every config line, but only those prefixed with 'GM:'. * Don't forward topic changes for detached channels. * Remove ~/.znc/configs/backups and instead only keep one backup under znc.conf-backup. * Update /msg *status help. * Add --datadir to znc-config. * Update bundled Csocket to the latest version. This fixes some bugs (e.g. not closing SSL connections properly). * Use $HOME if possible to get the user's home (No need to read /etc/passwd anymore). * Use -Wshadow and fix all those warnings. * Add /msg *status ListAvailMods. Thanks to SilverLeo. * Add OnRehashDone() module call. * Add rehashing (SIGHUP and /msg *status rehash). * Also write a pid file if we are compiled with --enable-debug. Thanks to SilverLeo. * Add ClearVHost and 'fix' SetVHost. Thanks to SilverLeo. * Increase the connect timeout for IRC connections to 2 mins. * Add a user's vhost to the list on the user page in webadmin. * Add --no-color switch and only use colors if we are on a terminal. * Add DenySetVHost config option. Thanks to Veit Wahlich aka cru. * Change --makeconf's default for KeepNick and KeepBuffer to false. * Add simple_away module. This sets you away some time after you disconnect from ZNC. * Don't write unneeded settings to the section. Thanks to SilverLeo. * Remove OnFinishedConfig() module call. Use OnBoot() instead. * Fix some GCC 4.3 warnings. Thanks to darix again. * Move the static data (webadmin's skins) to /usr/share/znc per default. Thanks to Marcus Rueckert aka darix. * New znc-buildmod which works on shells other than bash. * Add ClearAllChannelBuffers to *status. * Handle CTCPs to *status. * autoattach now saves and reloads its settings. * Let webadmin use the user's defaults for new chans. Thanks to SilverLeo. # ZNC 0.052 (2007-12-02) * Added saslauth module. * Add del command to autoattach. * Make awaynick save its settings and restore them when it is loaded again. * Added disconnect and connect commands to *status. * CTCPReply = VERSION now ignores ctcp version requests (as long as no client is attached). This works for every CTCP request. * Add -W to our default CXXFLAGS. * Remove save command from perform, it wasn't needed. * Add list command to stickychan. * --with-module-prefix=x now really uses x and not x/znc (Inspired by CNU :) ). * Use a dynamic select timeout (sleep until next cron runs). This should save some CPU time. * Fix NAMESX / UHNAMES, round two (multi-client breakage). * Module API change (without any breakage): OnLoad gets sMessage instead of sErrorMsg. * Fix a mem-leak. * Disable auto-rejoin on kick and add module kickrejoin. * Respect $CXXFLAGS env var in configure. * Removed some executable bits on graphiX' images. * Added README file and removed docs/. * Removed the antiidle module. * Fixes for GCC 4.3 (Debian bug #417793). * Some dead code / code duplications removed. * Rewrote Makefile.ins and don't strip binaries anymore by default. # ZNC 0.050 (2007-08-11) * fixed UHNAMES bug (ident was messed up, wrong joins were sent) * fixed /lusers bug (line was cached more than once) * added disabled chans to the core * send out a notice asking for the server password if client doesn't send one * added ConnectDelay config option * added timestamps on the backlog * added some module calls * added basic traffic stats * added usermodes support * API breakage (CModule::OnLoad got an extra param) * added fixed channels to the partyline module * fixed partyline bugs introduced by last item * fixed a NULL pointer dereference if /nick command was received from a client while not connected to IRC * added a JoinTries per-user config option which specifies how often we try to rejoin a channel (default: 0 -> unlimited) * make configure fail if it can't find openssl (or perl, ...) * new modules: antiidle, nickserv # ZNC 0.047 (2007-05-15) * NULL pointer dereference when a user uses webadmin while not on irc * A logged in user could access any file with /msg *status send/get * znc --makeconf now restarts znc correctly * New webadmin skin (+ german translations) * Updated to new Csocket version * Allow @ and . in user names which now can also be longer * Added crox and psychon to AUTHORS * Relay messages to other clients of the current user (for the crypt module) * Added chansaver Module * Moved awaynick functionality into a module * Added perform module from psychon * fixed bug when compiling without module support * Added a configurable Timer to the away module * Added support for Topics in the partyline module * Added support for reloading global modules * Added a timer to ping inactive clients * Migrated away from CString::ToString() in favor of explicit constructors * IMAP Authentication Module added * Fixed issues with gcc 4.1 * Added concept of default channels that a user is automatically joined to every time they attach * Added SetVHost command * Added error reporting and quit msgs as *status output * Added a server ping for idle connections - Thanks zparta * added -ldl fix for openssl crypto package. fixes static lib link requirement * Explicitly set RTLD_LOCAL, some systems require it - thanks x-x * Added SendBuffer and ClearBuffer client commands * Added support for to talk unencrypted * added with-modules-prefix and moved modules by default to PREFIX/libexec * Added license and contact info * remove compression initialization until standard has normalized a bit # ZNC 0.045 (2006-02-20) * Added +o/v -o/v for when users attach/detach - partyline module * Changed internal naming of CUserSock to CClient for consistency * Fixed some issues with older bsd boxes * Added ListenHost for binding to a specific ip instead of inaddr_any * Allow - and _ as valid username chars * respect compiler, we don't force you to use g++ anymore, don't include system includes for deps * Added Replace_n() and fixed internal loop bug in Replace() (thanks psycho for finding it) * Don't allow .. in GET * Added autoop module * Added support for buffering of /me actions * Added Template support in webadmin now you can write your own skins easily :) * Added ipv6 support * Support for multiple Listen Ports (note the config option "ListenPort" changed to "Listen") # ZNC 0.044 (2005-10-14) * Fixed issue where pipe between client and irc sockets would get out of sync, this was introduced in 0.043 * Added *status commands to list users and clients connected # ZNC 0.043 (2005-10-13) * Added Multi-Client support * Added Global partyline module * Added MOTD config option * Added Admin permission * Added SaveConfig admin-only *status command * Added Broadcast admin-only *status command # ZNC 0.041 (2005-09-08) * This release fixes some issues with 64bit systems. # ZNC 0.040 (2005-09-07) This release contains a lot of features/bugfixes and a great new global module called admin.cpp which will allow you to add/remove/edit users and settings on the fly via a web browser. # ZNC 0.039 (2005-09-07) This release contains a lot of features/bugfixes and a great new global module called admin.cpp which will allow you to add/remove/edit users and settings on the fly via a web browser. # ZNC 0.038 (2005-09-07) This release contains a lot of bugfixes and a great new global module called admin.cpp which will allow you to add/remove/edit users and settings on the fly via a web browser. # ZNC 0.037 (2005-05-22) # ZNC 0.036 (2005-05-15) # ZNC 0.035 (2005-05-14) # ZNC 0.034 (2005-05-01) # ZNC 0.033 (2005-04-26) # ZNC 0.030 (2005-04-21) # ZNC 0.029 (2005-04-12) # ZNC 0.028 (2005-04-04) # ZNC 0.027 (2005-04-04) # ZNC 0.025 (2005-04-03) # ZNC 0.023 (2005-03-10) znc-1.7.5/znc-buildmod.in0000755000175000017500000000230313542151610015460 0ustar somebodysomebody#!/bin/sh ERROR="[ !! ]" WARNING="[ ** ]" OK="[ ok ]" # Check if we got everything we need check_binary() { which $1 > /dev/null 2>&1 if test $? = 1 ; then echo "${ERROR} Could not find $1. $2" exit 1 fi } if test "x$CXX" = "x" ; then CXX="@CXX@" fi if test "x$CXX" = "x" ; then CXX=g++ fi check_binary ${CXX} "What happened to your compiler?" if test -z "$1"; then echo "${WARNING} USAGE: $0 [file.cpp ... ]" exit 1 fi CXXFLAGS="@CPPFLAGS@ @MODFLAGS@ -I@prefix@/include $CXXFLAGS" LIBS="@LIBS@ $LIBS" MODLINK="@MODLINK@ $MODLINK" VERSION="@PACKAGE_VERSION@" # Ugly cygwin stuff :( if test -n "@LIBZNC@"; then prefix="@prefix@" exec_prefix="@exec_prefix@" LDFLAGS="-L@libdir@ $LDFLAGS" LIBS="-lznc $LIBS" fi while test -n "$1" do FILE=$1 shift MOD="${FILE%.cpp}" MOD="${MOD%.cc}" MOD="${MOD##*/}" if test ! -f "${FILE}"; then echo "${ERROR} Building \"${MOD}\" for ZNC $VERSION... File not found" exit 1 else printf "Building \"${MOD}.so\" for ZNC $VERSION... " if ${CXX} ${CXXFLAGS} ${INCLUDES} ${LDFLAGS} ${MODLINK} -o "${MOD}.so" "${FILE}" ${LIBS} ; then echo "${OK}" else echo "${ERROR} Error while building \"${MOD}.so\"" exit 1 fi fi done exit 0 znc-1.7.5/webskins/0000755000175000017500000000000013542151610014365 5ustar somebodysomebodyznc-1.7.5/webskins/_default_/0000755000175000017500000000000013542151610016307 5ustar somebodysomebodyznc-1.7.5/webskins/_default_/tmpl/0000755000175000017500000000000013542151610017263 5ustar somebodysomebodyznc-1.7.5/webskins/_default_/tmpl/Banner.tmpl0000644000175000017500000000011613542151610021364 0ustar somebodysomebodyznc-1.7.5/webskins/_default_/tmpl/InfoBar.tmpl0000644000175000017500000000064013542151610021501 0ustar somebodysomebody
znc-1.7.5/webskins/_default_/tmpl/index.tmpl0000644000175000017500000000100613542151610021265 0ustar somebodysomebody

/msg *status help†and “/msg *status loadmod <module>â€). Once you have loaded some Web-enabled modules, the menu will expand." ?>

znc-1.7.5/webskins/_default_/tmpl/BreadCrumbs.tmpl0000644000175000017500000000046413542151610022356 0ustar somebodysomebody znc-1.7.5/webskins/_default_/tmpl/DocType.tmpl0000644000175000017500000000007513542151610021532 0ustar somebodysomebodyxml version="1.0" encoding="UTF-8"?> znc-1.7.5/webskins/_default_/tmpl/Menu.tmpl0000644000175000017500000000411613542151610021067 0ustar somebodysomebody znc-1.7.5/webskins/_default_/tmpl/MessageBar.tmpl0000644000175000017500000000031313542151610022167 0ustar somebodysomebody
znc-1.7.5/webskins/_default_/tmpl/FooterTag.tmpl0000644000175000017500000000000013542151610022041 0ustar somebodysomebodyznc-1.7.5/webskins/_default_/tmpl/_csrf_check.tmpl0000644000175000017500000000011513542151610022407 0ustar somebodysomebody znc-1.7.5/webskins/_default_/tmpl/Error.tmpl0000644000175000017500000000011113542151610021243 0ustar somebodysomebody

znc-1.7.5/webskins/_default_/tmpl/Footer.tmpl0000644000175000017500000000051013542151610021413 0ustar somebodysomebody
znc-1.7.5/webskins/_default_/tmpl/LowerBanner.tmpl0000644000175000017500000000006613542151610022401 0ustar somebodysomebody

znc-1.7.5/webskins/_default_/tmpl/ExtraHeader.tmpl0000644000175000017500000000023013542151610022350 0ustar somebodysomebodyznc-1.7.5/webskins/_default_/tmpl/Options.tmpl0000644000175000017500000000003113542151610021606 0ustar somebodysomebody znc-1.7.5/webskins/_default_/tmpl/Header.tmpl0000644000175000017500000000124113542151610021347 0ustar somebodysomebody This is a wrapper file which simply includes BaseHeader.tmpl so that new skins can make a Header.tmpl similar to... ...this way a skin can base itself off of the same html as the default skin but still add custom css/js @todo In the future I'd like to support something like or even just do a current file vs inc'd file comparison to make sure they aren't the same. This way we can from the "derived" Header.tmpl and not cause an recursive loop. znc-1.7.5/webskins/_default_/tmpl/LoginBar.tmpl0000644000175000017500000000122413542151610021655 0ustar somebodysomebody  
znc-1.7.5/webskins/_default_/tmpl/BaseHeader.tmpl0000644000175000017500000000375713542151610022160 0ustar somebodysomebody ZNC - <? VAR Title DEFAULT="Web Frontend" ?>
In your subpage (module page or static page) you'll probably want to do something like this... This is my super cool sub page! If you'd like to add your own local css file to be included after the global main.css, you can make your own Header.tmpl like so... znc-1.7.5/webskins/_default_/pub/0000755000175000017500000000000013542151610017075 5ustar somebodysomebodyznc-1.7.5/webskins/_default_/pub/selectize-standalone-0.12.1.min.js0000644000175000017500000012252313542151610025054 0ustar somebodysomebody/*! selectize.js - v0.12.1 | https://github.com/brianreavis/selectize.js | Apache License (v2) */ !function(a,b){"function"==typeof define&&define.amd?define("sifter",b):"object"==typeof exports?module.exports=b():a.Sifter=b()}(this,function(){var a=function(a,b){this.items=a,this.settings=b||{diacritics:!0}};a.prototype.tokenize=function(a){if(a=d(String(a||"").toLowerCase()),!a||!a.length)return[];var b,c,f,h,i=[],j=a.split(/ +/);for(b=0,c=j.length;c>b;b++){if(f=e(j[b]),this.settings.diacritics)for(h in g)g.hasOwnProperty(h)&&(f=f.replace(new RegExp(h,"g"),g[h]));i.push({string:j[b],regex:new RegExp(f,"i")})}return i},a.prototype.iterator=function(a,b){var c;c=f(a)?Array.prototype.forEach||function(a){for(var b=0,c=this.length;c>b;b++)a(this[b],b,this)}:function(a){for(var b in this)this.hasOwnProperty(b)&&a(this[b],b,this)},c.apply(a,[b])},a.prototype.getScoreFunction=function(a,b){var c,d,e,f;c=this,a=c.prepareSearch(a,b),e=a.tokens,d=a.options.fields,f=e.length;var g=function(a,b){var c,d;return a?(a=String(a||""),d=a.search(b.regex),-1===d?0:(c=b.string.length/a.length,0===d&&(c+=.5),c)):0},h=function(){var a=d.length;return a?1===a?function(a,b){return g(b[d[0]],a)}:function(b,c){for(var e=0,f=0;a>e;e++)f+=g(c[d[e]],b);return f/a}:function(){return 0}}();return f?1===f?function(a){return h(e[0],a)}:"and"===a.options.conjunction?function(a){for(var b,c=0,d=0;f>c;c++){if(b=h(e[c],a),0>=b)return 0;d+=b}return d/f}:function(a){for(var b=0,c=0;f>b;b++)c+=h(e[b],a);return c/f}:function(){return 0}},a.prototype.getSortFunction=function(a,c){var d,e,f,g,h,i,j,k,l,m,n;if(f=this,a=f.prepareSearch(a,c),n=!a.query&&c.sort_empty||c.sort,l=function(a,b){return"$score"===a?b.score:f.items[b.id][a]},h=[],n)for(d=0,e=n.length;e>d;d++)(a.query||"$score"!==n[d].field)&&h.push(n[d]);if(a.query){for(m=!0,d=0,e=h.length;e>d;d++)if("$score"===h[d].field){m=!1;break}m&&h.unshift({field:"$score",direction:"desc"})}else for(d=0,e=h.length;e>d;d++)if("$score"===h[d].field){h.splice(d,1);break}for(k=[],d=0,e=h.length;e>d;d++)k.push("desc"===h[d].direction?-1:1);return i=h.length,i?1===i?(g=h[0].field,j=k[0],function(a,c){return j*b(l(g,a),l(g,c))}):function(a,c){var d,e,f;for(d=0;i>d;d++)if(f=h[d].field,e=k[d]*b(l(f,a),l(f,c)))return e;return 0}:null},a.prototype.prepareSearch=function(a,b){if("object"==typeof a)return a;b=c({},b);var d=b.fields,e=b.sort,g=b.sort_empty;return d&&!f(d)&&(b.fields=[d]),e&&!f(e)&&(b.sort=[e]),g&&!f(g)&&(b.sort_empty=[g]),{options:b,query:String(a||"").toLowerCase(),tokens:this.tokenize(a),total:0,items:[]}},a.prototype.search=function(a,b){var c,d,e,f,g=this;return d=this.prepareSearch(a,b),b=d.options,a=d.query,f=b.score||g.getScoreFunction(d),a.length?g.iterator(g.items,function(a,e){c=f(a),(b.filter===!1||c>0)&&d.items.push({score:c,id:e})}):g.iterator(g.items,function(a,b){d.items.push({score:1,id:b})}),e=g.getSortFunction(d,b),e&&d.items.sort(e),d.total=d.items.length,"number"==typeof b.limit&&(d.items=d.items.slice(0,b.limit)),d};var b=function(a,b){return"number"==typeof a&&"number"==typeof b?a>b?1:b>a?-1:0:(a=h(String(a||"")),b=h(String(b||"")),a>b?1:b>a?-1:0)},c=function(a){var b,c,d,e;for(b=1,c=arguments.length;c>b;b++)if(e=arguments[b])for(d in e)e.hasOwnProperty(d)&&(a[d]=e[d]);return a},d=function(a){return(a+"").replace(/^\s+|\s+$|/g,"")},e=function(a){return(a+"").replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")},f=Array.isArray||$&&$.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)},g={a:"[aÀÃÂÃÄÅàáâãäåĀÄÄ…Ä„]",c:"[cÇçćĆÄÄŒ]",d:"[dÄ‘ÄÄÄŽ]",e:"[eÈÉÊËèéêëěĚĒēęĘ]",i:"[iÃŒÃÃŽÃìíîïĪī]",l:"[lÅ‚Å]",n:"[nÑñňŇńŃ]",o:"[oÒÓÔÕÕÖØòóôõöøŌÅ]",r:"[rřŘ]",s:"[sŠšśŚ]",t:"[tťŤ]",u:"[uÙÚÛÜùúûüůŮŪū]",y:"[yŸÿýÃ]",z:"[zŽžżŻźŹ]"},h=function(){var a,b,c,d,e="",f={};for(c in g)if(g.hasOwnProperty(c))for(d=g[c].substring(2,g[c].length-1),e+=d,a=0,b=d.length;b>a;a++)f[d.charAt(a)]=c;var h=new RegExp("["+e+"]","g");return function(a){return a.replace(h,function(a){return f[a]}).toLowerCase()}}();return a}),function(a,b){"function"==typeof define&&define.amd?define("microplugin",b):"object"==typeof exports?module.exports=b():a.MicroPlugin=b()}(this,function(){var a={};a.mixin=function(a){a.plugins={},a.prototype.initializePlugins=function(a){var c,d,e,f=this,g=[];if(f.plugins={names:[],settings:{},requested:{},loaded:{}},b.isArray(a))for(c=0,d=a.length;d>c;c++)"string"==typeof a[c]?g.push(a[c]):(f.plugins.settings[a[c].name]=a[c].options,g.push(a[c].name));else if(a)for(e in a)a.hasOwnProperty(e)&&(f.plugins.settings[e]=a[e],g.push(e));for(;g.length;)f.require(g.shift())},a.prototype.loadPlugin=function(b){var c=this,d=c.plugins,e=a.plugins[b];if(!a.plugins.hasOwnProperty(b))throw new Error('Unable to find "'+b+'" plugin');d.requested[b]=!0,d.loaded[b]=e.fn.apply(c,[c.plugins.settings[b]||{}]),d.names.push(b)},a.prototype.require=function(a){var b=this,c=b.plugins;if(!b.plugins.loaded.hasOwnProperty(a)){if(c.requested[a])throw new Error('Plugin has circular dependency ("'+a+'")');b.loadPlugin(a)}return c.loaded[a]},a.define=function(b,c){a.plugins[b]={name:b,fn:c}}};var b={isArray:Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)}};return a}),function(a,b){"function"==typeof define&&define.amd?define("selectize",["jquery","sifter","microplugin"],b):"object"==typeof exports?module.exports=b(require("jquery"),require("sifter"),require("microplugin")):a.Selectize=b(a.jQuery,a.Sifter,a.MicroPlugin)}(this,function(a,b,c){"use strict";var d=function(a,b){if("string"!=typeof b||b.length){var c="string"==typeof b?new RegExp(b,"i"):b,d=function(a){var b=0;if(3===a.nodeType){var e=a.data.search(c);if(e>=0&&a.data.length>0){var f=a.data.match(c),g=document.createElement("span");g.className="highlight";var h=a.splitText(e),i=(h.splitText(f[0].length),h.cloneNode(!0));g.appendChild(i),h.parentNode.replaceChild(g,h),b=1}}else if(1===a.nodeType&&a.childNodes&&!/(script|style)/i.test(a.tagName))for(var j=0;j/g,">").replace(/"/g,""")},B=function(a){return(a+"").replace(/\$/g,"$$$$")},C={};C.before=function(a,b,c){var d=a[b];a[b]=function(){return c.apply(a,arguments),d.apply(a,arguments)}},C.after=function(a,b,c){var d=a[b];a[b]=function(){var b=d.apply(a,arguments);return c.apply(a,arguments),b}};var D=function(a){var b=!1;return function(){b||(b=!0,a.apply(this,arguments))}},E=function(a,b){var c;return function(){var d=this,e=arguments;window.clearTimeout(c),c=window.setTimeout(function(){a.apply(d,e)},b)}},F=function(a,b,c){var d,e=a.trigger,f={};a.trigger=function(){var c=arguments[0];return-1===b.indexOf(c)?e.apply(a,arguments):void(f[c]=arguments)},c.apply(a,[]),a.trigger=e;for(d in f)f.hasOwnProperty(d)&&e.apply(a,f[d])},G=function(a,b,c,d){a.on(b,c,function(b){for(var c=b.target;c&&c.parentNode!==a[0];)c=c.parentNode;return b.currentTarget=c,d.apply(this,[b])})},H=function(a){var b={};if("selectionStart"in a)b.start=a.selectionStart,b.length=a.selectionEnd-b.start;else if(document.selection){a.focus();var c=document.selection.createRange(),d=document.selection.createRange().text.length;c.moveStart("character",-a.value.length),b.start=c.text.length-d,b.length=d}return b},I=function(a,b,c){var d,e,f={};if(c)for(d=0,e=c.length;e>d;d++)f[c[d]]=a.css(c[d]);else f=a.css();b.css(f)},J=function(b,c){if(!b)return 0;var d=a("").css({position:"absolute",top:-99999,left:-99999,width:"auto",padding:0,whiteSpace:"pre"}).text(b).appendTo("body");I(c,d,["letterSpacing","fontSize","fontFamily","fontWeight","textTransform"]);var e=d.width();return d.remove(),e},K=function(a){var b=null,c=function(c,d){var e,f,g,h,i,j,k,l;c=c||window.event||{},d=d||{},c.metaKey||c.altKey||(d.force||a.data("grow")!==!1)&&(e=a.val(),c.type&&"keydown"===c.type.toLowerCase()&&(f=c.keyCode,g=f>=97&&122>=f||f>=65&&90>=f||f>=48&&57>=f||32===f,f===q||f===p?(l=H(a[0]),l.length?e=e.substring(0,l.start)+e.substring(l.start+l.length):f===p&&l.start?e=e.substring(0,l.start-1)+e.substring(l.start+1):f===q&&"undefined"!=typeof l.start&&(e=e.substring(0,l.start)+e.substring(l.start+1))):g&&(j=c.shiftKey,k=String.fromCharCode(c.keyCode),k=j?k.toUpperCase():k.toLowerCase(),e+=k)),h=a.attr("placeholder"),!e&&h&&(e=h),i=J(e,a)+4,i!==b&&(b=i,a.width(i),a.triggerHandler("resize")))};a.on("keydown keyup update blur",c),c()},L=function(c,d){var e,f,g,h,i=this;h=c[0],h.selectize=i;var j=window.getComputedStyle&&window.getComputedStyle(h,null);if(g=j?j.getPropertyValue("direction"):h.currentStyle&&h.currentStyle.direction,g=g||c.parents("[dir]:first").attr("dir")||"",a.extend(i,{order:0,settings:d,$input:c,tabIndex:c.attr("tabindex")||"",tagType:"select"===h.tagName.toLowerCase()?v:w,rtl:/rtl/i.test(g),eventNS:".selectize"+ ++L.count,highlightedValue:null,isOpen:!1,isDisabled:!1,isRequired:c.is("[required]"),isInvalid:!1,isLocked:!1,isFocused:!1,isInputHidden:!1,isSetup:!1,isShiftDown:!1,isCmdDown:!1,isCtrlDown:!1,ignoreFocus:!1,ignoreBlur:!1,ignoreHover:!1,hasOptions:!1,currentResults:null,lastValue:"",caretPos:0,loading:0,loadedSearches:{},$activeOption:null,$activeItems:[],optgroups:{},options:{},userOptions:{},items:[],renderCache:{},onSearchChange:null===d.loadThrottle?i.onSearchChange:E(i.onSearchChange,d.loadThrottle)}),i.sifter=new b(this.options,{diacritics:d.diacritics}),i.settings.options){for(e=0,f=i.settings.options.length;f>e;e++)i.registerOption(i.settings.options[e]);delete i.settings.options}if(i.settings.optgroups){for(e=0,f=i.settings.optgroups.length;f>e;e++)i.registerOptionGroup(i.settings.optgroups[e]);delete i.settings.optgroups}i.settings.mode=i.settings.mode||(1===i.settings.maxItems?"single":"multi"),"boolean"!=typeof i.settings.hideSelected&&(i.settings.hideSelected="multi"===i.settings.mode),i.initializePlugins(i.settings.plugins),i.setupCallbacks(),i.setupTemplates(),i.setup()};return e.mixin(L),c.mixin(L),a.extend(L.prototype,{setup:function(){var b,c,d,e,g,h,i,j,k,l=this,m=l.settings,n=l.eventNS,o=a(window),p=a(document),q=l.$input;if(i=l.settings.mode,j=q.attr("class")||"",b=a("
").addClass(m.wrapperClass).addClass(j).addClass(i),c=a("
").addClass(m.inputClass).addClass("items").appendTo(b),d=a('').appendTo(c).attr("tabindex",q.is(":disabled")?"-1":l.tabIndex),h=a(m.dropdownParent||b),e=a("
").addClass(m.dropdownClass).addClass(i).hide().appendTo(h),g=a("
").addClass(m.dropdownContentClass).appendTo(e),l.settings.copyClassesToDropdown&&e.addClass(j),b.css({width:q[0].style.width}),l.plugins.names.length&&(k="plugin-"+l.plugins.names.join(" plugin-"),b.addClass(k),e.addClass(k)),(null===m.maxItems||m.maxItems>1)&&l.tagType===v&&q.attr("multiple","multiple"),l.settings.placeholder&&d.attr("placeholder",m.placeholder),!l.settings.splitOn&&l.settings.delimiter){var u=l.settings.delimiter.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&");l.settings.splitOn=new RegExp("\\s*"+u+"+\\s*")}q.attr("autocorrect")&&d.attr("autocorrect",q.attr("autocorrect")),q.attr("autocapitalize")&&d.attr("autocapitalize",q.attr("autocapitalize")),l.$wrapper=b,l.$control=c,l.$control_input=d,l.$dropdown=e,l.$dropdown_content=g,e.on("mouseenter","[data-selectable]",function(){return l.onOptionHover.apply(l,arguments)}),e.on("mousedown click","[data-selectable]",function(){return l.onOptionSelect.apply(l,arguments)}),G(c,"mousedown","*:not(input)",function(){return l.onItemSelect.apply(l,arguments)}),K(d),c.on({mousedown:function(){return l.onMouseDown.apply(l,arguments)},click:function(){return l.onClick.apply(l,arguments)}}),d.on({mousedown:function(a){a.stopPropagation()},keydown:function(){return l.onKeyDown.apply(l,arguments)},keyup:function(){return l.onKeyUp.apply(l,arguments)},keypress:function(){return l.onKeyPress.apply(l,arguments)},resize:function(){l.positionDropdown.apply(l,[])},blur:function(){return l.onBlur.apply(l,arguments)},focus:function(){return l.ignoreBlur=!1,l.onFocus.apply(l,arguments)},paste:function(){return l.onPaste.apply(l,arguments)}}),p.on("keydown"+n,function(a){l.isCmdDown=a[f?"metaKey":"ctrlKey"],l.isCtrlDown=a[f?"altKey":"ctrlKey"],l.isShiftDown=a.shiftKey}),p.on("keyup"+n,function(a){a.keyCode===t&&(l.isCtrlDown=!1),a.keyCode===r&&(l.isShiftDown=!1),a.keyCode===s&&(l.isCmdDown=!1)}),p.on("mousedown"+n,function(a){if(l.isFocused){if(a.target===l.$dropdown[0]||a.target.parentNode===l.$dropdown[0])return!1;l.$control.has(a.target).length||a.target===l.$control[0]||l.blur(a.target)}}),o.on(["scroll"+n,"resize"+n].join(" "),function(){l.isOpen&&l.positionDropdown.apply(l,arguments)}),o.on("mousemove"+n,function(){l.ignoreHover=!1}),this.revertSettings={$children:q.children().detach(),tabindex:q.attr("tabindex")},q.attr("tabindex",-1).hide().after(l.$wrapper),a.isArray(m.items)&&(l.setValue(m.items),delete m.items),x&&q.on("invalid"+n,function(a){a.preventDefault(),l.isInvalid=!0,l.refreshState()}),l.updateOriginalInput(),l.refreshItems(),l.refreshState(),l.updatePlaceholder(),l.isSetup=!0,q.is(":disabled")&&l.disable(),l.on("change",this.onChange),q.data("selectize",l),q.addClass("selectized"),l.trigger("initialize"),m.preload===!0&&l.onSearchChange("")},setupTemplates:function(){var b=this,c=b.settings.labelField,d=b.settings.optgroupLabelField,e={optgroup:function(a){return'
'+a.html+"
"},optgroup_header:function(a,b){return'
'+b(a[d])+"
"},option:function(a,b){return'
'+b(a[c])+"
"},item:function(a,b){return'
'+b(a[c])+"
"},option_create:function(a,b){return'
Add '+b(a.input)+"
"}};b.settings.render=a.extend({},e,b.settings.render)},setupCallbacks:function(){var a,b,c={initialize:"onInitialize",change:"onChange",item_add:"onItemAdd",item_remove:"onItemRemove",clear:"onClear",option_add:"onOptionAdd",option_remove:"onOptionRemove",option_clear:"onOptionClear",optgroup_add:"onOptionGroupAdd",optgroup_remove:"onOptionGroupRemove",optgroup_clear:"onOptionGroupClear",dropdown_open:"onDropdownOpen",dropdown_close:"onDropdownClose",type:"onType",load:"onLoad",focus:"onFocus",blur:"onBlur"};for(a in c)c.hasOwnProperty(a)&&(b=this.settings[c[a]],b&&this.on(a,b))},onClick:function(a){var b=this;b.isFocused||(b.focus(),a.preventDefault())},onMouseDown:function(b){{var c=this,d=b.isDefaultPrevented();a(b.target)}if(c.isFocused){if(b.target!==c.$control_input[0])return"single"===c.settings.mode?c.isOpen?c.close():c.open():d||c.setActiveItem(null),!1}else d||window.setTimeout(function(){c.focus()},0)},onChange:function(){this.$input.trigger("change")},onPaste:function(b){var c=this;c.isFull()||c.isInputHidden||c.isLocked?b.preventDefault():c.settings.splitOn&&setTimeout(function(){for(var b=a.trim(c.$control_input.val()||"").split(c.settings.splitOn),d=0,e=b.length;e>d;d++)c.createItem(b[d])},0)},onKeyPress:function(a){if(this.isLocked)return a&&a.preventDefault();var b=String.fromCharCode(a.keyCode||a.which);return this.settings.create&&"multi"===this.settings.mode&&b===this.settings.delimiter?(this.createItem(),a.preventDefault(),!1):void 0},onKeyDown:function(a){var b=(a.target===this.$control_input[0],this);if(b.isLocked)return void(a.keyCode!==u&&a.preventDefault());switch(a.keyCode){case g:if(b.isCmdDown)return void b.selectAll();break;case i:return void(b.isOpen&&(a.preventDefault(),a.stopPropagation(),b.close()));case o:if(!a.ctrlKey||a.altKey)break;case n:if(!b.isOpen&&b.hasOptions)b.open();else if(b.$activeOption){b.ignoreHover=!0;var c=b.getAdjacentOption(b.$activeOption,1);c.length&&b.setActiveOption(c,!0,!0)}return void a.preventDefault();case l:if(!a.ctrlKey||a.altKey)break;case k:if(b.$activeOption){b.ignoreHover=!0;var d=b.getAdjacentOption(b.$activeOption,-1);d.length&&b.setActiveOption(d,!0,!0)}return void a.preventDefault();case h:return void(b.isOpen&&b.$activeOption&&(b.onOptionSelect({currentTarget:b.$activeOption}),a.preventDefault()));case j:return void b.advanceSelection(-1,a);case m:return void b.advanceSelection(1,a);case u:return b.settings.selectOnTab&&b.isOpen&&b.$activeOption&&(b.onOptionSelect({currentTarget:b.$activeOption}),b.isFull()||a.preventDefault()),void(b.settings.create&&b.createItem()&&a.preventDefault());case p:case q:return void b.deleteSelection(a)}return!b.isFull()&&!b.isInputHidden||(f?a.metaKey:a.ctrlKey)?void 0:void a.preventDefault()},onKeyUp:function(a){var b=this;if(b.isLocked)return a&&a.preventDefault();var c=b.$control_input.val()||"";b.lastValue!==c&&(b.lastValue=c,b.onSearchChange(c),b.refreshOptions(),b.trigger("type",c))},onSearchChange:function(a){var b=this,c=b.settings.load;c&&(b.loadedSearches.hasOwnProperty(a)||(b.loadedSearches[a]=!0,b.load(function(d){c.apply(b,[a,d])})))},onFocus:function(a){var b=this,c=b.isFocused;return b.isDisabled?(b.blur(),a&&a.preventDefault(),!1):void(b.ignoreFocus||(b.isFocused=!0,"focus"===b.settings.preload&&b.onSearchChange(""),c||b.trigger("focus"),b.$activeItems.length||(b.showInput(),b.setActiveItem(null),b.refreshOptions(!!b.settings.openOnFocus)),b.refreshState()))},onBlur:function(a,b){var c=this;if(c.isFocused&&(c.isFocused=!1,!c.ignoreFocus)){if(!c.ignoreBlur&&document.activeElement===c.$dropdown_content[0])return c.ignoreBlur=!0,void c.onFocus(a);var d=function(){c.close(),c.setTextboxValue(""),c.setActiveItem(null),c.setActiveOption(null),c.setCaret(c.items.length),c.refreshState(),(b||document.body).focus(),c.ignoreFocus=!1,c.trigger("blur")};c.ignoreFocus=!0,c.settings.create&&c.settings.createOnBlur?c.createItem(null,!1,d):d()}},onOptionHover:function(a){this.ignoreHover||this.setActiveOption(a.currentTarget,!1)},onOptionSelect:function(b){var c,d,e=this;b.preventDefault&&(b.preventDefault(),b.stopPropagation()),d=a(b.currentTarget),d.hasClass("create")?e.createItem(null,function(){e.settings.closeAfterSelect&&e.close()}):(c=d.attr("data-value"),"undefined"!=typeof c&&(e.lastQuery=null,e.setTextboxValue(""),e.addItem(c),e.settings.closeAfterSelect?e.close():!e.settings.hideSelected&&b.type&&/mouse/.test(b.type)&&e.setActiveOption(e.getOption(c))))},onItemSelect:function(a){var b=this;b.isLocked||"multi"===b.settings.mode&&(a.preventDefault(),b.setActiveItem(a.currentTarget,a))},load:function(a){var b=this,c=b.$wrapper.addClass(b.settings.loadingClass);b.loading++,a.apply(b,[function(a){b.loading=Math.max(b.loading-1,0),a&&a.length&&(b.addOption(a),b.refreshOptions(b.isFocused&&!b.isInputHidden)),b.loading||c.removeClass(b.settings.loadingClass),b.trigger("load",a)}])},setTextboxValue:function(a){var b=this.$control_input,c=b.val()!==a;c&&(b.val(a).triggerHandler("update"),this.lastValue=a)},getValue:function(){return this.tagType===v&&this.$input.attr("multiple")?this.items:this.items.join(this.settings.delimiter)},setValue:function(a,b){var c=b?[]:["change"];F(this,c,function(){this.clear(b),this.addItems(a,b)})},setActiveItem:function(b,c){var d,e,f,g,h,i,j,k,l=this;if("single"!==l.settings.mode){if(b=a(b),!b.length)return a(l.$activeItems).removeClass("active"),l.$activeItems=[],void(l.isFocused&&l.showInput());if(d=c&&c.type.toLowerCase(),"mousedown"===d&&l.isShiftDown&&l.$activeItems.length){for(k=l.$control.children(".active:last"),g=Array.prototype.indexOf.apply(l.$control[0].childNodes,[k[0]]),h=Array.prototype.indexOf.apply(l.$control[0].childNodes,[b[0]]),g>h&&(j=g,g=h,h=j),e=g;h>=e;e++)i=l.$control[0].childNodes[e],-1===l.$activeItems.indexOf(i)&&(a(i).addClass("active"),l.$activeItems.push(i));c.preventDefault()}else"mousedown"===d&&l.isCtrlDown||"keydown"===d&&this.isShiftDown?b.hasClass("active")?(f=l.$activeItems.indexOf(b[0]),l.$activeItems.splice(f,1),b.removeClass("active")):l.$activeItems.push(b.addClass("active")[0]):(a(l.$activeItems).removeClass("active"),l.$activeItems=[b.addClass("active")[0]]);l.hideInput(),this.isFocused||l.focus()}},setActiveOption:function(b,c,d){var e,f,g,h,i,j=this;j.$activeOption&&j.$activeOption.removeClass("active"),j.$activeOption=null,b=a(b),b.length&&(j.$activeOption=b.addClass("active"),(c||!y(c))&&(e=j.$dropdown_content.height(),f=j.$activeOption.outerHeight(!0),c=j.$dropdown_content.scrollTop()||0,g=j.$activeOption.offset().top-j.$dropdown_content.offset().top+c,h=g,i=g-e+f,g+f>e+c?j.$dropdown_content.stop().animate({scrollTop:i},d?j.settings.scrollDuration:0):c>g&&j.$dropdown_content.stop().animate({scrollTop:h},d?j.settings.scrollDuration:0)))},selectAll:function(){var a=this;"single"!==a.settings.mode&&(a.$activeItems=Array.prototype.slice.apply(a.$control.children(":not(input)").addClass("active")),a.$activeItems.length&&(a.hideInput(),a.close()),a.focus())},hideInput:function(){var a=this;a.setTextboxValue(""),a.$control_input.css({opacity:0,position:"absolute",left:a.rtl?1e4:-1e4}),a.isInputHidden=!0},showInput:function(){this.$control_input.css({opacity:1,position:"relative",left:0}),this.isInputHidden=!1},focus:function(){var a=this;a.isDisabled||(a.ignoreFocus=!0,a.$control_input[0].focus(),window.setTimeout(function(){a.ignoreFocus=!1,a.onFocus()},0))},blur:function(a){this.$control_input[0].blur(),this.onBlur(null,a)},getScoreFunction:function(a){return this.sifter.getScoreFunction(a,this.getSearchOptions())},getSearchOptions:function(){var a=this.settings,b=a.sortField;return"string"==typeof b&&(b=[{field:b}]),{fields:a.searchField,conjunction:a.searchConjunction,sort:b}},search:function(b){var c,d,e,f=this,g=f.settings,h=this.getSearchOptions();if(g.score&&(e=f.settings.score.apply(this,[b]),"function"!=typeof e))throw new Error('Selectize "score" setting must be a function that returns a function');if(b!==f.lastQuery?(f.lastQuery=b,d=f.sifter.search(b,a.extend(h,{score:e})),f.currentResults=d):d=a.extend(!0,{},f.currentResults),g.hideSelected)for(c=d.items.length-1;c>=0;c--)-1!==f.items.indexOf(z(d.items[c].id))&&d.items.splice(c,1);return d},refreshOptions:function(b){var c,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s;"undefined"==typeof b&&(b=!0);var t=this,u=a.trim(t.$control_input.val()),v=t.search(u),w=t.$dropdown_content,x=t.$activeOption&&z(t.$activeOption.attr("data-value"));for(g=v.items.length,"number"==typeof t.settings.maxOptions&&(g=Math.min(g,t.settings.maxOptions)),h={},i=[],c=0;g>c;c++)for(j=t.options[v.items[c].id],k=t.render("option",j),l=j[t.settings.optgroupField]||"",m=a.isArray(l)?l:[l],e=0,f=m&&m.length;f>e;e++)l=m[e],t.optgroups.hasOwnProperty(l)||(l=""),h.hasOwnProperty(l)||(h[l]=[],i.push(l)),h[l].push(k);for(this.settings.lockOptgroupOrder&&i.sort(function(a,b){var c=t.optgroups[a].$order||0,d=t.optgroups[b].$order||0;return c-d}),n=[],c=0,g=i.length;g>c;c++)l=i[c],t.optgroups.hasOwnProperty(l)&&h[l].length?(o=t.render("optgroup_header",t.optgroups[l])||"",o+=h[l].join(""),n.push(t.render("optgroup",a.extend({},t.optgroups[l],{html:o})))):n.push(h[l].join(""));if(w.html(n.join("")),t.settings.highlight&&v.query.length&&v.tokens.length)for(c=0,g=v.tokens.length;g>c;c++)d(w,v.tokens[c].regex);if(!t.settings.hideSelected)for(c=0,g=t.items.length;g>c;c++)t.getOption(t.items[c]).addClass("selected");p=t.canCreate(u),p&&(w.prepend(t.render("option_create",{input:u})),s=a(w[0].childNodes[0])),t.hasOptions=v.items.length>0||p,t.hasOptions?(v.items.length>0?(r=x&&t.getOption(x),r&&r.length?q=r:"single"===t.settings.mode&&t.items.length&&(q=t.getOption(t.items[0])),q&&q.length||(q=s&&!t.settings.addPrecedence?t.getAdjacentOption(s,1):w.find("[data-selectable]:first"))):q=s,t.setActiveOption(q),b&&!t.isOpen&&t.open()):(t.setActiveOption(null),b&&t.isOpen&&t.close())},addOption:function(b){var c,d,e,f=this;if(a.isArray(b))for(c=0,d=b.length;d>c;c++)f.addOption(b[c]);else(e=f.registerOption(b))&&(f.userOptions[e]=!0,f.lastQuery=null,f.trigger("option_add",e,b))},registerOption:function(a){var b=z(a[this.settings.valueField]);return!b||this.options.hasOwnProperty(b)?!1:(a.$order=a.$order||++this.order,this.options[b]=a,b)},registerOptionGroup:function(a){var b=z(a[this.settings.optgroupValueField]);return b?(a.$order=a.$order||++this.order,this.optgroups[b]=a,b):!1},addOptionGroup:function(a,b){b[this.settings.optgroupValueField]=a,(a=this.registerOptionGroup(b))&&this.trigger("optgroup_add",a,b)},removeOptionGroup:function(a){this.optgroups.hasOwnProperty(a)&&(delete this.optgroups[a],this.renderCache={},this.trigger("optgroup_remove",a))},clearOptionGroups:function(){this.optgroups={},this.renderCache={},this.trigger("optgroup_clear")},updateOption:function(b,c){var d,e,f,g,h,i,j,k=this;if(b=z(b),f=z(c[k.settings.valueField]),null!==b&&k.options.hasOwnProperty(b)){if("string"!=typeof f)throw new Error("Value must be set in option data");j=k.options[b].$order,f!==b&&(delete k.options[b],g=k.items.indexOf(b),-1!==g&&k.items.splice(g,1,f)),c.$order=c.$order||j,k.options[f]=c,h=k.renderCache.item,i=k.renderCache.option,h&&(delete h[b],delete h[f]),i&&(delete i[b],delete i[f]),-1!==k.items.indexOf(f)&&(d=k.getItem(b),e=a(k.render("item",c)),d.hasClass("active")&&e.addClass("active"),d.replaceWith(e)),k.lastQuery=null,k.isOpen&&k.refreshOptions(!1)}},removeOption:function(a,b){var c=this;a=z(a);var d=c.renderCache.item,e=c.renderCache.option;d&&delete d[a],e&&delete e[a],delete c.userOptions[a],delete c.options[a],c.lastQuery=null,c.trigger("option_remove",a),c.removeItem(a,b)},clearOptions:function(){var a=this;a.loadedSearches={},a.userOptions={},a.renderCache={},a.options=a.sifter.items={},a.lastQuery=null,a.trigger("option_clear"),a.clear()},getOption:function(a){return this.getElementWithValue(a,this.$dropdown_content.find("[data-selectable]"))},getAdjacentOption:function(b,c){var d=this.$dropdown.find("[data-selectable]"),e=d.index(b)+c;return e>=0&&ed;d++)if(c[d].getAttribute("data-value")===b)return a(c[d]);return a()},getItem:function(a){return this.getElementWithValue(a,this.$control.children())},addItems:function(b,c){for(var d=a.isArray(b)?b:[b],e=0,f=d.length;f>e;e++)this.isPending=f-1>e,this.addItem(d[e],c)},addItem:function(b,c){var d=c?[]:["change"];F(this,d,function(){var d,e,f,g,h,i=this,j=i.settings.mode;return b=z(b),-1!==i.items.indexOf(b)?void("single"===j&&i.close()):void(i.options.hasOwnProperty(b)&&("single"===j&&i.clear(c),"multi"===j&&i.isFull()||(d=a(i.render("item",i.options[b])),h=i.isFull(),i.items.splice(i.caretPos,0,b),i.insertAtCaret(d),(!i.isPending||!h&&i.isFull())&&i.refreshState(),i.isSetup&&(f=i.$dropdown_content.find("[data-selectable]"),i.isPending||(e=i.getOption(b),g=i.getAdjacentOption(e,1).attr("data-value"),i.refreshOptions(i.isFocused&&"single"!==j),g&&i.setActiveOption(i.getOption(g))),!f.length||i.isFull()?i.close():i.positionDropdown(),i.updatePlaceholder(),i.trigger("item_add",b,d),i.updateOriginalInput({silent:c})))))})},removeItem:function(a,b){var c,d,e,f=this;c="object"==typeof a?a:f.getItem(a),a=z(c.attr("data-value")),d=f.items.indexOf(a),-1!==d&&(c.remove(),c.hasClass("active")&&(e=f.$activeItems.indexOf(c[0]),f.$activeItems.splice(e,1)),f.items.splice(d,1),f.lastQuery=null,!f.settings.persist&&f.userOptions.hasOwnProperty(a)&&f.removeOption(a,b),d0),b.$control_input.data("grow",!c&&!d)},isFull:function(){return null!==this.settings.maxItems&&this.items.length>=this.settings.maxItems},updateOriginalInput:function(a){var b,c,d,e,f=this;if(a=a||{},f.tagType===v){for(d=[],b=0,c=f.items.length;c>b;b++)e=f.options[f.items[b]][f.settings.labelField]||"",d.push('");d.length||this.$input.attr("multiple")||d.push(''),f.$input.html(d.join(""))}else f.$input.val(f.getValue()),f.$input.attr("value",f.$input.val());f.isSetup&&(a.silent||f.trigger("change",f.$input.val()))},updatePlaceholder:function(){if(this.settings.placeholder){var a=this.$control_input;this.items.length?a.removeAttr("placeholder"):a.attr("placeholder",this.settings.placeholder),a.triggerHandler("update",{force:!0})}},open:function(){var a=this;a.isLocked||a.isOpen||"multi"===a.settings.mode&&a.isFull()||(a.focus(),a.isOpen=!0,a.refreshState(),a.$dropdown.css({visibility:"hidden",display:"block"}),a.positionDropdown(),a.$dropdown.css({visibility:"visible"}),a.trigger("dropdown_open",a.$dropdown))},close:function(){var a=this,b=a.isOpen;"single"===a.settings.mode&&a.items.length&&a.hideInput(),a.isOpen=!1,a.$dropdown.hide(),a.setActiveOption(null),a.refreshState(),b&&a.trigger("dropdown_close",a.$dropdown)},positionDropdown:function(){var a=this.$control,b="body"===this.settings.dropdownParent?a.offset():a.position();b.top+=a.outerHeight(!0),this.$dropdown.css({width:a.outerWidth(),top:b.top,left:b.left})},clear:function(a){var b=this;b.items.length&&(b.$control.children(":not(input)").remove(),b.items=[],b.lastQuery=null,b.setCaret(0),b.setActiveItem(null),b.updatePlaceholder(),b.updateOriginalInput({silent:a}),b.refreshState(),b.showInput(),b.trigger("clear"))},insertAtCaret:function(b){var c=Math.min(this.caretPos,this.items.length);0===c?this.$control.prepend(b):a(this.$control[0].childNodes[c]).before(b),this.setCaret(c+1)},deleteSelection:function(b){var c,d,e,f,g,h,i,j,k,l=this;if(e=b&&b.keyCode===p?-1:1,f=H(l.$control_input[0]),l.$activeOption&&!l.settings.hideSelected&&(i=l.getAdjacentOption(l.$activeOption,-1).attr("data-value")),g=[],l.$activeItems.length){for(k=l.$control.children(".active:"+(e>0?"last":"first")),h=l.$control.children(":not(input)").index(k),e>0&&h++,c=0,d=l.$activeItems.length;d>c;c++)g.push(a(l.$activeItems[c]).attr("data-value")); b&&(b.preventDefault(),b.stopPropagation())}else(l.isFocused||"single"===l.settings.mode)&&l.items.length&&(0>e&&0===f.start&&0===f.length?g.push(l.items[l.caretPos-1]):e>0&&f.start===l.$control_input.val().length&&g.push(l.items[l.caretPos]));if(!g.length||"function"==typeof l.settings.onDelete&&l.settings.onDelete.apply(l,[g])===!1)return!1;for("undefined"!=typeof h&&l.setCaret(h);g.length;)l.removeItem(g.pop());return l.showInput(),l.positionDropdown(),l.refreshOptions(!0),i&&(j=l.getOption(i),j.length&&l.setActiveOption(j)),!0},advanceSelection:function(a,b){var c,d,e,f,g,h,i=this;0!==a&&(i.rtl&&(a*=-1),c=a>0?"last":"first",d=H(i.$control_input[0]),i.isFocused&&!i.isInputHidden?(f=i.$control_input.val().length,g=0>a?0===d.start&&0===d.length:d.start===f,g&&!f&&i.advanceCaret(a,b)):(h=i.$control.children(".active:"+c),h.length&&(e=i.$control.children(":not(input)").index(h),i.setActiveItem(null),i.setCaret(a>0?e+1:e))))},advanceCaret:function(a,b){var c,d,e=this;0!==a&&(c=a>0?"next":"prev",e.isShiftDown?(d=e.$control_input[c](),d.length&&(e.hideInput(),e.setActiveItem(d),b&&b.preventDefault())):e.setCaret(e.caretPos+a))},setCaret:function(b){var c=this;if(b="single"===c.settings.mode?c.items.length:Math.max(0,Math.min(c.items.length,b)),!c.isPending){var d,e,f,g;for(f=c.$control.children(":not(input)"),d=0,e=f.length;e>d;d++)g=a(f[d]).detach(),b>d?c.$control_input.before(g):c.$control.append(g)}c.caretPos=b},lock:function(){this.close(),this.isLocked=!0,this.refreshState()},unlock:function(){this.isLocked=!1,this.refreshState()},disable:function(){var a=this;a.$input.prop("disabled",!0),a.$control_input.prop("disabled",!0).prop("tabindex",-1),a.isDisabled=!0,a.lock()},enable:function(){var a=this;a.$input.prop("disabled",!1),a.$control_input.prop("disabled",!1).prop("tabindex",a.tabIndex),a.isDisabled=!1,a.unlock()},destroy:function(){var b=this,c=b.eventNS,d=b.revertSettings;b.trigger("destroy"),b.off(),b.$wrapper.remove(),b.$dropdown.remove(),b.$input.html("").append(d.$children).removeAttr("tabindex").removeClass("selectized").attr({tabindex:d.tabindex}).show(),b.$control_input.removeData("grow"),b.$input.removeData("selectize"),a(window).off(c),a(document).off(c),a(document.body).off(c),delete b.$input[0].selectize},render:function(a,b){var c,d,e="",f=!1,g=this,h=/^[\t \r\n]*<([a-z][a-z0-9\-_]*(?:\:[a-z][a-z0-9\-_]*)?)/i;return("option"===a||"item"===a)&&(c=z(b[g.settings.valueField]),f=!!c),f&&(y(g.renderCache[a])||(g.renderCache[a]={}),g.renderCache[a].hasOwnProperty(c))?g.renderCache[a][c]:(e=g.settings.render[a].apply(this,[b,A]),("option"===a||"option_create"===a)&&(e=e.replace(h,"<$1 data-selectable")),"optgroup"===a&&(d=b[g.settings.optgroupValueField]||"",e=e.replace(h,'<$1 data-group="'+B(A(d))+'"')),("option"===a||"item"===a)&&(e=e.replace(h,'<$1 data-value="'+B(A(c||""))+'"')),f&&(g.renderCache[a][c]=e),e)},clearCache:function(a){var b=this;"undefined"==typeof a?b.renderCache={}:delete b.renderCache[a]},canCreate:function(a){var b=this;if(!b.settings.create)return!1;var c=b.settings.createFilter;return!(!a.length||"function"==typeof c&&!c.apply(b,[a])||"string"==typeof c&&!new RegExp(c).test(a)||c instanceof RegExp&&!c.test(a))}}),L.count=0,L.defaults={options:[],optgroups:[],plugins:[],delimiter:",",splitOn:null,persist:!0,diacritics:!0,create:!1,createOnBlur:!1,createFilter:null,highlight:!0,openOnFocus:!0,maxOptions:1e3,maxItems:null,hideSelected:null,addPrecedence:!1,selectOnTab:!1,preload:!1,allowEmptyOption:!1,closeAfterSelect:!1,scrollDuration:60,loadThrottle:300,loadingClass:"loading",dataAttr:"data-data",optgroupField:"optgroup",valueField:"value",labelField:"text",optgroupLabelField:"label",optgroupValueField:"value",lockOptgroupOrder:!1,sortField:"$order",searchField:["text"],searchConjunction:"and",mode:null,wrapperClass:"selectize-control",inputClass:"selectize-input",dropdownClass:"selectize-dropdown",dropdownContentClass:"selectize-dropdown-content",dropdownParent:null,copyClassesToDropdown:!0,render:{}},a.fn.selectize=function(b){var c=a.fn.selectize.defaults,d=a.extend({},c,b),e=d.dataAttr,f=d.labelField,g=d.valueField,h=d.optgroupField,i=d.optgroupLabelField,j=d.optgroupValueField,k=function(b,c){var h,i,j,k,l=b.attr(e);if(l)for(c.options=JSON.parse(l),h=0,i=c.options.length;i>h;h++)c.items.push(c.options[h][g]);else{var m=a.trim(b.val()||"");if(!d.allowEmptyOption&&!m.length)return;for(j=m.split(d.delimiter),h=0,i=j.length;i>h;h++)k={},k[f]=j[h],k[g]=j[h],c.options.push(k);c.items=j}},l=function(b,c){var k,l,m,n,o=c.options,p={},q=function(a){var b=e&&a.attr(e);return"string"==typeof b&&b.length?JSON.parse(b):null},r=function(b,e){b=a(b);var i=z(b.attr("value"));if(i||d.allowEmptyOption)if(p.hasOwnProperty(i)){if(e){var j=p[i][h];j?a.isArray(j)?j.push(e):p[i][h]=[j,e]:p[i][h]=e}}else{var k=q(b)||{};k[f]=k[f]||b.text(),k[g]=k[g]||i,k[h]=k[h]||e,p[i]=k,o.push(k),b.is(":selected")&&c.items.push(i)}},s=function(b){var d,e,f,g,h;for(b=a(b),f=b.attr("label"),f&&(g=q(b)||{},g[i]=f,g[j]=f,c.optgroups.push(g)),h=a("option",b),d=0,e=h.length;e>d;d++)r(h[d],f)};for(c.maxItems=b.attr("multiple")?null:1,n=b.children(),k=0,l=n.length;l>k;k++)m=n[k].tagName.toLowerCase(),"optgroup"===m?s(n[k]):"option"===m&&r(n[k])};return this.each(function(){if(!this.selectize){var e,f=a(this),g=this.tagName.toLowerCase(),h=f.attr("placeholder")||f.attr("data-placeholder");h||d.allowEmptyOption||(h=f.children('option[value=""]').text());var i={placeholder:h,options:[],optgroups:[],items:[]};"select"===g?l(f,i):k(f,i),e=new L(f,a.extend(!0,{},c,i,b))}})},a.fn.selectize.defaults=L.defaults,a.fn.selectize.support={validity:x},L.define("drag_drop",function(){if(!a.fn.sortable)throw new Error('The "drag_drop" plugin requires jQuery UI "sortable".');if("multi"===this.settings.mode){var b=this;b.lock=function(){var a=b.lock;return function(){var c=b.$control.data("sortable");return c&&c.disable(),a.apply(b,arguments)}}(),b.unlock=function(){var a=b.unlock;return function(){var c=b.$control.data("sortable");return c&&c.enable(),a.apply(b,arguments)}}(),b.setup=function(){var c=b.setup;return function(){c.apply(this,arguments);var d=b.$control.sortable({items:"[data-value]",forcePlaceholderSize:!0,disabled:b.isLocked,start:function(a,b){b.placeholder.css("width",b.helper.css("width")),d.css({overflow:"visible"})},stop:function(){d.css({overflow:"hidden"});var c=b.$activeItems?b.$activeItems.slice():null,e=[];d.children("[data-value]").each(function(){e.push(a(this).attr("data-value"))}),b.setValue(e),b.setActiveItem(c)}})}}()}}),L.define("dropdown_header",function(b){var c=this;b=a.extend({title:"Untitled",headerClass:"selectize-dropdown-header",titleRowClass:"selectize-dropdown-header-title",labelClass:"selectize-dropdown-header-label",closeClass:"selectize-dropdown-header-close",html:function(a){return'
'+a.title+'×
'}},b),c.setup=function(){var d=c.setup;return function(){d.apply(c,arguments),c.$dropdown_header=a(b.html(b)),c.$dropdown.prepend(c.$dropdown_header)}}()}),L.define("optgroup_columns",function(b){var c=this;b=a.extend({equalizeWidth:!0,equalizeHeight:!0},b),this.getAdjacentOption=function(b,c){var d=b.closest("[data-group]").find("[data-selectable]"),e=d.index(b)+c;return e>=0&&e
',a=a.firstChild,c.body.appendChild(a),b=d.width=a.offsetWidth-a.clientWidth,c.body.removeChild(a)),b},e=function(){var e,f,g,h,i,j,k;if(k=a("[data-group]",c.$dropdown_content),f=k.length,f&&c.$dropdown_content.width()){if(b.equalizeHeight){for(g=0,e=0;f>e;e++)g=Math.max(g,k.eq(e).height());k.css({height:g})}b.equalizeWidth&&(j=c.$dropdown_content.innerWidth()-d(),h=Math.round(j/f),k.css({width:h}),f>1&&(i=j-h*(f-1),k.eq(f-1).css({width:i})))}};(b.equalizeHeight||b.equalizeWidth)&&(C.after(this,"positionDropdown",e),C.after(this,"refreshOptions",e))}),L.define("remove_button",function(b){if("single"!==this.settings.mode){b=a.extend({label:"×",title:"Remove",className:"remove",append:!0},b);var c=this,d=''+b.label+"",e=function(a,b){var c=a.search(/(<\/[^>]+>\s*)$/);return a.substring(0,c)+b+a.substring(c)};this.setup=function(){var f=c.setup;return function(){if(b.append){var g=c.settings.render.item;c.settings.render.item=function(){return e(g.apply(this,arguments),d)}}f.apply(this,arguments),this.$control.on("click","."+b.className,function(b){if(b.preventDefault(),!c.isLocked){var d=a(b.currentTarget).parent();c.setActiveItem(d),c.deleteSelection()&&c.setCaret(c.items.length)}})}}()}}),L.define("restore_on_backspace",function(a){var b=this;a.text=a.text||function(a){return a[this.settings.labelField]},this.onKeyDown=function(){var c=b.onKeyDown;return function(b){var d,e;return b.keyCode===p&&""===this.$control_input.val()&&!this.$activeItems.length&&(d=this.caretPos-1,d>=0&&d input, .twothird > textarea { width: 450px; } input.half, textarea.half, .half > input, .half > textarea { width: 300px; } input.third, textarea.third, .third > input, .third > textarea { width: 150px; } input.sixth, textarea.sixth, .sixth > input, .sixth > textarea { width: 75px; } input[type=number] { width: 75px; min-width: 75px; } table { border: 1px solid #ccc; border-spacing: 1px; } td, th { padding: 5px 7px; min-width: 35px; } thead td, th { background-color: #a0a0a0; } th { text-align: left; } tbody td { background-color: #cecece; } tr.evenrow td { background-color: #dadada; } .info { font-style: italic; font-size: 80%; } .subsection { clear: both; margin: 0; } .subsection div { float: left; } .subsection .inputlabel { width: 120px; text-align: right; padding: 10px 5px 0 0; } .subsection > input, .subsection select, .subsection textarea { margin: 5px 0 5px 0; min-width: 75px; vertical-align: middle; } .subsection div.checkbox { padding: 9px 0 0 3px; } .subsection div.checkbox input { min-width: 0; } .section .info { margin-bottom: 5px; display: block; } .subsection .info { text-align: right; } .half .info { width: 435px; } .third .info { width: 285px; } .twothird .info { width: 585px; } .full .info { width: 610px; clear: both; } td.mod_descr, td.mod_name, td.mod_args input { font-size: 80%; } td.mod_name, .checkboxandlabel { white-space: nowrap; } .lotsofcheckboxes .checkboxandlabel { display: block; float: left; width: 100%; margin-top: 0.5em; } #breadcrumb { width: 670px; padding: 0 0 3px 1px; margin-bottom: 10px; border-bottom: 1px solid #aaa; } td { word-wrap: break-word; } .textsection p { margin-bottom: 0.7em; } znc-1.7.5/webskins/_default_/pub/jquery-1.11.2.js0000644000175000017500000105303013542151610021472 0ustar somebodysomebody/*! * jQuery JavaScript Library v1.11.2 * http://jquery.com/ * * Includes Sizzle.js * http://sizzlejs.com/ * * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2014-12-17T15:27Z */ (function( global, factory ) { if ( typeof module === "object" && typeof module.exports === "object" ) { // For CommonJS and CommonJS-like environments where a proper window is present, // execute the factory and get jQuery // For environments that do not inherently posses a window with a document // (such as Node.js), expose a jQuery-making factory as module.exports // This accentuates the need for the creation of a real window // e.g. var jQuery = require("jquery")(window); // See ticket #14549 for more info module.exports = global.document ? factory( global, true ) : function( w ) { if ( !w.document ) { throw new Error( "jQuery requires a window with a document" ); } return factory( w ); }; } else { factory( global ); } // Pass this if window is not defined yet }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { // Can't do this because several apps including ASP.NET trace // the stack via arguments.caller.callee and Firefox dies if // you try to trace through "use strict" call chains. (#13335) // Support: Firefox 18+ // var deletedIds = []; var slice = deletedIds.slice; var concat = deletedIds.concat; var push = deletedIds.push; var indexOf = deletedIds.indexOf; var class2type = {}; var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty; var support = {}; var version = "1.11.2", // Define a local copy of jQuery jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' // Need init if jQuery is called (just allow error to be thrown if not included) return new jQuery.fn.init( selector, context ); }, // Support: Android<4.1, IE<9 // Make sure we trim BOM and NBSP rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, // Matches dashed string for camelizing rmsPrefix = /^-ms-/, rdashAlpha = /-([\da-z])/gi, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { return letter.toUpperCase(); }; jQuery.fn = jQuery.prototype = { // The current version of jQuery being used jquery: version, constructor: jQuery, // Start with an empty selector selector: "", // The default length of a jQuery object is 0 length: 0, toArray: function() { return slice.call( this ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num != null ? // Return just the one element from the set ( num < 0 ? this[ num + this.length ] : this[ num ] ) : // Return all the elements in a clean array slice.call( this ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems ) { // Build a new jQuery matched element set var ret = jQuery.merge( this.constructor(), elems ); // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); }, map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); }, slice: function() { return this.pushStack( slice.apply( this, arguments ) ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); }, end: function() { return this.prevObject || this.constructor(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: push, sort: deletedIds.sort, splice: deletedIds.splice }; jQuery.extend = jQuery.fn.extend = function() { var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; // skip the boolean and the target target = arguments[ i ] || {}; i++; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( i === length ) { target = this; i--; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend({ // Unique for each copy of jQuery on the page expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), // Assume jQuery is ready without the ready module isReady: true, error: function( msg ) { throw new Error( msg ); }, noop: function() {}, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { return jQuery.type(obj) === "function"; }, isArray: Array.isArray || function( obj ) { return jQuery.type(obj) === "array"; }, isWindow: function( obj ) { /* jshint eqeqeq: false */ return obj != null && obj == obj.window; }, isNumeric: function( obj ) { // parseFloat NaNs numeric-cast false positives (null|true|false|"") // ...but misinterprets leading-number strings, particularly hex literals ("0x...") // subtraction forces infinities to NaN // adding 1 corrects loss of precision from parseFloat (#15100) return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0; }, isEmptyObject: function( obj ) { var name; for ( name in obj ) { return false; } return true; }, isPlainObject: function( obj ) { var key; // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { return false; } try { // Not own constructor property must be Object if ( obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // Support: IE<9 // Handle iteration over inherited properties before own properties. if ( support.ownLast ) { for ( key in obj ) { return hasOwn.call( obj, key ); } } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. for ( key in obj ) {} return key === undefined || hasOwn.call( obj, key ); }, type: function( obj ) { if ( obj == null ) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call(obj) ] || "object" : typeof obj; }, // Evaluates a script in a global context // Workarounds based on findings by Jim Driscoll // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { if ( data && jQuery.trim( data ) ) { // We use execScript on Internet Explorer // We use an anonymous function so that context is window // rather than jQuery in Firefox ( window.execScript || function( data ) { window[ "eval" ].call( window, data ); } )( data ); } }, // Convert dashed to camelCase; used by the css and data modules // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); }, // args is for internal usage only each: function( obj, callback, args ) { var value, i = 0, length = obj.length, isArray = isArraylike( obj ); if ( args ) { if ( isArray ) { for ( ; i < length; i++ ) { value = callback.apply( obj[ i ], args ); if ( value === false ) { break; } } } else { for ( i in obj ) { value = callback.apply( obj[ i ], args ); if ( value === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isArray ) { for ( ; i < length; i++ ) { value = callback.call( obj[ i ], i, obj[ i ] ); if ( value === false ) { break; } } } else { for ( i in obj ) { value = callback.call( obj[ i ], i, obj[ i ] ); if ( value === false ) { break; } } } } return obj; }, // Support: Android<4.1, IE<9 trim: function( text ) { return text == null ? "" : ( text + "" ).replace( rtrim, "" ); }, // results is for internal usage only makeArray: function( arr, results ) { var ret = results || []; if ( arr != null ) { if ( isArraylike( Object(arr) ) ) { jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr ); } else { push.call( ret, arr ); } } return ret; }, inArray: function( elem, arr, i ) { var len; if ( arr ) { if ( indexOf ) { return indexOf.call( arr, elem, i ); } len = arr.length; i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; for ( ; i < len; i++ ) { // Skip accessing in sparse arrays if ( i in arr && arr[ i ] === elem ) { return i; } } } return -1; }, merge: function( first, second ) { var len = +second.length, j = 0, i = first.length; while ( j < len ) { first[ i++ ] = second[ j++ ]; } // Support: IE<9 // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) if ( len !== len ) { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, invert ) { var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert; // Go through the array, only saving the items // that pass the validator function for ( ; i < length; i++ ) { callbackInverse = !callback( elems[ i ], i ); if ( callbackInverse !== callbackExpect ) { matches.push( elems[ i ] ); } } return matches; }, // arg is for internal usage only map: function( elems, callback, arg ) { var value, i = 0, length = elems.length, isArray = isArraylike( elems ), ret = []; // Go through the array, translating each of the items to their new values if ( isArray ) { for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } // Go through every key on the object, } else { for ( i in elems ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } } // Flatten any nested arrays return concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { var args, proxy, tmp; if ( typeof context === "string" ) { tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind args = slice.call( arguments, 2 ); proxy = function() { return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || jQuery.guid++; return proxy; }, now: function() { return +( new Date() ); }, // jQuery.support is not used in Core but other projects attach their // properties to it so it needs to exist. support: support }); // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); function isArraylike( obj ) { var length = obj.length, type = jQuery.type( obj ); if ( type === "function" || jQuery.isWindow( obj ) ) { return false; } if ( obj.nodeType === 1 && length ) { return true; } return type === "array" || length === 0 || typeof length === "number" && length > 0 && ( length - 1 ) in obj; } var Sizzle = /*! * Sizzle CSS Selector Engine v2.2.0-pre * http://sizzlejs.com/ * * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2014-12-16 */ (function( window ) { var i, support, Expr, getText, isXML, tokenize, compile, select, outermostContext, sortInput, hasDuplicate, // Local document vars setDocument, document, docElem, documentIsHTML, rbuggyQSA, rbuggyMatches, matches, contains, // Instance-specific data expando = "sizzle" + 1 * new Date(), preferredDoc = window.document, dirruns = 0, done = 0, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; } return 0; }, // General-purpose constants MAX_NEGATIVE = 1 << 31, // Instance methods hasOwn = ({}).hasOwnProperty, arr = [], pop = arr.pop, push_native = arr.push, push = arr.push, slice = arr.slice, // Use a stripped-down indexOf as it's faster than native // http://jsperf.com/thor-indexof-vs-for/5 indexOf = function( list, elem ) { var i = 0, len = list.length; for ( ; i < len; i++ ) { if ( list[i] === elem ) { return i; } } return -1; }, booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", // Regular expressions // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace whitespace = "[\\x20\\t\\r\\n\\f]", // http://www.w3.org/TR/css3-syntax/#characters characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", // Loosely modeled on CSS identifier characters // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier identifier = characterEncoding.replace( "w", "w#" ), // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + // Operator (capture 2) "*([*^$|!~]?=)" + whitespace + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]", pseudos = ":(" + characterEncoding + ")(?:\\((" + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: // 1. quoted (capture 3; capture 4 or capture 5) "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + // 2. simple (capture 6) "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + // 3. anything else (capture 2) ".*" + ")\\)|)", // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter rwhitespace = new RegExp( whitespace + "+", "g" ), rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), rpseudo = new RegExp( pseudos ), ridentifier = new RegExp( "^" + identifier + "$" ), matchExpr = { "ID": new RegExp( "^#(" + characterEncoding + ")" ), "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), "ATTR": new RegExp( "^" + attributes ), "PSEUDO": new RegExp( "^" + pseudos ), "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), // For use in libraries implementing .is() // We use this for POS matching in `select` "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rnative = /^[^{]+\{\s*\[native \w/, // Easily-parseable/retrievable ID or TAG or CLASS selectors rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, rescape = /'|\\/g, // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), funescape = function( _, escaped, escapedWhitespace ) { var high = "0x" + escaped - 0x10000; // NaN means non-codepoint // Support: Firefox<24 // Workaround erroneous numeric interpretation of +"0x" return high !== high || escapedWhitespace ? escaped : high < 0 ? // BMP codepoint String.fromCharCode( high + 0x10000 ) : // Supplemental Plane codepoint (surrogate pair) String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); }, // Used for iframes // See setDocument() // Removing the function wrapper causes a "Permission Denied" // error in IE unloadHandler = function() { setDocument(); }; // Optimize for push.apply( _, NodeList ) try { push.apply( (arr = slice.call( preferredDoc.childNodes )), preferredDoc.childNodes ); // Support: Android<4.0 // Detect silently failing push.apply arr[ preferredDoc.childNodes.length ].nodeType; } catch ( e ) { push = { apply: arr.length ? // Leverage slice if possible function( target, els ) { push_native.apply( target, slice.call(els) ); } : // Support: IE<9 // Otherwise append directly function( target, els ) { var j = target.length, i = 0; // Can't trust NodeList.length while ( (target[j++] = els[i++]) ) {} target.length = j - 1; } }; } function Sizzle( selector, context, results, seed ) { var match, elem, m, nodeType, // QSA vars i, groups, old, nid, newContext, newSelector; if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { setDocument( context ); } context = context || document; results = results || []; nodeType = context.nodeType; if ( typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { return results; } if ( !seed && documentIsHTML ) { // Try to shortcut find operations when possible (e.g., not under DocumentFragment) if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { // Speed-up: Sizzle("#ID") if ( (m = match[1]) ) { if ( nodeType === 9 ) { elem = context.getElementById( m ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document (jQuery #6963) if ( elem && elem.parentNode ) { // Handle the case where IE, Opera, and Webkit return items // by name instead of ID if ( elem.id === m ) { results.push( elem ); return results; } } else { return results; } } else { // Context is not a document if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && contains( context, elem ) && elem.id === m ) { results.push( elem ); return results; } } // Speed-up: Sizzle("TAG") } else if ( match[2] ) { push.apply( results, context.getElementsByTagName( selector ) ); return results; // Speed-up: Sizzle(".CLASS") } else if ( (m = match[3]) && support.getElementsByClassName ) { push.apply( results, context.getElementsByClassName( m ) ); return results; } } // QSA path if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { nid = old = expando; newContext = context; newSelector = nodeType !== 1 && selector; // qSA works strangely on Element-rooted queries // We can work around this by specifying an extra ID on the root // and working up from there (Thanks to Andrew Dupont for the technique) // IE 8 doesn't work on object elements if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { groups = tokenize( selector ); if ( (old = context.getAttribute("id")) ) { nid = old.replace( rescape, "\\$&" ); } else { context.setAttribute( "id", nid ); } nid = "[id='" + nid + "'] "; i = groups.length; while ( i-- ) { groups[i] = nid + toSelector( groups[i] ); } newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; newSelector = groups.join(","); } if ( newSelector ) { try { push.apply( results, newContext.querySelectorAll( newSelector ) ); return results; } catch(qsaError) { } finally { if ( !old ) { context.removeAttribute("id"); } } } } } // All others return select( selector.replace( rtrim, "$1" ), context, results, seed ); } /** * Create key-value caches of limited size * @returns {Function(string, Object)} Returns the Object data after storing it on itself with * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) * deleting the oldest entry */ function createCache() { var keys = []; function cache( key, value ) { // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key + " " ) > Expr.cacheLength ) { // Only keep the most recent entries delete cache[ keys.shift() ]; } return (cache[ key + " " ] = value); } return cache; } /** * Mark a function for special use by Sizzle * @param {Function} fn The function to mark */ function markFunction( fn ) { fn[ expando ] = true; return fn; } /** * Support testing using an element * @param {Function} fn Passed the created div and expects a boolean result */ function assert( fn ) { var div = document.createElement("div"); try { return !!fn( div ); } catch (e) { return false; } finally { // Remove from its parent by default if ( div.parentNode ) { div.parentNode.removeChild( div ); } // release memory in IE div = null; } } /** * Adds the same handler for all of the specified attrs * @param {String} attrs Pipe-separated list of attributes * @param {Function} handler The method that will be applied */ function addHandle( attrs, handler ) { var arr = attrs.split("|"), i = attrs.length; while ( i-- ) { Expr.attrHandle[ arr[i] ] = handler; } } /** * Checks document order of two siblings * @param {Element} a * @param {Element} b * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b */ function siblingCheck( a, b ) { var cur = b && a, diff = cur && a.nodeType === 1 && b.nodeType === 1 && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); // Use IE sourceIndex if available on both nodes if ( diff ) { return diff; } // Check if b follows a if ( cur ) { while ( (cur = cur.nextSibling) ) { if ( cur === b ) { return -1; } } } return a ? 1 : -1; } /** * Returns a function to use in pseudos for input types * @param {String} type */ function createInputPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === type; }; } /** * Returns a function to use in pseudos for buttons * @param {String} type */ function createButtonPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && elem.type === type; }; } /** * Returns a function to use in pseudos for positionals * @param {Function} fn */ function createPositionalPseudo( fn ) { return markFunction(function( argument ) { argument = +argument; return markFunction(function( seed, matches ) { var j, matchIndexes = fn( [], seed.length, argument ), i = matchIndexes.length; // Match elements found at the specified indexes while ( i-- ) { if ( seed[ (j = matchIndexes[i]) ] ) { seed[j] = !(matches[j] = seed[j]); } } }); }); } /** * Checks a node for validity as a Sizzle context * @param {Element|Object=} context * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value */ function testContext( context ) { return context && typeof context.getElementsByTagName !== "undefined" && context; } // Expose support vars for convenience support = Sizzle.support = {}; /** * Detects XML nodes * @param {Element|Object} elem An element or a document * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = elem && (elem.ownerDocument || elem).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; /** * Sets document-related variables once based on the current document * @param {Element|Object} [doc] An element or document object to use to set the document * @returns {Object} Returns the current document */ setDocument = Sizzle.setDocument = function( node ) { var hasCompare, parent, doc = node ? node.ownerDocument || node : preferredDoc; // If no document and documentElement is available, return if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { return document; } // Set our document document = doc; docElem = doc.documentElement; parent = doc.defaultView; // Support: IE>8 // If iframe document is assigned to "document" variable and if iframe has been reloaded, // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 // IE6-8 do not support the defaultView property so parent will be undefined if ( parent && parent !== parent.top ) { // IE11 does not have attachEvent, so all must suffer if ( parent.addEventListener ) { parent.addEventListener( "unload", unloadHandler, false ); } else if ( parent.attachEvent ) { parent.attachEvent( "onunload", unloadHandler ); } } /* Support tests ---------------------------------------------------------------------- */ documentIsHTML = !isXML( doc ); /* Attributes ---------------------------------------------------------------------- */ // Support: IE<8 // Verify that getAttribute really returns attributes and not properties // (excepting IE8 booleans) support.attributes = assert(function( div ) { div.className = "i"; return !div.getAttribute("className"); }); /* getElement(s)By* ---------------------------------------------------------------------- */ // Check if getElementsByTagName("*") returns only elements support.getElementsByTagName = assert(function( div ) { div.appendChild( doc.createComment("") ); return !div.getElementsByTagName("*").length; }); // Support: IE<9 support.getElementsByClassName = rnative.test( doc.getElementsByClassName ); // Support: IE<10 // Check if getElementById returns elements by name // The broken getElementById methods don't pick up programatically-set names, // so use a roundabout getElementsByName test support.getById = assert(function( div ) { docElem.appendChild( div ).id = expando; return !doc.getElementsByName || !doc.getElementsByName( expando ).length; }); // ID find and filter if ( support.getById ) { Expr.find["ID"] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var m = context.getElementById( id ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 return m && m.parentNode ? [ m ] : []; } }; Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { return elem.getAttribute("id") === attrId; }; }; } else { // Support: IE6/7 // getElementById is not reliable as a find shortcut delete Expr.find["ID"]; Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return node && node.value === attrId; }; }; } // Tag Expr.find["TAG"] = support.getElementsByTagName ? function( tag, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( tag ); // DocumentFragment nodes don't have gEBTN } else if ( support.qsa ) { return context.querySelectorAll( tag ); } } : function( tag, context ) { var elem, tmp = [], i = 0, // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too results = context.getElementsByTagName( tag ); // Filter out possible comments if ( tag === "*" ) { while ( (elem = results[i++]) ) { if ( elem.nodeType === 1 ) { tmp.push( elem ); } } return tmp; } return results; }; // Class Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { if ( documentIsHTML ) { return context.getElementsByClassName( className ); } }; /* QSA/matchesSelector ---------------------------------------------------------------------- */ // QSA and matchesSelector support // matchesSelector(:active) reports false when true (IE9/Opera 11.5) rbuggyMatches = []; // qSa(:focus) reports false when true (Chrome 21) // We allow this because of a bug in IE8/9 that throws an error // whenever `document.activeElement` is accessed on an iframe // So, we allow :focus to pass through QSA all the time to avoid the IE error // See http://bugs.jquery.com/ticket/13378 rbuggyQSA = []; if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { // Build QSA regex // Regex strategy adopted from Diego Perini assert(function( div ) { // Select is set to empty string on purpose // This is to test IE's treatment of not explicitly // setting a boolean content attribute, // since its presence should be enough // http://bugs.jquery.com/ticket/12359 docElem.appendChild( div ).innerHTML = "" + ""; // Support: IE8, Opera 11-12.16 // Nothing should be selected when empty strings follow ^= or $= or *= // The test attribute must be unknown in Opera but "safe" for WinRT // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section if ( div.querySelectorAll("[msallowcapture^='']").length ) { rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); } // Support: IE8 // Boolean attributes and "value" are not treated correctly if ( !div.querySelectorAll("[selected]").length ) { rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); } // Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+ if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { rbuggyQSA.push("~="); } // Webkit/Opera - :checked should return selected option elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked // IE8 throws error here and will not see later tests if ( !div.querySelectorAll(":checked").length ) { rbuggyQSA.push(":checked"); } // Support: Safari 8+, iOS 8+ // https://bugs.webkit.org/show_bug.cgi?id=136851 // In-page `selector#id sibing-combinator selector` fails if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { rbuggyQSA.push(".#.+[+~]"); } }); assert(function( div ) { // Support: Windows 8 Native Apps // The type and name attributes are restricted during .innerHTML assignment var input = doc.createElement("input"); input.setAttribute( "type", "hidden" ); div.appendChild( input ).setAttribute( "name", "D" ); // Support: IE8 // Enforce case-sensitivity of name attribute if ( div.querySelectorAll("[name=d]").length ) { rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); } // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) // IE8 throws error here and will not see later tests if ( !div.querySelectorAll(":enabled").length ) { rbuggyQSA.push( ":enabled", ":disabled" ); } // Opera 10-11 does not throw on post-comma invalid pseudos div.querySelectorAll("*,:x"); rbuggyQSA.push(",.*:"); }); } if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector) )) ) { assert(function( div ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9) support.disconnectedMatch = matches.call( div, "div" ); // This should fail with an exception // Gecko does not error, returns false instead matches.call( div, "[s!='']:x" ); rbuggyMatches.push( "!=", pseudos ); }); } rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); /* Contains ---------------------------------------------------------------------- */ hasCompare = rnative.test( docElem.compareDocumentPosition ); // Element contains another // Purposefully does not implement inclusive descendent // As in, an element does not contain itself contains = hasCompare || rnative.test( docElem.contains ) ? function( a, b ) { var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode; return a === bup || !!( bup && bup.nodeType === 1 && ( adown.contains ? adown.contains( bup ) : a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 )); } : function( a, b ) { if ( b ) { while ( (b = b.parentNode) ) { if ( b === a ) { return true; } } } return false; }; /* Sorting ---------------------------------------------------------------------- */ // Document order sorting sortOrder = hasCompare ? function( a, b ) { // Flag for duplicate removal if ( a === b ) { hasDuplicate = true; return 0; } // Sort on method existence if only one input has compareDocumentPosition var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; if ( compare ) { return compare; } // Calculate position if both inputs belong to the same document compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? a.compareDocumentPosition( b ) : // Otherwise we know they are disconnected 1; // Disconnected nodes if ( compare & 1 || (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { // Choose the first element that is related to our preferred document if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { return -1; } if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { return 1; } // Maintain original order return sortInput ? ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 0; } return compare & 4 ? -1 : 1; } : function( a, b ) { // Exit early if the nodes are identical if ( a === b ) { hasDuplicate = true; return 0; } var cur, i = 0, aup = a.parentNode, bup = b.parentNode, ap = [ a ], bp = [ b ]; // Parentless nodes are either documents or disconnected if ( !aup || !bup ) { return a === doc ? -1 : b === doc ? 1 : aup ? -1 : bup ? 1 : sortInput ? ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 0; // If the nodes are siblings, we can do a quick check } else if ( aup === bup ) { return siblingCheck( a, b ); } // Otherwise we need full lists of their ancestors for comparison cur = a; while ( (cur = cur.parentNode) ) { ap.unshift( cur ); } cur = b; while ( (cur = cur.parentNode) ) { bp.unshift( cur ); } // Walk down the tree looking for a discrepancy while ( ap[i] === bp[i] ) { i++; } return i ? // Do a sibling check if the nodes have a common ancestor siblingCheck( ap[i], bp[i] ) : // Otherwise nodes in our document sort first ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0; }; return doc; }; Sizzle.matches = function( expr, elements ) { return Sizzle( expr, null, null, elements ); }; Sizzle.matchesSelector = function( elem, expr ) { // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } // Make sure that attribute selectors are quoted expr = expr.replace( rattributeQuotes, "='$1']" ); if ( support.matchesSelector && documentIsHTML && ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { try { var ret = matches.call( elem, expr ); // IE 9's matchesSelector returns false on disconnected nodes if ( ret || support.disconnectedMatch || // As well, disconnected nodes are said to be in a document // fragment in IE 9 elem.document && elem.document.nodeType !== 11 ) { return ret; } } catch (e) {} } return Sizzle( expr, document, null, [ elem ] ).length > 0; }; Sizzle.contains = function( context, elem ) { // Set document vars if needed if ( ( context.ownerDocument || context ) !== document ) { setDocument( context ); } return contains( context, elem ); }; Sizzle.attr = function( elem, name ) { // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } var fn = Expr.attrHandle[ name.toLowerCase() ], // Don't get fooled by Object.prototype properties (jQuery #13807) val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? fn( elem, name, !documentIsHTML ) : undefined; return val !== undefined ? val : support.attributes || !documentIsHTML ? elem.getAttribute( name ) : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null; }; Sizzle.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; /** * Document sorting and removing duplicates * @param {ArrayLike} results */ Sizzle.uniqueSort = function( results ) { var elem, duplicates = [], j = 0, i = 0; // Unless we *know* we can detect duplicates, assume their presence hasDuplicate = !support.detectDuplicates; sortInput = !support.sortStable && results.slice( 0 ); results.sort( sortOrder ); if ( hasDuplicate ) { while ( (elem = results[i++]) ) { if ( elem === results[ i ] ) { j = duplicates.push( i ); } } while ( j-- ) { results.splice( duplicates[ j ], 1 ); } } // Clear input after sorting to release objects // See https://github.com/jquery/sizzle/pull/225 sortInput = null; return results; }; /** * Utility function for retrieving the text value of an array of DOM nodes * @param {Array|Element} elem */ getText = Sizzle.getText = function( elem ) { var node, ret = "", i = 0, nodeType = elem.nodeType; if ( !nodeType ) { // If no nodeType, this is expected to be an array while ( (node = elem[i++]) ) { // Do not traverse comment nodes ret += getText( node ); } } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { // Use textContent for elements // innerText usage removed for consistency of new lines (jQuery #11153) if ( typeof elem.textContent === "string" ) { return elem.textContent; } else { // Traverse its children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { ret += getText( elem ); } } } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } // Do not include comment or processing instruction nodes return ret; }; Expr = Sizzle.selectors = { // Can be adjusted by the user cacheLength: 50, createPseudo: markFunction, match: matchExpr, attrHandle: {}, find: {}, relative: { ">": { dir: "parentNode", first: true }, " ": { dir: "parentNode" }, "+": { dir: "previousSibling", first: true }, "~": { dir: "previousSibling" } }, preFilter: { "ATTR": function( match ) { match[1] = match[1].replace( runescape, funescape ); // Move the given value to match[3] whether quoted or unquoted match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); if ( match[2] === "~=" ) { match[3] = " " + match[3] + " "; } return match.slice( 0, 4 ); }, "CHILD": function( match ) { /* matches from matchExpr["CHILD"] 1 type (only|nth|...) 2 what (child|of-type) 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 4 xn-component of xn+y argument ([+-]?\d*n|) 5 sign of xn-component 6 x of xn-component 7 sign of y-component 8 y of y-component */ match[1] = match[1].toLowerCase(); if ( match[1].slice( 0, 3 ) === "nth" ) { // nth-* requires argument if ( !match[3] ) { Sizzle.error( match[0] ); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); // other types prohibit arguments } else if ( match[3] ) { Sizzle.error( match[0] ); } return match; }, "PSEUDO": function( match ) { var excess, unquoted = !match[6] && match[2]; if ( matchExpr["CHILD"].test( match[0] ) ) { return null; } // Accept quoted arguments as-is if ( match[3] ) { match[2] = match[4] || match[5] || ""; // Strip excess characters from unquoted arguments } else if ( unquoted && rpseudo.test( unquoted ) && // Get excess from tokenize (recursively) (excess = tokenize( unquoted, true )) && // advance to the next closing parenthesis (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { // excess is a negative index match[0] = match[0].slice( 0, excess ); match[2] = unquoted.slice( 0, excess ); } // Return only captures needed by the pseudo filter method (type and argument) return match.slice( 0, 3 ); } }, filter: { "TAG": function( nodeNameSelector ) { var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); return nodeNameSelector === "*" ? function() { return true; } : function( elem ) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; }, "CLASS": function( className ) { var pattern = classCache[ className + " " ]; return pattern || (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && classCache( className, function( elem ) { return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); }); }, "ATTR": function( name, operator, check ) { return function( elem ) { var result = Sizzle.attr( elem, name ); if ( result == null ) { return operator === "!="; } if ( !operator ) { return true; } result += ""; return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf( check ) === 0 : operator === "*=" ? check && result.indexOf( check ) > -1 : operator === "$=" ? check && result.slice( -check.length ) === check : operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : false; }; }, "CHILD": function( type, what, argument, first, last ) { var simple = type.slice( 0, 3 ) !== "nth", forward = type.slice( -4 ) !== "last", ofType = what === "of-type"; return first === 1 && last === 0 ? // Shortcut for :nth-*(n) function( elem ) { return !!elem.parentNode; } : function( elem, context, xml ) { var cache, outerCache, node, diff, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType; if ( parent ) { // :(first|last|only)-(child|of-type) if ( simple ) { while ( dir ) { node = elem; while ( (node = node[ dir ]) ) { if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { return false; } } // Reverse direction for :only-* (if we haven't yet done so) start = dir = type === "only" && !start && "nextSibling"; } return true; } start = [ forward ? parent.firstChild : parent.lastChild ]; // non-xml :nth-child(...) stores cache data on `parent` if ( forward && useCache ) { // Seek `elem` from a previously-cached index outerCache = parent[ expando ] || (parent[ expando ] = {}); cache = outerCache[ type ] || []; nodeIndex = cache[0] === dirruns && cache[1]; diff = cache[0] === dirruns && cache[2]; node = nodeIndex && parent.childNodes[ nodeIndex ]; while ( (node = ++nodeIndex && node && node[ dir ] || // Fallback to seeking `elem` from the start (diff = nodeIndex = 0) || start.pop()) ) { // When found, cache indexes on `parent` and break if ( node.nodeType === 1 && ++diff && node === elem ) { outerCache[ type ] = [ dirruns, nodeIndex, diff ]; break; } } // Use previously-cached element index if available } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { diff = cache[1]; // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) } else { // Use the same loop as above to seek `elem` from the start while ( (node = ++nodeIndex && node && node[ dir ] || (diff = nodeIndex = 0) || start.pop()) ) { if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { // Cache the index of each encountered element if ( useCache ) { (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; } if ( node === elem ) { break; } } } } // Incorporate the offset, then check against cycle size diff -= last; return diff === first || ( diff % first === 0 && diff / first >= 0 ); } }; }, "PSEUDO": function( pseudo, argument ) { // pseudo-class names are case-insensitive // http://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters // Remember that setFilters inherits from pseudos var args, fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || Sizzle.error( "unsupported pseudo: " + pseudo ); // The user may use createPseudo to indicate that // arguments are needed to create the filter function // just as Sizzle does if ( fn[ expando ] ) { return fn( argument ); } // But maintain support for old signatures if ( fn.length > 1 ) { args = [ pseudo, pseudo, "", argument ]; return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? markFunction(function( seed, matches ) { var idx, matched = fn( seed, argument ), i = matched.length; while ( i-- ) { idx = indexOf( seed, matched[i] ); seed[ idx ] = !( matches[ idx ] = matched[i] ); } }) : function( elem ) { return fn( elem, 0, args ); }; } return fn; } }, pseudos: { // Potentially complex pseudos "not": markFunction(function( selector ) { // Trim the selector passed to compile // to avoid treating leading and trailing // spaces as combinators var input = [], results = [], matcher = compile( selector.replace( rtrim, "$1" ) ); return matcher[ expando ] ? markFunction(function( seed, matches, context, xml ) { var elem, unmatched = matcher( seed, null, xml, [] ), i = seed.length; // Match elements unmatched by `matcher` while ( i-- ) { if ( (elem = unmatched[i]) ) { seed[i] = !(matches[i] = elem); } } }) : function( elem, context, xml ) { input[0] = elem; matcher( input, null, xml, results ); // Don't keep the element (issue #299) input[0] = null; return !results.pop(); }; }), "has": markFunction(function( selector ) { return function( elem ) { return Sizzle( selector, elem ).length > 0; }; }), "contains": markFunction(function( text ) { text = text.replace( runescape, funescape ); return function( elem ) { return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; }; }), // "Whether an element is represented by a :lang() selector // is based solely on the element's language value // being equal to the identifier C, // or beginning with the identifier C immediately followed by "-". // The matching of C against the element's language value is performed case-insensitively. // The identifier C does not have to be a valid language name." // http://www.w3.org/TR/selectors/#lang-pseudo "lang": markFunction( function( lang ) { // lang value must be a valid identifier if ( !ridentifier.test(lang || "") ) { Sizzle.error( "unsupported lang: " + lang ); } lang = lang.replace( runescape, funescape ).toLowerCase(); return function( elem ) { var elemLang; do { if ( (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { elemLang = elemLang.toLowerCase(); return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; } } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); return false; }; }), // Miscellaneous "target": function( elem ) { var hash = window.location && window.location.hash; return hash && hash.slice( 1 ) === elem.id; }, "root": function( elem ) { return elem === docElem; }, "focus": function( elem ) { return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); }, // Boolean properties "enabled": function( elem ) { return elem.disabled === false; }, "disabled": function( elem ) { return elem.disabled === true; }, "checked": function( elem ) { // In CSS3, :checked should return both checked and selected elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked var nodeName = elem.nodeName.toLowerCase(); return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); }, "selected": function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } return elem.selected === true; }, // Contents "empty": function( elem ) { // http://www.w3.org/TR/selectors/#empty-pseudo // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), // but not by others (comment: 8; processing instruction: 7; etc.) // nodeType < 6 works because attributes (2) do not appear as children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { if ( elem.nodeType < 6 ) { return false; } } return true; }, "parent": function( elem ) { return !Expr.pseudos["empty"]( elem ); }, // Element/input types "header": function( elem ) { return rheader.test( elem.nodeName ); }, "input": function( elem ) { return rinputs.test( elem.nodeName ); }, "button": function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === "button" || name === "button"; }, "text": function( elem ) { var attr; return elem.nodeName.toLowerCase() === "input" && elem.type === "text" && // Support: IE<8 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); }, // Position-in-collection "first": createPositionalPseudo(function() { return [ 0 ]; }), "last": createPositionalPseudo(function( matchIndexes, length ) { return [ length - 1 ]; }), "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { return [ argument < 0 ? argument + length : argument ]; }), "even": createPositionalPseudo(function( matchIndexes, length ) { var i = 0; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "odd": createPositionalPseudo(function( matchIndexes, length ) { var i = 1; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; --i >= 0; ) { matchIndexes.push( i ); } return matchIndexes; }), "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; ++i < length; ) { matchIndexes.push( i ); } return matchIndexes; }) } }; Expr.pseudos["nth"] = Expr.pseudos["eq"]; // Add button/input type pseudos for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { Expr.pseudos[ i ] = createInputPseudo( i ); } for ( i in { submit: true, reset: true } ) { Expr.pseudos[ i ] = createButtonPseudo( i ); } // Easy API for creating new setFilters function setFilters() {} setFilters.prototype = Expr.filters = Expr.pseudos; Expr.setFilters = new setFilters(); tokenize = Sizzle.tokenize = function( selector, parseOnly ) { var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[ selector + " " ]; if ( cached ) { return parseOnly ? 0 : cached.slice( 0 ); } soFar = selector; groups = []; preFilters = Expr.preFilter; while ( soFar ) { // Comma and first run if ( !matched || (match = rcomma.exec( soFar )) ) { if ( match ) { // Don't consume trailing commas as valid soFar = soFar.slice( match[0].length ) || soFar; } groups.push( (tokens = []) ); } matched = false; // Combinators if ( (match = rcombinators.exec( soFar )) ) { matched = match.shift(); tokens.push({ value: matched, // Cast descendant combinators to space type: match[0].replace( rtrim, " " ) }); soFar = soFar.slice( matched.length ); } // Filters for ( type in Expr.filter ) { if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || (match = preFilters[ type ]( match ))) ) { matched = match.shift(); tokens.push({ value: matched, type: type, matches: match }); soFar = soFar.slice( matched.length ); } } if ( !matched ) { break; } } // Return the length of the invalid excess // if we're just parsing // Otherwise, throw an error or return tokens return parseOnly ? soFar.length : soFar ? Sizzle.error( selector ) : // Cache the tokens tokenCache( selector, groups ).slice( 0 ); }; function toSelector( tokens ) { var i = 0, len = tokens.length, selector = ""; for ( ; i < len; i++ ) { selector += tokens[i].value; } return selector; } function addCombinator( matcher, combinator, base ) { var dir = combinator.dir, checkNonElements = base && dir === "parentNode", doneName = done++; return combinator.first ? // Check against closest ancestor/preceding element function( elem, context, xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { return matcher( elem, context, xml ); } } } : // Check against all ancestor/preceding elements function( elem, context, xml ) { var oldCache, outerCache, newCache = [ dirruns, doneName ]; // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching if ( xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { if ( matcher( elem, context, xml ) ) { return true; } } } } else { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { outerCache = elem[ expando ] || (elem[ expando ] = {}); if ( (oldCache = outerCache[ dir ]) && oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { // Assign to newCache so results back-propagate to previous elements return (newCache[ 2 ] = oldCache[ 2 ]); } else { // Reuse newcache so results back-propagate to previous elements outerCache[ dir ] = newCache; // A match means we're done; a fail means we have to keep checking if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { return true; } } } } } }; } function elementMatcher( matchers ) { return matchers.length > 1 ? function( elem, context, xml ) { var i = matchers.length; while ( i-- ) { if ( !matchers[i]( elem, context, xml ) ) { return false; } } return true; } : matchers[0]; } function multipleContexts( selector, contexts, results ) { var i = 0, len = contexts.length; for ( ; i < len; i++ ) { Sizzle( selector, contexts[i], results ); } return results; } function condense( unmatched, map, filter, context, xml ) { var elem, newUnmatched = [], i = 0, len = unmatched.length, mapped = map != null; for ( ; i < len; i++ ) { if ( (elem = unmatched[i]) ) { if ( !filter || filter( elem, context, xml ) ) { newUnmatched.push( elem ); if ( mapped ) { map.push( i ); } } } } return newUnmatched; } function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { if ( postFilter && !postFilter[ expando ] ) { postFilter = setMatcher( postFilter ); } if ( postFinder && !postFinder[ expando ] ) { postFinder = setMatcher( postFinder, postSelector ); } return markFunction(function( seed, results, context, xml ) { var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, // Get initial elements from seed or context elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), // Prefilter to get matcher input, preserving a map for seed-results synchronization matcherIn = preFilter && ( seed || !selector ) ? condense( elems, preMap, preFilter, context, xml ) : elems, matcherOut = matcher ? // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, postFinder || ( seed ? preFilter : preexisting || postFilter ) ? // ...intermediate processing is necessary [] : // ...otherwise use results directly results : matcherIn; // Find primary matches if ( matcher ) { matcher( matcherIn, matcherOut, context, xml ); } // Apply postFilter if ( postFilter ) { temp = condense( matcherOut, postMap ); postFilter( temp, [], context, xml ); // Un-match failing elements by moving them back to matcherIn i = temp.length; while ( i-- ) { if ( (elem = temp[i]) ) { matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); } } } if ( seed ) { if ( postFinder || preFilter ) { if ( postFinder ) { // Get the final matcherOut by condensing this intermediate into postFinder contexts temp = []; i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) ) { // Restore matcherIn since elem is not yet a final match temp.push( (matcherIn[i] = elem) ); } } postFinder( null, (matcherOut = []), temp, xml ); } // Move matched elements from seed to results to keep them synchronized i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) && (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { seed[temp] = !(results[temp] = elem); } } } // Add elements to results, through postFinder if defined } else { matcherOut = condense( matcherOut === results ? matcherOut.splice( preexisting, matcherOut.length ) : matcherOut ); if ( postFinder ) { postFinder( null, results, matcherOut, xml ); } else { push.apply( results, matcherOut ); } } }); } function matcherFromTokens( tokens ) { var checkContext, matcher, j, len = tokens.length, leadingRelative = Expr.relative[ tokens[0].type ], implicitRelative = leadingRelative || Expr.relative[" "], i = leadingRelative ? 1 : 0, // The foundational matcher ensures that elements are reachable from top-level context(s) matchContext = addCombinator( function( elem ) { return elem === checkContext; }, implicitRelative, true ), matchAnyContext = addCombinator( function( elem ) { return indexOf( checkContext, elem ) > -1; }, implicitRelative, true ), matchers = [ function( elem, context, xml ) { var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( (checkContext = context).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); // Avoid hanging onto element (issue #299) checkContext = null; return ret; } ]; for ( ; i < len; i++ ) { if ( (matcher = Expr.relative[ tokens[i].type ]) ) { matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; } else { matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); // Return special upon seeing a positional matcher if ( matcher[ expando ] ) { // Find the next relative operator (if any) for proper handling j = ++i; for ( ; j < len; j++ ) { if ( Expr.relative[ tokens[j].type ] ) { break; } } return setMatcher( i > 1 && elementMatcher( matchers ), i > 1 && toSelector( // If the preceding token was a descendant combinator, insert an implicit any-element `*` tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) ).replace( rtrim, "$1" ), matcher, i < j && matcherFromTokens( tokens.slice( i, j ) ), j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), j < len && toSelector( tokens ) ); } matchers.push( matcher ); } } return elementMatcher( matchers ); } function matcherFromGroupMatchers( elementMatchers, setMatchers ) { var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function( seed, context, xml, results, outermost ) { var elem, j, matcher, matchedCount = 0, i = "0", unmatched = seed && [], setMatched = [], contextBackup = outermostContext, // We must always have either seed elements or outermost context elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), // Use integer dirruns iff this is the outermost matcher dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), len = elems.length; if ( outermost ) { outermostContext = context !== document && context; } // Add elements passing elementMatchers directly to results // Keep `i` a string if there are no elements so `matchedCount` will be "00" below // Support: IE<9, Safari // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id for ( ; i !== len && (elem = elems[i]) != null; i++ ) { if ( byElement && elem ) { j = 0; while ( (matcher = elementMatchers[j++]) ) { if ( matcher( elem, context, xml ) ) { results.push( elem ); break; } } if ( outermost ) { dirruns = dirrunsUnique; } } // Track unmatched elements for set filters if ( bySet ) { // They will have gone through all possible matchers if ( (elem = !matcher && elem) ) { matchedCount--; } // Lengthen the array for every element, matched or not if ( seed ) { unmatched.push( elem ); } } } // Apply set filters to unmatched elements matchedCount += i; if ( bySet && i !== matchedCount ) { j = 0; while ( (matcher = setMatchers[j++]) ) { matcher( unmatched, setMatched, context, xml ); } if ( seed ) { // Reintegrate element matches to eliminate the need for sorting if ( matchedCount > 0 ) { while ( i-- ) { if ( !(unmatched[i] || setMatched[i]) ) { setMatched[i] = pop.call( results ); } } } // Discard index placeholder values to get only actual matches setMatched = condense( setMatched ); } // Add matches to results push.apply( results, setMatched ); // Seedless set matches succeeding multiple successful matchers stipulate sorting if ( outermost && !seed && setMatched.length > 0 && ( matchedCount + setMatchers.length ) > 1 ) { Sizzle.uniqueSort( results ); } } // Override manipulation of globals by nested matchers if ( outermost ) { dirruns = dirrunsUnique; outermostContext = contextBackup; } return unmatched; }; return bySet ? markFunction( superMatcher ) : superMatcher; } compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { var i, setMatchers = [], elementMatchers = [], cached = compilerCache[ selector + " " ]; if ( !cached ) { // Generate a function of recursive functions that can be used to check each element if ( !match ) { match = tokenize( selector ); } i = match.length; while ( i-- ) { cached = matcherFromTokens( match[i] ); if ( cached[ expando ] ) { setMatchers.push( cached ); } else { elementMatchers.push( cached ); } } // Cache the compiled function cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); // Save selector and tokenization cached.selector = selector; } return cached; }; /** * A low-level selection function that works with Sizzle's compiled * selector functions * @param {String|Function} selector A selector or a pre-compiled * selector function built with Sizzle.compile * @param {Element} context * @param {Array} [results] * @param {Array} [seed] A set of elements to match against */ select = Sizzle.select = function( selector, context, results, seed ) { var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, match = !seed && tokenize( (selector = compiled.selector || selector) ); results = results || []; // Try to minimize operations if there is no seed and only one group if ( match.length === 1 ) { // Take a shortcut and set the context if the root selector is an ID tokens = match[0] = match[0].slice( 0 ); if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && support.getById && context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; if ( !context ) { return results; // Precompiled matchers will still verify ancestry, so step up a level } else if ( compiled ) { context = context.parentNode; } selector = selector.slice( tokens.shift().value.length ); } // Fetch a seed set for right-to-left matching i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; while ( i-- ) { token = tokens[i]; // Abort if we hit a combinator if ( Expr.relative[ (type = token.type) ] ) { break; } if ( (find = Expr.find[ type ]) ) { // Search, expanding context for leading sibling combinators if ( (seed = find( token.matches[0].replace( runescape, funescape ), rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context )) ) { // If seed is empty or no tokens remain, we can return early tokens.splice( i, 1 ); selector = seed.length && toSelector( tokens ); if ( !selector ) { push.apply( results, seed ); return results; } break; } } } } // Compile and execute a filtering function if one is not provided // Provide `match` to avoid retokenization if we modified the selector above ( compiled || compile( selector, match ) )( seed, context, !documentIsHTML, results, rsibling.test( selector ) && testContext( context.parentNode ) || context ); return results; }; // One-time assignments // Sort stability support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; // Support: Chrome 14-35+ // Always assume duplicates if they aren't passed to the comparison function support.detectDuplicates = !!hasDuplicate; // Initialize against the default document setDocument(); // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) // Detached nodes confoundingly follow *each other* support.sortDetached = assert(function( div1 ) { // Should return 1, but returns 4 (following) return div1.compareDocumentPosition( document.createElement("div") ) & 1; }); // Support: IE<8 // Prevent attribute/property "interpolation" // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx if ( !assert(function( div ) { div.innerHTML = ""; return div.firstChild.getAttribute("href") === "#" ; }) ) { addHandle( "type|href|height|width", function( elem, name, isXML ) { if ( !isXML ) { return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); } }); } // Support: IE<9 // Use defaultValue in place of getAttribute("value") if ( !support.attributes || !assert(function( div ) { div.innerHTML = ""; div.firstChild.setAttribute( "value", "" ); return div.firstChild.getAttribute( "value" ) === ""; }) ) { addHandle( "value", function( elem, name, isXML ) { if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { return elem.defaultValue; } }); } // Support: IE<9 // Use getAttributeNode to fetch booleans when getAttribute lies if ( !assert(function( div ) { return div.getAttribute("disabled") == null; }) ) { addHandle( booleans, function( elem, name, isXML ) { var val; if ( !isXML ) { return elem[ name ] === true ? name.toLowerCase() : (val = elem.getAttributeNode( name )) && val.specified ? val.value : null; } }); } return Sizzle; })( window ); jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.pseudos; jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; var rneedsContext = jQuery.expr.match.needsContext; var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); var risSimple = /^.[^:#\[\.,]*$/; // Implement the identical functionality for filter and not function winnow( elements, qualifier, not ) { if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep( elements, function( elem, i ) { /* jshint -W018 */ return !!qualifier.call( elem, i, elem ) !== not; }); } if ( qualifier.nodeType ) { return jQuery.grep( elements, function( elem ) { return ( elem === qualifier ) !== not; }); } if ( typeof qualifier === "string" ) { if ( risSimple.test( qualifier ) ) { return jQuery.filter( qualifier, elements, not ); } qualifier = jQuery.filter( qualifier, elements ); } return jQuery.grep( elements, function( elem ) { return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; }); } jQuery.filter = function( expr, elems, not ) { var elem = elems[ 0 ]; if ( not ) { expr = ":not(" + expr + ")"; } return elems.length === 1 && elem.nodeType === 1 ? jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { return elem.nodeType === 1; })); }; jQuery.fn.extend({ find: function( selector ) { var i, ret = [], self = this, len = self.length; if ( typeof selector !== "string" ) { return this.pushStack( jQuery( selector ).filter(function() { for ( i = 0; i < len; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } }) ); } for ( i = 0; i < len; i++ ) { jQuery.find( selector, self[ i ], ret ); } // Needed because $( selector, context ) becomes $( context ).find( selector ) ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); ret.selector = this.selector ? this.selector + " " + selector : selector; return ret; }, filter: function( selector ) { return this.pushStack( winnow(this, selector || [], false) ); }, not: function( selector ) { return this.pushStack( winnow(this, selector || [], true) ); }, is: function( selector ) { return !!winnow( this, // If this is a positional/relative selector, check membership in the returned set // so $("p:first").is("p:last") won't return true for a doc with two "p". typeof selector === "string" && rneedsContext.test( selector ) ? jQuery( selector ) : selector || [], false ).length; } }); // Initialize a jQuery object // A central reference to the root jQuery(document) var rootjQuery, // Use the correct document accordingly with window argument (sandbox) document = window.document, // A simple way to check for HTML strings // Prioritize #id over to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, init = jQuery.fn.init = function( selector, context ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if ( !selector ) { return this; } // Handle HTML strings if ( typeof selector === "string" ) { if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; // scripts is true for back-compat // Intentionally let the error be thrown if parseHTML is not present jQuery.merge( this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true ) ); // HANDLE: $(html, props) if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); } } } return this; // HANDLE: $(#id) } else { elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(DOMElement) } else if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return typeof rootjQuery.ready !== "undefined" ? rootjQuery.ready( selector ) : // Execute immediately if ready is not present selector( jQuery ); } if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); }; // Give the init function the jQuery prototype for later instantiation init.prototype = jQuery.fn; // Initialize central reference rootjQuery = jQuery( document ); var rparentsprev = /^(?:parents|prev(?:Until|All))/, // methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, contents: true, next: true, prev: true }; jQuery.extend({ dir: function( elem, dir, until ) { var matched = [], cur = elem[ dir ]; while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { if ( cur.nodeType === 1 ) { matched.push( cur ); } cur = cur[dir]; } return matched; }, sibling: function( n, elem ) { var r = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { r.push( n ); } } return r; } }); jQuery.fn.extend({ has: function( target ) { var i, targets = jQuery( target, this ), len = targets.length; return this.filter(function() { for ( i = 0; i < len; i++ ) { if ( jQuery.contains( this, targets[i] ) ) { return true; } } }); }, closest: function( selectors, context ) { var cur, i = 0, l = this.length, matched = [], pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : 0; for ( ; i < l; i++ ) { for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { // Always skip document fragments if ( cur.nodeType < 11 && (pos ? pos.index(cur) > -1 : // Don't pass non-elements to Sizzle cur.nodeType === 1 && jQuery.find.matchesSelector(cur, selectors)) ) { matched.push( cur ); break; } } } return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); }, // Determine the position of an element within // the matched set of elements index: function( elem ) { // No argument, return index in parent if ( !elem ) { return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; } // index in selector if ( typeof elem === "string" ) { return jQuery.inArray( this[0], jQuery( elem ) ); } // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used elem.jquery ? elem[0] : elem, this ); }, add: function( selector, context ) { return this.pushStack( jQuery.unique( jQuery.merge( this.get(), jQuery( selector, context ) ) ) ); }, addBack: function( selector ) { return this.add( selector == null ? this.prevObject : this.prevObject.filter(selector) ); } }); function sibling( cur, dir ) { do { cur = cur[ dir ]; } while ( cur && cur.nodeType !== 1 ); return cur; } jQuery.each({ parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return jQuery.dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { return sibling( elem, "nextSibling" ); }, prev: function( elem ) { return sibling( elem, "previousSibling" ); }, nextAll: function( elem ) { return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); }, children: function( elem ) { return jQuery.sibling( elem.firstChild ); }, contents: function( elem ) { return jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var ret = jQuery.map( this, fn, until ); if ( name.slice( -5 ) !== "Until" ) { selector = until; } if ( selector && typeof selector === "string" ) { ret = jQuery.filter( selector, ret ); } if ( this.length > 1 ) { // Remove duplicates if ( !guaranteedUnique[ name ] ) { ret = jQuery.unique( ret ); } // Reverse order for parents* and prev-derivatives if ( rparentsprev.test( name ) ) { ret = ret.reverse(); } } return this.pushStack( ret ); }; }); var rnotwhite = (/\S+/g); // String to Object options format cache var optionsCache = {}; // Convert String-formatted options into Object-formatted ones and store in cache function createOptions( options ) { var object = optionsCache[ options ] = {}; jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { object[ flag ] = true; }); return object; } /* * Create a callback list using the following parameters: * * options: an optional list of space-separated options that will change how * the callback list behaves or a more traditional option object * * By default a callback list will act like an event callback list and can be * "fired" multiple times. * * Possible options: * * once: will ensure the callback list can only be fired once (like a Deferred) * * memory: will keep track of previous values and will call any callback added * after the list has been fired right away with the latest "memorized" * values (like a Deferred) * * unique: will ensure a callback can only be added once (no duplicate in the list) * * stopOnFalse: interrupt callings when a callback returns false * */ jQuery.Callbacks = function( options ) { // Convert options from String-formatted to Object-formatted if needed // (we check in cache first) options = typeof options === "string" ? ( optionsCache[ options ] || createOptions( options ) ) : jQuery.extend( {}, options ); var // Flag to know if list is currently firing firing, // Last fire value (for non-forgettable lists) memory, // Flag to know if list was already fired fired, // End of the loop when firing firingLength, // Index of currently firing callback (modified by remove if needed) firingIndex, // First callback to fire (used internally by add and fireWith) firingStart, // Actual callback list list = [], // Stack of fire calls for repeatable lists stack = !options.once && [], // Fire callbacks fire = function( data ) { memory = options.memory && data; fired = true; firingIndex = firingStart || 0; firingStart = 0; firingLength = list.length; firing = true; for ( ; list && firingIndex < firingLength; firingIndex++ ) { if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { memory = false; // To prevent further calls using add break; } } firing = false; if ( list ) { if ( stack ) { if ( stack.length ) { fire( stack.shift() ); } } else if ( memory ) { list = []; } else { self.disable(); } } }, // Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { if ( list ) { // First, we save the current length var start = list.length; (function add( args ) { jQuery.each( args, function( _, arg ) { var type = jQuery.type( arg ); if ( type === "function" ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } } else if ( arg && arg.length && type !== "string" ) { // Inspect recursively add( arg ); } }); })( arguments ); // Do we need to add the callbacks to the // current firing batch? if ( firing ) { firingLength = list.length; // With memory, if we're not firing then // we should call right away } else if ( memory ) { firingStart = start; fire( memory ); } } return this; }, // Remove a callback from the list remove: function() { if ( list ) { jQuery.each( arguments, function( _, arg ) { var index; while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { list.splice( index, 1 ); // Handle firing indexes if ( firing ) { if ( index <= firingLength ) { firingLength--; } if ( index <= firingIndex ) { firingIndex--; } } } }); } return this; }, // Check if a given callback is in the list. // If no argument is given, return whether or not list has callbacks attached. has: function( fn ) { return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); }, // Remove all callbacks from the list empty: function() { list = []; firingLength = 0; return this; }, // Have the list do nothing anymore disable: function() { list = stack = memory = undefined; return this; }, // Is it disabled? disabled: function() { return !list; }, // Lock the list in its current state lock: function() { stack = undefined; if ( !memory ) { self.disable(); } return this; }, // Is it locked? locked: function() { return !stack; }, // Call all callbacks with the given context and arguments fireWith: function( context, args ) { if ( list && ( !fired || stack ) ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; if ( firing ) { stack.push( args ); } else { fire( args ); } } return this; }, // Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; }; jQuery.extend({ Deferred: function( func ) { var tuples = [ // action, add listener, listener list, final state [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], [ "notify", "progress", jQuery.Callbacks("memory") ] ], state = "pending", promise = { state: function() { return state; }, always: function() { deferred.done( arguments ).fail( arguments ); return this; }, then: function( /* fnDone, fnFail, fnProgress */ ) { var fns = arguments; return jQuery.Deferred(function( newDefer ) { jQuery.each( tuples, function( i, tuple ) { var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; // deferred[ done | fail | progress ] for forwarding actions to newDefer deferred[ tuple[1] ](function() { var returned = fn && fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise() .done( newDefer.resolve ) .fail( newDefer.reject ) .progress( newDefer.notify ); } else { newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); } }); }); fns = null; }).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; } }, deferred = {}; // Keep pipe for back-compat promise.pipe = promise.then; // Add list-specific methods jQuery.each( tuples, function( i, tuple ) { var list = tuple[ 2 ], stateString = tuple[ 3 ]; // promise[ done | fail | progress ] = list.add promise[ tuple[1] ] = list.add; // Handle state if ( stateString ) { list.add(function() { // state = [ resolved | rejected ] state = stateString; // [ reject_list | resolve_list ].disable; progress_list.lock }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); } // deferred[ resolve | reject | notify ] deferred[ tuple[0] ] = function() { deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); return this; }; deferred[ tuple[0] + "With" ] = list.fireWith; }); // Make the deferred a promise promise.promise( deferred ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; }, // Deferred helper when: function( subordinate /* , ..., subordinateN */ ) { var i = 0, resolveValues = slice.call( arguments ), length = resolveValues.length, // the count of uncompleted subordinates remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that. deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values updateFunc = function( i, contexts, values ) { return function( value ) { contexts[ i ] = this; values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; if ( values === progressValues ) { deferred.notifyWith( contexts, values ); } else if ( !(--remaining) ) { deferred.resolveWith( contexts, values ); } }; }, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolved if ( length > 1 ) { progressValues = new Array( length ); progressContexts = new Array( length ); resolveContexts = new Array( length ); for ( ; i < length; i++ ) { if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { resolveValues[ i ].promise() .done( updateFunc( i, resolveContexts, resolveValues ) ) .fail( deferred.reject ) .progress( updateFunc( i, progressContexts, progressValues ) ); } else { --remaining; } } } // if we're not waiting on anything, resolve the master if ( !remaining ) { deferred.resolveWith( resolveContexts, resolveValues ); } return deferred.promise(); } }); // The deferred used on DOM ready var readyList; jQuery.fn.ready = function( fn ) { // Add the callback jQuery.ready.promise().done( fn ); return this; }; jQuery.extend({ // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // Hold (or release) the ready event holdReady: function( hold ) { if ( hold ) { jQuery.readyWait++; } else { jQuery.ready( true ); } }, // Handle when the DOM is ready ready: function( wait ) { // Abort if there are pending holds or we're already ready if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { return; } // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready ); } // Remember that the DOM is ready jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.triggerHandler ) { jQuery( document ).triggerHandler( "ready" ); jQuery( document ).off( "ready" ); } } }); /** * Clean-up method for dom ready events */ function detach() { if ( document.addEventListener ) { document.removeEventListener( "DOMContentLoaded", completed, false ); window.removeEventListener( "load", completed, false ); } else { document.detachEvent( "onreadystatechange", completed ); window.detachEvent( "onload", completed ); } } /** * The ready event handler and self cleanup method */ function completed() { // readyState === "complete" is good enough for us to call the dom ready in oldIE if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { detach(); jQuery.ready(); } } jQuery.ready.promise = function( obj ) { if ( !readyList ) { readyList = jQuery.Deferred(); // Catch cases where $(document).ready() is called after the browser event has already occurred. // we once tried to use readyState "interactive" here, but it caused issues like the one // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready setTimeout( jQuery.ready ); // Standards-based browsers support DOMContentLoaded } else if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", completed, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", completed, false ); // If IE event model is used } else { // Ensure firing before onload, maybe late but safe also for iframes document.attachEvent( "onreadystatechange", completed ); // A fallback to window.onload, that will always work window.attachEvent( "onload", completed ); // If IE and not a frame // continually check to see if the document is ready var top = false; try { top = window.frameElement == null && document.documentElement; } catch(e) {} if ( top && top.doScroll ) { (function doScrollCheck() { if ( !jQuery.isReady ) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); // and execute any waiting functions jQuery.ready(); } })(); } } } return readyList.promise( obj ); }; var strundefined = typeof undefined; // Support: IE<9 // Iteration over object's inherited properties before its own var i; for ( i in jQuery( support ) ) { break; } support.ownLast = i !== "0"; // Note: most support tests are defined in their respective modules. // false until the test is run support.inlineBlockNeedsLayout = false; // Execute ASAP in case we need to set body.style.zoom jQuery(function() { // Minified: var a,b,c,d var val, div, body, container; body = document.getElementsByTagName( "body" )[ 0 ]; if ( !body || !body.style ) { // Return for frameset docs that don't have a body return; } // Setup div = document.createElement( "div" ); container = document.createElement( "div" ); container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; body.appendChild( container ).appendChild( div ); if ( typeof div.style.zoom !== strundefined ) { // Support: IE<8 // Check if natively block-level elements act like inline-block // elements when setting their display to 'inline' and giving // them layout div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; if ( val ) { // Prevent IE 6 from affecting layout for positioned elements #11048 // Prevent IE from shrinking the body in IE 7 mode #12869 // Support: IE<8 body.style.zoom = 1; } } body.removeChild( container ); }); (function() { var div = document.createElement( "div" ); // Execute the test only if not already executed in another module. if (support.deleteExpando == null) { // Support: IE<9 support.deleteExpando = true; try { delete div.test; } catch( e ) { support.deleteExpando = false; } } // Null elements to avoid leaks in IE. div = null; })(); /** * Determines whether an object can have data */ jQuery.acceptData = function( elem ) { var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ], nodeType = +elem.nodeType || 1; // Do not set data on non-element DOM nodes because it will not be cleared (#8335). return nodeType !== 1 && nodeType !== 9 ? false : // Nodes accept data unless otherwise specified; rejection can be conditional !noData || noData !== true && elem.getAttribute("classid") === noData; }; var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, rmultiDash = /([A-Z])/g; function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : // Only convert to a number if it doesn't change the string +data + "" === data ? +data : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch( e ) {} // Make sure we set the data so it isn't changed later jQuery.data( elem, key, data ); } else { data = undefined; } } return data; } // checks a cache object for emptiness function isEmptyDataObject( obj ) { var name; for ( name in obj ) { // if the public data object is empty, the private is still empty if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { continue; } if ( name !== "toJSON" ) { return false; } } return true; } function internalData( elem, name, data, pvt /* Internal Use Only */ ) { if ( !jQuery.acceptData( elem ) ) { return; } var ret, thisCache, internalKey = jQuery.expando, // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is // attached directly to the object so GC can occur automatically cache = isNode ? jQuery.cache : elem, // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { return; } if ( !id ) { // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; } else { id = internalKey; } } if ( !cache[ id ] ) { // Avoid exposing jQuery metadata on plain JS objects when the object // is serialized using JSON.stringify cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; } // An object can be passed to jQuery.data instead of a key/value pair; this gets // shallow copied over onto the existing cache if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { cache[ id ] = jQuery.extend( cache[ id ], name ); } else { cache[ id ].data = jQuery.extend( cache[ id ].data, name ); } } thisCache = cache[ id ]; // jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined // data. if ( !pvt ) { if ( !thisCache.data ) { thisCache.data = {}; } thisCache = thisCache.data; } if ( data !== undefined ) { thisCache[ jQuery.camelCase( name ) ] = data; } // Check for both converted-to-camel and non-converted data property names // If a data property was specified if ( typeof name === "string" ) { // First Try to find as-is property data ret = thisCache[ name ]; // Test for null|undefined property data if ( ret == null ) { // Try to find the camelCased property ret = thisCache[ jQuery.camelCase( name ) ]; } } else { ret = thisCache; } return ret; } function internalRemoveData( elem, name, pvt ) { if ( !jQuery.acceptData( elem ) ) { return; } var thisCache, i, isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, id = isNode ? elem[ jQuery.expando ] : jQuery.expando; // If there is already no cache entry for this object, there is no // purpose in continuing if ( !cache[ id ] ) { return; } if ( name ) { thisCache = pvt ? cache[ id ] : cache[ id ].data; if ( thisCache ) { // Support array or space separated string names for data keys if ( !jQuery.isArray( name ) ) { // try the string as a key before any manipulation if ( name in thisCache ) { name = [ name ]; } else { // split the camel cased version by spaces unless a key with the spaces exists name = jQuery.camelCase( name ); if ( name in thisCache ) { name = [ name ]; } else { name = name.split(" "); } } } else { // If "name" is an array of keys... // When data is initially created, via ("key", "val") signature, // keys will be converted to camelCase. // Since there is no way to tell _how_ a key was added, remove // both plain key and camelCase key. #12786 // This will only penalize the array argument path. name = name.concat( jQuery.map( name, jQuery.camelCase ) ); } i = name.length; while ( i-- ) { delete thisCache[ name[i] ]; } // If there is no data left in the cache, we want to continue // and let the cache object itself get destroyed if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { return; } } } // See jQuery.data for more information if ( !pvt ) { delete cache[ id ].data; // Don't destroy the parent cache unless the internal data object // had been the only thing left in it if ( !isEmptyDataObject( cache[ id ] ) ) { return; } } // Destroy the cache if ( isNode ) { jQuery.cleanData( [ elem ], true ); // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) /* jshint eqeqeq: false */ } else if ( support.deleteExpando || cache != cache.window ) { /* jshint eqeqeq: true */ delete cache[ id ]; // When all else fails, null } else { cache[ id ] = null; } } jQuery.extend({ cache: {}, // The following elements (space-suffixed to avoid Object.prototype collisions) // throw uncatchable exceptions if you attempt to set expando properties noData: { "applet ": true, "embed ": true, // ...but Flash objects (which have this classid) *can* handle expandos "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" }, hasData: function( elem ) { elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; return !!elem && !isEmptyDataObject( elem ); }, data: function( elem, name, data ) { return internalData( elem, name, data ); }, removeData: function( elem, name ) { return internalRemoveData( elem, name ); }, // For internal use only. _data: function( elem, name, data ) { return internalData( elem, name, data, true ); }, _removeData: function( elem, name ) { return internalRemoveData( elem, name, true ); } }); jQuery.fn.extend({ data: function( key, value ) { var i, name, data, elem = this[0], attrs = elem && elem.attributes; // Special expections of .data basically thwart jQuery.access, // so implement the relevant behavior ourselves // Gets all values if ( key === undefined ) { if ( this.length ) { data = jQuery.data( elem ); if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { i = attrs.length; while ( i-- ) { // Support: IE11+ // The attrs elements can be null (#14894) if ( attrs[ i ] ) { name = attrs[ i ].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.slice(5) ); dataAttr( elem, name, data[ name ] ); } } } jQuery._data( elem, "parsedAttrs", true ); } } return data; } // Sets multiple values if ( typeof key === "object" ) { return this.each(function() { jQuery.data( this, key ); }); } return arguments.length > 1 ? // Sets one value this.each(function() { jQuery.data( this, key, value ); }) : // Gets one value // Try to fetch any internally stored data first elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; }, removeData: function( key ) { return this.each(function() { jQuery.removeData( this, key ); }); } }); jQuery.extend({ queue: function( elem, type, data ) { var queue; if ( elem ) { type = ( type || "fx" ) + "queue"; queue = jQuery._data( elem, type ); // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { if ( !queue || jQuery.isArray(data) ) { queue = jQuery._data( elem, type, jQuery.makeArray(data) ); } else { queue.push( data ); } } return queue || []; } }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), startLength = queue.length, fn = queue.shift(), hooks = jQuery._queueHooks( elem, type ), next = function() { jQuery.dequeue( elem, type ); }; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); startLength--; } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift( "inprogress" ); } // clear up the last queue stop function delete hooks.stop; fn.call( elem, next, hooks ); } if ( !startLength && hooks ) { hooks.empty.fire(); } }, // not intended for public consumption - generates a queueHooks object, or returns the current one _queueHooks: function( elem, type ) { var key = type + "queueHooks"; return jQuery._data( elem, key ) || jQuery._data( elem, key, { empty: jQuery.Callbacks("once memory").add(function() { jQuery._removeData( elem, type + "queue" ); jQuery._removeData( elem, key ); }) }); } }); jQuery.fn.extend({ queue: function( type, data ) { var setter = 2; if ( typeof type !== "string" ) { data = type; type = "fx"; setter--; } if ( arguments.length < setter ) { return jQuery.queue( this[0], type ); } return data === undefined ? this : this.each(function() { var queue = jQuery.queue( this, type, data ); // ensure a hooks for this queue jQuery._queueHooks( this, type ); if ( type === "fx" && queue[0] !== "inprogress" ) { jQuery.dequeue( this, type ); } }); }, dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, obj ) { var tmp, count = 1, defer = jQuery.Deferred(), elements = this, i = this.length, resolve = function() { if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } }; if ( typeof type !== "string" ) { obj = type; type = undefined; } type = type || "fx"; while ( i-- ) { tmp = jQuery._data( elements[ i ], type + "queueHooks" ); if ( tmp && tmp.empty ) { count++; tmp.empty.add( resolve ); } } resolve(); return defer.promise( obj ); } }); var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; var isHidden = function( elem, el ) { // isHidden might be called from jQuery#filter function; // in that case, element will be second argument elem = el || elem; return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); }; // Multifunctional method to get and set values of a collection // The value/s can optionally be executed if it's a function var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, length = elems.length, bulk = key == null; // Sets many values if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); } // Sets one value } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { raw = true; } if ( bulk ) { // Bulk operations run against the entire set if ( raw ) { fn.call( elems, value ); fn = null; // ...except when executing function values } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } if ( fn ) { for ( ; i < length; i++ ) { fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); } } } return chainable ? elems : // Gets bulk ? fn.call( elems ) : length ? fn( elems[0], key ) : emptyGet; }; var rcheckableType = (/^(?:checkbox|radio)$/i); (function() { // Minified: var a,b,c var input = document.createElement( "input" ), div = document.createElement( "div" ), fragment = document.createDocumentFragment(); // Setup div.innerHTML = "
a"; // IE strips leading whitespace when .innerHTML is used support.leadingWhitespace = div.firstChild.nodeType === 3; // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables support.tbody = !div.getElementsByTagName( "tbody" ).length; // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; // Makes sure cloning an html5 element does not cause problems // Where outerHTML is undefined, this still works support.html5Clone = document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; // Check if a disconnected checkbox will retain its checked // value of true after appended to the DOM (IE6/7) input.type = "checkbox"; input.checked = true; fragment.appendChild( input ); support.appendChecked = input.checked; // Make sure textarea (and checkbox) defaultValue is properly cloned // Support: IE6-IE11+ div.innerHTML = ""; support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; // #11217 - WebKit loses check when the name is after the checked attribute fragment.appendChild( div ); div.innerHTML = ""; // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 // old WebKit doesn't clone checked state correctly in fragments support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; // Support: IE<9 // Opera does not clone events (and typeof div.attachEvent === undefined). // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() support.noCloneEvent = true; if ( div.attachEvent ) { div.attachEvent( "onclick", function() { support.noCloneEvent = false; }); div.cloneNode( true ).click(); } // Execute the test only if not already executed in another module. if (support.deleteExpando == null) { // Support: IE<9 support.deleteExpando = true; try { delete div.test; } catch( e ) { support.deleteExpando = false; } } })(); (function() { var i, eventName, div = document.createElement( "div" ); // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) for ( i in { submit: true, change: true, focusin: true }) { eventName = "on" + i; if ( !(support[ i + "Bubbles" ] = eventName in window) ) { // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) div.setAttribute( eventName, "t" ); support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; } } // Null elements to avoid leaks in IE. div = null; })(); var rformElems = /^(?:input|select|textarea)$/i, rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; function returnTrue() { return true; } function returnFalse() { return false; } function safeActiveElement() { try { return document.activeElement; } catch ( err ) { } } /* * Helper functions for managing events -- not part of the public interface. * Props to Dean Edwards' addEvent library for many of the ideas. */ jQuery.event = { global: {}, add: function( elem, types, handler, data, selector ) { var tmp, events, t, handleObjIn, special, eventHandle, handleObj, handlers, type, namespaces, origType, elemData = jQuery._data( elem ); // Don't attach events to noData or text/comment nodes (but allow plain objects) if ( !elemData ) { return; } // Caller can pass in an object of custom data in lieu of the handler if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; } // Make sure that the handler has a unique ID, used to find/remove it later if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure and main handler, if this is the first if ( !(events = elemData.events) ) { events = elemData.events = {}; } if ( !(eventHandle = elemData.handle) ) { eventHandle = elemData.handle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }; // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events eventHandle.elem = elem; } // Handle multiple events separated by a space types = ( types || "" ).match( rnotwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[t] ) || []; type = origType = tmp[1]; namespaces = ( tmp[2] || "" ).split( "." ).sort(); // There *must* be a type, no attaching namespace-only handlers if ( !type ) { continue; } // If event changes its type, use the special event handlers for the changed type special = jQuery.event.special[ type ] || {}; // If selector defined, determine special event api type, otherwise given type type = ( selector ? special.delegateType : special.bindType ) || type; // Update special based on newly reset type special = jQuery.event.special[ type ] || {}; // handleObj is passed to all event handlers handleObj = jQuery.extend({ type: type, origType: origType, data: data, handler: handler, guid: handler.guid, selector: selector, needsContext: selector && jQuery.expr.match.needsContext.test( selector ), namespace: namespaces.join(".") }, handleObjIn ); // Init the event handler queue if we're the first if ( !(handlers = events[ type ]) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener/attachEvent if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add to the element's handler list, delegates in front if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } // Nullify elem to prevent memory leaks in IE elem = null; }, // Detach an event or set of events from an element remove: function( elem, types, handler, selector, mappedTypes ) { var j, handleObj, tmp, origCount, t, events, special, handlers, type, namespaces, origType, elemData = jQuery.hasData( elem ) && jQuery._data( elem ); if ( !elemData || !(events = elemData.events) ) { return; } // Once for each type.namespace in types; type may be omitted types = ( types || "" ).match( rnotwhite ) || [ "" ]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[t] ) || []; type = origType = tmp[1]; namespaces = ( tmp[2] || "" ).split( "." ).sort(); // Unbind all events (on this namespace, if provided) for the element if ( !type ) { for ( type in events ) { jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } continue; } special = jQuery.event.special[ type ] || {}; type = ( selector ? special.delegateType : special.bindType ) || type; handlers = events[ type ] || []; tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); // Remove matching events origCount = j = handlers.length; while ( j-- ) { handleObj = handlers[ j ]; if ( ( mappedTypes || origType === handleObj.origType ) && ( !handler || handler.guid === handleObj.guid ) && ( !tmp || tmp.test( handleObj.namespace ) ) && ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { handlers.splice( j, 1 ); if ( handleObj.selector ) { handlers.delegateCount--; } if ( special.remove ) { special.remove.call( elem, handleObj ); } } } // Remove generic event handler if we removed something and no more handlers exist // (avoids potential for endless recursion during removal of special event handlers) if ( origCount && !handlers.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { delete elemData.handle; // removeData also checks for emptiness and clears the expando if empty // so use it instead of delete jQuery._removeData( elem, "events" ); } }, trigger: function( event, data, elem, onlyHandlers ) { var handle, ontype, cur, bubbleType, special, tmp, i, eventPath = [ elem || document ], type = hasOwn.call( event, "type" ) ? event.type : event, namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; cur = tmp = elem = elem || document; // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // focus/blur morphs to focusin/out; ensure we're not firing them right now if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } if ( type.indexOf(".") >= 0 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split("."); type = namespaces.shift(); namespaces.sort(); } ontype = type.indexOf(":") < 0 && "on" + type; // Caller can pass in a jQuery.Event object, Object, or just an event type string event = event[ jQuery.expando ] ? event : new jQuery.Event( type, typeof event === "object" && event ); // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) event.isTrigger = onlyHandlers ? 2 : 3; event.namespace = namespaces.join("."); event.namespace_re = event.namespace ? new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : null; // Clean up the event in case it is being reused event.result = undefined; if ( !event.target ) { event.target = elem; } // Clone any incoming data and prepend the event, creating the handler arg list data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // Determine event propagation path in advance, per W3C events spec (#9951) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } for ( ; cur; cur = cur.parentNode ) { eventPath.push( cur ); tmp = cur; } // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === (elem.ownerDocument || document) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); } } // Fire handlers on the event path i = 0; while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { event.type = i > 1 ? bubbleType : special.bindType || type; // jQuery handler handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); } // Native handler handle = ontype && cur[ ontype ]; if ( handle && handle.apply && jQuery.acceptData( cur ) ) { event.result = handle.apply( cur, data ); if ( event.result === false ) { event.preventDefault(); } } } event.type = type; // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && jQuery.acceptData( elem ) ) { // Call a native DOM method on the target with the same name name as the event. // Can't use an .isFunction() check here because IE6/7 fails that test. // Don't do default actions on window, that's where global variables be (#6170) if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; if ( tmp ) { elem[ ontype ] = null; } // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; try { elem[ type ](); } catch ( e ) { // IE<9 dies on focus/blur to hidden element (#1486,#12518) // only reproducible on winXP IE8 native, not IE9 in IE8 mode } jQuery.event.triggered = undefined; if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; }, dispatch: function( event ) { // Make a writable jQuery.Event from the native event object event = jQuery.event.fix( event ); var i, ret, handleObj, matched, j, handlerQueue = [], args = slice.call( arguments ), handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event args[0] = event; event.delegateTarget = this; // Call the preDispatch hook for the mapped type, and let it bail if desired if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { return; } // Determine handlers handlerQueue = jQuery.event.handlers.call( this, event, handlers ); // Run delegates first; they may want to stop propagation beneath us i = 0; while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { event.currentTarget = matched.elem; j = 0; while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { // Triggered event must either 1) have no namespace, or // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) .apply( matched.elem, args ); if ( ret !== undefined ) { if ( (event.result = ret) === false ) { event.preventDefault(); event.stopPropagation(); } } } } } // Call the postDispatch hook for the mapped type if ( special.postDispatch ) { special.postDispatch.call( this, event ); } return event.result; }, handlers: function( event, handlers ) { var sel, handleObj, matches, i, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target; // Find delegate handlers // Black-hole SVG instance trees (#13180) // Avoid non-left-click bubbling in Firefox (#3861) if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { /* jshint eqeqeq: false */ for ( ; cur != this; cur = cur.parentNode || this ) { /* jshint eqeqeq: true */ // Don't check non-elements (#13208) // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { matches = []; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; // Don't conflict with Object.prototype properties (#13203) sel = handleObj.selector + " "; if ( matches[ sel ] === undefined ) { matches[ sel ] = handleObj.needsContext ? jQuery( sel, this ).index( cur ) >= 0 : jQuery.find( sel, this, null, [ cur ] ).length; } if ( matches[ sel ] ) { matches.push( handleObj ); } } if ( matches.length ) { handlerQueue.push({ elem: cur, handlers: matches }); } } } } // Add the remaining (directly-bound) handlers if ( delegateCount < handlers.length ) { handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); } return handlerQueue; }, fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } // Create a writable copy of the event object and normalize some properties var i, prop, copy, type = event.type, originalEvent = event, fixHook = this.fixHooks[ type ]; if ( !fixHook ) { this.fixHooks[ type ] = fixHook = rmouseEvent.test( type ) ? this.mouseHooks : rkeyEvent.test( type ) ? this.keyHooks : {}; } copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; event = new jQuery.Event( originalEvent ); i = copy.length; while ( i-- ) { prop = copy[ i ]; event[ prop ] = originalEvent[ prop ]; } // Support: IE<9 // Fix target property (#1925) if ( !event.target ) { event.target = originalEvent.srcElement || document; } // Support: Chrome 23+, Safari? // Target should not be a text node (#504, #13143) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } // Support: IE<9 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) event.metaKey = !!event.metaKey; return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; }, // Includes some event props shared by KeyEvent and MouseEvent props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), fixHooks: {}, keyHooks: { props: "char charCode key keyCode".split(" "), filter: function( event, original ) { // Add which for key events if ( event.which == null ) { event.which = original.charCode != null ? original.charCode : original.keyCode; } return event; } }, mouseHooks: { props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), filter: function( event, original ) { var body, eventDoc, doc, button = original.button, fromElement = original.fromElement; // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && original.clientX != null ) { eventDoc = event.target.ownerDocument || document; doc = eventDoc.documentElement; body = eventDoc.body; event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); } // Add relatedTarget, if necessary if ( !event.relatedTarget && fromElement ) { event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; } // Add which for click: 1 === left; 2 === middle; 3 === right // Note: button is not normalized, so don't use it if ( !event.which && button !== undefined ) { event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); } return event; } }, special: { load: { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, focus: { // Fire native event if possible so blur/focus sequence is correct trigger: function() { if ( this !== safeActiveElement() && this.focus ) { try { this.focus(); return false; } catch ( e ) { // Support: IE<9 // If we error on focus to hidden element (#1486, #12518), // let .trigger() run the handlers } } }, delegateType: "focusin" }, blur: { trigger: function() { if ( this === safeActiveElement() && this.blur ) { this.blur(); return false; } }, delegateType: "focusout" }, click: { // For checkbox, fire native event so checked state will be right trigger: function() { if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { this.click(); return false; } }, // For cross-browser consistency, don't fire native .click() on links _default: function( event ) { return jQuery.nodeName( event.target, "a" ); } }, beforeunload: { postDispatch: function( event ) { // Support: Firefox 20+ // Firefox doesn't alert if the returnValue field is not set. if ( event.result !== undefined && event.originalEvent ) { event.originalEvent.returnValue = event.result; } } } }, simulate: function( type, elem, event, bubble ) { // Piggyback on a donor event to simulate a different one. // Fake originalEvent to avoid donor's stopPropagation, but if the // simulated event prevents default then we do the same on the donor. var e = jQuery.extend( new jQuery.Event(), event, { type: type, isSimulated: true, originalEvent: {} } ); if ( bubble ) { jQuery.event.trigger( e, null, elem ); } else { jQuery.event.dispatch.call( elem, e ); } if ( e.isDefaultPrevented() ) { event.preventDefault(); } } }; jQuery.removeEvent = document.removeEventListener ? function( elem, type, handle ) { if ( elem.removeEventListener ) { elem.removeEventListener( type, handle, false ); } } : function( elem, type, handle ) { var name = "on" + type; if ( elem.detachEvent ) { // #8545, #7054, preventing memory leaks for custom events in IE6-8 // detachEvent needed property on element, by name of that event, to properly expose it to GC if ( typeof elem[ name ] === strundefined ) { elem[ name ] = null; } elem.detachEvent( name, handle ); } }; jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !(this instanceof jQuery.Event) ) { return new jQuery.Event( src, props ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = src.defaultPrevented || src.defaultPrevented === undefined && // Support: IE < 9, Android < 4.0 src.returnValue === false ? returnTrue : returnFalse; // Event type } else { this.type = src; } // Put explicitly provided properties onto the event object if ( props ) { jQuery.extend( this, props ); } // Create a timestamp if incoming event doesn't have one this.timeStamp = src && src.timeStamp || jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse, preventDefault: function() { var e = this.originalEvent; this.isDefaultPrevented = returnTrue; if ( !e ) { return; } // If preventDefault exists, run it on the original event if ( e.preventDefault ) { e.preventDefault(); // Support: IE // Otherwise set the returnValue property of the original event to false } else { e.returnValue = false; } }, stopPropagation: function() { var e = this.originalEvent; this.isPropagationStopped = returnTrue; if ( !e ) { return; } // If stopPropagation exists, run it on the original event if ( e.stopPropagation ) { e.stopPropagation(); } // Support: IE // Set the cancelBubble property of the original event to true e.cancelBubble = true; }, stopImmediatePropagation: function() { var e = this.originalEvent; this.isImmediatePropagationStopped = returnTrue; if ( e && e.stopImmediatePropagation ) { e.stopImmediatePropagation(); } this.stopPropagation(); } }; // Create mouseenter/leave events using mouseover/out and event-time checks jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout", pointerenter: "pointerover", pointerleave: "pointerout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { delegateType: fix, bindType: fix, handle: function( event ) { var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj; // For mousenter/leave call the handler if related is outside the target. // NB: No relatedTarget if the mouse left/entered the browser window if ( !related || (related !== target && !jQuery.contains( target, related )) ) { event.type = handleObj.origType; ret = handleObj.handler.apply( this, arguments ); event.type = fix; } return ret; } }; }); // IE submit delegation if ( !support.submitBubbles ) { jQuery.event.special.submit = { setup: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Lazy-add a submit handler when a descendant form may potentially be submitted jQuery.event.add( this, "click._submit keypress._submit", function( e ) { // Node name check avoids a VML-related crash in IE (#9807) var elem = e.target, form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; if ( form && !jQuery._data( form, "submitBubbles" ) ) { jQuery.event.add( form, "submit._submit", function( event ) { event._submit_bubble = true; }); jQuery._data( form, "submitBubbles", true ); } }); // return undefined since we don't need an event listener }, postDispatch: function( event ) { // If form was submitted by the user, bubble the event up the tree if ( event._submit_bubble ) { delete event._submit_bubble; if ( this.parentNode && !event.isTrigger ) { jQuery.event.simulate( "submit", this.parentNode, event, true ); } } }, teardown: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Remove delegated handlers; cleanData eventually reaps submit handlers attached above jQuery.event.remove( this, "._submit" ); } }; } // IE change delegation and checkbox/radio fix if ( !support.changeBubbles ) { jQuery.event.special.change = { setup: function() { if ( rformElems.test( this.nodeName ) ) { // IE doesn't fire change on a check/radio until blur; trigger it on click // after a propertychange. Eat the blur-change in special.change.handle. // This still fires onchange a second time for check/radio after blur. if ( this.type === "checkbox" || this.type === "radio" ) { jQuery.event.add( this, "propertychange._change", function( event ) { if ( event.originalEvent.propertyName === "checked" ) { this._just_changed = true; } }); jQuery.event.add( this, "click._change", function( event ) { if ( this._just_changed && !event.isTrigger ) { this._just_changed = false; } // Allow triggered, simulated change events (#11500) jQuery.event.simulate( "change", this, event, true ); }); } return false; } // Delegated event; lazy-add a change handler on descendant inputs jQuery.event.add( this, "beforeactivate._change", function( e ) { var elem = e.target; if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { jQuery.event.add( elem, "change._change", function( event ) { if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { jQuery.event.simulate( "change", this.parentNode, event, true ); } }); jQuery._data( elem, "changeBubbles", true ); } }); }, handle: function( event ) { var elem = event.target; // Swallow native change events from checkbox/radio, we already triggered them above if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { return event.handleObj.handler.apply( this, arguments ); } }, teardown: function() { jQuery.event.remove( this, "._change" ); return !rformElems.test( this.nodeName ); } }; } // Create "bubbling" focus and blur events if ( !support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler on the document while someone wants focusin/focusout var handler = function( event ) { jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); }; jQuery.event.special[ fix ] = { setup: function() { var doc = this.ownerDocument || this, attaches = jQuery._data( doc, fix ); if ( !attaches ) { doc.addEventListener( orig, handler, true ); } jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); }, teardown: function() { var doc = this.ownerDocument || this, attaches = jQuery._data( doc, fix ) - 1; if ( !attaches ) { doc.removeEventListener( orig, handler, true ); jQuery._removeData( doc, fix ); } else { jQuery._data( doc, fix, attaches ); } } }; }); } jQuery.fn.extend({ on: function( types, selector, data, fn, /*INTERNAL*/ one ) { var type, origFn; // Types can be a map of types/handlers if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } for ( type in types ) { this.on( type, selector, data, types[ type ], one ); } return this; } if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return this; } if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } return this.each( function() { jQuery.event.add( this, types, fn, data, selector ); }); }, one: function( types, selector, data, fn ) { return this.on( types, selector, data, fn, 1 ); }, off: function( types, selector, fn ) { var handleObj, type; if ( types && types.preventDefault && types.handleObj ) { // ( event ) dispatched jQuery.Event handleObj = types.handleObj; jQuery( types.delegateTarget ).off( handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler ); return this; } if ( typeof types === "object" ) { // ( types-object [, selector] ) for ( type in types ) { this.off( type, selector, types[ type ] ); } return this; } if ( selector === false || typeof selector === "function" ) { // ( types [, fn] ) fn = selector; selector = undefined; } if ( fn === false ) { fn = returnFalse; } return this.each(function() { jQuery.event.remove( this, types, fn, selector ); }); }, trigger: function( type, data ) { return this.each(function() { jQuery.event.trigger( type, data, this ); }); }, triggerHandler: function( type, data ) { var elem = this[0]; if ( elem ) { return jQuery.event.trigger( type, data, elem, true ); } } }); function createSafeFragment( document ) { var list = nodeNames.split( "|" ), safeFrag = document.createDocumentFragment(); if ( safeFrag.createElement ) { while ( list.length ) { safeFrag.createElement( list.pop() ); } } return safeFrag; } var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), rleadingWhitespace = /^\s+/, rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, rtagName = /<([\w:]+)/, rtbody = /\s*$/g, // We have to close these tags to support XHTML (#13200) wrapMap = { option: [ 1, "" ], legend: [ 1, "
", "
" ], area: [ 1, "", "" ], param: [ 1, "", "" ], thead: [ 1, "", "
" ], tr: [ 2, "", "
" ], col: [ 2, "", "
" ], td: [ 3, "", "
" ], // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, // unless wrapped in a div with non-breaking characters in front of it. _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] }, safeFragment = createSafeFragment( document ), fragmentDiv = safeFragment.appendChild( document.createElement("div") ); wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; function getAll( context, tag ) { var elems, elem, i = 0, found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : undefined; if ( !found ) { for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { if ( !tag || jQuery.nodeName( elem, tag ) ) { found.push( elem ); } else { jQuery.merge( found, getAll( elem, tag ) ); } } } return tag === undefined || tag && jQuery.nodeName( context, tag ) ? jQuery.merge( [ context ], found ) : found; } // Used in buildFragment, fixes the defaultChecked property function fixDefaultChecked( elem ) { if ( rcheckableType.test( elem.type ) ) { elem.defaultChecked = elem.checked; } } // Support: IE<8 // Manipulating tables requires a tbody function manipulationTarget( elem, content ) { return jQuery.nodeName( elem, "table" ) && jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? elem.getElementsByTagName("tbody")[0] || elem.appendChild( elem.ownerDocument.createElement("tbody") ) : elem; } // Replace/restore the type attribute of script elements for safe DOM manipulation function disableScript( elem ) { elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; return elem; } function restoreScript( elem ) { var match = rscriptTypeMasked.exec( elem.type ); if ( match ) { elem.type = match[1]; } else { elem.removeAttribute("type"); } return elem; } // Mark scripts as having already been evaluated function setGlobalEval( elems, refElements ) { var elem, i = 0; for ( ; (elem = elems[i]) != null; i++ ) { jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); } } function cloneCopyEvent( src, dest ) { if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { return; } var type, i, l, oldData = jQuery._data( src ), curData = jQuery._data( dest, oldData ), events = oldData.events; if ( events ) { delete curData.handle; curData.events = {}; for ( type in events ) { for ( i = 0, l = events[ type ].length; i < l; i++ ) { jQuery.event.add( dest, type, events[ type ][ i ] ); } } } // make the cloned public data object a copy from the original if ( curData.data ) { curData.data = jQuery.extend( {}, curData.data ); } } function fixCloneNodeIssues( src, dest ) { var nodeName, e, data; // We do not need to do anything for non-Elements if ( dest.nodeType !== 1 ) { return; } nodeName = dest.nodeName.toLowerCase(); // IE6-8 copies events bound via attachEvent when using cloneNode. if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { data = jQuery._data( dest ); for ( e in data.events ) { jQuery.removeEvent( dest, e, data.handle ); } // Event data gets referenced instead of copied if the expando gets copied too dest.removeAttribute( jQuery.expando ); } // IE blanks contents when cloning scripts, and tries to evaluate newly-set text if ( nodeName === "script" && dest.text !== src.text ) { disableScript( dest ).text = src.text; restoreScript( dest ); // IE6-10 improperly clones children of object elements using classid. // IE10 throws NoModificationAllowedError if parent is null, #12132. } else if ( nodeName === "object" ) { if ( dest.parentNode ) { dest.outerHTML = src.outerHTML; } // This path appears unavoidable for IE9. When cloning an object // element in IE9, the outerHTML strategy above is not sufficient. // If the src has innerHTML and the destination does not, // copy the src.innerHTML into the dest.innerHTML. #10324 if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { dest.innerHTML = src.innerHTML; } } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { // IE6-8 fails to persist the checked state of a cloned checkbox // or radio button. Worse, IE6-7 fail to give the cloned element // a checked appearance if the defaultChecked value isn't also set dest.defaultChecked = dest.checked = src.checked; // IE6-7 get confused and end up setting the value of a cloned // checkbox/radio button to an empty string instead of "on" if ( dest.value !== src.value ) { dest.value = src.value; } // IE6-8 fails to return the selected option to the default selected // state when cloning options } else if ( nodeName === "option" ) { dest.defaultSelected = dest.selected = src.defaultSelected; // IE6-8 fails to set the defaultValue to the correct value when // cloning other types of input fields } else if ( nodeName === "input" || nodeName === "textarea" ) { dest.defaultValue = src.defaultValue; } } jQuery.extend({ clone: function( elem, dataAndEvents, deepDataAndEvents ) { var destElements, node, clone, i, srcElements, inPage = jQuery.contains( elem.ownerDocument, elem ); if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { clone = elem.cloneNode( true ); // IE<=8 does not properly clone detached, unknown element nodes } else { fragmentDiv.innerHTML = elem.outerHTML; fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); } if ( (!support.noCloneEvent || !support.noCloneChecked) && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 destElements = getAll( clone ); srcElements = getAll( elem ); // Fix all IE cloning issues for ( i = 0; (node = srcElements[i]) != null; ++i ) { // Ensure that the destination node is not null; Fixes #9587 if ( destElements[i] ) { fixCloneNodeIssues( node, destElements[i] ); } } } // Copy the events from the original to the clone if ( dataAndEvents ) { if ( deepDataAndEvents ) { srcElements = srcElements || getAll( elem ); destElements = destElements || getAll( clone ); for ( i = 0; (node = srcElements[i]) != null; i++ ) { cloneCopyEvent( node, destElements[i] ); } } else { cloneCopyEvent( elem, clone ); } } // Preserve script evaluation history destElements = getAll( clone, "script" ); if ( destElements.length > 0 ) { setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); } destElements = srcElements = node = null; // Return the cloned set return clone; }, buildFragment: function( elems, context, scripts, selection ) { var j, elem, contains, tmp, tag, tbody, wrap, l = elems.length, // Ensure a safe fragment safe = createSafeFragment( context ), nodes = [], i = 0; for ( ; i < l; i++ ) { elem = elems[ i ]; if ( elem || elem === 0 ) { // Add nodes directly if ( jQuery.type( elem ) === "object" ) { jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); // Convert non-html into a text node } else if ( !rhtml.test( elem ) ) { nodes.push( context.createTextNode( elem ) ); // Convert html into DOM nodes } else { tmp = tmp || safe.appendChild( context.createElement("div") ); // Deserialize a standard representation tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); wrap = wrapMap[ tag ] || wrapMap._default; tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; // Descend through wrappers to the right content j = wrap[0]; while ( j-- ) { tmp = tmp.lastChild; } // Manually add leading whitespace removed by IE if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); } // Remove IE's autoinserted from table fragments if ( !support.tbody ) { // String was a , *may* have spurious elem = tag === "table" && !rtbody.test( elem ) ? tmp.firstChild : // String was a bare or wrap[1] === "
" && !rtbody.test( elem ) ? tmp : 0; j = elem && elem.childNodes.length; while ( j-- ) { if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { elem.removeChild( tbody ); } } } jQuery.merge( nodes, tmp.childNodes ); // Fix #12392 for WebKit and IE > 9 tmp.textContent = ""; // Fix #12392 for oldIE while ( tmp.firstChild ) { tmp.removeChild( tmp.firstChild ); } // Remember the top-level container for proper cleanup tmp = safe.lastChild; } } } // Fix #11356: Clear elements from fragment if ( tmp ) { safe.removeChild( tmp ); } // Reset defaultChecked for any radios and checkboxes // about to be appended to the DOM in IE 6/7 (#8060) if ( !support.appendChecked ) { jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); } i = 0; while ( (elem = nodes[ i++ ]) ) { // #4087 - If origin and destination elements are the same, and this is // that element, do not do anything if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { continue; } contains = jQuery.contains( elem.ownerDocument, elem ); // Append to fragment tmp = getAll( safe.appendChild( elem ), "script" ); // Preserve script evaluation history if ( contains ) { setGlobalEval( tmp ); } // Capture executables if ( scripts ) { j = 0; while ( (elem = tmp[ j++ ]) ) { if ( rscriptType.test( elem.type || "" ) ) { scripts.push( elem ); } } } } tmp = null; return safe; }, cleanData: function( elems, /* internal */ acceptData ) { var elem, type, id, data, i = 0, internalKey = jQuery.expando, cache = jQuery.cache, deleteExpando = support.deleteExpando, special = jQuery.event.special; for ( ; (elem = elems[i]) != null; i++ ) { if ( acceptData || jQuery.acceptData( elem ) ) { id = elem[ internalKey ]; data = id && cache[ id ]; if ( data ) { if ( data.events ) { for ( type in data.events ) { if ( special[ type ] ) { jQuery.event.remove( elem, type ); // This is a shortcut to avoid jQuery.event.remove's overhead } else { jQuery.removeEvent( elem, type, data.handle ); } } } // Remove cache only if it was not already removed by jQuery.event.remove if ( cache[ id ] ) { delete cache[ id ]; // IE does not allow us to delete expando properties from nodes, // nor does it have a removeAttribute function on Document nodes; // we must handle all of these cases if ( deleteExpando ) { delete elem[ internalKey ]; } else if ( typeof elem.removeAttribute !== strundefined ) { elem.removeAttribute( internalKey ); } else { elem[ internalKey ] = null; } deletedIds.push( id ); } } } } } }); jQuery.fn.extend({ text: function( value ) { return access( this, function( value ) { return value === undefined ? jQuery.text( this ) : this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); }, null, value, arguments.length ); }, append: function() { return this.domManip( arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.appendChild( elem ); } }); }, prepend: function() { return this.domManip( arguments, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { var target = manipulationTarget( this, elem ); target.insertBefore( elem, target.firstChild ); } }); }, before: function() { return this.domManip( arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this ); } }); }, after: function() { return this.domManip( arguments, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this.nextSibling ); } }); }, remove: function( selector, keepData /* Internal Use Only */ ) { var elem, elems = selector ? jQuery.filter( selector, this ) : this, i = 0; for ( ; (elem = elems[i]) != null; i++ ) { if ( !keepData && elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem ) ); } if ( elem.parentNode ) { if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { setGlobalEval( getAll( elem, "script" ) ); } elem.parentNode.removeChild( elem ); } } return this; }, empty: function() { var elem, i = 0; for ( ; (elem = this[i]) != null; i++ ) { // Remove element nodes and prevent memory leaks if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); } // Remove any remaining nodes while ( elem.firstChild ) { elem.removeChild( elem.firstChild ); } // If this is a select, ensure that it displays empty (#12336) // Support: IE<9 if ( elem.options && jQuery.nodeName( elem, "select" ) ) { elem.options.length = 0; } } return this; }, clone: function( dataAndEvents, deepDataAndEvents ) { dataAndEvents = dataAndEvents == null ? false : dataAndEvents; deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; return this.map(function() { return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); }); }, html: function( value ) { return access( this, function( value ) { var elem = this[ 0 ] || {}, i = 0, l = this.length; if ( value === undefined ) { return elem.nodeType === 1 ? elem.innerHTML.replace( rinlinejQuery, "" ) : undefined; } // See if we can take a shortcut and just use innerHTML if ( typeof value === "string" && !rnoInnerhtml.test( value ) && ( support.htmlSerialize || !rnoshimcache.test( value ) ) && ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { value = value.replace( rxhtmlTag, "<$1>" ); try { for (; i < l; i++ ) { // Remove element nodes and prevent memory leaks elem = this[i] || {}; if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); elem.innerHTML = value; } } elem = 0; // If using innerHTML throws an exception, use the fallback method } catch(e) {} } if ( elem ) { this.empty().append( value ); } }, null, value, arguments.length ); }, replaceWith: function() { var arg = arguments[ 0 ]; // Make the changes, replacing each context element with the new content this.domManip( arguments, function( elem ) { arg = this.parentNode; jQuery.cleanData( getAll( this ) ); if ( arg ) { arg.replaceChild( elem, this ); } }); // Force removal if there was no new content (e.g., from empty arguments) return arg && (arg.length || arg.nodeType) ? this : this.remove(); }, detach: function( selector ) { return this.remove( selector, true ); }, domManip: function( args, callback ) { // Flatten any nested arrays args = concat.apply( [], args ); var first, node, hasScripts, scripts, doc, fragment, i = 0, l = this.length, set = this, iNoClone = l - 1, value = args[0], isFunction = jQuery.isFunction( value ); // We can't cloneNode fragments that contain checked, in WebKit if ( isFunction || ( l > 1 && typeof value === "string" && !support.checkClone && rchecked.test( value ) ) ) { return this.each(function( index ) { var self = set.eq( index ); if ( isFunction ) { args[0] = value.call( this, index, self.html() ); } self.domManip( args, callback ); }); } if ( l ) { fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); first = fragment.firstChild; if ( fragment.childNodes.length === 1 ) { fragment = first; } if ( first ) { scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); hasScripts = scripts.length; // Use the original fragment for the last item instead of the first because it can end up // being emptied incorrectly in certain situations (#8070). for ( ; i < l; i++ ) { node = fragment; if ( i !== iNoClone ) { node = jQuery.clone( node, true, true ); // Keep references to cloned scripts for later restoration if ( hasScripts ) { jQuery.merge( scripts, getAll( node, "script" ) ); } } callback.call( this[i], node, i ); } if ( hasScripts ) { doc = scripts[ scripts.length - 1 ].ownerDocument; // Reenable scripts jQuery.map( scripts, restoreScript ); // Evaluate executable scripts on first document insertion for ( i = 0; i < hasScripts; i++ ) { node = scripts[ i ]; if ( rscriptType.test( node.type || "" ) && !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { if ( node.src ) { // Optional AJAX dependency, but won't run scripts if not present if ( jQuery._evalUrl ) { jQuery._evalUrl( node.src ); } } else { jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); } } } } // Fix #11809: Avoid leaking memory fragment = first = null; } } return this; } }); jQuery.each({ appendTo: "append", prependTo: "prepend", insertBefore: "before", insertAfter: "after", replaceAll: "replaceWith" }, function( name, original ) { jQuery.fn[ name ] = function( selector ) { var elems, i = 0, ret = [], insert = jQuery( selector ), last = insert.length - 1; for ( ; i <= last; i++ ) { elems = i === last ? this : this.clone(true); jQuery( insert[i] )[ original ]( elems ); // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() push.apply( ret, elems.get() ); } return this.pushStack( ret ); }; }); var iframe, elemdisplay = {}; /** * Retrieve the actual display of a element * @param {String} name nodeName of the element * @param {Object} doc Document object */ // Called only from within defaultDisplay function actualDisplay( name, doc ) { var style, elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), // getDefaultComputedStyle might be reliably used only on attached element display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? // Use of this method is a temporary fix (more like optmization) until something better comes along, // since it was removed from specification and supported only in FF style.display : jQuery.css( elem[ 0 ], "display" ); // We don't have any data stored on the element, // so use "detach" method as fast way to get rid of the element elem.detach(); return display; } /** * Try to determine the default display value of an element * @param {String} nodeName */ function defaultDisplay( nodeName ) { var doc = document, display = elemdisplay[ nodeName ]; if ( !display ) { display = actualDisplay( nodeName, doc ); // If the simple way fails, read from inside an iframe if ( display === "none" || !display ) { // Use the already-created iframe if possible iframe = (iframe || jQuery( "