]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Move stuff around a bit:
authorPeter Powell <petpow@saberuk.com>
Sat, 5 Oct 2013 03:55:11 +0000 (04:55 +0100)
committerPeter Powell <petpow@saberuk.com>
Sun, 15 Dec 2013 06:46:35 +0000 (06:46 +0000)
- Create FileSystem class:
  * Move ServerConfig::CleanFilename to FileSystem::GetFileName and rewrite.
  * Move ServerConfig::ExpandPath to FileSystem.
  * Move ServerConfig::FileExists to FileSystem.
  * Move ServerConfig::StartsWithWindowsDriveLetter to FileSystem.
- Move FileReader to fileutils.cpp and fix documentation.
- Move UserManager::DoBackgroundUserStuff to usermanager.cpp.

13 files changed:
include/configreader.h
include/fileutils.h [new file with mode: 0644]
include/inspircd.h
include/modules.h
src/commands/cmd_rehash.cpp
src/configreader.cpp
src/fileutils.cpp [new file with mode: 0644]
src/inspircd.cpp
src/modmanager_dynamic.cpp
src/modules.cpp
src/modules/m_xline_db.cpp
src/usermanager.cpp
src/userprocess.cpp [deleted file]

index 0fbf234c330b5c0a41856eb45d886c7eb266f9e7..a46f9cf95ce2bb5b370f0b85062bb2fa7538d069 100644 (file)
@@ -225,10 +225,10 @@ class CoreExport ServerConfig
                        , Log(LOG_PATH)
                        , Module(MOD_PATH) { }
 
-               std::string PrependConfig(const std::string& fn) const { return ServerConfig::ExpandPath(Config, fn); }
-               std::string PrependData(const std::string& fn) const { return ServerConfig::ExpandPath(Data, fn); }
-               std::string PrependLog(const std::string& fn) const { return ServerConfig::ExpandPath(Log, fn); }
-               std::string PrependModule(const std::string& fn) const { return ServerConfig::ExpandPath(Module, fn); }
+               std::string PrependConfig(const std::string& fn) const { return FileSystem::ExpandPath(Config, fn); }
+               std::string PrependData(const std::string& fn) const { return FileSystem::ExpandPath(Data, fn); }
+               std::string PrependLog(const std::string& fn) const { return FileSystem::ExpandPath(Log, fn); }
+               std::string PrependModule(const std::string& fn) const { return FileSystem::ExpandPath(Module, fn); }
        };
 
        /** Get a configuration tag
@@ -551,30 +551,8 @@ class CoreExport ServerConfig
 
        void Fill();
 
-       /** Returns true if the given string starts with a windows drive letter
-        */
-       static bool StartsWithWindowsDriveLetter(const std::string& path);
-
        bool ApplyDisabledCommands(const std::string& data);
 
-       /** Clean a filename, stripping the directories (and drives) from string.
-        * @param name Directory to tidy
-        * @return The cleaned filename
-        */
-       static const char* CleanFilename(const char* name);
-
-       /** Check if a file exists.
-        * @param file The full path to a file
-        * @return True if the file exists and is readable.
-        */
-       static bool FileExists(const char* file);
-
-       /** Expands a path fragment to a full path.
-        * @param base The base path to expand from
-        * @param fragment The path fragment to expand on top of base.
-        */
-       static std::string ExpandPath(const std::string& base, const std::string& fragment);
-
        /** Escapes a value for storage in a configuration key.
         * @param str The string to escape.
         * @param xml Are we using the XML config format?
diff --git a/include/fileutils.h b/include/fileutils.h
new file mode 100644 (file)
index 0000000..45865bb
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ *   Copyright (C) 2013 Peter Powell <petpow@saberuk.com>
+ *
+ * This file is part of InspIRCd.  InspIRCd 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, version 2.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+/** Provides an easy method of reading a text file into memory. */
+class CoreExport FileReader : public classbase
+{
+       /** The lines of text in the file. */
+       std::vector<std::string> lines;
+
+       /** File size in bytes. */
+       unsigned long totalSize;
+
+ public:
+       /** Initializes a new file reader. */
+       FileReader() : totalSize(0) { }
+
+       /** Initializes a new file reader and reads the specified file.
+        * @param filename The file to read into memory.
+        */
+       FileReader(const std::string& filename);
+
+       /** Loads a text file from disk.
+        * @param filename The file to read into memory.
+        * @throw CoreException The file can not be loaded.
+        */
+       void Load(const std::string& filename);
+
+       /** Retrieves the entire contents of the file cache as a single string. */
+       std::string GetString() const;
+
+       /** Retrieves the entire contents of the file cache as a vector of strings. */
+       const std::vector<std::string>& GetVector() const { return lines; }
+
+       /** Retrieves the total size in bytes of the file. */
+       unsigned long TotalSize() const { return totalSize; }
+};
+
+/** Implements methods for file system access */
+class CoreExport FileSystem
+{
+private:
+       FileSystem() { }
+
+public:
+       /** Expands a path fragment to a full path.
+        * @param base The base path to expand from
+        * @param fragment The path fragment to expand on top of base.
+        */
+       static std::string ExpandPath(const std::string& base, const std::string& fragment);
+
+       /**
+        * Checks whether a file with the specified name exists on the filesystem.
+        * @param path The path to a file.
+        * @return True if the file exists; otherwise, false.
+       */
+       static bool FileExists(const std::string& path);
+
+       /** Gets the file name segment of a path.
+        * @param path The path to extract the file name from.
+        * @return The file name segment of a path.
+        */
+       static std::string GetFileName(const std::string& path);
+
+       /** Determines whether the given path starts with a Windows drive letter.
+        * @param path The path to validate.
+        * @returns True if the path begins with a Windows drive letter; otherwise, false.
+        */
+       static bool StartsWithWindowsDriveLetter(const std::string& path);
+};
index f43141c383152294499f8f9c24c6b15908094bf1..e02a5deb54b52a277493736ad8ecc7ac75b6cd6c 100644 (file)
@@ -54,6 +54,7 @@ CoreExport extern InspIRCd* ServerInstance;
 #include "caller.h"
 #include "cull_list.h"
 #include "extensible.h"
+#include "fileutils.h"
 #include "numerics.h"
 #include "uid.h"
 #include "users.h"
index 931d85032f512354264d3bdd11757b7be85456a2..b7cffd1a080d740ff33c7ffcc18fa93cc815464f 100644 (file)
@@ -1078,44 +1078,6 @@ class CoreExport Module : public classbase, public usecountbase
        virtual void OnSetUserIP(LocalUser* user);
 };
 
-/** Provides an easy method of reading a text file into memory. */
-class CoreExport FileReader : public classbase
-{
-       /** The lines of text in the file.
-        */
-       std::vector<std::string> lines;
-
-       /** Content size in bytes
-        */
-       unsigned long totalSize;
-
- public:
-       /** Initializes a new file reader.
-        */
-       FileReader() : totalSize(0) { }
-
-       /** Initializes a new file reader and reads the specified file.
-        * @param filename The file to read into memory.
-        */
-       FileReader(const std::string& filename);
-
-       /** Loads a text file from disk.
-        * @param filename The file to read into memory.
-        * @throw CoreException The file can not be loaded.
-        */
-       void Load(const std::string& filename);
-
-       /** Retrieves the entire contents of the file cache as a single string.
-        */
-       std::string GetString();
-
-       /** Retrieves the entire contents of the file cache as a vector of strings.
-        */
-       const std::vector<std::string>& GetVector() { return lines; }
-
-       unsigned long TotalSize() { return totalSize; }
-};
-
 /** A list of modules
  */
 typedef std::vector<Module*> IntModuleList;
index 1fa72696243ef9d8fcf087b44ba4372aff61428f..07183ec7db7f85ddba5456d28031b1cc8892c2c0 100644 (file)
@@ -75,15 +75,13 @@ CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, Use
        // Rehash for me. Try to start the rehash thread
        if (!ServerInstance->ConfigThread)
        {
-               std::string m = user->nick + " is rehashing config file " + ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()) + " on " + ServerInstance->Config->ServerName;
+               std::string m = user->nick + " is rehashing config file " + FileSystem::GetFileName(ServerInstance->ConfigFileName) + " on " + ServerInstance->Config->ServerName;
                ServerInstance->SNO->WriteGlobalSno('a', m);
 
                if (IS_LOCAL(user))
-                       user->WriteNumeric(RPL_REHASHING, "%s :Rehashing",
-                               ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()));
+                       user->WriteNumeric(RPL_REHASHING, "%s :Rehashing", FileSystem::GetFileName(ServerInstance->ConfigFileName).c_str());
                else
-                       ServerInstance->PI->SendUserNotice(user, std::string("*** Rehashing server ") +
-                               ServerConfig::CleanFilename(ServerInstance->ConfigFileName.c_str()));
+                       ServerInstance->PI->SendUserNotice(user, "*** Rehashing server " + FileSystem::GetFileName(ServerInstance->ConfigFileName));
 
                /* Don't do anything with the logs here -- logs are restarted
                 * after the config thread has completed.
index 7493d980cbf5f4a3fd0a3f8bb2c4c33053c22edd..341414e0d5f8759bca70bfc69aa21108745e1b19 100644 (file)
@@ -734,11 +734,6 @@ void ServerConfig::ApplyModules(User* user)
        }
 }
 
-bool ServerConfig::StartsWithWindowsDriveLetter(const std::string &path)
-{
-       return (path.length() > 2 && isalpha(path[0]) && path[1] == ':');
-}
-
 ConfigTag* ServerConfig::ConfValue(const std::string &tag)
 {
        ConfigTagList found = config_data.equal_range(tag);
@@ -757,18 +752,6 @@ ConfigTagList ServerConfig::ConfTags(const std::string& tag)
        return config_data.equal_range(tag);
 }
 
-bool ServerConfig::FileExists(const char* file)
-{
-       struct stat sb;
-       if (stat(file, &sb) == -1)
-               return false;
-
-       if ((sb.st_mode & S_IFDIR) > 0)
-               return false;
-
-       return !access(file, F_OK);
-}
-
 std::string ServerConfig::Escape(const std::string& str, bool xml)
 {
        std::string escaped;
@@ -793,22 +776,6 @@ std::string ServerConfig::Escape(const std::string& str, bool xml)
        return escaped;
 }
 
-std::string ServerConfig::ExpandPath(const std::string& base, const std::string& fragment)
-{
-       // The fragment is an absolute path, don't modify it.
-       if (fragment[0] == '/' || ServerConfig::StartsWithWindowsDriveLetter(fragment))
-               return fragment;
-
-       return base + '/' + fragment;
-}
-
-const char* ServerConfig::CleanFilename(const char* name)
-{
-       const char* p = name + strlen(name);
-       while ((p != name) && (*p != '/') && (*p != '\\')) p--;
-       return (p != name ? ++p : p);
-}
-
 void ConfigReaderThread::Run()
 {
        Config->Read();
diff --git a/src/fileutils.cpp b/src/fileutils.cpp
new file mode 100644 (file)
index 0000000..ee89cca
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ *   Copyright (C) 2013 Peter Powell <petpow@saberuk.com>
+ *
+ * This file is part of InspIRCd.  InspIRCd 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, version 2.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+
+#include <fstream>
+
+FileReader::FileReader(const std::string& filename)
+{
+       Load(filename);
+}
+
+void FileReader::Load(const std::string& filename)
+{
+       // If the file is stored in the file cache then we used that version instead.
+       std::string realName = ServerInstance->Config->Paths.PrependConfig(filename);
+       ConfigFileCache::iterator it = ServerInstance->Config->Files.find(realName);
+       if (it != ServerInstance->Config->Files.end())
+       {
+               this->lines = it->second;
+       }
+       else
+       {
+               lines.clear();
+
+               std::ifstream stream(realName.c_str());
+               if (!stream.is_open())
+                       throw CoreException(filename + " does not exist or is not readable!");
+
+               std::string line;
+               while (std::getline(stream, line))
+               {
+                       lines.push_back(line);
+                       totalSize += line.size() + 2;
+               }
+
+               stream.close();
+       }
+}
+
+std::string FileReader::GetString() const
+{
+       std::string buffer;
+       for (file_cache::const_iterator it = this->lines.begin(); it != this->lines.end(); ++it)
+       {
+               buffer.append(*it);
+               buffer.append("\r\n");
+       }
+       return buffer;
+}
+
+std::string FileSystem::ExpandPath(const std::string& base, const std::string& fragment)
+{
+       // The fragment is an absolute path, don't modify it.
+       if (fragment[0] == '/' || FileSystem::StartsWithWindowsDriveLetter(fragment))
+               return fragment;
+
+       return base + '/' + fragment;
+}
+
+bool FileSystem::FileExists(const std::string& file)
+{
+       struct stat sb;
+       if (stat(file.c_str(), &sb) == -1)
+               return false;
+
+       if ((sb.st_mode & S_IFDIR) > 0)
+               return false;
+
+       return !access(file.c_str(), F_OK);
+}
+
+std::string FileSystem::GetFileName(const std::string& name)
+{
+#ifdef _WIN32
+       size_t pos = name.find_last_of("\\/");
+#else
+       size_t pos = name.rfind('/');   
+#endif
+       return pos == std::string::npos ? name : name.substr(++pos);
+}
+
+bool FileSystem::StartsWithWindowsDriveLetter(const std::string& path)
+{
+       return (path.length() > 2 && isalpha(path[0]) && path[1] == ':');
+}
index 368ca6e8bd3cdefa4f61f8f9ebfa436639b54cc4..de92872700347dcadb60d03d3d7a6f3d9806a664 100644 (file)
@@ -380,14 +380,14 @@ InspIRCd::InspIRCd(int argc, char** argv) :
                Logs->AddLogTypes("*", fls, true);
        }
 
-       if (!ServerConfig::FileExists(ConfigFileName.c_str()))
+       if (!FileSystem::FileExists(ConfigFileName))
        {
 #ifdef _WIN32
                /* Windows can (and defaults to) hide file extensions, so let's play a bit nice for windows users. */
                std::string txtconf = this->ConfigFileName;
                txtconf.append(".txt");
 
-               if (ServerConfig::FileExists(txtconf.c_str()))
+               if (FileSystem::FileExists(txtconf))
                {
                        ConfigFileName = txtconf;
                }
index de2593d7236e50946fdf87a93718debca05a438c..0d0042cabac0c9e93b6a2a53e9df07caa1f4c3f0 100644 (file)
@@ -39,7 +39,7 @@ bool ModuleManager::Load(const std::string& filename, bool defer)
 
        const std::string moduleFile = ServerInstance->Config->Paths.PrependModule(filename);
 
-       if (!ServerConfig::FileExists(moduleFile.c_str()))
+       if (!FileSystem::FileExists(moduleFile))
        {
                LastModuleError = "Module file could not be found: " + filename;
                ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
index 487bc4ea0cca85d6cae87b12beacf3f9cdd64a4a..92f619743d11f0b640c57539f8eb0765b49b9a8a 100644 (file)
@@ -25,7 +25,6 @@
 
 
 #include <iostream>
-#include <fstream>
 #include "inspircd.h"
 #include "xline.h"
 #include "socket.h"
@@ -708,47 +707,3 @@ Module* ModuleManager::Find(const std::string &name)
        else
                return modfind->second;
 }
-
-FileReader::FileReader(const std::string& filename)
-{
-       Load(filename);
-}
-
-void FileReader::Load(const std::string& filename)
-{
-       // If the file is stored in the file cache then we used that version instead.
-       std::string realName = ServerInstance->Config->Paths.PrependConfig(filename);
-       ConfigFileCache::iterator it = ServerInstance->Config->Files.find(realName);
-       if (it != ServerInstance->Config->Files.end())
-       {
-               this->lines = it->second;
-       }
-       else
-       {
-               lines.clear();
-
-               std::ifstream stream(realName.c_str());
-               if (!stream.is_open())
-                       throw CoreException(filename + " does not exist or is not readable!");
-
-               std::string line;
-               while (std::getline(stream, line))
-               {
-                       lines.push_back(line);
-                       totalSize += line.size() + 2;
-               }
-
-               stream.close();
-       }
-}
-
-std::string FileReader::GetString()
-{
-       std::string buffer;
-       for (file_cache::iterator it = this->lines.begin(); it != this->lines.end(); ++it)
-       {
-               buffer.append(*it);
-               buffer.append("\r\n");
-       }
-       return buffer;
-}
index d482dca2bf047a5333483a598c9b4bcc02373b63..222bbe17bd5020e1022efccd7571767b55d2dfe6 100644 (file)
@@ -156,7 +156,7 @@ class ModuleXLineDB : public Module
        bool ReadDatabase()
        {
                // If the xline database doesn't exist then we don't need to load it.
-               if (!ServerConfig::FileExists(xlinedbpath.c_str()))
+               if (!FileSystem::FileExists(xlinedbpath))
                        return true;
 
                std::ifstream stream(xlinedbpath.c_str());
index 538feaade093e2d1bc2cb36e3eb3c6002b7c97ea..1917606863872e9976836a1a0aca2eef64e340ef 100644 (file)
@@ -337,3 +337,71 @@ bool UserManager::AllModulesReportReady(LocalUser* user)
        FIRST_MOD_RESULT(OnCheckReady, res, (user));
        return (res == MOD_RES_PASSTHRU);
 }
+
+/**
+ * This function is called once a second from the mainloop.
+ * It is intended to do background checking on all the user structs, e.g.
+ * stuff like ping checks, registration timeouts, etc.
+ */
+void UserManager::DoBackgroundUserStuff()
+{
+       /*
+        * loop over all local users..
+        */
+       for (LocalUserList::iterator i = local_users.begin(); i != local_users.end(); ++i)
+       {
+               LocalUser* curr = *i;
+
+               if (curr->quitting)
+                       continue;
+
+               if (curr->CommandFloodPenalty || curr->eh.getSendQSize())
+               {
+                       unsigned int rate = curr->MyClass->GetCommandRate();
+                       if (curr->CommandFloodPenalty > rate)
+                               curr->CommandFloodPenalty -= rate;
+                       else
+                               curr->CommandFloodPenalty = 0;
+                       curr->eh.OnDataReady();
+               }
+
+               switch (curr->registered)
+               {
+                       case REG_ALL:
+                               if (ServerInstance->Time() > curr->nping)
+                               {
+                                       // This user didn't answer the last ping, remove them
+                                       if (!curr->lastping)
+                                       {
+                                               time_t time = ServerInstance->Time() - (curr->nping - curr->MyClass->GetPingTime());
+                                               const std::string message = "Ping timeout: " + ConvToStr(time) + (time == 1 ? " seconds" : " second");
+                                               this->QuitUser(curr, message);
+                                               continue;
+                                       }
+
+                                       curr->Write("PING :" + ServerInstance->Config->ServerName);
+                                       curr->lastping = 0;
+                                       curr->nping = ServerInstance->Time() + curr->MyClass->GetPingTime();
+                               }
+                               break;
+                       case REG_NICKUSER:
+                               if (AllModulesReportReady(curr))
+                               {
+                                       /* User has sent NICK/USER, modules are okay, DNS finished. */
+                                       curr->FullConnect();
+                                       continue;
+                               }
+                               break;
+               }
+
+               if (curr->registered != REG_ALL && (ServerInstance->Time() > (curr->age + curr->MyClass->GetRegTimeout())))
+               {
+                       /*
+                        * registration timeout -- didnt send USER/NICK/HOST
+                        * in the time specified in their connection class.
+                        */
+                       this->QuitUser(curr, "Registration timeout");
+                       continue;
+               }
+       }
+}
diff --git a/src/userprocess.cpp b/src/userprocess.cpp
deleted file mode 100644 (file)
index fe55fb3..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * InspIRCd -- Internet Relay Chat Daemon
- *
- *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- *   Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
- *   Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc>
- *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
- *   Copyright (C) 2006 Craig McLure <craig@chatspike.net>
- *
- * This file is part of InspIRCd.  InspIRCd 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, version 2.
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-
-#include "inspircd.h"
-#include "xline.h"
-#include "socketengine.h"
-#include "command_parse.h"
-
-/**
- * This function is called once a second from the mainloop.
- * It is intended to do background checking on all the user structs, e.g.
- * stuff like ping checks, registration timeouts, etc.
- */
-void UserManager::DoBackgroundUserStuff()
-{
-       /*
-        * loop over all local users..
-        */
-       for (LocalUserList::iterator i = local_users.begin(); i != local_users.end(); ++i)
-       {
-               LocalUser* curr = *i;
-
-               if (curr->quitting)
-                       continue;
-
-               if (curr->CommandFloodPenalty || curr->eh.getSendQSize())
-               {
-                       unsigned int rate = curr->MyClass->GetCommandRate();
-                       if (curr->CommandFloodPenalty > rate)
-                               curr->CommandFloodPenalty -= rate;
-                       else
-                               curr->CommandFloodPenalty = 0;
-                       curr->eh.OnDataReady();
-               }
-
-               switch (curr->registered)
-               {
-                       case REG_ALL:
-                               if (ServerInstance->Time() > curr->nping)
-                               {
-                                       // This user didn't answer the last ping, remove them
-                                       if (!curr->lastping)
-                                       {
-                                               time_t time = ServerInstance->Time() - (curr->nping - curr->MyClass->GetPingTime());
-                                               const std::string message = "Ping timeout: " + ConvToStr(time) + (time == 1 ? " seconds" : " second");
-                                               this->QuitUser(curr, message);
-                                               continue;
-                                       }
-
-                                       curr->Write("PING :" + ServerInstance->Config->ServerName);
-                                       curr->lastping = 0;
-                                       curr->nping = ServerInstance->Time() + curr->MyClass->GetPingTime();
-                               }
-                               break;
-                       case REG_NICKUSER:
-                               if (AllModulesReportReady(curr))
-                               {
-                                       /* User has sent NICK/USER, modules are okay, DNS finished. */
-                                       curr->FullConnect();
-                                       continue;
-                               }
-                               break;
-               }
-
-               if (curr->registered != REG_ALL && (ServerInstance->Time() > (curr->age + curr->MyClass->GetRegTimeout())))
-               {
-                       /*
-                        * registration timeout -- didnt send USER/NICK/HOST
-                        * in the time specified in their connection class.
-                        */
-                       this->QuitUser(curr, "Registration timeout");
-                       continue;
-               }
-       }
-}